diff --git a/src/DependencyInjection/SonataAdminExtension.php b/src/DependencyInjection/SonataAdminExtension.php
index cc638d36f2..6d7c2ce272 100644
--- a/src/DependencyInjection/SonataAdminExtension.php
+++ b/src/DependencyInjection/SonataAdminExtension.php
@@ -178,7 +178,7 @@ public function load(array $configs, ContainerBuilder $container)
->replaceArgument(0, $classes)
->replaceArgument(1, $config['options']);
- // remove non used service
+ // NEXT_MAJOR: Remove this block
if (!isset($bundles['JMSTranslationBundle'])) {
$container->removeDefinition('sonata.admin.translator.extractor.jms_translator_bundle');
}
diff --git a/src/Resources/config/core.xml b/src/Resources/config/core.xml
index dc6c29ca38..a538ffb2b0 100644
--- a/src/Resources/config/core.xml
+++ b/src/Resources/config/core.xml
@@ -47,7 +47,9 @@
+
+
The controller service "%service_id%" is deprecated in favor of several action services since version 3.38.0 and will be removed in 4.0.
diff --git a/src/Translator/Extractor/AdminExtractor.php b/src/Translator/Extractor/AdminExtractor.php
new file mode 100644
index 0000000000..25f00c762d
--- /dev/null
+++ b/src/Translator/Extractor/AdminExtractor.php
@@ -0,0 +1,123 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Sonata\AdminBundle\Translator\Extractor;
+
+use Sonata\AdminBundle\Admin\BreadcrumbsBuilderInterface;
+use Sonata\AdminBundle\Admin\Pool;
+use Sonata\AdminBundle\Translator\LabelTranslatorStrategyInterface;
+use Symfony\Component\Translation\Extractor\ExtractorInterface;
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * @internal
+ */
+final class AdminExtractor implements ExtractorInterface, LabelTranslatorStrategyInterface
+{
+ private const PUBLIC_ADMIN_METHODS = [
+ 'getShow',
+ 'getDatagrid',
+ 'getList',
+ 'getForm',
+ ];
+
+ private const BREADCRUMB_ACTIONS = [
+ 'list',
+ 'edit',
+ 'create',
+ 'update',
+ 'batch',
+ 'delete',
+ ];
+
+ /**
+ * @var string
+ */
+ private $prefix = '';
+
+ /**
+ * @var MessageCatalogue|null
+ */
+ private $catalogue;
+
+ /**
+ * @var Pool
+ */
+ private $adminPool;
+
+ /**
+ * @var LabelTranslatorStrategyInterface|null
+ */
+ private $labelStrategy;
+
+ /**
+ * @var string|null
+ */
+ private $domain;
+
+ /**
+ * @var BreadcrumbsBuilderInterface
+ */
+ private $breadcrumbsBuilder;
+
+ public function __construct(Pool $adminPool, BreadcrumbsBuilderInterface $breadcrumbsBuilder)
+ {
+ $this->adminPool = $adminPool;
+ $this->breadcrumbsBuilder = $breadcrumbsBuilder;
+ }
+
+ public function extract($resource, MessageCatalogue $catalogue)
+ {
+ $this->catalogue = $catalogue;
+
+ foreach ($this->adminPool->getAdminGroups() as $name => $group) {
+ $catalogue->set($name, $this->prefix.$name, $group['label_catalogue']);
+ }
+
+ foreach ($this->adminPool->getAdminServiceIds() as $id) {
+ $admin = $this->adminPool->getInstance($id);
+
+ $this->labelStrategy = $admin->getLabelTranslatorStrategy();
+ $this->domain = $admin->getTranslationDomain();
+
+ $label = $admin->getLabel();
+ if (!empty($label)) {
+ $catalogue->set($label, $this->prefix.$label, $admin->getTranslationDomain());
+ }
+
+ $admin->setLabelTranslatorStrategy($this);
+
+ foreach (self::PUBLIC_ADMIN_METHODS as $method) {
+ $admin->$method();
+ }
+
+ foreach (self::BREADCRUMB_ACTIONS as $action) {
+ $this->breadcrumbsBuilder->getBreadcrumbs($admin, $action);
+ }
+ }
+ }
+
+ public function setPrefix($prefix): void
+ {
+ $this->prefix = $prefix;
+ }
+
+ public function getLabel($label, $context = '', $type = ''): string
+ {
+ $label = $this->labelStrategy->getLabel($label, $context, $type);
+
+ $this->catalogue->set($label, $this->prefix.$label, $this->domain);
+
+ return $label;
+ }
+}
diff --git a/src/Translator/Extractor/JMSTranslatorBundle/AdminExtractor.php b/src/Translator/Extractor/JMSTranslatorBundle/AdminExtractor.php
index 4b66c34b8e..8fde6606b3 100644
--- a/src/Translator/Extractor/JMSTranslatorBundle/AdminExtractor.php
+++ b/src/Translator/Extractor/JMSTranslatorBundle/AdminExtractor.php
@@ -26,6 +26,10 @@
use Symfony\Component\Translation\TranslatorInterface;
/**
+ * NEXT_MAJOR: Remove this class and the jms/translation-bundle dev dependency.
+ *
+ * @deprecated since sonata-project/admin-bundle 3.x. Use `translation:update` Symfony command instead.
+ *
* @final since sonata-project/admin-bundle 3.52
*/
class AdminExtractor implements ExtractorInterface, TranslatorInterface, SecurityHandlerInterface, LabelTranslatorStrategyInterface
diff --git a/tests/DependencyInjection/SonataAdminExtensionTest.php b/tests/DependencyInjection/SonataAdminExtensionTest.php
index efe791a8ad..fec2734734 100644
--- a/tests/DependencyInjection/SonataAdminExtensionTest.php
+++ b/tests/DependencyInjection/SonataAdminExtensionTest.php
@@ -33,6 +33,7 @@
use Sonata\AdminBundle\Templating\MutableTemplateRegistryInterface;
use Sonata\AdminBundle\Templating\TemplateRegistry;
use Sonata\AdminBundle\Translator\BCLabelTranslatorStrategy;
+use Sonata\AdminBundle\Translator\Extractor\AdminExtractor;
use Sonata\AdminBundle\Translator\FormLabelTranslatorStrategy;
use Sonata\AdminBundle\Translator\LabelTranslatorStrategyInterface;
use Sonata\AdminBundle\Translator\NativeLabelTranslatorStrategy;
@@ -97,6 +98,7 @@ public function testHasCoreServicesAlias(): void
MutableTemplateRegistryInterface::class,
TemplateRegistry::class
);
+ $this->assertContainerBuilderHasService(AdminExtractor::class);
}
/**
diff --git a/tests/Translator/Extractor/AdminExtractorTest.php b/tests/Translator/Extractor/AdminExtractorTest.php
new file mode 100644
index 0000000000..fba8b4a314
--- /dev/null
+++ b/tests/Translator/Extractor/AdminExtractorTest.php
@@ -0,0 +1,124 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Sonata\AdminBundle\Tests\Translator\Extractor;
+
+use PHPUnit\Framework\TestCase;
+use Sonata\AdminBundle\Admin\AdminInterface;
+use Sonata\AdminBundle\Admin\BreadcrumbsBuilderInterface;
+use Sonata\AdminBundle\Admin\Pool;
+use Sonata\AdminBundle\Translator\Extractor\AdminExtractor;
+use Symfony\Component\DependencyInjection\Container;
+use Symfony\Component\Translation\MessageCatalogue;
+
+final class AdminExtractorTest extends TestCase
+{
+ /**
+ * @var AdminExtractor
+ */
+ private $adminExtractor;
+
+ /**
+ * @var Pool
+ */
+ private $pool;
+
+ /**
+ * @var AdminInterface
+ */
+ private $fooAdmin;
+
+ /**
+ * @var AdminInterface
+ */
+ private $barAdmin;
+
+ /**
+ * @var BreadcrumbsBuilderInterface
+ */
+ private $breadcrumbsBuilder;
+
+ protected function setUp(): void
+ {
+ $this->fooAdmin = $this->createStub(AdminInterface::class);
+ $this->barAdmin = $this->createStub(AdminInterface::class);
+
+ $container = new Container();
+ $container->set('foo_admin', $this->fooAdmin);
+ $container->set('bar_admin', $this->barAdmin);
+
+ $this->pool = new Pool($container, 'title', 'logo_title');
+ $this->pool->setAdminServiceIds(['foo_admin', 'bar_admin']);
+ $this->pool->setAdminGroups(['group' => [
+ 'label_catalogue' => 'admin_domain',
+ ]]);
+
+ $this->breadcrumbsBuilder = $this->createMock(BreadcrumbsBuilderInterface::class);
+ $this->adminExtractor = new AdminExtractor($this->pool, $this->breadcrumbsBuilder);
+ }
+
+ public function testExtractEmpty(): void
+ {
+ $catalogue = new MessageCatalogue('en');
+
+ $this->adminExtractor->extract([], $catalogue);
+ $this->assertFalse($catalogue->has('foo', 'foo_admin_domain'));
+ }
+
+ public function testExtract(): void
+ {
+ $this->fooAdmin
+ ->method('getLabel')
+ ->willReturn('foo_label');
+ $this->fooAdmin
+ ->method('getTranslationDomain')
+ ->willReturn('foo_admin_domain');
+
+ $catalogue = new MessageCatalogue('en');
+
+ $this->adminExtractor->extract([], $catalogue);
+
+ $this->assertCount(2, $catalogue->getDomains());
+ $message = $catalogue->get('foo', 'foo_admin_domain');
+ $this->assertSame('foo', $message);
+
+ $this->assertTrue($catalogue->has('group', 'admin_domain'));
+ $this->assertTrue($catalogue->has('foo_label', 'foo_admin_domain'));
+ }
+
+ public function testExtractWithException(): void
+ {
+ $this->fooAdmin
+ ->method('getShow')
+ ->willThrowException(new \RuntimeException('Foo throws exception'));
+
+ $catalogue = new MessageCatalogue('en');
+
+ $this->expectException(\RuntimeException::class);
+ $this->expectExceptionMessage('Foo throws exception');
+
+ $this->adminExtractor->extract([], $catalogue);
+ }
+
+ public function testExtractCallsBreadcrumbs(): void
+ {
+ $numberOfAdmins = \count($this->pool->getAdminServiceIds());
+ $numberOfActionsToCheck = 6;
+
+ $this->breadcrumbsBuilder->expects($this->exactly($numberOfAdmins * $numberOfActionsToCheck))
+ ->method('getBreadcrumbs');
+ $catalogue = new MessageCatalogue('en');
+
+ $this->adminExtractor->extract([], $catalogue);
+ }
+}
diff --git a/tests/Translator/Extractor/JMSTranslatorBundle/AdminExtractorTest.php b/tests/Translator/Extractor/JMSTranslatorBundle/AdminExtractorTest.php
index 97c412aadd..9dd79546e9 100644
--- a/tests/Translator/Extractor/JMSTranslatorBundle/AdminExtractorTest.php
+++ b/tests/Translator/Extractor/JMSTranslatorBundle/AdminExtractorTest.php
@@ -27,6 +27,10 @@
/**
* Test for AdminExtractor.
*
+ * NEXT_MAJOR: Remove this class.
+ *
+ * @group legacy
+ *
* @author Andrej Hudec
*/
class AdminExtractorTest extends TestCase