Use Repository managed by Doctrine automatically#982
Use Repository managed by Doctrine automatically#982loic425 wants to merge 2 commits intoSylius:1.13from
Conversation
7d7a59e to
bf76da2
Compare
bf76da2 to
5c399aa
Compare
| $operation = $operation->withResource($resource); | ||
|
|
||
| if (null === $operation->getRepository()) { | ||
| $operation = $operation->withRepository($resourceConfiguration->getServiceId('repository')); |
There was a problem hiding this comment.
We do not use this repository by default anymore.
| } | ||
|
|
||
| if (null === $operation->getProvider()) { | ||
| $operation = $operation->withProvider(Provider::class); |
There was a problem hiding this comment.
This Provider was kind of Doctrine related, we use another improved one which is configured if the Resource is managed by Doctrine only.
| $this->assertInstanceOf(ProviderResourceMetadataCollectionFactory::class, $this->factory); | ||
| } | ||
|
|
||
| public function testItCreatesResourceMetadataWithDefaultProviderOnHttpOperations(): void |
There was a problem hiding this comment.
I've removed this default provider which was a lot related to Doctrine.
| App\Subscription\: | ||
| resource: '../src/Subscription' | ||
|
|
||
| App\Subscription\Factory\SubscriptionFactory: |
There was a problem hiding this comment.
We can still use a factory service here but the app.factory.subscription doesn't exist if we do not configure any driver.
So It's more complicated like this, cause we need to tag this factory to be used in the repository locator.
| @@ -31,49 +33,33 @@ | |||
| final class Provider implements ProviderInterface | |||
| { | |||
| public function __construct( | |||
| private ContainerInterface $locator, | |||
There was a problem hiding this comment.
Hopefully, this provider is experimental, so we could move it and improve it.
src/Bundle/Resources/config/services/integrations/doctrine/orm.xml
Outdated
Show resolved
Hide resolved
src/Bundle/Resources/config/services/integrations/doctrine/orm.xml
Outdated
Show resolved
Hide resolved
.../src/Doctrine/Orm/Metadata/Resource/Factory/DoctrineOrmResourceMetadataCollectionFactory.php
Outdated
Show resolved
Hide resolved
193218c to
1ac8171
Compare
1ac8171 to
d8655a6
Compare
.../src/Doctrine/Common/Metadata/Resource/Factory/DoctrineResourceMetadataCollectionFactory.php
Outdated
Show resolved
Hide resolved
.../src/Doctrine/ORM/Metadata/Resource/Factory/DoctrineORMResourceMetadataCollectionFactory.php
Show resolved
Hide resolved
.../src/Doctrine/ORM/Metadata/Resource/Factory/DoctrineORMResourceMetadataCollectionFactory.php
Show resolved
Hide resolved
.../src/Doctrine/ORM/Metadata/Resource/Factory/DoctrineORMResourceMetadataCollectionFactory.php
Show resolved
Hide resolved
fc5fb9b to
fb88f77
Compare
Co-authored-by: Dmitri Perunov <diimpp@gmail.com>
fb88f77 to
960c0f7
Compare
| <services> | ||
| <defaults public="true" /> | ||
|
|
||
| <service id="sylius.doctrine_orm.metadata.resource.metadata_collection_factory" |
There was a problem hiding this comment.
| <service id="sylius.doctrine_orm.metadata.resource.metadata_collection_factory" | |
| <service id="sylius.resource_metadata_collection.factory.doctrine.orm" |
Would make it easier to find since it'd be in line with the decorated service
| <argument type="service" id=".inner" /> | ||
| </service> | ||
|
|
||
| <service id="sylius.state_provider.doctrine.orm.state.provider" class="Sylius\Resource\Doctrine\ORM\State\Provider"> |
There was a problem hiding this comment.
| <service id="sylius.state_provider.doctrine.orm.state.provider" class="Sylius\Resource\Doctrine\ORM\State\Provider"> | |
| <service id="sylius.state_provider.doctrine.orm" class="Sylius\Resource\Doctrine\ORM\State\Provider"> |
Seems a bit superfluous
| /** @var ResourceMetadata $resource */ | ||
| foreach ($resourceCollectionMetadata->getIterator() as $i => $resource) { |
There was a problem hiding this comment.
| /** @var ResourceMetadata $resource */ | |
| foreach ($resourceCollectionMetadata->getIterator() as $i => $resource) { | |
| foreach ($resourceCollectionMetadata->getIterator() as $i => $resource) { |
Setting phpstan params (TKey, TValue) on ResourceMetadataCollection would ease type-hinting
| return null; | ||
| } | ||
|
|
||
| return 'sylius.state_provider.doctrine.orm.state.provider'; |
There was a problem hiding this comment.
Maybe put it in a const, or pass through the constructor as a parameter?
The Persist & Remove processors already use the Repository managed by Doctrine.
But the system was using a driver detection using the config (by default, a resource is configured with 'doctrine/orm' as driver).
At the end, we'll be able to use the Resource without any driver configuration. You can look at the current DoctrineOrmDriver to see how much the complexity is.
With this new system, if you use a Repository managed by Doctrine, it will be used automatically, otherwise, you are able to use custom providers which are more powerful (retrieve sth from anywhere you want).
Moreover, the driver system has some issues with the repository (see #981)
So it's hard to maintain & trust the Sylius Repository configuration system.
Indeed, the repository to be used by Doctrine is configured on Runtime.
We have this System in ApiPlatform
https://github.com/api-platform/core/blob/main/src/Doctrine/Orm/Metadata/Resource/DoctrineOrmResourceCollectionMetadataFactory.php
More explanation about driver false
Setting driver to false already exists, it disables the driver system. It was introduced to detach a resource from Doctrine when the resource was not an entity.
In this case, there's no built-in factory & repository.
About repository DI
with current implementation, RepositoryInterface was generic and that's why it was introduced a binding via the repository name which is not well-known and not documented.
In Symfony, by default, when we use the Entity maker command, we also have a service entity repository which is automatically created.
Cause this is a service, it could be injected directly or with an interface. This is the normal way to inject services in Symfony.
In Sylius E-commerce, we still need to create this "sylius.repository.order" but we'll need to declare these services manually instead as we do for every services.
If you have a generic EntityRepository, it's still possible to configure a binding with name via Symfony DI configuration.
It could be automatic, this "automation" already exists in this package and could be moved to Sylius E-commerce where the repository will be created with an
app.repository.bookid.RepositoryInterface is already optional
Implementing this interface is already optional since this new resource metadata implementation.
The Persist and Remove processors retrieve the repository managed by Doctrine.
So this PR just use the same solution with providers.