Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default withMermaid(defineVersionedConfig({
description: "Immutable Value Objects for PHP 8.3+",
base: BASE_PATH,
versioning: {
latestVersion: '2.6',
latestVersion: '2.7',
},
head: [
[
Expand Down Expand Up @@ -75,6 +75,54 @@ export default withMermaid(defineVersionedConfig({

sidebar: {
"/": [
{
"text": "Get Started",
"items": [
{"text": "Installation", "link": "/install"},
{"text": "Basic Usage", "link": "/basic-usage"}
]
},
{
"text": "Using Bag",
"items": [
{"text": "Collections", "link": "/collections"},
{"text": "Casting Values", "link": "/casting"},
{"text": "Mapping", "link": "/mapping"},
{"text": "Variadics", "link": "/variadics"},
{"text": "Hiding Properties", "link": "/hidden"},
{"text": "Transformers", "link": "/transformers"},
{"text": "Optionals", "link": "/optionals"},
{"text": "Validation", "link": "/validation"},
{"text": "Computed Properties", "link": "/computed-properties"},
{"text": "Output", "link": "/output"},
{"text": "Wrapping", "link": "/wrapping"},
{"text": "Factories / Testing", "link": "/testing"},
{"text": "TypeScript", "link": "/typescript"},
{"text": "Memoization", link: "/memoization"}
]
},
{
"text": "Laravel Integration",
"items": [
{"text": "Controller Injection", "link": "/laravel-controller-injection"},
{"text": "Route Parameter Binding", "link": "/laravel-route-parameter-binding"},
{"text": "Eloquent Casting", "link": "/laravel-eloquent-casting"},
{"text": "Generating Bag Classes", "link": "/laravel-artisan-make-bag-command"},
{"text": "Laravel Debugbar Integration", "link": "/laravel-debugbar"}
]
},
{
"text": "Other",
"items": [
{"text": "Creating Bags from Objects", "link": "/object-to-bag"},
{"text": "Why Bag?", "link": "/why"},
{"text": "How Bag Works", "link": "/how-bag-works"},
]
},
{"text": "What's New", "link": "/whats-new"},
{"text": "Upgrading to Bag 2", "link": "/upgrading"}
],
"2.6": [
{
"text": "Get Started",
"items": [
Expand Down
50 changes: 50 additions & 0 deletions docs/memoization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Memoization

If you find yourself creating the same value objects multiple times (e.g. related models for an Eloquent collection), you can use the `Bag::memoize()` or `Bag::memoizeUsing()` methods to cache the created value objects in memory.

> [!NOTE]
> Memoization is only done in memory, and will not be persisted e.g. across requests.

## Using `Bag::memoize()`

To use `Bag::memoize()` you must first add the `Bag\Attributes\MemoizeUsing` attribute to your value class:

```php
use Bag\Attributes\MemoizeUsing;
use Bag\Bag;

#[MemoizeUsing('id')]
readonly class MyValue extends Bag
{
public function __construct(
public int $id,
public string $name,
) {}
}
```

You may specify one or more properties (as an array) to use as the cache key.

Once you have added the attribute, you can use the `Bag::memoize()` method to create or retrieve a cached instance of the value object:

```php
$value1 = MyValue::memoize(id: 1, name: 'Davey Shafik');
$value2 = MyValue::memoize(id: 1, name: 'Not Davey Shafik');

$value1 === $value2; // true
```

In the above example, the second call to `MyValue::memoize()` returns the same instance as the first call, because the `id` property is used as the cache key.

## Using `Bag::memoizeUsing()`

If you need more control over the cache key, you can use the `Bag::memoizeUsing()` method instead. This method allows you to specify the properties to use as the cache key at the time of calling the method.

This will override the `#[MemoizeUsing]` attribute if it is present.

```php
$value1 = MyValue::memoizeUsing('id', id: 1, name: 'Davey Shafik');
$value2 = MyValue::memoizeUsing(['id'], id: 1, name: 'Not Davey Shafik');

$value1 === $value2; // true
```
164 changes: 164 additions & 0 deletions docs/versions/2.6/basic-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Basic Usage

## Creating a Value Object

To create a new Value Object, extend the `Bag\Bag` class and define your properties in the constructor:

```php
use Bag\Bag;

readonly class MyValue extends Bag {
public function __construct(
public string $name,
public int $age,
) {
}
}
```

> [!TIP]
> You can add an `@method` annotation to your class to provide auto-complete for the `::from()` method, or use the [Artisan Command with the --doc option](laravel-artisan-make-bag-command.md#updating-documentation) to generate it for you.


## Instantiating a Value Object

To create a new instance of your Value Object, call the `::from()` method. You can use an array, a Collection, named arguments, or positional arguments.


### Named Arguments

```php
$value = MyValue::from(
name: 'Davey Shafik',
age: => 40,
);
```

### Array or Collection of Arguments

```php
$value = MyValue::from([
'name' => 'Davey Shafik',
'age' => 40,
]);
```

or:

```php
$value = MyValue::from(collect([
'name' => 'Davey Shafik',
'age' => 40,
]));
```

### Positional Arguments

```php
$value = MyValue::from('Davey Shafik', 40);
```

> [!WARNING]
> If you use positional arguments, you must ensure they are in the same order as the constructor.

> [!WARNING]
> If you have a single array argument, **and** an array [transformer](./transformers), the transformer will be applied to the array, potentially causing unwanted side-effects.

## Type Casting

If the input value matches the type of the property (including [union types](https://www.php.net/manual/en/language.types.type-system.php#language.types.type-system.composite.union)), it will be used as-is. Otherwise, Bag will cast all values to their defined type _automatically_ for all scalar types, as well as the following:

- `Bag` objects
- `\Bag\Collection` and `\Illuminate\Support\Collection` objects
- `\DateTimeInterface` objects will be cast using standard [PHP Date/Time formats](https://www.php.net/manual/en/datetime.formats.php)
- This includes `\DateTime`, `\DateTimeImmutable`, `\Carbon\Carbon` and `\Carbon\CarbonImmutable`
- Enums

> [!TIP]
> We recommend using `\Carbon\CarbonImmutable` for all date times.

## Default Values

You can define default values for your properties by setting them in the constructor:

```php
use Bag\Bag;

readonly class MyValue extends Bag {
public function __construct(
public string $name,
public int $age = 40,
) {
}
}

$value = MyValue::from([
'name' => 'Davey Shafik',
])->toArray(); // ['name' => 'Davey Shafik', 'age' => 40]
```

## Nullable Values

Bag will fill missing nullable values without a default value with `null`:

```php
use Bag\Bag;

readonly class MyValue extends Bag {
public function __construct(
public string $name,
public ?int $age,
) {
}
}

$value = MyValue::from([
'name' => 'Davey Shafik',
])->toArray(); // ['name' => 'Davey Shafik', 'age' => null]
```

## Stripping Extra Parameters

By default, Bag will throw a `\Bag\Exceptions\AdditionalPropertiesException` exception if you try to instantiate a non-variadic Bag with extra parameters. You can disable this behavior by adding the `StripExtraParameters` attribute to the class:

```php
use Bag\Attributes\StripExtraParameters;
use Bag\Bag;

#[StripExtraParameters]
readonly class MyValue extends Bag {
public function __construct(
public string $name,
public ?int $age,
) {
}
}

$value = MyValue::from([
'name' => 'Davey Shafik',
'test' => true,
])->toArray(); // [ 'name' => 'Davey Shafik', 'age' => null ] (note that 'test' is stripped)
```

> [!TIP]
> You can also use the `StripExtraParameters` attribute when [injecting a Bag object into a controller](./laravel-controller-injection.md#avoiding-extra-parameters).

### Modifying a Value Object

Value Objects are immutable, so you cannot change their properties directly. Instead, you can create a new instance with the updated values using the `Bag->with()` or `Bag->append()` methods:

```php
$value = MyValue::from([
'name' => 'Davey Shafik',
'age' => 40,
]);

$newValue = $value->with(age: 41);

dump($newValue->toArray()); // ['name' => 'Davey Shafik', 'age' => 41]
```

You can pass either named arguments, or an array or Collection of key-value pairs to the `Bag->with()` method.

> [!TIP]
> The `Bag->append()` method works the same way as `Bag->with()`, but it will not validate the new value object. You can manually validate the object using `Bag->valid()`.
Loading