Skip to content

Commit

Permalink
feat(EntityGenerator): Entity generator uses DefaultValuesResolverInt…
Browse files Browse the repository at this point in the history
…erface to compute required ENUM fields length acording to their default values.
  • Loading branch information
ambroisemaupate committed Mar 23, 2023
1 parent db82ebf commit 20263b6
Show file tree
Hide file tree
Showing 26 changed files with 513 additions and 85 deletions.
40 changes: 21 additions & 19 deletions lib/EntityGenerator/src/EntityGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use RZ\Roadiz\EntityGenerator\Field\AbstractFieldGenerator;
use RZ\Roadiz\EntityGenerator\Field\CollectionFieldGenerator;
use RZ\Roadiz\EntityGenerator\Field\CustomFormsFieldGenerator;
use RZ\Roadiz\EntityGenerator\Field\DefaultValuesResolverInterface;
use RZ\Roadiz\EntityGenerator\Field\DocumentsFieldGenerator;
use RZ\Roadiz\EntityGenerator\Field\ManyToManyFieldGenerator;
use RZ\Roadiz\EntityGenerator\Field\ManyToOneFieldGenerator;
Expand All @@ -25,23 +26,24 @@

class EntityGenerator implements EntityGeneratorInterface
{
private NodeTypeInterface $nodeType;
private array $fieldGenerators;
private NodeTypeResolverInterface $nodeTypeResolver;
protected NodeTypeInterface $nodeType;
protected NodeTypeResolverInterface $nodeTypeResolver;
protected DefaultValuesResolverInterface $defaultValuesResolver;
protected array $fieldGenerators;
protected array $options;

/**
* @param NodeTypeInterface $nodeType
* @param NodeTypeResolverInterface $nodeTypeResolver
* @param array $options
*/
public function __construct(NodeTypeInterface $nodeType, NodeTypeResolverInterface $nodeTypeResolver, array $options = [])
{
public function __construct(
NodeTypeInterface $nodeType,
NodeTypeResolverInterface $nodeTypeResolver,
DefaultValuesResolverInterface $defaultValuesResolver,
array $options = []
) {
$resolver = new OptionsResolver();
$this->configureOptions($resolver);

$this->nodeType = $nodeType;
$this->nodeTypeResolver = $nodeTypeResolver;
$this->defaultValuesResolver = $defaultValuesResolver;
$this->fieldGenerators = [];
$this->options = $resolver->resolve($options);

Expand Down Expand Up @@ -109,19 +111,19 @@ public function configureOptions(OptionsResolver $resolver): void
protected function getFieldGenerator(NodeTypeFieldInterface $field): ?AbstractFieldGenerator
{
if ($field->isYaml()) {
return new YamlFieldGenerator($field, $this->options);
return new YamlFieldGenerator($field, $this->defaultValuesResolver, $this->options);
}
if ($field->isCollection()) {
return new CollectionFieldGenerator($field, $this->options);
return new CollectionFieldGenerator($field, $this->defaultValuesResolver, $this->options);
}
if ($field->isCustomForms()) {
return new CustomFormsFieldGenerator($field, $this->options);
return new CustomFormsFieldGenerator($field, $this->defaultValuesResolver, $this->options);
}
if ($field->isDocuments()) {
return new DocumentsFieldGenerator($field, $this->options);
return new DocumentsFieldGenerator($field, $this->defaultValuesResolver, $this->options);
}
if ($field->isManyToOne()) {
return new ManyToOneFieldGenerator($field, $this->options);
return new ManyToOneFieldGenerator($field, $this->defaultValuesResolver, $this->options);
}
if ($field->isManyToMany()) {
$configuration = Yaml::parse($field->getDefaultValues() ?? '');
Expand All @@ -134,15 +136,15 @@ protected function getFieldGenerator(NodeTypeFieldInterface $field): ?AbstractFi
* Manually create a Many-to-Many relation using a proxy class
* for handling position for example.
*/
return new ProxiedManyToManyFieldGenerator($field, $this->options);
return new ProxiedManyToManyFieldGenerator($field, $this->defaultValuesResolver, $this->options);
}
return new ManyToManyFieldGenerator($field, $this->options);
return new ManyToManyFieldGenerator($field, $this->defaultValuesResolver, $this->options);
}
if ($field->isNodes()) {
return new NodesFieldGenerator($field, $this->nodeTypeResolver, $this->options);
return new NodesFieldGenerator($field, $this->nodeTypeResolver, $this->defaultValuesResolver, $this->options);
}
if (!$field->isVirtual()) {
return new NonVirtualFieldGenerator($field, $this->options);
return new NonVirtualFieldGenerator($field, $this->defaultValuesResolver, $this->options);
}

return null;
Expand Down
18 changes: 10 additions & 8 deletions lib/EntityGenerator/src/EntityGeneratorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,27 @@

use RZ\Roadiz\Contracts\NodeType\NodeTypeInterface;
use RZ\Roadiz\Contracts\NodeType\NodeTypeResolverInterface;
use RZ\Roadiz\EntityGenerator\Field\DefaultValuesResolverInterface;

final class EntityGeneratorFactory
{
private NodeTypeResolverInterface $nodeTypeResolverBag;
private DefaultValuesResolverInterface $defaultValuesResolver;
private array $options;

/**
* @param NodeTypeResolverInterface $nodeTypeResolverBag
* @param array $options
*/
public function __construct(NodeTypeResolverInterface $nodeTypeResolverBag, array $options)
{
public function __construct(
NodeTypeResolverInterface $nodeTypeResolverBag,
DefaultValuesResolverInterface $defaultValuesResolver,
array $options
) {
$this->nodeTypeResolverBag = $nodeTypeResolverBag;
$this->defaultValuesResolver = $defaultValuesResolver;
$this->options = $options;
}

public function create(NodeTypeInterface $nodeType): EntityGeneratorInterface
{
return new EntityGenerator($nodeType, $this->nodeTypeResolverBag, $this->options);
return new EntityGenerator($nodeType, $this->nodeTypeResolverBag, $this->defaultValuesResolver, $this->options);
}

public function createWithCustomRepository(NodeTypeInterface $nodeType): EntityGeneratorInterface
Expand All @@ -35,7 +37,7 @@ public function createWithCustomRepository(NodeTypeInterface $nodeType): EntityG
'\\Repository\\' .
$nodeType->getSourceEntityClassName() . 'Repository';

return new EntityGenerator($nodeType, $this->nodeTypeResolverBag, $options);
return new EntityGenerator($nodeType, $this->nodeTypeResolverBag, $this->defaultValuesResolver, $options);
}

public function createCustomRepository(NodeTypeInterface $nodeType): RepositoryGeneratorInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ abstract class AbstractConfigurableFieldGenerator extends AbstractFieldGenerator
{
protected array $configuration;

public function __construct(NodeTypeFieldInterface $field, array $options = [])
{
parent::__construct($field, $options);
public function __construct(
NodeTypeFieldInterface $field,
DefaultValuesResolverInterface $defaultValuesResolver,
array $options = []
) {
parent::__construct($field, $defaultValuesResolver, $options);

if (empty($this->field->getDefaultValues())) {
throw new \LogicException('Default values must be a valid YAML for ' . static::class);
Expand Down
33 changes: 9 additions & 24 deletions lib/EntityGenerator/src/Field/AbstractFieldGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,23 @@

abstract class AbstractFieldGenerator
{
const USE_NATIVE_JSON = 'use_native_json';
const TAB = ' ';
const ANNOTATION_PREFIX = AbstractFieldGenerator::TAB . ' *';
public const TAB = ' ';
public const ANNOTATION_PREFIX = AbstractFieldGenerator::TAB . ' *';

protected NodeTypeFieldInterface $field;
protected DefaultValuesResolverInterface $defaultValuesResolver;
protected array $options;

/**
* @param NodeTypeFieldInterface $field
* @param array $options
*/
public function __construct(NodeTypeFieldInterface $field, array $options = [])
{
public function __construct(
NodeTypeFieldInterface $field,
DefaultValuesResolverInterface $defaultValuesResolver,
array $options = []
) {
$this->field = $field;
$this->defaultValuesResolver = $defaultValuesResolver;
$this->options = $options;
}

/**
* @param array $ormParams
*
* @return string
*/
public static function flattenORMParameters(array $ormParams): string
{
$flatParams = [];
foreach ($ormParams as $key => $value) {
$flatParams[] = $key . '=' . $value;
}

return implode(', ', $flatParams);
}

/**
* Generate PHP code for current doctrine field.
*
Expand Down
22 changes: 22 additions & 0 deletions lib/EntityGenerator/src/Field/DefaultValuesResolverInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\EntityGenerator\Field;

use RZ\Roadiz\Contracts\NodeType\NodeTypeFieldInterface;

interface DefaultValuesResolverInterface
{
/**
* @param NodeTypeFieldInterface $field
* @return array All possible default values for given field name across all node-types.
*/
public function getDefaultValuesAmongAllFields(NodeTypeFieldInterface $field): array;

/**
* @param NodeTypeFieldInterface $field
* @return int Max length of all possible default values for given field name across all node-types.
*/
public function getMaxDefaultValuesLengthAmongAllFields(NodeTypeFieldInterface $field): int;
}
15 changes: 7 additions & 8 deletions lib/EntityGenerator/src/Field/NodesFieldGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ class NodesFieldGenerator extends AbstractFieldGenerator
{
private NodeTypeResolverInterface $nodeTypeResolver;

/**
* @param NodeTypeFieldInterface $field
* @param NodeTypeResolverInterface $nodeTypeResolver
* @param array $options
*/
public function __construct(NodeTypeFieldInterface $field, NodeTypeResolverInterface $nodeTypeResolver, array $options = [])
{
parent::__construct($field, $options);
public function __construct(
NodeTypeFieldInterface $field,
NodeTypeResolverInterface $nodeTypeResolver,
DefaultValuesResolverInterface $defaultValuesResolver,
array $options = []
) {
parent::__construct($field, $defaultValuesResolver, $options);
$this->nodeTypeResolver = $nodeTypeResolver;
}

Expand Down
28 changes: 18 additions & 10 deletions lib/EntityGenerator/src/Field/NonVirtualFieldGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,25 @@ protected function getFieldLength(): ?int
if ($this->getDoctrineType() !== 'string') {
return null;
}
switch (true) {
case $this->field->isColor():
return 10;
case $this->field->isCountry():
return 5;
case $this->field->isPassword():
case $this->field->isGeoTag():
return 128;
default:
return 250;
return match (true) {
$this->field->isColor() => 10,
$this->field->isCountry() => 5,
$this->field->isPassword(), $this->field->isGeoTag() => 128,
$this->field->isEnum() => $this->defaultValuesResolver->getMaxDefaultValuesLengthAmongAllFields($this->field),
default => 250,
};
}

protected function getMaxDefaultValuesLength(): int
{
// get max length of exploded default values
$max = 0;
foreach (explode(',', $this->field->getDefaultValues()) as $value) {
$value = trim($value);
$max = max($max, strlen($value));
}

return $max > 0 ? $max : 250;
}

protected function isExcludingFieldFromJmsSerialization(): bool
Expand Down
47 changes: 47 additions & 0 deletions lib/EntityGenerator/tests/mocks/GeneratedNodesSources/NSMock.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
ORM\Index(columns: ["fooIndexed"]),
ORM\Index(columns: ["boolIndexed"]),
ORM\Index(columns: ["foo_decimal_excluded"]),
ORM\Index(columns: ["layout"]),
ApiFilter(PropertyFilter::class)
]
class NSMock extends \mock\Entity\NodesSources
Expand Down Expand Up @@ -933,6 +934,52 @@ public function setFooBarTypedSources(?array $fooBarTypedSources): static
}


/**
* ForBar layout enum.
* Default values: light, dark, transparent
*/
#[
SymfonySerializer\SerializedName(serializedName: "layout"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
SymfonySerializer\MaxDepth(2),
ApiFilter(OrmFilter\SearchFilter::class, strategy: "exact"),
ApiFilter(\RZ\Roadiz\CoreBundle\Api\Filter\NotFilter::class),
Gedmo\Versioned,
ORM\Column(
name: "layout",
type: "string",
nullable: true,
length: 11
),
Serializer\Groups(["nodes_sources", "nodes_sources_default"]),
Serializer\MaxDepth(2),
Serializer\Type("string")
]
private ?string $layout = null;

/**
* @return string|null
*/
public function getLayout(): ?string
{
return $this->layout;
}

/**
* @param string|null $layout
*
* @return $this
*/
public function setLayout(?string $layout): static
{
$this->layout = null !== $layout ?
(string) $layout :
null;

return $this;
}


/**
* For many_to_one field.
* Default values: classname: \MyCustomEntity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
ORM\Index(columns: ["fooIndexed"]),
ORM\Index(columns: ["boolIndexed"]),
ORM\Index(columns: ["foo_decimal_excluded"]),
ORM\Index(columns: ["layout"]),
ApiFilter(PropertyFilter::class)
]
class NSMock extends \mock\Entity\NodesSources
Expand Down Expand Up @@ -933,6 +934,52 @@ public function setFooBarTypedSources(?array $fooBarTypedSources): static
}


/**
* ForBar layout enum.
* Default values: light, dark, transparent
*/
#[
SymfonySerializer\SerializedName(serializedName: "layout"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
SymfonySerializer\MaxDepth(2),
ApiFilter(OrmFilter\SearchFilter::class, strategy: "exact"),
ApiFilter(\RZ\Roadiz\CoreBundle\Api\Filter\NotFilter::class),
Gedmo\Versioned,
ORM\Column(
name: "layout",
type: "string",
nullable: true,
length: 11
),
Serializer\Groups(["nodes_sources", "nodes_sources_default"]),
Serializer\MaxDepth(2),
Serializer\Type("string")
]
private ?string $layout = null;

/**
* @return string|null
*/
public function getLayout(): ?string
{
return $this->layout;
}

/**
* @param string|null $layout
*
* @return $this
*/
public function setLayout(?string $layout): static
{
$this->layout = null !== $layout ?
(string) $layout :
null;

return $this;
}


/**
* For many_to_one field.
* Default values: classname: \MyCustomEntity
Expand Down
Loading

0 comments on commit 20263b6

Please sign in to comment.