Skip to content

Commit

Permalink
feat: inflector as service (#6447)
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka authored Jul 2, 2024
1 parent 90e71f0 commit 74986cb
Show file tree
Hide file tree
Showing 18 changed files with 92 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use ApiPlatform\Elasticsearch\Exception\IndexNotFoundException;
use ApiPlatform\Elasticsearch\Metadata\Document\DocumentMetadata;
use ApiPlatform\Metadata\InflectorInterface;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Util\Inflector;
use Elastic\Elasticsearch\Exception\ClientResponseException;
Expand All @@ -32,7 +33,7 @@
final class CatDocumentMetadataFactory implements DocumentMetadataFactoryInterface
{
// @phpstan-ignore-next-line
public function __construct(private readonly Client $client, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory, private readonly ?DocumentMetadataFactoryInterface $decorated = null)
public function __construct(private readonly Client $client, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory, private readonly ?DocumentMetadataFactoryInterface $decorated = null, private readonly ?InflectorInterface $inflector = new Inflector())
{
}

Expand Down Expand Up @@ -61,7 +62,7 @@ public function create(string $resourceClass): DocumentMetadata
return $this->handleNotFound($documentMetadata, $resourceClass);
}

$index = Inflector::tableize($resourceShortName);
$index = $this->inflector->tableize($resourceShortName);

try {
// @phpstan-ignore-next-line
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use ApiPlatform\Elasticsearch\State\ItemProvider;
use ApiPlatform\Elasticsearch\State\Options;
use ApiPlatform\Metadata\CollectionOperationInterface;
use ApiPlatform\Metadata\InflectorInterface;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
Expand All @@ -27,7 +28,7 @@

final class ElasticsearchProviderResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface
{
public function __construct(private readonly ?Client $client, private readonly ResourceMetadataCollectionFactoryInterface $decorated, private readonly bool $triggerDeprecation = true) // @phpstan-ignore-line
public function __construct(private readonly ?Client $client, private readonly ResourceMetadataCollectionFactoryInterface $decorated, private readonly bool $triggerDeprecation = true, private readonly ?InflectorInterface $inflector = new Inflector()) // @phpstan-ignore-line
{
}

Expand Down Expand Up @@ -106,7 +107,7 @@ public function create(string $resourceClass): ResourceMetadataCollection
private function hasIndices(Operation $operation): bool
{
$shortName = $operation->getShortName();
$index = Inflector::tableize($shortName);
$index = $this->inflector->tableize($shortName);

try {
$this->client->cat()->indices(['index' => $index]); // @phpstan-ignore-line
Expand Down
5 changes: 3 additions & 2 deletions src/Elasticsearch/State/CollectionProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use ApiPlatform\Elasticsearch\Metadata\Document\DocumentMetadata;
use ApiPlatform\Elasticsearch\Metadata\Document\Factory\DocumentMetadataFactoryInterface;
use ApiPlatform\Elasticsearch\Paginator;
use ApiPlatform\Metadata\InflectorInterface;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Util\Inflector;
use ApiPlatform\State\ApiResource\Error;
Expand All @@ -39,7 +40,7 @@ final class CollectionProvider implements ProviderInterface
/**
* @param RequestBodySearchCollectionExtensionInterface[] $collectionExtensions
*/
public function __construct(private readonly LegacyClient|Client $client, private readonly ?DocumentMetadataFactoryInterface $documentMetadataFactory = null, private readonly ?DenormalizerInterface $denormalizer = null, private readonly ?Pagination $pagination = null, private readonly iterable $collectionExtensions = []) // @phpstan-ignore-line
public function __construct(private readonly LegacyClient|Client $client, private readonly ?DocumentMetadataFactoryInterface $documentMetadataFactory = null, private readonly ?DenormalizerInterface $denormalizer = null, private readonly ?Pagination $pagination = null, private readonly iterable $collectionExtensions = [], private readonly ?InflectorInterface $inflector = new Inflector()) // @phpstan-ignore-line
{
}

Expand Down Expand Up @@ -102,6 +103,6 @@ private function convertDocumentMetadata(DocumentMetadata $documentMetadata): Op

private function getIndex(Operation $operation): string
{
return Inflector::tableize($operation->getShortName());
return $this->inflector->tableize($operation->getShortName());
}
}
5 changes: 3 additions & 2 deletions src/Elasticsearch/State/ItemProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use ApiPlatform\Elasticsearch\Metadata\Document\Factory\DocumentMetadataFactoryInterface;
use ApiPlatform\Elasticsearch\Serializer\DocumentNormalizer;
use ApiPlatform\Metadata\Exception\RuntimeException;
use ApiPlatform\Metadata\InflectorInterface;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Util\Inflector;
use ApiPlatform\State\ApiResource\Error;
Expand All @@ -37,7 +38,7 @@
*/
final class ItemProvider implements ProviderInterface
{
public function __construct(private readonly LegacyClient|Client $client, private readonly ?DocumentMetadataFactoryInterface $documentMetadataFactory = null, private readonly ?DenormalizerInterface $denormalizer = null) // @phpstan-ignore-line
public function __construct(private readonly LegacyClient|Client $client, private readonly ?DocumentMetadataFactoryInterface $documentMetadataFactory = null, private readonly ?DenormalizerInterface $denormalizer = null, private readonly ?InflectorInterface $inflector = new Inflector()) // @phpstan-ignore-line
{
}

Expand Down Expand Up @@ -96,6 +97,6 @@ private function convertDocumentMetadata(DocumentMetadata $documentMetadata): Op

private function getIndex(Operation $operation): string
{
return Inflector::tableize($operation->getShortName());
return $this->inflector->tableize($operation->getShortName());
}
}
5 changes: 3 additions & 2 deletions src/GraphQl/Type/FieldsBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use ApiPlatform\Metadata\GraphQl\Operation;
use ApiPlatform\Metadata\GraphQl\Query;
use ApiPlatform\Metadata\GraphQl\Subscription;
use ApiPlatform\Metadata\InflectorInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
Expand Down Expand Up @@ -50,7 +51,7 @@ final class FieldsBuilder implements FieldsBuilderInterface, FieldsBuilderEnumIn
{
private readonly ContextAwareTypeBuilderInterface|TypeBuilderEnumInterface|TypeBuilderInterface $typeBuilder;

public function __construct(private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ResourceClassResolverInterface $resourceClassResolver, private readonly TypesContainerInterface $typesContainer, ContextAwareTypeBuilderInterface|TypeBuilderEnumInterface|TypeBuilderInterface $typeBuilder, private readonly TypeConverterInterface $typeConverter, private readonly ResolverFactoryInterface $itemResolverFactory, private readonly ?ResolverFactoryInterface $collectionResolverFactory, private readonly ?ResolverFactoryInterface $itemMutationResolverFactory, private readonly ?ResolverFactoryInterface $itemSubscriptionResolverFactory, private readonly ContainerInterface $filterLocator, private readonly Pagination $pagination, private readonly ?NameConverterInterface $nameConverter, private readonly string $nestingSeparator)
public function __construct(private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ResourceClassResolverInterface $resourceClassResolver, private readonly TypesContainerInterface $typesContainer, ContextAwareTypeBuilderInterface|TypeBuilderEnumInterface|TypeBuilderInterface $typeBuilder, private readonly TypeConverterInterface $typeConverter, private readonly ResolverFactoryInterface $itemResolverFactory, private readonly ?ResolverFactoryInterface $collectionResolverFactory, private readonly ?ResolverFactoryInterface $itemMutationResolverFactory, private readonly ?ResolverFactoryInterface $itemSubscriptionResolverFactory, private readonly ContainerInterface $filterLocator, private readonly Pagination $pagination, private readonly ?NameConverterInterface $nameConverter, private readonly string $nestingSeparator, private readonly ?InflectorInterface $inflector = new Inflector())
{
if ($typeBuilder instanceof TypeBuilderInterface) {
@trigger_error(sprintf('$typeBuilder argument of FieldsBuilder implementing "%s" is deprecated since API Platform 3.1. It has to implement "%s" instead.', TypeBuilderInterface::class, TypeBuilderEnumInterface::class), \E_USER_DEPRECATED);
Expand Down Expand Up @@ -113,7 +114,7 @@ public function getCollectionQueryFields(string $resourceClass, Operation $opera
$extraArgs = $this->resolveResourceArgs($operation->getExtraArgs() ?? [], $operation);
$configuration['args'] = $args ?: $configuration['args'] ?? $fieldConfiguration['args'] + $extraArgs;

return [Inflector::pluralize($fieldName) => array_merge($fieldConfiguration, $configuration)];
return [$this->inflector->pluralize($fieldName) => array_merge($fieldConfiguration, $configuration)];
}

return [];
Expand Down
27 changes: 27 additions & 0 deletions src/Metadata/InflectorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Metadata;

interface InflectorInterface
{
/**
* Returns a snake case transformed string.
*/
public function tableize(string $input): string;

/**
* Returns the plural forms of a string.
*/
public function pluralize(string $singular): string;
}
7 changes: 6 additions & 1 deletion src/Metadata/Operation/DashPathSegmentNameGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace ApiPlatform\Metadata\Operation;

use ApiPlatform\Metadata\InflectorInterface;
use ApiPlatform\Metadata\Util\Inflector;

/**
Expand All @@ -22,12 +23,16 @@
*/
final class DashPathSegmentNameGenerator implements PathSegmentNameGeneratorInterface
{
public function __construct(private readonly ?InflectorInterface $inflector = new Inflector())
{
}

/**
* {@inheritdoc}
*/
public function getSegmentName(string $name, bool $collection = true): string
{
return $collection ? $this->dashize(Inflector::pluralize($name)) : $this->dashize($name);
return $collection ? $this->dashize($this->inflector->pluralize($name)) : $this->dashize($name);
}

private function dashize(string $string): string
Expand Down
9 changes: 7 additions & 2 deletions src/Metadata/Operation/UnderscorePathSegmentNameGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace ApiPlatform\Metadata\Operation;

use ApiPlatform\Metadata\InflectorInterface;
use ApiPlatform\Metadata\Util\Inflector;

/**
Expand All @@ -22,13 +23,17 @@
*/
final class UnderscorePathSegmentNameGenerator implements PathSegmentNameGeneratorInterface
{
public function __construct(private readonly ?InflectorInterface $inflector = new Inflector())
{
}

/**
* {@inheritdoc}
*/
public function getSegmentName(string $name, bool $collection = true): string
{
$name = Inflector::tableize($name);
$name = $this->inflector->tableize($name);

return $collection ? Inflector::pluralize($name) : $name;
return $collection ? $this->inflector->pluralize($name) : $name;
}
}
3 changes: 2 additions & 1 deletion src/Metadata/Util/AttributeFilterExtractorTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace ApiPlatform\Metadata\Util;

use ApiPlatform\Metadata\ApiFilter;
use Symfony\Component\String\UnicodeString;

/**
* Generates a service id for a generic filter.
Expand Down Expand Up @@ -133,6 +134,6 @@ private function generateFilterId(\ReflectionClass $reflectionClass, string $fil
{
$suffix = null !== $filterId ? '_'.$filterId : $filterId;

return 'annotated_'.Inflector::tableize(str_replace('\\', '', $reflectionClass->getName().(new \ReflectionClass($filterClass))->getName().$suffix));
return 'annotated_'.(new UnicodeString(str_replace('\\', '', $reflectionClass->getName().(new \ReflectionClass($filterClass))->getName().$suffix)))->snake()->toString();
}
}
21 changes: 10 additions & 11 deletions src/Metadata/Util/Inflector.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace ApiPlatform\Metadata\Util;

use ApiPlatform\Metadata\InflectorInterface;
use Doctrine\Inflector\Inflector as LegacyInflector;
use Doctrine\Inflector\InflectorFactory;
use Symfony\Component\String\Inflector\EnglishInflector;
Expand All @@ -21,9 +22,12 @@
/**
* @internal
*/
final class Inflector
final class Inflector implements InflectorInterface
{
private static bool $keepLegacyInflector = true;
public function __construct(private bool $keepLegacyInflector = true)
{
}

private static ?LegacyInflector $instance = null;

private static function getInstance(): LegacyInflector
Expand All @@ -32,17 +36,12 @@ private static function getInstance(): LegacyInflector
?? static::$instance = InflectorFactory::create()->build();
}

public static function keepLegacyInflector(bool $keepLegacyInflector): void
{
static::$keepLegacyInflector = $keepLegacyInflector;
}

/**
* @see InflectorObject::tableize()
*/
public static function tableize(string $word): string
public function tableize(string $word): string
{
if (!static::$keepLegacyInflector) {
if (!$this->keepLegacyInflector) {
return (new UnicodeString($word))->snake()->toString();
}

Expand All @@ -52,9 +51,9 @@ public static function tableize(string $word): string
/**
* @see InflectorObject::pluralize()
*/
public static function pluralize(string $word): string
public function pluralize(string $word): string
{
if (!static::$keepLegacyInflector) {
if (!$this->keepLegacyInflector) {
$pluralize = (new EnglishInflector())->pluralize($word);

return end($pluralize);
Expand Down
11 changes: 5 additions & 6 deletions src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
use ApiPlatform\Metadata\FilterInterface;
use ApiPlatform\Metadata\UriVariableTransformerInterface;
use ApiPlatform\Metadata\UrlGeneratorInterface;
use ApiPlatform\Metadata\Util\Inflector;
use ApiPlatform\Problem\Serializer\ConstraintViolationListNormalizer;
use ApiPlatform\State\ApiResource\Error;
use ApiPlatform\State\ParameterProviderInterface;
Expand Down Expand Up @@ -210,7 +209,7 @@ public function load(array $configs, ContainerBuilder $container): void
$container->setAlias('api_platform.state.item_provider', 'api_platform.state_provider.object');
}

$this->registerInflectorConfiguration($config);
$this->registerInflectorConfiguration($container, $config);
}

private function registerCommonConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader, array $formats, array $patchFormats, array $errorFormats, array $docsFormats, array $jsonSchemaFormats): void
Expand Down Expand Up @@ -297,6 +296,7 @@ private function registerCommonConfiguration(ContainerBuilder $container, array
$container->setParameter('api_platform.http_cache.invalidation.xkey.glue', $config['defaults']['cache_headers']['invalidation']['xkey']['glue'] ?? $config['http_cache']['invalidation']['xkey']['glue']);

$container->setAlias('api_platform.path_segment_name_generator', $config['path_segment_name_generator']);
$container->setAlias('api_platform.inflector', $config['inflector']);

if ($config['name_converter']) {
$container->setAlias('api_platform.name_converter', $config['name_converter']);
Expand Down Expand Up @@ -994,13 +994,12 @@ private function registerArgumentResolverConfiguration(XmlFileLoader $loader): v
$loader->load('argument_resolver.xml');
}

private function registerInflectorConfiguration(array $config): void
private function registerInflectorConfiguration(ContainerBuilder $container, array $config): void
{
$container->setParameter('api_platform.keep_legacy_inflector', $config['keep_legacy_inflector'] ?? false);

if ($config['keep_legacy_inflector']) {
Inflector::keepLegacyInflector(true);
trigger_deprecation('api-platform/core', '3.2', 'Using doctrine/inflector is deprecated since API Platform 3.2 and will be removed in API Platform 4. Use symfony/string instead. Run "composer require symfony/string" and set "keep_legacy_inflector" to false in config.');
} else {
Inflector::keepLegacyInflector(false);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bundle/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarNode('name_converter')->defaultNull()->info('Specify a name converter to use.')->end()
->scalarNode('asset_package')->defaultNull()->info('Specify an asset package name to use.')->end()
->scalarNode('path_segment_name_generator')->defaultValue('api_platform.metadata.path_segment_name_generator.underscore')->info('Specify a path name generator to use.')->end()
->scalarNode('inflector')->defaultValue('api_platform.metadata.inflector')->info('Specify an inflector to use.')->end()
->arrayNode('validator')
->addDefaultsIfNotSet()
->children()
Expand Down
13 changes: 11 additions & 2 deletions src/Symfony/Bundle/Resources/config/api.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,17 @@
<service id="api_platform.path_segment_name_generator.underscore" class="ApiPlatform\Operation\UnderscorePathSegmentNameGenerator" public="false" />
<service id="api_platform.path_segment_name_generator.dash" class="ApiPlatform\Operation\DashPathSegmentNameGenerator" public="false" />

<service id="api_platform.metadata.path_segment_name_generator.underscore" class="ApiPlatform\Metadata\Operation\UnderscorePathSegmentNameGenerator" public="false" />
<service id="api_platform.metadata.path_segment_name_generator.dash" class="ApiPlatform\Metadata\Operation\DashPathSegmentNameGenerator" public="false" />
<service id="api_platform.metadata.path_segment_name_generator.underscore" class="ApiPlatform\Metadata\Operation\UnderscorePathSegmentNameGenerator" public="false">
<argument type="service" id="api_platform.inflector" on-invalid="null" />
</service>

<service id="api_platform.metadata.path_segment_name_generator.dash" class="ApiPlatform\Metadata\Operation\DashPathSegmentNameGenerator" public="false">
<argument type="service" id="api_platform.inflector" on-invalid="null" />
</service>

<service id="api_platform.metadata.inflector" class="ApiPlatform\Metadata\Util\Inflector" public="false">
<argument>%api_platform.keep_legacy_inflector%</argument>
</service>

<!-- Action -->
<service id="api_platform.action.exception" class="ApiPlatform\Action\ExceptionAction" public="true">
Expand Down
Loading

0 comments on commit 74986cb

Please sign in to comment.