Skip to content

Commit

Permalink
Merge pull request #18 from liip/group-without-version
Browse files Browse the repository at this point in the history
improve configuration for serializing versions and groups
  • Loading branch information
ChristianRiesen authored Jul 7, 2020
2 parents 06c9f2b + d147760 commit d4b4bd4
Show file tree
Hide file tree
Showing 9 changed files with 339 additions and 62 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

# 2.0.0

* [BC Break]: Configuration of the serializer generator changed to configuration model.
The new format allows to more precisely specify which serializers to generate.

# 1.0.0

Initial release
57 changes: 44 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,28 @@ use Liip\Serializer\SerializerGenerator;
use Liip\Serializer\Template\Deserialization;
use Liip\Serializer\Template\Serialization;


$classMetaData = [
Product::class => [
['api'],
['api', 'product-details'],
],
User::class => [
['api'],
],
];

$versions = ['1', '2', '4'];
$configuration = GeneratorConfiguration::createFomArray([
'default_group_combinations' => ['api'],
'default_versions' => ['', '1', '2'],
'classes' => [
Product::class => [
'default_versions' => ['1', '2'], // optional, falls back to global list
'group_combinations' => [ // optional, falls back to global default_group_combinations
[
'groups' => [], // generate without groups
],
[
'groups' => ['api'], // global groups are overwritten, not merged. versions are taken from class default
],
[
'groups' => ['api', 'detail'],
'versions' => ['2'], // only generate the combination of api and detail for version 2
],
],
],
Other::class => [], // generate this class with default groups and versions
]
]);

$parsers = [
new ReflectionParser(),
Expand All @@ -66,12 +76,33 @@ $parsers = [
];
$builder = new Builder(new Parser($parsers), new RecursionChecker(null, []));

$serializerGenerator = new SerializerGenerator( new Serialization(), $versions, $classMetaData, $cacheDirectory);
$serializerGenerator = new SerializerGenerator( new Serialization(), $configuration, $cacheDirectory);
$deserializerGenerator = new DeserializerGenerator(new Deserialization(), [Product::class, User::class], $cacheDirectory);
$serializerGenerator->generate($builder);
$deserializerGenerator->generate($builder);
```

### Configuration format

Specify global defaults for the versions to be generated, and the group
combinations.

Then specify for which classes to generate the serializer and deserializer.

For each class, you can overwrite which versions to generate. If you specify
no group combinations, the global default group combinations are used. If you
specify group combinations, you can again overwrite the versions to generate.

Note that defaults are not merged - the most specific list is used exclusively.

#### Version

To generate a file without version, specify version `''` in the list of versions.

#### Groups

To generate a serializer without groups, specify an empty group combination `[]`.

## Serialize using the generated code
In this example, we serialize an object of class `Product` for version 2:

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "2.x-dev"
}
},
"config": {
Expand Down
73 changes: 73 additions & 0 deletions src/Configuration/ClassToGenerate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

declare(strict_types=1);

namespace Liip\Serializer\Configuration;

class ClassToGenerate implements \IteratorAggregate
{
/**
* @var GeneratorConfiguration
*/
private $configuration;

/**
* A list of group combinations, potentially with a version overwrite.
*
* @see GroupCombination::$groups
*
* @var GroupCombination[]
*/
private $groupCombinations = [];

/**
* Fully qualified class name.
*
* @var string
*/
private $className;

/**
* Overwrite global default list of versions to generate.
*
* @see GroupCombination::$versions
*
* @var string[]|null
*/
private $defaultVersions;

public function __construct(GeneratorConfiguration $configuration, string $className, ?array $defaultVersions = null)
{
$this->configuration = $configuration;
$this->className = $className;
$this->defaultVersions = null === $defaultVersions ? null : array_map('strval', $defaultVersions);
}

public function getClassName(): string
{
return $this->className;
}

public function getDefaultVersions(): array
{
if (null !== $this->defaultVersions) {
return $this->defaultVersions;
}

return $this->configuration->getDefaultVersions();
}

public function addGroupCombination(GroupCombination $groupCombination): void
{
$this->groupCombinations[] = $groupCombination;
}

public function getIterator()
{
if ($this->groupCombinations) {
return new \ArrayIterator($this->groupCombinations);
}

return new \ArrayIterator($this->configuration->getDefaultGroupCombinations($this));
}
}
114 changes: 114 additions & 0 deletions src/Configuration/GeneratorConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

declare(strict_types=1);

namespace Liip\Serializer\Configuration;

/**
* Configuration for the serializer generator.
*
* The configuration has a list of default group combinations, a list of
* default versions, and a list of classes. For each class, you can overwrite
* the group combinations. For each group combination, you can again overwrite
* the versions to generate.
*/
class GeneratorConfiguration implements \IteratorAggregate
{
/**
* A list of group combinations.
*
* @see GroupCombination::$groups
*
* @var string[][]
*/
private $defaultGroupCombinations;

/**
* List of versions to generate. An empty string '' means to generate without a version.
* e.g. ['', '2', '3']
*
* @var string[]
*/
private $defaultVersions;

/**
* @var ClassToGenerate[]
*/
private $classesToGenerate = [];

public function __construct(array $defaultGroupCombinations, array $defaultVersions)
{
$this->defaultGroupCombinations = $defaultGroupCombinations ?: [[]];
$this->defaultVersions = array_map('strval', $defaultVersions) ?: [''];
}

/**
* Create configuration from array definition
*
* [
* 'default_group_combinations' => ['api'],
* 'default_versions' => ['', '1', '2'],
* 'classes' => [
* Product::class => [
* 'default_versions' => ['1', '2'], // optional, falls back to global list
* 'group_combinations' => [ // optional, falls back to global default_group_combinations
* [
* 'groups' => [], // generate without groups
* ],
* [
* 'groups' => ['api'], // global groups are overwritten, not merged. versions are taken from class default
* ],
* [
* 'groups' => ['api', 'detail'],
* 'versions' => ['2'], // only generate the combination of api and detail for version 2
* ],
* ],
* ],
* Other::class => [], // generate this class with default groups and versions
* ]
* ]
*/
public static function createFomArray(array $config): self
{
if (!\array_key_exists('classes', $config) || \count($config['classes']) < 1) {
throw new \InvalidArgumentException('You need to specify the classes to generate');
}
$instance = new self($config['default_group_combinations'] ?? [], $config['default_versions'] ?? []);
foreach ($config['classes'] as $className => $classConfig) {
$classToGenerate = new ClassToGenerate($instance, $className, $classConfig['default_versions'] ?? null);
foreach ($classConfig['group_combinations'] ?? [] as $groupCombination) {
$classToGenerate->addGroupCombination(
new GroupCombination($classToGenerate, $groupCombination['groups'], $groupCombination['versions'] ?? null)
);
}
$instance->addClassToGenerate($classToGenerate);
}

return $instance;
}

public function addClassToGenerate(ClassToGenerate $classToGenerate): void
{
$this->classesToGenerate[] = $classToGenerate;
}

/**
* @return string[]
*/
public function getDefaultVersions(): array
{
return $this->defaultVersions;
}

public function getDefaultGroupCombinations(ClassToGenerate $classToGenerate): array
{
return array_map(static function (array $combination) use ($classToGenerate) {
return new GroupCombination($classToGenerate, $combination);
}, $this->defaultGroupCombinations);
}

public function getIterator()
{
return new \ArrayIterator($this->classesToGenerate);
}
}
66 changes: 66 additions & 0 deletions src/Configuration/GroupCombination.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace Liip\Serializer\Configuration;

class GroupCombination
{
/**
* @var ClassToGenerate
*/
private $containingClass;

/**
* One combination of groups to generate.
*
* An empty array means to generate with no groups.
* e.g. ['api', 'details'].
*
* @var string[]
*/
private $groups;

/**
* List of versions to generate.
*
* An empty string '' means to generate without a version.
* e.g. ['', '2', '3']
*
* If not specified, this falls back to the class default.
* If the array is not null, it must have a length > 0.
*
* @var string[]|null
*/
private $versions;

public function __construct(ClassToGenerate $containingClass, array $groups, ?array $versions = null)
{
$this->containingClass = $containingClass;
$this->groups = $groups;
if (null !== $versions && 0 === \count($versions)) {
throw new \InvalidArgumentException('Version list may not be empty. To generate without version, specify an empty string. To use the default versions, pass null.');
}
$this->versions = $versions;
}

/**
* @return string[]
*/
public function getGroups(): array
{
return $this->groups;
}

/**
* @return string[]
*/
public function getVersions(): array
{
if (null !== $this->versions) {
return $this->versions;
}

return $this->containingClass->getDefaultVersions();
}
}
Loading

0 comments on commit d4b4bd4

Please sign in to comment.