Skip to content

Commit 307b7c0

Browse files
authored
[UPMERGE] 1.13 -> 1.14 (#1067)
This PR has been generated automatically. For more details see [upmerge_pr.yaml](/Sylius/SyliusResourceBundle/blob/1.13/.github/workflows/upmerge_pr.yaml). **Remember!** The upmerge should always be merged with using `Merge pull request` button. In case of conflicts, please resolve them manually with usign the following commands: ``` git fetch upstream gh pr checkout <this-pr-number> git merge upstream/1.14 -m "Resolve conflicts between 1.13 and 1.14" ``` If you use other name for the upstream remote, please replace `upstream` with the name of your remote pointing to the `Sylius/SyliusResourceBundle` repository. Once the conflicts are resolved, please run `git merge --continue` and push the changes to this PR.
2 parents af31ef1 + a6d4d40 commit 307b7c0

File tree

12 files changed

+245
-123
lines changed

12 files changed

+245
-123
lines changed

CHANGELOG.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
## CHANGELOG
22

3+
## v1.13.1 (2025-09-24)
4+
5+
#### Details
6+
7+
- [#1037](https://github.com/Sylius/SyliusResourceBundle/pull/1037) Add missing event short name on apply state machine transition ([@loic425](https://github.com/loic425))
8+
- [#1045](https://github.com/Sylius/SyliusResourceBundle/pull/1045) Fix - Add missing redirect & redirect arguments ([@loic425](https://github.com/loic425))
9+
- [#1064](https://github.com/Sylius/SyliusResourceBundle/pull/1064) Fix missing behat transliterator package ([@loic425](https://github.com/loic425))
10+
- [#1063](https://github.com/Sylius/SyliusResourceBundle/pull/1063) Add an error message for non existing repository method & suggest to use CreatePaginatorTrait ([@loic425](https://github.com/loic425))
11+
312
## v1.13.0 (2025-06-04)
413

14+
#### Details
15+
516
- [#1025](https://github.com/Sylius/SyliusResourceBundle/pull/1025) Fix implicit nullable parameter + add ECS rule to 1.12 ([@GSadee](https://github.com/GSadee))
617
- [#1024](https://github.com/Sylius/SyliusResourceBundle/pull/1024) Fix implicit nullable parameter + add ECS rule ([@GSadee](https://github.com/GSadee))
718

8-
#### Details
9-
1019
## v1.13.0-BETA.1 (2025-05-28)
1120

1221
#### Details

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
],
2727
"require": {
2828
"php": "^8.1",
29+
"behat/transliterator": "^1.2",
2930
"babdev/pagerfanta-bundle": "^4.4",
3031
"doctrine/annotations": "^2.0",
3132
"doctrine/collections": "^2.2",
@@ -87,7 +88,7 @@
8788
"vimeo/psalm": "^5.26",
8889
"willdurand/hateoas-bundle": "^2.5",
8990
"winzou/state-machine-bundle": "^0.6.2",
90-
"zenstruck/foundry": "^2.3"
91+
"zenstruck/foundry": "^2.3 <2.7"
9192
},
9293
"conflict": {
9394
"doctrine/orm": "<2.18",

psalm.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@
4040
<referencedFunction name="ReflectionClass::getAttributes" />
4141
<file name="src/Bundle/Form/DataTransformer/CollectionToStringTransformer.php" />
4242
<file name="src/Component/src/Doctrine/Persistence/InMemoryRepository.php" />
43+
<file name="src/Component/src/Symfony/Request/State/Provider.php" />
4344
</errorLevel>
4445
</ArgumentTypeCoercion>
4546

4647
<DeprecatedClass>
4748
<errorLevel type="info">
4849
<referencedClass name="Doctrine\ORM\Event\LifecycleEventArgs" /> <!-- deprecated in doctrine/orm 2.14 -->
50+
<referencedClass name="Gedmo\Sluggable\Util\Urlizer" /> <!-- deprecated in gedmo/doctrine-extensions 3.21 -->
4951
</errorLevel>
5052
<errorLevel type="suppress">
5153
<referencedClass name="Sylius\Component\Resource\Exception\VariantWithNoOptionsValuesException" />
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sylius\Bundle\ResourceBundle\Doctrine\ORM;
15+
16+
use Doctrine\ORM\EntityRepository as DoctrineEntityRepository;
17+
use Doctrine\ORM\QueryBuilder;
18+
use Pagerfanta\Adapter\ArrayAdapter;
19+
use Pagerfanta\Doctrine\ORM\QueryAdapter;
20+
use Pagerfanta\Pagerfanta;
21+
use Pagerfanta\PagerfantaInterface;
22+
use Sylius\Resource\Model\ResourceInterface;
23+
24+
/**
25+
* @mixin DoctrineEntityRepository
26+
*/
27+
trait CreatePaginatorTrait
28+
{
29+
/**
30+
* @return iterable<int, ResourceInterface>
31+
*/
32+
public function createPaginator(array $criteria = [], array $sorting = []): iterable
33+
{
34+
$queryBuilder = $this->createQueryBuilder('o');
35+
36+
$this->applyCriteria($queryBuilder, $criteria);
37+
$this->applySorting($queryBuilder, $sorting);
38+
39+
return $this->getPaginator($queryBuilder);
40+
}
41+
42+
protected function getPaginator(QueryBuilder $queryBuilder): PagerfantaInterface
43+
{
44+
if (!class_exists(QueryAdapter::class)) {
45+
throw new \LogicException('You can not use the "paginator" if Pargefanta Doctrine ORM Adapter is not available. Try running "composer require pagerfanta/doctrine-orm-adapter".');
46+
}
47+
48+
// Use output walkers option in the query adapter should be false as it affects performance greatly (see sylius/sylius#3775)
49+
return new Pagerfanta(new QueryAdapter($queryBuilder, false, false));
50+
}
51+
52+
/**
53+
* @param array $objects
54+
*/
55+
protected function getArrayPaginator($objects): PagerfantaInterface
56+
{
57+
return new Pagerfanta(new ArrayAdapter($objects));
58+
}
59+
60+
protected function applyCriteria(QueryBuilder $queryBuilder, array $criteria = []): void
61+
{
62+
foreach ($criteria as $property => $value) {
63+
if (!in_array($property, array_merge($this->getClassMetadata()->getAssociationNames(), $this->getClassMetadata()->getFieldNames()), true)) {
64+
continue;
65+
}
66+
67+
$name = $this->getPropertyName($property);
68+
69+
if (null === $value) {
70+
$queryBuilder->andWhere($queryBuilder->expr()->isNull($name));
71+
} elseif (is_array($value)) {
72+
$queryBuilder->andWhere($queryBuilder->expr()->in($name, $value));
73+
} elseif ('' !== $value) {
74+
$parameter = str_replace('.', '_', $property);
75+
$queryBuilder
76+
->andWhere($queryBuilder->expr()->eq($name, ':' . $parameter))
77+
->setParameter($parameter, $value)
78+
;
79+
}
80+
}
81+
}
82+
83+
protected function applySorting(QueryBuilder $queryBuilder, array $sorting = []): void
84+
{
85+
foreach ($sorting as $property => $order) {
86+
if (!in_array($property, array_merge($this->getClassMetadata()->getAssociationNames(), $this->getClassMetadata()->getFieldNames()), true)) {
87+
continue;
88+
}
89+
90+
if (!empty($order)) {
91+
$queryBuilder->addOrderBy($this->getPropertyName($property), $order);
92+
}
93+
}
94+
}
95+
96+
protected function getPropertyName(string $name): string
97+
{
98+
if (!str_contains($name, '.')) {
99+
return 'o' . '.' . $name;
100+
}
101+
102+
return $name;
103+
}
104+
}

src/Bundle/Doctrine/ORM/ResourceRepositoryTrait.php

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,16 @@
1313

1414
namespace Sylius\Bundle\ResourceBundle\Doctrine\ORM;
1515

16-
use Doctrine\ORM\EntityManagerInterface;
17-
use Doctrine\ORM\Mapping\ClassMetadata;
18-
use Doctrine\ORM\QueryBuilder;
19-
use Pagerfanta\Adapter\ArrayAdapter;
20-
use Pagerfanta\Doctrine\ORM\QueryAdapter;
21-
use Pagerfanta\Pagerfanta;
16+
use Doctrine\ORM\EntityRepository as DoctrineEntityRepository;
2217
use Sylius\Resource\Model\ResourceInterface;
2318

2419
/**
25-
* @property EntityManagerInterface $_em
26-
* @property ClassMetadata $_class
27-
*
28-
* @method QueryBuilder createQueryBuilder(string $alias, string $indexBy = null)
29-
* @method ?object find($id, $lockMode = null, $lockVersion = null)
20+
* @mixin DoctrineEntityRepository
3021
*/
3122
trait ResourceRepositoryTrait
3223
{
24+
use CreatePaginatorTrait;
25+
3326
public function add(ResourceInterface $resource): void
3427
{
3528
$this->getEntityManager()->persist($resource);
@@ -43,80 +36,4 @@ public function remove(ResourceInterface $resource): void
4336
$this->getEntityManager()->flush();
4437
}
4538
}
46-
47-
/**
48-
* @return iterable<int, ResourceInterface>
49-
*/
50-
public function createPaginator(array $criteria = [], array $sorting = []): iterable
51-
{
52-
$queryBuilder = $this->createQueryBuilder('o');
53-
54-
$this->applyCriteria($queryBuilder, $criteria);
55-
$this->applySorting($queryBuilder, $sorting);
56-
57-
return $this->getPaginator($queryBuilder);
58-
}
59-
60-
protected function getPaginator(QueryBuilder $queryBuilder): Pagerfanta
61-
{
62-
if (!class_exists(QueryAdapter::class)) {
63-
throw new \LogicException('You can not use the "paginator" if Pargefanta Doctrine ORM Adapter is not available. Try running "composer require pagerfanta/doctrine-orm-adapter".');
64-
}
65-
66-
// Use output walkers option in the query adapter should be false as it affects performance greatly (see sylius/sylius#3775)
67-
return new Pagerfanta(new QueryAdapter($queryBuilder, false, false));
68-
}
69-
70-
/**
71-
* @param array $objects
72-
*/
73-
protected function getArrayPaginator($objects): Pagerfanta
74-
{
75-
return new Pagerfanta(new ArrayAdapter($objects));
76-
}
77-
78-
protected function applyCriteria(QueryBuilder $queryBuilder, array $criteria = []): void
79-
{
80-
foreach ($criteria as $property => $value) {
81-
if (!in_array($property, array_merge($this->getClassMetadata()->getAssociationNames(), $this->getClassMetadata()->getFieldNames()), true)) {
82-
continue;
83-
}
84-
85-
$name = $this->getPropertyName($property);
86-
87-
if (null === $value) {
88-
$queryBuilder->andWhere($queryBuilder->expr()->isNull($name));
89-
} elseif (is_array($value)) {
90-
$queryBuilder->andWhere($queryBuilder->expr()->in($name, $value));
91-
} elseif ('' !== $value) {
92-
$parameter = str_replace('.', '_', $property);
93-
$queryBuilder
94-
->andWhere($queryBuilder->expr()->eq($name, ':' . $parameter))
95-
->setParameter($parameter, $value)
96-
;
97-
}
98-
}
99-
}
100-
101-
protected function applySorting(QueryBuilder $queryBuilder, array $sorting = []): void
102-
{
103-
foreach ($sorting as $property => $order) {
104-
if (!in_array($property, array_merge($this->getClassMetadata()->getAssociationNames(), $this->getClassMetadata()->getFieldNames()), true)) {
105-
continue;
106-
}
107-
108-
if (!empty($order)) {
109-
$queryBuilder->addOrderBy($this->getPropertyName($property), $order);
110-
}
111-
}
112-
}
113-
114-
protected function getPropertyName(string $name): string
115-
{
116-
if (false === strpos($name, '.')) {
117-
return 'o' . '.' . $name;
118-
}
119-
120-
return $name;
121-
}
12239
}

src/Bundle/Resources/config/services.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
<service id="Sylius\Bundle\ResourceBundle\Form\Type\DefaultResourceType" alias="sylius.form.type.default" />
7070

7171
<service id="sylius.registry.resource_repository" class="Sylius\Component\Registry\ServiceRegistry" public="false">
72-
<argument>Sylius\Component\Resource\Repository\RepositoryInterface</argument>
72+
<argument>Doctrine\Persistence\ObjectRepository</argument>
7373
<argument>resource repository</argument>
7474
</service>
7575
<service id="sylius.registry.form_builder" class="Sylius\Component\Registry\ServiceRegistry" public="false">

src/Bundle/spec/Grid/Renderer/TwigGridRendererSpec.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ function it_uses_twig_to_render_the_action(
5858
): void {
5959
$action->getType()->willReturn('link');
6060
$action->getOptions()->willReturn([]);
61+
$action->getTemplate()->willReturn(null);
6162

6263
$gridView->getRequestConfiguration()->willReturn($requestConfiguration);
6364
$requestConfiguration->getRequest()->willReturn($request);
@@ -83,6 +84,7 @@ function it_throws_an_exception_if_template_is_not_configured_for_given_action_t
8384
): void {
8485
$action->getOptions()->willReturn([]);
8586
$action->getType()->willReturn('foo');
87+
$action->getTemplate()->willReturn(null);
8688

8789
$this
8890
->shouldThrow(new \InvalidArgumentException('Missing template for action type "foo".'))

src/Component/spec/Symfony/Request/State/ProviderSpec.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
use Pagerfanta\Pagerfanta;
1717
use PhpSpec\ObjectBehavior;
1818
use Psr\Container\ContainerInterface;
19+
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\CreatePaginatorTrait;
1920
use Sylius\Component\Resource\Tests\Dummy\RepositoryWithCallables;
2021
use Sylius\Resource\Context\Context;
2122
use Sylius\Resource\Context\Option\RequestOption;
2223
use Sylius\Resource\Doctrine\Persistence\RepositoryInterface;
24+
use Sylius\Resource\Exception\RuntimeException;
2325
use Sylius\Resource\Metadata\Index;
2426
use Sylius\Resource\Metadata\Operation;
2527
use Sylius\Resource\Symfony\ExpressionLanguage\ArgumentParserInterface;
@@ -172,4 +174,38 @@ function it_calls_repository_as_string_with_specific_repository_method_an_argume
172174
$response = $this->provide($operation, new Context(new RequestOption($request->getWrappedObject())));
173175
$response->shouldReturn($stdClass);
174176
}
177+
178+
function it_throws_an_exception_when_repository_method_does_not_exist(
179+
Operation $operation,
180+
Request $request,
181+
ContainerInterface $locator,
182+
): void {
183+
$operation->getRepository()->willReturn('App\Repository');
184+
$operation->getRepositoryMethod()->willReturn('notFoundMethod');
185+
$operation->getRepositoryArguments()->willReturn(['id' => "request.attributes.get('id')"]);
186+
187+
$locator->has('App\Repository')->willReturn(true);
188+
$locator->get('App\Repository')->willReturn(new \stdClass());
189+
190+
$errorMessage = sprintf('Method "notFoundMethod" not found on repository "%s". You can either add it or configure another one in the repositoryMethod option for your operation.', \stdClass::class);
191+
192+
$this->shouldThrow(new RuntimeException($errorMessage))->during('provide', [$operation, new Context(new RequestOption($request->getWrappedObject()))]);
193+
}
194+
195+
function it_throws_an_exception_when_repository_method_does_not_exist_and_suggest_to_use_create_paginator_if_it_is_appropriated(
196+
Operation $operation,
197+
Request $request,
198+
ContainerInterface $locator,
199+
): void {
200+
$operation->getRepository()->willReturn('App\Repository');
201+
$operation->getRepositoryMethod()->willReturn('createPaginator');
202+
$operation->getRepositoryArguments()->willReturn(['id' => "request.attributes.get('id')"]);
203+
204+
$locator->has('App\Repository')->willReturn(true);
205+
$locator->get('App\Repository')->willReturn(new \stdClass());
206+
207+
$errorMessage = sprintf('Method "createPaginator" not found on repository "%s". You can use the "%s" trait on this repository class.', \stdClass::class, CreatePaginatorTrait::class);
208+
209+
$this->shouldThrow(new RuntimeException($errorMessage))->during('provide', [$operation, new Context(new RequestOption($request->getWrappedObject()))]);
210+
}
175211
}

0 commit comments

Comments
 (0)