Skip to content

Commit

Permalink
feat(EntityGenerator): Added ApiProperty documentation for generated …
Browse files Browse the repository at this point in the history
…entities non-virtual fields
  • Loading branch information
ambroisemaupate committed Jan 16, 2024
1 parent fa4a0be commit d6e4462
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 26 deletions.
83 changes: 61 additions & 22 deletions lib/EntityGenerator/src/Attribute/AttributeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ class AttributeGenerator
{
protected string $className;
/**
* @var array<string|int, string|int>
* @var array<string|int, string|int|array>
*/
protected array $parameters;

/**
* @param string $className
* @param int[]|string[] $parameters
* @param array<string|int, string|int|array> $parameters
*/
public function __construct(string $className, array $parameters = [])
{
Expand All @@ -24,55 +24,94 @@ public function __construct(string $className, array $parameters = [])

public static function wrapString(string $string): string
{
return sprintf('"%s"', $string);
return sprintf('"%s"', str_replace('"', '\\"', $string));
}

public function generate(int $currentIndentation = 0): string
{
$formattedParams = [];
if (count($this->parameters) > 3) {
foreach ($this->parameters as $name => $parameter) {
if (is_string($name) && !empty($name)) {
$formattedParams[] = sprintf(
'%s%s: %s',
str_repeat(' ', $currentIndentation + 4),
$name,
$parameter
);
} else {
$formattedParams[] = sprintf(
'%s%s',
str_repeat(' ', $currentIndentation + 4),
$parameter
);
if (empty($parameter)) {
continue;
}
$formattedParams[] = $this->formatProperties($name, $parameter, $currentIndentation);
}
return
str_repeat(' ', $currentIndentation) .
$this->className .
sprintf(
'(%s%s%s)',
PHP_EOL,
implode(',' . PHP_EOL, $formattedParams),
implode(',' . PHP_EOL, array_filter($formattedParams)),
PHP_EOL . str_repeat(' ', $currentIndentation),
);
} elseif (count($this->parameters) > 0) {
foreach ($this->parameters as $name => $parameter) {
if (is_string($name) && !empty($name)) {
$formattedParams[] = sprintf('%s: %s', $name, $parameter);
} else {
$formattedParams[] = $parameter;
if (empty($parameter)) {
continue;
}
$formattedParams[] = $this->formatProperties($name, $parameter, -4);
}
return
str_repeat(' ', $currentIndentation) .
$this->className .
sprintf(
'(%s)',
implode(', ', $formattedParams)
implode(', ', array_filter($formattedParams))
);
} else {
return str_repeat(' ', $currentIndentation) . $this->className;
}
}

/**
* @param string $name
* @param array<string, mixed> $parameter
* @param int $currentIndentation
* @return string
* @throws \JsonException
*/
protected function formatArrayObject(string $name, array $parameter, int $currentIndentation = 0): string
{
$encodedParameterContent = [];
foreach ($parameter as $key => $value) {
if (is_string($key)) {
$encodedParameterContent[] = sprintf(
'%s => %s',
self::wrapString($key),
\json_encode($value, \JSON_THROW_ON_ERROR)
);
}
}
return sprintf(
'%s%s: %s',
str_repeat(' ', $currentIndentation + 4),
$name,
'[' . implode(', ', $encodedParameterContent) . ']'
);
}

protected function formatProperties(string|int $name, mixed $parameter, int $currentIndentation = 0): ?string
{
if (empty($parameter)) {
return null;
}
if (is_string($name) && \is_array($parameter)) {
return $this->formatArrayObject($name, $parameter, $currentIndentation);
}
if (is_string($name) && !empty($name)) {
return sprintf(
'%s%s: %s',
str_repeat(' ', $currentIndentation + 4),
$name,
$parameter
);
}
return sprintf(
'%s%s',
str_repeat(' ', $currentIndentation + 4),
$parameter
);
}
}
21 changes: 21 additions & 0 deletions lib/EntityGenerator/src/Field/AbstractFieldGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,27 @@ protected function getFieldAttributes(bool $exclude = false): array
$attributes[] = new AttributeGenerator('SymfonySerializer\Groups', [
$this->getSerializationGroups()
]);

$description = $this->field->getLabel();
if (!empty($this->field->getDescription())) {
$description .= ': ' . $this->field->getDescription();
}
if ($this->field->isEnum()) {
$enumValues = explode(',', $this->field->getDefaultValues());
$enumValues = array_filter(array_map('trim', $enumValues));
$openapiContext = [
'type' => 'string',
'enum' => $enumValues,
'example' => $enumValues[0] ?? null,
];
}
$attributes[] = new AttributeGenerator('\ApiPlatform\Metadata\ApiProperty', [
'description' => AttributeGenerator::wrapString($description),
'schema' => $openapiContext ?? null,
'example' => $this->field->getPlaceholder() ?
AttributeGenerator::wrapString($this->field->getPlaceholder()) :
null,
]);
if ($this->getSerializationMaxDepth() > 0) {
$attributes[] = new AttributeGenerator('SymfonySerializer\MaxDepth', [
$this->getSerializationMaxDepth()
Expand Down
15 changes: 15 additions & 0 deletions lib/EntityGenerator/tests/mocks/GeneratedNodesSources/NSMock.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class NSMock extends \mock\Entity\NodesSources
#[
SymfonySerializer\SerializedName(serializedName: "fooDatetime"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default", "foo_datetime"]),
\ApiPlatform\Metadata\ApiProperty(description: "Foo DateTime field"),
SymfonySerializer\MaxDepth(2),
ApiFilter(OrmFilter\OrderFilter::class),
ApiFilter(OrmFilter\DateFilter::class),
Expand Down Expand Up @@ -79,6 +80,7 @@ public function setFooDatetime(?\DateTime $fooDatetime): static
#[
SymfonySerializer\SerializedName(serializedName: "foo"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "Foo field: Maecenas sed diam eget risus varius blandit sit amet non magna"),
SymfonySerializer\MaxDepth(1),
Gedmo\Versioned,
ORM\Column(
Expand Down Expand Up @@ -123,6 +125,7 @@ public function setFoo(?string $foo): static
#[
SymfonySerializer\SerializedName(serializedName: "fooIndexed"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "Foo indexed field: Maecenas sed diam eget risus varius blandit sit amet non magna"),
SymfonySerializer\MaxDepth(1),
ApiFilter(OrmFilter\SearchFilter::class, strategy: "partial"),
ApiFilter(\RZ\Roadiz\CoreBundle\Api\Filter\NotFilter::class),
Expand Down Expand Up @@ -169,6 +172,7 @@ public function setFooIndexed(?string $fooIndexed): static
#[
SymfonySerializer\SerializedName(serializedName: "boolIndexed"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "Bool indexed field: Maecenas sed diam eget risus varius blandit sit amet non magna"),
SymfonySerializer\MaxDepth(1),
ApiFilter(OrmFilter\OrderFilter::class),
ApiFilter(OrmFilter\BooleanFilter::class),
Expand Down Expand Up @@ -229,6 +233,7 @@ public function setBoolIndexed(bool $boolIndexed): static
#[
SymfonySerializer\SerializedName(serializedName: "fooMarkdown"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "Foo markdown field: Maecenas sed diam eget risus varius blandit sit amet non magna"),
SymfonySerializer\MaxDepth(1),
Gedmo\Versioned,
ORM\Column(name: "foo_markdown", type: "text", nullable: true),
Expand Down Expand Up @@ -319,6 +324,7 @@ public function setFooMarkdownExcluded(?string $fooMarkdownExcluded): static
#[
SymfonySerializer\SerializedName(serializedName: "fooDecimalExcluded"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "Foo expression excluded decimal: Maecenas sed diam eget risus varius blandit sit amet non magna"),
SymfonySerializer\MaxDepth(2),
ApiFilter(OrmFilter\OrderFilter::class),
ApiFilter(OrmFilter\NumericFilter::class),
Expand Down Expand Up @@ -383,6 +389,7 @@ public function setFooDecimalExcluded(int|float|null $fooDecimalExcluded): stati
#[
SymfonySerializer\SerializedName(serializedName: "singleEventReference"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "Référence à l'événement: Maecenas sed diam eget risus varius blandit sit amet non magna"),
SymfonySerializer\MaxDepth(2),
ORM\ManyToOne(targetEntity: \App\Entity\Base\Event::class),
ORM\JoinColumn(name: "single_event_reference_id", referencedColumnName: "id", onDelete: "SET NULL"),
Expand Down Expand Up @@ -436,6 +443,7 @@ public function setSingleEventReference(?\App\Entity\Base\Event $singleEventRefe
#[
SymfonySerializer\SerializedName(serializedName: "eventReferences"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "Remontée d'événements manuelle: Maecenas sed diam eget risus varius blandit sit amet non magna"),
SymfonySerializer\MaxDepth(2),
ORM\ManyToMany(targetEntity: \App\Entity\Base\Event::class),
ORM\JoinTable(name: "node_type_event_references"),
Expand Down Expand Up @@ -623,6 +631,7 @@ public function setEventReferencesExcluded(Collection|array $eventReferencesExcl
Serializer\Exclude,
SymfonySerializer\SerializedName(serializedName: "bar"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default", "nodes_sources_documents"]),
\ApiPlatform\Metadata\ApiProperty(description: "Bar documents field: Maecenas sed diam eget risus varius blandit sit amet non magna"),
SymfonySerializer\MaxDepth(1)
]
private ?array $bar = null;
Expand Down Expand Up @@ -697,6 +706,7 @@ public function addBar(\mock\Entity\Document $document): static
Serializer\Exclude,
SymfonySerializer\SerializedName(serializedName: "theForms"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default", "nodes_sources_custom_forms"]),
\ApiPlatform\Metadata\ApiProperty(description: "Custom forms field"),
SymfonySerializer\MaxDepth(2)
]
private ?array $theForms = null;
Expand Down Expand Up @@ -771,6 +781,7 @@ public function addTheForms(\mock\Entity\CustomForm $customForm): static
Serializer\Exclude,
SymfonySerializer\SerializedName(serializedName: "fooBar"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default", "nodes_sources_nodes"]),
\ApiPlatform\Metadata\ApiProperty(description: "ForBar nodes field: Maecenas sed diam eget risus varius blandit sit amet non magna"),
SymfonySerializer\MaxDepth(2)
]
private ?array $fooBarSources = null;
Expand Down Expand Up @@ -886,6 +897,7 @@ public function setFooBarHiddenSources(?array $fooBarHiddenSources): static
Serializer\Exclude,
SymfonySerializer\SerializedName(serializedName: "fooBarTyped"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default", "nodes_sources_nodes"]),
\ApiPlatform\Metadata\ApiProperty(description: "ForBar nodes typed field"),
SymfonySerializer\MaxDepth(2)
]
private ?array $fooBarTypedSources = null;
Expand Down Expand Up @@ -941,6 +953,7 @@ public function setFooBarTypedSources(?array $fooBarTypedSources): static
#[
SymfonySerializer\SerializedName(serializedName: "layout"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "ForBar layout enum", schema: ["type" => "string", "enum" => ["light","dark","transparent"], "example" => "light"]),
SymfonySerializer\MaxDepth(2),
ApiFilter(OrmFilter\SearchFilter::class, strategy: "exact"),
ApiFilter(\RZ\Roadiz\CoreBundle\Api\Filter\NotFilter::class),
Expand Down Expand Up @@ -989,6 +1002,7 @@ public function setLayout(?string $layout): static
#[
SymfonySerializer\SerializedName(serializedName: "fooManyToOne"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "For many_to_one field"),
SymfonySerializer\MaxDepth(2),
ORM\ManyToOne(targetEntity: \MyCustomEntity::class),
ORM\JoinColumn(name: "foo_many_to_one_id", referencedColumnName: "id", onDelete: "SET NULL"),
Expand Down Expand Up @@ -1030,6 +1044,7 @@ public function setFooManyToOne(?\MyCustomEntity $fooManyToOne = null): static
#[
SymfonySerializer\SerializedName(serializedName: "fooManyToMany"),
SymfonySerializer\Groups(["nodes_sources", "nodes_sources_default"]),
\ApiPlatform\Metadata\ApiProperty(description: "For many_to_many field"),
SymfonySerializer\MaxDepth(2),
ORM\ManyToMany(targetEntity: \MyCustomEntity::class),
ORM\JoinTable(name: "node_type_foo_many_to_many"),
Expand Down
Loading

0 comments on commit d6e4462

Please sign in to comment.