diff --git a/.phpstan/phpstan-baseline.neon b/.phpstan/phpstan-baseline.neon index 7a1ba644762..6631eb6280a 100644 --- a/.phpstan/phpstan-baseline.neon +++ b/.phpstan/phpstan-baseline.neon @@ -33,7 +33,7 @@ parameters: - # will be fixed in v4. Code is marked as deprecated message: "#^Result of \\&\\& is always false\\.$#" - count: 1 + count: 2 path: ../src/Admin/AbstractAdmin.php - @@ -271,3 +271,8 @@ parameters: message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" count: 1 path: ../src/Menu/MenuBuilder.php + + - + message: '#Else branch is unreachable because ternary operator condition is always true#' + count: 1 + path: ../src/Admin/AbstractAdmin.php diff --git a/composer.json b/composer.json index a97e30037b5..687fb828382 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,7 @@ "symfony/security-core": "^4.4", "symfony/security-csrf": "^4.4", "symfony/string": "^5.1", - "symfony/translation": "^4.4", + "symfony/translation": "^4.4 || ^5.1", "symfony/twig-bridge": "^4.4", "symfony/twig-bundle": "^4.4", "symfony/validator": "^4.4", diff --git a/src/Admin/AbstractAdmin.php b/src/Admin/AbstractAdmin.php index e724129b6b6..d061e1b0e47 100644 --- a/src/Admin/AbstractAdmin.php +++ b/src/Admin/AbstractAdmin.php @@ -52,9 +52,10 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface as RoutingUrlGeneratorInterface; use Symfony\Component\Security\Acl\Model\DomainObjectInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; use Symfony\Component\Validator\Mapping\GenericMetadata; use Symfony\Component\Validator\Validator\ValidatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Thomas Rabaix @@ -309,7 +310,7 @@ abstract class AbstractAdmin implements AdminInterface, DomainObjectInterface, A * * NEXT_MAJOR: remove this property * - * @var \Symfony\Component\Translation\TranslatorInterface + * @var TranslatorInterface|LegacyTranslatorInterface * * @deprecated since sonata-project/admin-bundle 3.9, to be removed with 4.0 */ @@ -2441,6 +2442,10 @@ public function transChoice($id, $count, array $parameters = [], $domain = null, __METHOD__ ), E_USER_DEPRECATED); + if (!method_exists($this->translator, 'transChoice')) { + throw new \RuntimeException('AbstractAdmin::transChoice is only supported with symfony/translation 4.4'); + } + $domain = $domain ?: $this->getTranslationDomain(); return $this->translator->transChoice($id, $count, $parameters, $domain, $locale); @@ -2461,9 +2466,11 @@ public function getTranslationDomain() * * NEXT_MAJOR: remove this method * + * @param LegacyTranslatorInterface|TranslatorInterface $translator + * * @deprecated since sonata-project/admin-bundle 3.9, to be removed with 4.0 */ - public function setTranslator(TranslatorInterface $translator) + public function setTranslator($translator) { $args = \func_get_args(); if (isset($args[1]) && $args[1]) { @@ -2473,6 +2480,16 @@ public function setTranslator(TranslatorInterface $translator) ), E_USER_DEPRECATED); } + if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) { + throw new \TypeError(sprintf( + 'Argument 1 passed to "%s()" must be an instance of "%s" or "%s", %s given.', + __METHOD__, + LegacyTranslatorInterface::class, + TranslatorInterface::class, + \is_object($translator) ? 'instance of '.\get_class($translator) : \gettype($translator) + )); + } + $this->translator = $translator; } @@ -2482,6 +2499,8 @@ public function setTranslator(TranslatorInterface $translator) * NEXT_MAJOR: remove this method * * @deprecated since sonata-project/admin-bundle 3.9, to be removed with 4.0 + * + * @return LegacyTranslatorInterface|TranslatorInterface */ public function getTranslator() { diff --git a/src/Form/Type/Filter/ChoiceType.php b/src/Form/Type/Filter/ChoiceType.php index 91638fb9317..462cfe3855b 100644 --- a/src/Form/Type/Filter/ChoiceType.php +++ b/src/Form/Type/Filter/ChoiceType.php @@ -18,7 +18,8 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType as FormChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @final since sonata-project/admin-bundle 3.52 @@ -47,12 +48,22 @@ class ChoiceType extends AbstractType * * @deprecated since sonata-project/admin-bundle 3.5, to be removed with 4.0 * - * @var TranslatorInterface + * @var TranslatorInterface|LegacyTranslatorInterface */ protected $translator; - public function __construct(TranslatorInterface $translator) + public function __construct($translator) { + if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) { + throw new \TypeError(sprintf( + 'Argument 1 passed to "%s()" must be an instance of "%s" or "%s", %s given.', + __METHOD__, + LegacyTranslatorInterface::class, + TranslatorInterface::class, + \is_object($translator) ? 'instance of '.\get_class($translator) : \gettype($translator) + )); + } + $this->translator = $translator; } diff --git a/src/Form/Type/Filter/DateRangeType.php b/src/Form/Type/Filter/DateRangeType.php index 01825fc1c00..3af88a76ef9 100644 --- a/src/Form/Type/Filter/DateRangeType.php +++ b/src/Form/Type/Filter/DateRangeType.php @@ -18,7 +18,8 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @final since sonata-project/admin-bundle 3.52 @@ -42,12 +43,22 @@ class DateRangeType extends AbstractType * * @deprecated since sonata-project/admin-bundle 3.5, to be removed with 4.0 * - * @var TranslatorInterface + * @var TranslatorInterface|LegacyTranslatorInterface */ protected $translator; - public function __construct(TranslatorInterface $translator) + public function __construct($translator) { + if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) { + throw new \TypeError(sprintf( + 'Argument 1 passed to "%s()" must be an instance of "%s" or "%s", %s given.', + __METHOD__, + LegacyTranslatorInterface::class, + TranslatorInterface::class, + \is_object($translator) ? 'instance of '.\get_class($translator) : \gettype($translator) + )); + } + $this->translator = $translator; } diff --git a/src/Form/Type/Filter/DateTimeRangeType.php b/src/Form/Type/Filter/DateTimeRangeType.php index 66f5309c56c..b6d45b6dd99 100644 --- a/src/Form/Type/Filter/DateTimeRangeType.php +++ b/src/Form/Type/Filter/DateTimeRangeType.php @@ -18,7 +18,8 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @final since sonata-project/admin-bundle 3.52 @@ -42,12 +43,22 @@ class DateTimeRangeType extends AbstractType * * @deprecated since sonata-project/admin-bundle 3.5, to be removed with 4.0 * - * @var TranslatorInterface + * @var TranslatorInterface|LegacyTranslatorInterface */ protected $translator; - public function __construct(TranslatorInterface $translator) + public function __construct($translator) { + if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) { + throw new \TypeError(sprintf( + 'Argument 1 passed to "%s()" must be an instance of "%s" or "%s", %s given.', + __METHOD__, + LegacyTranslatorInterface::class, + TranslatorInterface::class, + \is_object($translator) ? 'instance of '.\get_class($translator) : \gettype($translator) + )); + } + $this->translator = $translator; } diff --git a/src/Form/Type/Filter/DateTimeType.php b/src/Form/Type/Filter/DateTimeType.php index 4bb209c850c..469799642ea 100644 --- a/src/Form/Type/Filter/DateTimeType.php +++ b/src/Form/Type/Filter/DateTimeType.php @@ -18,7 +18,8 @@ use Symfony\Component\Form\Extension\Core\Type\DateTimeType as FormDateTimeType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @final since sonata-project/admin-bundle 3.52 @@ -67,12 +68,22 @@ class DateTimeType extends AbstractType * * @deprecated since sonata-project/admin-bundle 3.5, to be removed with 4.0 * - * @var TranslatorInterface + * @var TranslatorInterface|LegacyTranslatorInterface */ protected $translator; - public function __construct(TranslatorInterface $translator) + public function __construct($translator) { + if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) { + throw new \TypeError(sprintf( + 'Argument 1 passed to "%s()" must be an instance of "%s" or "%s", %s given.', + __METHOD__, + LegacyTranslatorInterface::class, + TranslatorInterface::class, + \is_object($translator) ? 'instance of '.\get_class($translator) : \gettype($translator) + )); + } + $this->translator = $translator; } diff --git a/src/Form/Type/Filter/DateType.php b/src/Form/Type/Filter/DateType.php index 24cefd185e8..81bdef23761 100644 --- a/src/Form/Type/Filter/DateType.php +++ b/src/Form/Type/Filter/DateType.php @@ -18,7 +18,8 @@ use Symfony\Component\Form\Extension\Core\Type\DateType as FormDateType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @final since sonata-project/admin-bundle 3.52 @@ -67,12 +68,22 @@ class DateType extends AbstractType * * @deprecated since sonata-project/admin-bundle 3.5, to be removed with 4.0 * - * @var TranslatorInterface + * @var TranslatorInterface|LegacyTranslatorInterface */ protected $translator; - public function __construct(TranslatorInterface $translator) + public function __construct($translator) { + if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) { + throw new \TypeError(sprintf( + 'Argument 1 passed to "%s()" must be an instance of "%s" or "%s", %s given.', + __METHOD__, + LegacyTranslatorInterface::class, + TranslatorInterface::class, + \is_object($translator) ? 'instance of '.\get_class($translator) : \gettype($translator) + )); + } + $this->translator = $translator; } diff --git a/src/Form/Type/Filter/NumberType.php b/src/Form/Type/Filter/NumberType.php index 4da94e8a31e..2f21765dc89 100644 --- a/src/Form/Type/Filter/NumberType.php +++ b/src/Form/Type/Filter/NumberType.php @@ -18,7 +18,8 @@ use Symfony\Component\Form\Extension\Core\Type\NumberType as FormNumberType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @final since sonata-project/admin-bundle 3.52 @@ -57,12 +58,22 @@ class NumberType extends AbstractType * * @deprecated since sonata-project/admin-bundle 3.5, to be removed with 4.0 * - * @var TranslatorInterface + * @var TranslatorInterface|LegacyTranslatorInterface */ protected $translator; - public function __construct(TranslatorInterface $translator) + public function __construct($translator) { + if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) { + throw new \TypeError(sprintf( + 'Argument 1 passed to "%s()" must be an instance of "%s" or "%s", %s given.', + __METHOD__, + LegacyTranslatorInterface::class, + TranslatorInterface::class, + \is_object($translator) ? 'instance of '.\get_class($translator) : \gettype($translator) + )); + } + $this->translator = $translator; } diff --git a/src/Twig/Extension/SonataAdminExtension.php b/src/Twig/Extension/SonataAdminExtension.php index 2d4553ea50f..811a28ab05c 100644 --- a/src/Twig/Extension/SonataAdminExtension.php +++ b/src/Twig/Extension/SonataAdminExtension.php @@ -26,7 +26,7 @@ use Symfony\Component\Security\Acl\Voter\FieldVote; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; -use Symfony\Component\Translation\TranslatorInterface as LegacyTranslationInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Environment; use Twig\Error\LoaderError; @@ -104,11 +104,11 @@ public function __construct( ), E_USER_DEPRECATED); } - if (!$translator instanceof TranslatorInterface && !$translator instanceof LegacyTranslationInterface) { + if (!$translator instanceof TranslatorInterface && !$translator instanceof LegacyTranslatorInterface) { throw new \TypeError(sprintf( 'Argument 2 must be an instance of "%s" or preferably "%s", "%s given"', TranslatorInterface::class, - LegacyTranslationInterface::class, + LegacyTranslatorInterface::class, \get_class($translator) )); } diff --git a/tests/Admin/AdminTest.php b/tests/Admin/AdminTest.php index f56e2ae2dfe..247e07ff2ac 100644 --- a/tests/Admin/AdminTest.php +++ b/tests/Admin/AdminTest.php @@ -83,10 +83,11 @@ use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; use Symfony\Component\Validator\Mapping\MemberMetadata; use Symfony\Component\Validator\Mapping\PropertyMetadataInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class AdminTest extends TestCase { @@ -1445,10 +1446,16 @@ public function testTransWithMessageDomain(): void */ public function testTransChoice(): void { + if (!interface_exists(LegacyTranslatorInterface::class)) { + $this->markTestSkipped('This test is only available using Symfony 4'); + + return; + } + $admin = new PostAdmin('sonata.post.admin.post', 'NewsBundle\Entity\Post', 'Sonata\NewsBundle\Controller\PostAdminController'); $admin->setTranslationDomain('fooMessageDomain'); - $translator = $this->createMock(TranslatorInterface::class); + $translator = $this->createMock(LegacyTranslatorInterface::class); $admin->setTranslator($translator); $translator->expects($this->once()) @@ -1464,9 +1471,15 @@ public function testTransChoice(): void */ public function testTransChoiceWithMessageDomain(): void { + if (!interface_exists(LegacyTranslatorInterface::class)) { + $this->markTestSkipped('This test is only available using Symfony 4'); + + return; + } + $admin = new PostAdmin('sonata.post.admin.post', 'NewsBundle\Entity\Post', 'Sonata\NewsBundle\Controller\PostAdminController'); - $translator = $this->createMock(TranslatorInterface::class); + $translator = $this->createMock(LegacyTranslatorInterface::class); $admin->setTranslator($translator); $translator->expects($this->once()) diff --git a/tests/Form/Type/Filter/DateTimeRangeTypeTest.php b/tests/Form/Type/Filter/DateTimeRangeTypeTest.php index 6741e8ccedd..eeb1666e8ef 100644 --- a/tests/Form/Type/Filter/DateTimeRangeTypeTest.php +++ b/tests/Form/Type/Filter/DateTimeRangeTypeTest.php @@ -17,7 +17,7 @@ use Sonata\Form\Type\DateTimeRangeType as FormDateTimeRangeType; use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class DateTimeRangeTypeTest extends TypeTestCase { diff --git a/tests/Form/Widget/FormSonataFilterChoiceWidgetTest.php b/tests/Form/Widget/FormSonataFilterChoiceWidgetTest.php index b2ab5e061a6..e4b5faec8cc 100644 --- a/tests/Form/Widget/FormSonataFilterChoiceWidgetTest.php +++ b/tests/Form/Widget/FormSonataFilterChoiceWidgetTest.php @@ -18,7 +18,7 @@ use Sonata\AdminBundle\Tests\Fixtures\TestExtension; use Symfony\Component\Form\Extension\Core\Type\ChoiceType as SymfonyChoiceType; use Symfony\Component\Form\FormTypeGuesserInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class FormSonataFilterChoiceWidgetTest extends BaseWidgetTest { diff --git a/tests/Translator/Extractor/JMSTranslatorBundle/AdminExtractorTest.php b/tests/Translator/Extractor/JMSTranslatorBundle/AdminExtractorTest.php index 7e56bbaa14f..6cb6720eeb2 100644 --- a/tests/Translator/Extractor/JMSTranslatorBundle/AdminExtractorTest.php +++ b/tests/Translator/Extractor/JMSTranslatorBundle/AdminExtractorTest.php @@ -23,6 +23,7 @@ use Sonata\AdminBundle\Admin\Pool; use Sonata\AdminBundle\Translator\Extractor\JMSTranslatorBundle\AdminExtractor; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; /** * Test for AdminExtractor. @@ -62,6 +63,10 @@ class AdminExtractorTest extends TestCase protected function setUp(): void { + if (!interface_exists(LegacyTranslatorInterface::class)) { + $this->markTestSkipped('This test is only available using Symfony 4'); + } + if (!interface_exists(ExtractorInterface::class)) { $this->markTestSkipped('JMS Translator Bundle does not exist'); } diff --git a/tests/Twig/Extension/SonataAdminExtensionTest.php b/tests/Twig/Extension/SonataAdminExtensionTest.php index 54dad24d8fb..83ecad40f65 100644 --- a/tests/Twig/Extension/SonataAdminExtensionTest.php +++ b/tests/Twig/Extension/SonataAdminExtensionTest.php @@ -290,6 +290,12 @@ public function testConstructThrowsExceptionWithWrongTranslationArgument(): void */ public function testConstructWithLegacyTranslator(): void { + if (!interface_exists(LegacyTranslatorInterface::class)) { + $this->markTestSkipped('This test is only available using Symfony 4'); + + return; + } + new SonataAdminExtension( $this->pool, null,