diff --git a/src/Sylius/Bundle/ApiBundle/Doctrine/ORM/QueryExtension/Common/TranslationOrderLocaleExtension.php b/src/Sylius/Bundle/ApiBundle/Doctrine/ORM/QueryExtension/Common/TranslationOrderLocaleExtension.php index ee1f119523..753851f230 100644 --- a/src/Sylius/Bundle/ApiBundle/Doctrine/ORM/QueryExtension/Common/TranslationOrderLocaleExtension.php +++ b/src/Sylius/Bundle/ApiBundle/Doctrine/ORM/QueryExtension/Common/TranslationOrderLocaleExtension.php @@ -18,10 +18,16 @@ use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; +use Sylius\Bundle\ApiBundle\SectionResolver\ShopApiSection; +use Sylius\Bundle\CoreBundle\SectionResolver\SectionProviderInterface; use Sylius\Component\Resource\Model\TranslatableInterface; final class TranslationOrderLocaleExtension implements QueryCollectionExtensionInterface { + public function __construct(private readonly SectionProviderInterface $sectionProvider) + { + } + /** @param array $context */ public function applyToCollection( QueryBuilder $queryBuilder, @@ -42,11 +48,24 @@ final class TranslationOrderLocaleExtension implements QueryCollectionExtensionI } $localeCode = $this->resolveContextLocaleCode($context); + $rootAlias = $queryBuilder->getRootAliases()[0]; + if (empty($localeCode)) { + if ($this->sectionProvider->getSection() instanceof ShopApiSection) { + return; + } + + $queryBuilder + ->addSelect('translation') + ->leftJoin( + sprintf('%s.translations', $rootAlias), + 'translation', + ) + ; + return; } - $rootAlias = $queryBuilder->getRootAliases()[0]; $localeCodeParameterName = $queryNameGenerator->generateParameterName('localeCode'); $queryBuilder diff --git a/src/Sylius/Bundle/ApiBundle/Filter/Doctrine/TranslationOrderNameAndLocaleFilter.php b/src/Sylius/Bundle/ApiBundle/Filter/Doctrine/TranslationOrderNameAndLocaleFilter.php index 60f4f41277..358b46932f 100644 --- a/src/Sylius/Bundle/ApiBundle/Filter/Doctrine/TranslationOrderNameAndLocaleFilter.php +++ b/src/Sylius/Bundle/ApiBundle/Filter/Doctrine/TranslationOrderNameAndLocaleFilter.php @@ -23,7 +23,7 @@ final class TranslationOrderNameAndLocaleFilter extends AbstractFilter { protected function filterProperty( string $property, - $value, + $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/extensions.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/extensions.xml index 7ce981605d..f0d9abbc08 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/extensions.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/extensions.xml @@ -22,6 +22,7 @@ + diff --git a/src/Sylius/Bundle/ApiBundle/Tests/Doctrine/ORM/QueryExtension/Common/TranslationOrderLocaleExtensionTest.php b/src/Sylius/Bundle/ApiBundle/Tests/Doctrine/ORM/QueryExtension/Common/TranslationOrderLocaleExtensionTest.php index 1586c8f0ee..5d71b99ee3 100644 --- a/src/Sylius/Bundle/ApiBundle/Tests/Doctrine/ORM/QueryExtension/Common/TranslationOrderLocaleExtensionTest.php +++ b/src/Sylius/Bundle/ApiBundle/Tests/Doctrine/ORM/QueryExtension/Common/TranslationOrderLocaleExtensionTest.php @@ -21,24 +21,29 @@ use Doctrine\ORM\QueryBuilder; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Sylius\Bundle\ApiBundle\Doctrine\ORM\QueryExtension\Common\TranslationOrderLocaleExtension; +use Sylius\Bundle\ApiBundle\SectionResolver\ShopApiSection; +use Sylius\Bundle\CoreBundle\SectionResolver\SectionProviderInterface; use Sylius\Component\Core\Model\ProductInterface; final class TranslationOrderLocaleExtensionTest extends TestCase { - private QueryNameGeneratorInterface&MockObject $queryNameGenerator; + private MockObject&QueryNameGeneratorInterface $queryNameGenerator; - private QueryBuilder&MockObject $queryBuilder; + private MockObject&QueryBuilder $queryBuilder; private EntityManagerInterface&MockObject $entityManager; private ClassMetadata&MockObject $classMetadata; + private MockObject&SectionProviderInterface $sectionProvider; + protected function setUp(): void { $this->queryNameGenerator = $this->createMock(QueryNameGeneratorInterface::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->entityManager = $this->createMock(EntityManagerInterface::class); $this->classMetadata = $this->createMock(ClassMetadata::class); + $this->sectionProvider = $this->createMock(SectionProviderInterface::class); } /** @test */ @@ -101,7 +106,7 @@ final class TranslationOrderLocaleExtensionTest extends TestCase } /** @test */ - public function it_does_nothing_when_no_locale_code_has_been_resolved_from_filters(): void + public function it_joins_all_translations_if_no_locale_code_has_been_resolved_from_filters(): void { $this->queryBuilder ->expects($this->once()) @@ -123,6 +128,70 @@ final class TranslationOrderLocaleExtensionTest extends TestCase ->willReturn(true) ; + $this->queryBuilder + ->expects($this->once()) + ->method('getRootAliases') + ->willReturn(['alias']) + ; + + $this->queryBuilder + ->expects($this->once()) + ->method('addSelect') + ->with('translation') + ->willReturnSelf() + ; + + $this->queryBuilder + ->expects($this->once()) + ->method('leftJoin') + ->with('alias.translations', 'translation') + ->willReturnSelf() + ; + + $this->doApplyToCollection(ProductInterface::class, [ + 'filters' => [ + 'order' => [ + 'translation.name' => 'test', + ], + ], + ]); + } + + /** @test */ + public function it_does_nothing_when_no_locale_code_has_been_resolved_from_filters_and_it_is_shop_section(): void + { + $this->queryBuilder + ->expects($this->once()) + ->method('getEntityManager') + ->willReturn($this->entityManager) + ; + + $this->entityManager + ->expects($this->once()) + ->method('getClassMetadata') + ->with(ProductInterface::class) + ->willReturn($this->classMetadata) + ; + + $this->classMetadata + ->expects($this->once()) + ->method('hasAssociation') + ->with('translations') + ->willReturn(true) + ; + + $this->queryBuilder + ->expects($this->once()) + ->method('getRootAliases') + ->willReturn(['alias']) + ; + + $this->sectionProvider + ->expects($this->once()) + ->method('getSection') + ->willReturn(new ShopApiSection()) + ; + $this->queryBuilder ->expects($this->never()) ->method('leftJoin') @@ -140,6 +209,7 @@ final class TranslationOrderLocaleExtensionTest extends TestCase /** * @test + * * @dataProvider getLocaleCodeContexts */ public function it_joins_on_a_specific_translation_when_locale_code_has_been_resolved_from_filters( @@ -210,7 +280,7 @@ final class TranslationOrderLocaleExtensionTest extends TestCase /** @param array $context */ private function doApplyToCollection(string $resourceClass, array $context = []): void { - (new TranslationOrderLocaleExtension())->applyToCollection( + (new TranslationOrderLocaleExtension($this->sectionProvider))->applyToCollection( queryBuilder: $this->queryBuilder, queryNameGenerator: $this->queryNameGenerator, resourceClass: $resourceClass,