Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenvanassche committed Oct 4, 2024
1 parent 83e64a3 commit b65bfc0
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 31 deletions.
10 changes: 4 additions & 6 deletions config/data.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<?php

use Illuminate\Support\Enumerable;
use Spatie\LaravelData\Mappers\NameMapper;

return [
/**
* The package will use this format when working with dates. If this option
Expand Down Expand Up @@ -130,10 +127,11 @@
'validation_strategy' => \Spatie\LaravelData\Support\Creation\ValidationStrategy::OnlyRequests->value,

/**
* The default name mapping strategy for data objects' keys.
* This has to be a class implementing the `Spatie\LaravelData\Mappers\NameMapper` interface.
* A data object can map the names of its properties when transforming (output) or when
* creating (input). By default, the package will not map any names. You can set a
* global strategy here, or override it on a specific data object.
*/
'naming_strategy' => [
'name_mapping_strategy' => [
'input' => null,
'output' => null,
],
Expand Down
9 changes: 9 additions & 0 deletions docs/as-a-data-transfer-object/mapping-property-names.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ class ContractData extends Data
}
```

It is possible to set a default name mapping strategy for all data objects in the `data.php` config file:

```php
'name_mapping_strategy' => [
'input' => SnakeCaseMapper::class,
'output' => null,
],
```


## Mapping Nested Properties

Expand Down
9 changes: 9 additions & 0 deletions docs/as-a-resource/mapping-property-names.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ class ContractData extends Data
}
```

It is possible to set a default name mapping strategy for all data objects in the `data.php` config file:

```php
'name_mapping_strategy' => [
'input' => null,
'output' => SnakeCaseMapper::class,
],
```

You can now create a data object as such:

```php
Expand Down
96 changes: 94 additions & 2 deletions docs/installation-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ php artisan vendor:publish --provider="Spatie\LaravelData\LaravelDataServiceProv
This is the contents of the published config file:

```php

return [
/**
* The package will use this format when working with dates. If this option
Expand All @@ -26,6 +27,29 @@ return [
*/
'date_format' => DATE_ATOM,

/**
* When transforming or casting dates, the following timezone will be used to
* convert the date to the correct timezone. If set to null no timezone will
* be passed.
*/
'date_timezone' => null,

/**
* It is possible to enable certain features of the package, these would otherwise
* be breaking changes, and thus they are disabled by default. In the next major
* version of the package, these features will be enabled by default.
*/
'features' => [
'cast_and_transform_iterables' => false,

/**
* When trying to set a computed property value, the package will throw an exception.
* You can disable this behaviour by setting this option to true, which will then just
* ignore the value being passed into the computed property and recalculate it.
*/
'ignore_exception_when_trying_to_set_computed_property_value' => false,
],

/**
* Global transformers will take complex types and transform them into simple
* types.
Expand All @@ -43,6 +67,7 @@ return [
'casts' => [
DateTimeInterface::class => Spatie\LaravelData\Casts\DateTimeInterfaceCast::class,
BackedEnum::class => Spatie\LaravelData\Casts\EnumCast::class,
// Enumerable::class => Spatie\LaravelData\Casts\EnumerableCast::class,
],

/**
Expand Down Expand Up @@ -92,13 +117,19 @@ return [
* when running in production. This will speed up the package. You
* can configure where data objects are stored and which cache
* store should be used.
*
* Structures are cached forever as they'll become stale when your
* application is deployed with changes. You can set a duration
* in seconds if you want the cache to clear after a certain
* timeframe.
*/
'structure_caching' => [
'enabled' => true,
'directories' => [app_path('Data')],
'cache' => [
'store' => env('CACHE_STORE', 'file'),
'store' => env('CACHE_STORE', env('CACHE_DRIVER', 'file')),
'prefix' => 'laravel-data',
'duration' => null,
],
'reflection_discovery' => [
'enabled' => true,
Expand All @@ -114,10 +145,71 @@ return [
*/
'validation_strategy' => \Spatie\LaravelData\Support\Creation\ValidationStrategy::OnlyRequests->value,

/**
* A data object can map the names of its properties when transforming (output) or when
* creating (input). By default, the package will not map any names. You can set a
* global strategy here, or override it on a specific data object.
*/
'name_mapping_strategy' => [
'input' => null,
'output' => null,
],

/**
* When using an invalid include, exclude, only or except partial, the package will
* throw an
* throw an exception. You can disable this behaviour by setting this option to true.
*/
'ignore_invalid_partials' => false,

/**
* When transforming a nested chain of data objects, the package can end up in an infinite
* loop when including a recursive relationship. The max transformation depth can be
* set as a safety measure to prevent this from happening. When set to null, the
* package will not enforce a maximum depth.
*/
'max_transformation_depth' => null,

/**
* When the maximum transformation depth is reached, the package will throw an exception.
* You can disable this behaviour by setting this option to true which will return an
* empty array.
*/
'throw_when_max_transformation_depth_reached' => true,

/**
* When using the `make:data` command, the package will use these settings to generate
* the data classes. You can override these settings by passing options to the command.
*/
'commands' => [
/**
* Provides default configuration for the `make:data` command. These settings can be overridden with options
* passed directly to the `make:data` command for generating single Data classes, or if not set they will
* automatically fall back to these defaults. See `php artisan make:data --help` for more information
*/
'make' => [
/**
* The default namespace for generated Data classes. This exists under the application's root namespace,
* so the default 'Data` will end up as '\App\Data', and generated Data classes will be placed in the
* app/Data/ folder. Data classes can live anywhere, but this is where `make:data` will put them.
*/
'namespace' => 'Data',

/**
* This suffix will be appended to all data classes generated by make:data, so that they are less likely
* to conflict with other related classes, controllers or models with a similar name without resorting
* to adding an alias for the Data object. Set to a blank string (not null) to disable.
*/
'suffix' => 'Data',
],
],

/**
* When using Livewire, the package allows you to enable or disable the synths
* these synths will automatically handle the data objects and their
* properties when used in a Livewire component.
*/
'livewire' => [
'enable_synths' => false,
],
];
```
28 changes: 11 additions & 17 deletions src/Resolvers/NameMappersResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,29 @@ public function execute(
protected function resolveInputNameMapper(
Collection $attributes
): ?NameMapper {
/** @var \Spatie\LaravelData\Attributes\MapInputName|\Spatie\LaravelData\Attributes\MapName|null $mapper */
/** @var MapInputName|MapName|null $mapper */
$mapper = $attributes->first(fn (object $attribute) => $attribute instanceof MapInputName)
?? $attributes->first(fn (object $attribute) => $attribute instanceof MapName)
?? $this->resolveDefaultNameMapper(input: true);
?? $attributes->first(fn (object $attribute) => $attribute instanceof MapName);

if ($mapper) {
return $this->resolveMapper($mapper->input);
}

return null;
return $this->resolveDefaultNameMapper(config('data.name_mapping_strategy.input'));
}

protected function resolveOutputNameMapper(
Collection $attributes
): ?NameMapper {
/** @var \Spatie\LaravelData\Attributes\MapOutputName|\Spatie\LaravelData\Attributes\MapName|null $mapper */
/** @var MapOutputName|MapName|null $mapper */
$mapper = $attributes->first(fn (object $attribute) => $attribute instanceof MapOutputName)
?? $attributes->first(fn (object $attribute) => $attribute instanceof MapName)
?? $this->resolveDefaultNameMapper(input: false);
?? $attributes->first(fn (object $attribute) => $attribute instanceof MapName);

if ($mapper) {
return $this->resolveMapper($mapper->output);
}

return null;
return $this->resolveDefaultNameMapper(config('data.name_mapping_strategy.output'));
}

protected function resolveMapper(string|int|NameMapper $value): ?NameMapper
Expand Down Expand Up @@ -89,17 +87,13 @@ protected function resolveMapperClass(int|string|NameMapper $value): NameMapper
return new ProvidedNameMapper($value);
}

private function resolveDefaultNameMapper(bool $input): null|MapInputName|MapOutputName
{
$nameMapper = $input ? config('data.naming_strategy.input') : config('data.naming_strategy.output');

if ($nameMapper === null) {
protected function resolveDefaultNameMapper(
?string $value,
): ?NameMapper {
if ($value === null) {
return null;
}

return match ($input) {
true => new MapInputName($nameMapper),
false => new MapOutputName($nameMapper),
};
return $this->resolveMapperClass($value);
}
}
12 changes: 6 additions & 6 deletions tests/Resolvers/NameMappersResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ function getAttributes(object $class): Collection
});

it('can have default mappers', function () {
config()->set('data.naming_strategy.input', CamelCaseMapper::class);
config()->set('data.naming_strategy.output', SnakeCaseMapper::class);
config()->set('data.name_mapping_strategy.input', CamelCaseMapper::class);
config()->set('data.name_mapping_strategy.output', SnakeCaseMapper::class);

$attributes = getAttributes(new class () {
public $property;
Expand All @@ -118,8 +118,8 @@ function getAttributes(object $class): Collection
});

it('input name mappers only work when no mappers are specified', function () {
config()->set('data.naming_strategy.input', CamelCaseMapper::class);
config()->set('data.naming_strategy.output', SnakeCaseMapper::class);
config()->set('data.name_mapping_strategy.input', CamelCaseMapper::class);
config()->set('data.name_mapping_strategy.output', SnakeCaseMapper::class);

$attributes = getAttributes(new class () {
#[MapInputName(StudlyCaseMapper::class)]
Expand All @@ -133,8 +133,8 @@ function getAttributes(object $class): Collection
});

it('output name mappers only work when no mappers are specified', function () {
config()->set('data.naming_strategy.input', CamelCaseMapper::class);
config()->set('data.naming_strategy.output', SnakeCaseMapper::class);
config()->set('data.name_mapping_strategy.input', CamelCaseMapper::class);
config()->set('data.name_mapping_strategy.output', SnakeCaseMapper::class);

$attributes = getAttributes(new class () {
#[MapOutputName(StudlyCaseMapper::class)]
Expand Down

0 comments on commit b65bfc0

Please sign in to comment.