Skip to content

Commit 99b7df5

Browse files
authored
Feature: Replace the old denormalizer-dependencies feature with a backwards compatible method-dependencies feature, that can be used on constructors, factories, normalizers and denormalizers. (#20)
1 parent 4249823 commit 99b7df5

31 files changed

+653
-153
lines changed

docs/VOM.md

Lines changed: 127 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ The Versatile Object Mapper - or in short VOM - is a PHP library to transform an
3232
* [Constructor Property Promotion](#constructor-property-promotion)
3333
* [Factory Methods](#factory-methods)
3434
+ [Factory in another class](#factory-in-another-class)
35-
* [Method Calls](#method-calls)
36-
+ [Denormalizer Methods](#denormalizer-methods)
37-
- [Denormalizer Dependencies](#denormalizer-dependencies)
38-
+ [Normalizer Methods](#normalizer-methods)
35+
* [Denormalizer Methods](#denormalizer-methods)
36+
* [Normalizer Methods](#normalizer-methods)
37+
* [Custom serialization](#custom-serialization)
38+
* [Method Dependencies](#method-dependencies)
3939
* [Disable Nesting](#disable-nesting)
4040
* [Root flag](#root-flag)
4141
* [Collections](#collections)
@@ -50,6 +50,7 @@ The Versatile Object Mapper - or in short VOM - is a PHP library to transform an
5050
+ [Booleans](#booleans)
5151
+ [DateTime](#datetime)
5252
* [Value Map](#value-map)
53+
* [Scenarios](#scenarios)
5354
* [Regular Expression Extractors](#regular-expression-extractors)
5455
- [Interfaces and Abstract Classes](#interfaces-and-abstract-classes)
5556
- [Context](#context)
@@ -470,9 +471,7 @@ class RepositoryWithFactory
470471
}
471472
```
472473

473-
### Method Calls
474-
475-
#### Denormalizer Methods
474+
### Denormalizer Methods
476475

477476
If your models don't follow the symfony conventions for mutators, VOM can call custom methods with arguments.
478477
It will query the source data using the argument accessor (the same way as for VOM\Property) and call the method.
@@ -554,58 +553,6 @@ class Calls
554553
$objectMapper->denormalize($data, Calls:class, context: ['groups' => ['one']]);
555554
```
556555

557-
##### Denormalizer Dependencies
558-
559-
If you need any dependencies in addition to the source data to be mapped, it is possible to inject any object (like a symfony service) into the denormalizer methods.
560-
To do so, just typehint the dependency in the denormalizer method along with the VOM arguments. Additionally, you need to register the dependency.
561-
562-
```php
563-
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
564-
use Zolex\VOM\Mapping as VOM;
565-
566-
#[VOM\Model]
567-
class DenormalizerDependency
568-
{
569-
public string $var;
570-
571-
#[VOM\Denormalizer]
572-
public function denormalizeData(
573-
ParameterBagInterface $parameterBag,
574-
#[VOM\Argument(...)]
575-
int $something,
576-
#[VOM\Argument(...)]
577-
string $else
578-
): void {
579-
$this->var = $parameterBag->get('foo') ? $something ? $else;
580-
}
581-
}
582-
```
583-
584-
To register the dependency in symfony framework, you can simply add any symfony service by adding it to the package config:
585-
586-
_config/packages/zolex_vom.yaml_
587-
```yaml
588-
zolex_vom:
589-
denormalizer:
590-
dependencies:
591-
- '@parameter_bag'
592-
- '@serializer'
593-
```
594-
595-
Without symfony, you simply call the respective method on the `ModelMetadataFactory`
596-
597-
```php
598-
$factory = new \Zolex\VOM\Metadata\Factory\ModelMetadataFactory(/*...*/);
599-
$factory->injectDenormalizerDependency(new \Some\Dependency());
600-
```
601-
602-
If you are using the `VersatileObjectMapperFactory` you can pass the dependencies to the `create` method.
603-
604-
```php
605-
$vom = VersatileObjectMapperFactory::create(null, [new DependencyA(), new DependencyB()]);
606-
```
607-
608-
609556
##### Non-Scalar Denormalizer Arguments
610557

611558
To prevent unnecessary usage of denormalizers when dealing with arrays, the denormalizer methods only accept scalar arguments by default.
@@ -635,7 +582,7 @@ class BadHabits
635582
}
636583
```
637584

638-
#### Normalizer Methods
585+
### Normalizer Methods
639586

640587
Similar to the denormalizer methods, also normalizer methods can be configured to be called during normalization. These methods must not have any required arguments.
641588
Normalizer methods must be prefixed with `get`, `has`, `is` or `normalize`. Groups can be added on normalizer methods with the first three prefixes (virtual property) or on the related property when using the `normalize` prefix.
@@ -677,7 +624,7 @@ class Calls
677624
}
678625
```
679626

680-
##### Custom serialization
627+
### Custom serialization
681628

682629
The normalizer attribute can be added on the `__toString()` method. Note that in this case it must be the only normalizer on the model and return a string representation of the object.
683630

@@ -740,6 +687,125 @@ class Calls
740687
}
741688
```
742689

690+
### Method Dependencies
691+
692+
If you need any dependencies in addition to the source data to be mapped, it is possible to inject any object (like a symfony service) into methods.
693+
To do so, just typehint the dependency in the method along with the VOM arguments. All dependencies must be explicitly registered.
694+
In symfony framework, you can simply add any symfony service by adding it to the package config:
695+
696+
_config/packages/zolex_vom.yaml_
697+
```yaml
698+
zolex_vom:
699+
method_dependencies:
700+
- '@parameter_bag'
701+
```
702+
703+
Without symfony, you simply call the respective method on the `ModelMetadataFactory`
704+
705+
```php
706+
$factory = new \Zolex\VOM\Metadata\Factory\ModelMetadataFactory(/*...*/);
707+
$factory->injectMethodDependency(new \Some\Dependency());
708+
```
709+
710+
If you are using the `VersatileObjectMapperFactory` you can pass the dependencies to the `create` method.
711+
712+
```php
713+
$vom = VersatileObjectMapperFactory::create(null, [new DependencyA(), new DependencyB()]);
714+
```
715+
716+
**Constructor Dependency**
717+
718+
```php
719+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
720+
use Zolex\VOM\Mapping as VOM;
721+
722+
#[VOM\Model]
723+
class ConstructorDependency
724+
{
725+
private string $foobar;
726+
727+
public function __construct(
728+
#[VOM\Argument]
729+
int $something,
730+
ParameterBagInterface $parameterBag,
731+
#[VOM\Argument]
732+
string $else
733+
): self {
734+
$this->foobar = $parameterBag->get('foobar');
735+
}
736+
}
737+
```
738+
739+
**Normalizer Dependency**
740+
741+
```php
742+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
743+
use Zolex\VOM\Mapping as VOM;
744+
745+
#[VOM\Model]
746+
class NormalizerDependency
747+
{
748+
#[VOM\Normalizer]
749+
public function getData(
750+
#[VOM\Argument]
751+
int $something,
752+
ParameterBagInterface $parameterBag,
753+
#[VOM\Argument]
754+
string $else
755+
): array {
756+
return [
757+
'foo' => $parameterBag->get('foo')
758+
];
759+
}
760+
}
761+
```
762+
763+
**Denormalizer Dependency**
764+
765+
```php
766+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
767+
use Zolex\VOM\Mapping as VOM;
768+
769+
#[VOM\Model]
770+
class DenormalizerDependency
771+
{
772+
public string $var;
773+
774+
#[VOM\Denormalizer]
775+
public function denormalizeData(
776+
#[VOM\Argument]
777+
int $something,
778+
ParameterBagInterface $parameterBag,
779+
#[VOM\Argument]
780+
string $else
781+
): void {
782+
$this->var = $parameterBag->get('foo') ? $something ? $else;
783+
}
784+
}
785+
```
786+
787+
**Factory Dependency**
788+
789+
```php
790+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
791+
use Zolex\VOM\Mapping as VOM;
792+
793+
#[VOM\Model]
794+
class NormalizerDependency
795+
{
796+
#[VOM\Factory]
797+
public static function create(
798+
#[VOM\Argument]
799+
int $something,
800+
ParameterBagInterface $parameterBag,
801+
#[VOM\Argument]
802+
string $else
803+
): self {
804+
return new self($parameterBag->get('foo'));
805+
}
806+
}
807+
```
808+
743809
### Disable Nesting
744810

745811
The data structures can be as deeply nested as you want. By default, nesting is enabled. That is when no accessor is given or the accessor is symfony property access syntax.

phpunit.xml.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<directory>tests</directory>
2424
</testsuite>
2525
</testsuites>
26-
<source>
26+
<source ignoreSuppressionOfDeprecations="true">
2727
<include>
2828
<directory suffix=".php">src</directory>
2929
</include>

src/Mapping/Normalizer.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313

1414
namespace Zolex\VOM\Mapping;
1515

16+
use Zolex\VOM\Metadata\ModelMetadata;
17+
1618
#[\Attribute(\Attribute::TARGET_METHOD)]
1719
final class Normalizer
1820
{
1921
public function __construct(
2022
private readonly ?string $accessor = null,
21-
private readonly ?string $scenario = null,
23+
private readonly ?string $scenario = ModelMetadata::DEFAULT_SCENARIO,
2224
) {
2325
}
2426

src/Metadata/DenormalizerMetadata.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ class DenormalizerMetadata extends AbstractCallableMetadata
1818
public function __construct(
1919
string $class,
2020
string $method,
21-
/* @var array|ArgumentMetadata[] $arguments */
22-
array $arguments,
23-
private readonly string $virtualPropertyName,
21+
/* @var array|ArgumentMetadata[][] $arguments */
22+
array $arguments = [],
23+
private readonly ?string $virtualPropertyName = null,
2424
) {
2525
parent::__construct($class, $method, $arguments);
2626
}
2727

28-
public function getPropertyName(): string
28+
public function getPropertyName(): ?string
2929
{
3030
return $this->virtualPropertyName;
3131
}

0 commit comments

Comments
 (0)