Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions scoper.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
ApiPlatform\Core\Annotation\ApiResource::class,
],
'patchers' => [
function (string $filePath, string $prefix, string $content): string {
static function (string $filePath, string $prefix, string $content): string {
//
// PHP-CS-Fixer patch
//
Expand All @@ -35,7 +35,7 @@ function (string $filePath, string $prefix, string $content): string {

// TODO: Temporary patch until the issue is fixed upstream
// @link https://github.com/humbug/php-scoper/issues/285
function (string $filePath, string $prefix, string $content): string {
static function (string $filePath, string $prefix, string $content): string {
if (!str_contains($content, '@')) {
return $content;
}
Expand All @@ -51,7 +51,7 @@ function (string $filePath, string $prefix, string $content): string {
$content
);
},
function (string $filePath, string $prefix, string $content): string {
static function (string $filePath, string $prefix, string $content): string {
if (!str_starts_with($filePath, 'src/AnnotationGenerator/')) {
return $content;
}
Expand Down
108 changes: 108 additions & 0 deletions src/AttributeGenerator/ApiPlatformCoreAttributeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\OpenApi\Model\Operation;
use ApiPlatform\OpenApi\Model\Parameter;
use ApiPlatform\OpenApi\Model\Response;
use ApiPlatform\SchemaGenerator\Model\Attribute;
use ApiPlatform\SchemaGenerator\Model\Class_;
use ApiPlatform\SchemaGenerator\Model\Property;
Expand All @@ -39,6 +42,21 @@
*/
final class ApiPlatformCoreAttributeGenerator extends AbstractAttributeGenerator
{
/**
* Hints for not typed array parameters.
*/
private const PRAMETER_TYPE_HINTS = [
Operation::class => [
'responses' => Response::class.'[]',
'parameters' => Parameter::class.'[]',
],
];

/**
* @var array<class-string, array<string, string|null>>
*/
private static array $parameterTypes = [];

public function generateClassAttributes(Class_ $class): array
{
if ($class->hasChild || $class->isEnum()) {
Expand Down Expand Up @@ -85,6 +103,22 @@ public function generateClassAttributes(Class_ $class): array
unset($methodConfig['class']);
}

if (\is_array($methodConfig['openapi'] ?? null)) {
$methodConfig['openapi'] = Literal::new(
'Operation',
self::extractParameters(Operation::class, $methodConfig['openapi'])
);
$class->addUse(new Use_(Operation::class));
array_walk_recursive(
self::$parameterTypes,
static function (?string $type) use ($class): void {
if (null !== $type) {
$class->addUse(new Use_(str_replace('[]', '', $type)));
}
}
);
}

$arguments['operations'][] = new Literal(\sprintf('new %s(...?:)',
$operationMetadataClass,
), [$methodConfig ?? []]);
Expand All @@ -95,6 +129,80 @@ public function generateClassAttributes(Class_ $class): array
return [new Attribute('ApiResource', $arguments)];
}

/**
* @param class-string $type
* @param mixed[] $values
*
* @return mixed[]
*/
private static function extractParameters(string $type, array $values): array
{
$types = self::$parameterTypes[$type] ??=
(static::PRAMETER_TYPE_HINTS[$type] ?? []) + array_reduce(
(new \ReflectionClass($type))->getConstructor()?->getParameters() ?? [],
static fn (array $types, \ReflectionParameter $refl): array => $types + [
$refl->getName() => $refl->getType() instanceof \ReflectionNamedType
&& !$refl->getType()->isBuiltin()
? $refl->getType()->getName()
: null,
],
[]
);
if (isset(self::$parameterTypes[$type])) {
$types = self::$parameterTypes[$type];
} else {
$types = static::PRAMETER_TYPE_HINTS[$type] ?? [];
$parameterRefls = (new \ReflectionClass($type))
->getConstructor()
?->getParameters() ?? [];
foreach ($parameterRefls as $refl) {
$paramName = $refl->getName();
if (\array_key_exists($paramName, $types)) {
continue;
}
$paramType = $refl->getType();
if ($paramType instanceof \ReflectionNamedType && !$paramType->isBuiltin()) {
$types[$paramName] = $paramType->getName();
} else {
$types[$paramName] = null;
}
}
self::$parameterTypes[$type] = $types;
}

$parameters = array_intersect_key($values, $types);
foreach ($parameters as $name => $parameter) {
$type = $types[$name];
if (null === $type || !\is_array($parameter)) {
continue;
}
$isArrayType = str_ends_with($type, '[]');
/**
* @var class-string
*/
$type = $isArrayType ? substr($type, 0, -2) : $type;
$shortName = (new \ReflectionClass($type))->getShortName();
if ($isArrayType) {
$parameters[$name] = [];
foreach ($parameter as $key => $values) {
$parameters[$name][$key] = Literal::new(
$shortName,
self::extractParameters($type, $values)
);
}
} else {
$parameters[$name] = Literal::new(
$shortName,
\ArrayObject::class === $type
? [$parameter]
: self::extractParameters($type, $parameter)
);
}
}

return $parameters;
}

/**
* Verifies that the operations' config is valid.
*
Expand Down
2 changes: 1 addition & 1 deletion src/AttributeGenerator/ConfigurationAttributeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function generateClassAttributes(Class_ $class): array

$getAttributesNames = static fn (array $config) => $config === [[]]
? []
: array_unique(array_map(fn (array $v) => array_keys($v)[0], $config));
: array_unique(array_map(static fn (array $v) => array_keys($v)[0], $config));
$typeAttributesNames = $getAttributesNames($typeAttributes);
$vocabAttributesNames = $getAttributesNames($vocabAttributes);

Expand Down
4 changes: 2 additions & 2 deletions src/AttributeGenerator/DoctrineMongoDBAttributeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ public function generateClassAttributes(Class_ $class): array
$directChildren = array_merge($directChildren, array_filter($this->classes, fn (Class_ $childClass) => $parentName === $childClass->parent()));
}
$parentNames = array_keys($directChildren);
$childNames = array_merge($childNames, array_keys(array_filter($directChildren, fn (Class_ $childClass) => !$childClass->isAbstract)));
$childNames = array_merge($childNames, array_keys(array_filter($directChildren, static fn (Class_ $childClass) => !$childClass->isAbstract)));
}
$mapNames = array_merge([$class->name()], $childNames);

$attributes[] = new Attribute('MongoDB\Document');
$attributes[] = new Attribute('MongoDB\InheritanceType', [\in_array($this->config['doctrine']['inheritanceType'], ['SINGLE_COLLECTION', 'COLLECTION_PER_CLASS', 'NONE'], true) ? $this->config['doctrine']['inheritanceType'] : 'SINGLE_COLLECTION']);
$attributes[] = new Attribute('MongoDB\DiscriminatorField', ['discr']);
$attributes[] = new Attribute('MongoDB\DiscriminatorMap', [array_reduce($mapNames, fn (array $map, string $mapName) => $map + [u($mapName)->camel()->toString() => new Literal(\sprintf('%s::class', $mapName))], [])]);
$attributes[] = new Attribute('MongoDB\DiscriminatorMap', [array_reduce($mapNames, static fn (array $map, string $mapName) => $map + [u($mapName)->camel()->toString() => new Literal(\sprintf('%s::class', $mapName))], [])]);
} else {
$attributes[] = new Attribute('MongoDB\Document');
}
Expand Down
4 changes: 2 additions & 2 deletions src/AttributeGenerator/DoctrineOrmAttributeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ public function generateClassAttributes(Class_ $class): array
$directChildren = array_merge($directChildren, array_filter($this->classes, fn (Class_ $childClass) => $parentName === $childClass->parent()));
}
$parentNames = array_keys($directChildren);
$childNames = array_merge($childNames, array_keys(array_filter($directChildren, fn (Class_ $childClass) => !$childClass->isAbstract)));
$childNames = array_merge($childNames, array_keys(array_filter($directChildren, static fn (Class_ $childClass) => !$childClass->isAbstract)));
}
$mapNames = array_merge([$class->name()], $childNames);

$attributes[] = new Attribute('ORM\Entity');
$attributes[] = new Attribute('ORM\InheritanceType', [\in_array($this->config['doctrine']['inheritanceType'], ['JOINED', 'SINGLE_TABLE', 'TABLE_PER_CLASS', 'NONE'], true) ? $this->config['doctrine']['inheritanceType'] : 'JOINED']);
$attributes[] = new Attribute('ORM\DiscriminatorColumn', ['name' => 'discr']);
$attributes[] = new Attribute('ORM\DiscriminatorMap', [array_reduce($mapNames, fn (array $map, string $mapName) => $map + [u($mapName)->camel()->toString() => new Literal(\sprintf('%s::class', $mapName))], [])]);
$attributes[] = new Attribute('ORM\DiscriminatorMap', [array_reduce($mapNames, static fn (array $map, string $mapName) => $map + [u($mapName)->camel()->toString() => new Literal(\sprintf('%s::class', $mapName))], [])]);
} else {
$attributes[] = new Attribute('ORM\Entity');
}
Expand Down
2 changes: 1 addition & 1 deletion src/ClassMutator/ClassPropertiesAppender.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ private function getParentClasses(array $graphs, RdfResource $resource, array $p
return $this->getParentClasses($graphs, $resource, [$resource]);
}

$filterBNodes = fn ($parentClasses) => array_filter($parentClasses, fn ($parentClass) => !$parentClass->isBNode());
$filterBNodes = static fn ($parentClasses) => array_filter($parentClasses, static fn ($parentClass) => !$parentClass->isBNode());
if (!$subclasses = $resource->all('rdfs:subClassOf', 'resource')) {
return $filterBNodes($parentClasses);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Model/AddAttributeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function addAttribute(Attribute $attribute): self
}
} else {
$this->attributes = array_map(
fn (Attribute $attr) => $attr->name() === $attribute->name()
static fn (Attribute $attr) => $attr->name() === $attribute->name()
? new Attribute($attr->name(), array_merge(
$attr->args(),
$attribute->args(),
Expand All @@ -44,7 +44,7 @@ public function getAttributeWithName(string $name): ?Attribute
{
return array_values(array_filter(
$this->attributes,
fn (Attribute $attr) => $attr->name() === $name
static fn (Attribute $attr) => $attr->name() === $name
))[0] ?? null;
}
}
4 changes: 2 additions & 2 deletions src/Model/Type/UnionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function __construct(array $types)

public function __toString(): string
{
return implode('|', array_map(fn (Type $type) => $type instanceof CompositeType ? '('.$type.')' : $type, $this->types));
return implode('|', array_map(static fn (Type $type) => $type instanceof CompositeType ? '('.$type.')' : $type, $this->types));
}

public function getPhp(): string
Expand All @@ -39,6 +39,6 @@ public function getPhp(): string
$phpTypes[$type->getPhp()] = $type;
}

return implode('|', array_map(fn (Type $type) => $type instanceof CompositeType ? '('.$type->getPhp().')' : $type->getPhp(), $phpTypes));
return implode('|', array_map(static fn (Type $type) => $type instanceof CompositeType ? '('.$type->getPhp().')' : $type->getPhp(), $phpTypes));
}
}
8 changes: 4 additions & 4 deletions src/SchemaGeneratorConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ public function getConfigTreeBuilder(): TreeBuilder
$namespacePrefix = $this->defaultPrefix ?? 'App\\';

/* @see https://yaml.org/type/omap.html */
$transformOmap = fn (array $nodeConfig) => array_map(
fn ($v, $k) => \is_int($k) ? $v : [$k => $v],
$transformOmap = static fn (array $nodeConfig) => array_map(
static fn ($v, $k) => \is_int($k) ? $v : [$k => $v],
array_values($nodeConfig),
array_keys($nodeConfig)
);

// @phpstan-ignore-next-line node is not null
$attributesNode = fn () => (new NodeBuilder())
$attributesNode = static fn () => (new NodeBuilder())
->arrayNode('attributes')
->info('Attributes (merged with generated attributes)')
->variablePrototype()->end()
Expand All @@ -78,7 +78,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->defaultValue([self::SCHEMA_ORG_URI => ['format' => 'rdfxml']])
->beforeNormalization()
->ifArray()
->then(fn (array $v) => array_map(fn ($rdf) => \is_scalar($rdf) ? ['uri' => $rdf] : $rdf, $v))
->then(static fn (array $v) => array_map(static fn ($rdf) => \is_scalar($rdf) ? ['uri' => $rdf] : $rdf, $v))
->end()
->useAttributeAsKey('uri')
->arrayPrototype()
Expand Down
2 changes: 1 addition & 1 deletion src/TypesGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ private function getParentClasses(array $graphs, RdfResource $resource, array $p
return $this->getParentClasses($graphs, $resource, [$resource]);
}

$filterBNodes = fn ($parentClasses) => array_filter($parentClasses, fn ($parentClass) => !$parentClass->isBNode());
$filterBNodes = static fn ($parentClasses) => array_filter($parentClasses, static fn ($parentClass) => !$parentClass->isBNode());
if (!$subclasses = $resource->all('rdfs:subClassOf', 'resource')) {
return $filterBNodes($parentClasses);
}
Expand Down
Loading