Skip to content

Commit 6babb3d

Browse files
authored
feat: replace doctrine/inflector by symfony/string (#5637)
* feat: replace doctrine/inflector by symfony/string * fix: use the last element for a better match instead of the first * feat: adding deprecation * feat: adding config flag to activate new symfony inflector * fix: revert change on old inflector * fix: remove unused import
1 parent 4ef0ef8 commit 6babb3d

File tree

5 files changed

+40
-11
lines changed

5 files changed

+40
-11
lines changed

src/Metadata/Util/Inflector.php

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,39 @@
1313

1414
namespace ApiPlatform\Metadata\Util;
1515

16-
use Doctrine\Inflector\Inflector as InflectorObject;
16+
use Doctrine\Inflector\Inflector as LegacyInflector;
1717
use Doctrine\Inflector\InflectorFactory;
18+
use Symfony\Component\String\Inflector\EnglishInflector;
19+
use Symfony\Component\String\UnicodeString;
1820

1921
/**
20-
* Facade for Doctrine Inflector.
21-
*
2222
* @internal
2323
*/
2424
final class Inflector
2525
{
26-
private static ?InflectorObject $instance = null;
26+
private static bool $keepLegacyInflector;
27+
private static ?LegacyInflector $instance = null;
2728

28-
private static function getInstance(): InflectorObject
29+
private static function getInstance(): LegacyInflector
2930
{
3031
return self::$instance
3132
?? self::$instance = InflectorFactory::create()->build();
3233
}
3334

35+
public static function keepLegacyInflector(bool $keepLegacyInflector): void
36+
{
37+
self::$keepLegacyInflector = $keepLegacyInflector;
38+
}
39+
3440
/**
3541
* @see InflectorObject::tableize()
3642
*/
3743
public static function tableize(string $word): string
3844
{
45+
if (!self::$keepLegacyInflector) {
46+
return (new UnicodeString($word))->snake()->toString();
47+
}
48+
3949
return self::getInstance()->tableize($word);
4050
}
4151

@@ -44,6 +54,11 @@ public static function tableize(string $word): string
4454
*/
4555
public static function pluralize(string $word): string
4656
{
57+
if (!self::$keepLegacyInflector) {
58+
$pluralize = (new EnglishInflector())->pluralize($word);
59+
return end($pluralize);
60+
}
61+
4762
return self::getInstance()->pluralize($word);
4863
}
4964
}

src/Metadata/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"doctrine/inflector": "^2.0",
3232
"psr/cache": "^3.0",
3333
"psr/log": "^1.0 || ^2.0 || ^3.0",
34-
"symfony/property-info": "^6.1"
34+
"symfony/property-info": "^6.1",
35+
"symfony/string": "^6.1"
3536
},
3637
"require-dev": {
3738
"phpstan/phpdoc-parser": "^1.16",

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use ApiPlatform\GraphQl\Resolver\QueryItemResolverInterface;
3232
use ApiPlatform\GraphQl\Type\Definition\TypeInterface as GraphQlTypeInterface;
3333
use ApiPlatform\Metadata\ApiResource;
34+
use ApiPlatform\Metadata\Util\Inflector;
3435
use ApiPlatform\State\ProcessorInterface;
3536
use ApiPlatform\State\ProviderInterface;
3637
use ApiPlatform\Symfony\GraphQl\Resolver\Factory\DataCollectorResolverFactory;
@@ -141,6 +142,8 @@ public function load(array $configs, ContainerBuilder $container): void
141142
if (!$container->has('api_platform.state.item_provider')) {
142143
$container->setAlias('api_platform.state.item_provider', 'api_platform.state_provider.object');
143144
}
145+
146+
$this->registerInflectorConfiguration($config);
144147
}
145148

146149
private function registerCommonConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader, array $formats, array $patchFormats, array $errorFormats): void
@@ -160,6 +163,7 @@ private function registerCommonConfiguration(ContainerBuilder $container, array
160163

161164
$container->setParameter('api_platform.enable_entrypoint', $config['enable_entrypoint']);
162165
$container->setParameter('api_platform.enable_docs', $config['enable_docs']);
166+
$container->setParameter('api_platform.keep_legacy_inflector', $config['keep_legacy_inflector']);
163167
$container->setParameter('api_platform.title', $config['title']);
164168
$container->setParameter('api_platform.description', $config['description']);
165169
$container->setParameter('api_platform.version', $config['version']);
@@ -786,4 +790,14 @@ private function registerArgumentResolverConfiguration(XmlFileLoader $loader): v
786790
{
787791
$loader->load('argument_resolver.xml');
788792
}
793+
794+
private function registerInflectorConfiguration(array $config): void
795+
{
796+
if ($config['keep_legacy_inflector']) {
797+
Inflector::keepLegacyInflector(true);
798+
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.');
799+
} else {
800+
Inflector::keepLegacyInflector(false);
801+
}
802+
}
789803
}

src/Symfony/Bundle/DependencyInjection/Configuration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ public function getConfigTreeBuilder(): TreeBuilder
109109
->booleanNode('enable_entrypoint')->defaultTrue()->info('Enable the entrypoint')->end()
110110
->booleanNode('enable_docs')->defaultTrue()->info('Enable the docs')->end()
111111
->booleanNode('enable_profiler')->defaultTrue()->info('Enable the data collector and the WebProfilerBundle integration.')->end()
112+
->booleanNode('keep_legacy_inflector')->defaultTrue()->info('Keep doctrine/inflector instead of symfony/string to generate plurals for routes.')->end()
112113
->arrayNode('collection')
113114
->addDefaultsIfNotSet()
114115
->children()

src/Util/Inflector.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,17 @@
1313

1414
namespace ApiPlatform\Util;
1515

16-
use Doctrine\Inflector\Inflector as InflectorObject;
16+
use Doctrine\Inflector\Inflector as LegacyInflector;
1717
use Doctrine\Inflector\InflectorFactory;
1818

1919
/**
20-
* Facade for Doctrine Inflector.
21-
*
2220
* @internal
2321
*/
2422
final class Inflector
2523
{
26-
private static ?InflectorObject $instance = null;
24+
private static ?LegacyInflector $instance = null;
2725

28-
private static function getInstance(): InflectorObject
26+
private static function getInstance(): LegacyInflector
2927
{
3028
return self::$instance
3129
?? self::$instance = InflectorFactory::create()->build();

0 commit comments

Comments
 (0)