-
-
Notifications
You must be signed in to change notification settings - Fork 930
feat(symfony): Autoconfigure classes using #[ApiResource]
attribute
#6943
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php
Outdated
Show resolved
Hide resolved
24c6b04
to
939fe53
Compare
src/Symfony/Bundle/DependencyInjection/Compiler/AttributeResourcePass.php
Outdated
Show resolved
Hide resolved
#[ApiResource]
attribute#[ApiResource]
attribute
#[ApiResource]
attribute#[ApiResource]
attribute
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very smart! I like this.
Nice! It reminds me a discussion we had with @nicolas-grekas ^^. core/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php Lines 342 to 348 in 7b3bf83
The way core/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php Lines 385 to 433 in 7b3bf83
This is quite heavy work for no real gain, especially that the resources discovered with this patch will already be discovered there right? Last thing, inside the route loader we declare directory resources (so that the container is rebuilt when these file changes) at: core/src/Symfony/Routing/ApiLoader.php Lines 52 to 54 in 7b3bf83
If we remove that |
Removing the directory scanning would be a breaking change as the Of-course, this is the target. |
Mhh okay but this means that we only need this for the Entity directory, we can remove all the code handling our paths (for example ApiResource). What about the DirectoryResource to rebuild the container on file change? Are services tagged as |
If this doesn’t work for the Entity directory (that we won’t deprecate IMHO), then is this patch really useful? |
Let's reintroduce the I'll try to move the directory scan to the compiler pass. |
32ba921
to
d2a7a55
Compare
Well, I haven't found a solution yet to avoid scanning the configured folders twice (all the Entity, Document and ApiResource folders of the project and bundles).
|
…)` and `ContainerBuilder::findExcludedServiceIds()` for auto-discovering value-objects (GromNaN) This PR was squashed before being merged into the 7.3 branch. Discussion ---------- [DependencyInjection] Add `Definition::addExcludedTag()` and `ContainerBuilder::findExcludedServiceIds()` for auto-discovering value-objects | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | - | License | MIT We could **not** use the method `findTaggedServiceIds` in #59401 (comment), same for api-platform/core#6943. As "using the container loading tools to do resource discovery quite seamlessly" [seems to be a good idea](#59401 (review)), this changes make it easier. I'm not closed to alternative ideas if we want to go further with this use-case. ### Usage Let's create a `AppModel` attribute class and use it on any class of the project. In the extension class: ```php $this->registerAttributeForAutoconfiguration(AppModel::class, static function (ChildDefinition $definition) { $definition->addExcludedTag('app.model'); }); ``` In a compiler pass: ```php $classes = []; foreach($containerBuilder->findExcludedServiceIds('app.model') as $id => $tags) { $classes[] = $containerBuilder->getDefinition($id)->getClass(); } $containerBuilder->setParameter('.app.model_classes', $classes); ``` And this parameter can be injected into a service, or directly update a service definition to inject this list of classes. The attribute parameters can be injected into the tag, and retrieved in the compiler pass, for more advanced configuration. Commits ------- 7a0443b [DependencyInjection] Add `Definition::addExcludedTag()` and `ContainerBuilder::findExcludedServiceIds()` for auto-discovering value-objects
So I think we need to move the extraction of the classes names into the compiler pass and inject them into a |
Here's how it should be designed to take full advantage of the container builder. Goals
Advantage: no need for additional cache unless explicitly required by a custom implementation Backward-compatibility constraints:
AttributesDetection: Use Symfony Cache invalidation: The Symfony cache is automatically invalidated and regenerated when one of this classes is modified, removed or added in the autoconfigured directories. XML/Yaml filesDetection:: List files during container compilation. Cache invalidation: Adding this files and directories as "resources"; even if they doesn't exist, the container cache is automatically invalidated and regenerated when on of the files is modified, removed or added in the configured directories. |
Hello, I may miss a link in this discussion, but I didn't see here anything related to symfony/symfony#59987 as for SF7.3 #[Entity] tagged classes will be automatically excluded from services, and therefore default config.yaml services definition folders will be cleaned. Sorry if already mentionned. |
For now we can merge this as-is, we'll deprecate the |
thanks @GromNaN! |
@@ -141,6 +141,7 @@ public function getConfigTreeBuilder(): TreeBuilder | |||
->end() | |||
->arrayNode('resource_class_directories') | |||
->prototype('scalar')->end() | |||
->setDeprecated('api-platform/symfony', '4.1', 'The "resource_class_directories" configuration is deprecated, classes using #[ApiResource] attribute are autoconfigured by the dependency injection container.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, this feature break some functionality.
If this option was deprecated, and planned to be removed in future, this will break any additional features like filters (sorting/filtering) on the same level as #[ApiResource]
in resource - this means they are not loaded with all the operations they are should be.
Simple reproducer:
api-platform/core:4.2.x-dev
<?php
use ApiPlatform\Doctrine\Common\Filter\SearchFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\OpenApi\Model\Operation;
use App\Expense\Application\Controller\GetCollectionCostController;
use App\Shared\Domain\Entity\AbstractEntity;
#[ApiResource(
operations: [
new GetCollection(
uriTemplate: 'expense/cost',
inputFormats: ['jsonld' => ['application/ld+json']],
outputFormats: ['jsonld' => ['application/ld+json']],
controller: GetCollectionCostController::class,
openapi: new Operation(tags: ['Expense'], summary: 'Returns the collection of Cost resources.', description: 'Returns the collection of Cost resources.'),
normalizationContext: ['groups' => ['api:read']],
denormalizationContext: ['groups' => ['api:write']],
output: Cost::class,
priority: 2,
),
],
)]
#[ApiFilter(filterClass: SearchFilter::class, properties: ['comment' => SearchFilterInterface::STRATEGY_IPARTIAL])]
class Cost extends AbstractEntity
{
}
With setting resource_class_directories
:
and deprecated message:
Since api-platform/symfony 4.1: The "resource_class_directories" configuration is deprecated, classes using #[ApiResource] attribute are autoconfigured by the dependency injection container.
Without setting resource_class_directories
:
I don't know how to fix it. Unless there is some other way to fix it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Settings the #[ApiFilter]
attribute directly on property (like in https://api-platform.com/docs/core/filters/#apifilter-attribute) also not works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting thanks I'll investigate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any information about that @soyuka ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should other attributes such as #[ApiFilter]
be added to the AutoConfiguration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to achive the same result as is in https://api-platform.com/docs/core/filters/#filtering-multiple-properties-with-property and I failed...
Cannot instance new SearchFilter
like wrote in docs (because of required arguments like ManagerRegistry)...
So for me +1 to keep ApiFilter
class to be not deprecated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, ApiFilter
scans all fields and adds all possible combinations.
We will not achieve this in the way described in the documentation (you have to write each field separately) :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, let's make ApiFilter
to be automatically autoconfigured ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're working on filter compatibility, searching is at #7121.
Additionally, ApiFilter scans all fields and adds all possible combinations.
And its really bad at doing this, for example it'll use a search filter on everything though it should only for strings. There are lots of wrong usage of filters because of this (people trying to use SearchFilter on dates for example).
Don't worry I'm not deprecating ApiFilter right now, and yes there will be a script to transform your filters to parameters automatically.
This is a journey that started almost 5 years ago for me and I'll go through and I don't want to break existing code ovbiously, but ApiFilter is poor engineering and needs to be changed for a better developer experience.
TLDR: ignore the deprecation for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for response. I already know what way further development goes.
Using the Symfony bundle, classes with the
#[ApiResource]
attribute must be insrc/ApiResource
,src/Entity
(for Doctrine ORM) orsrc/Document
(for MongoDB ODM). It's possible to add custom paths in the configuration, but that's one more little thing to take care of.By using the Symfony autoconfiguration feature, we can detect classes with the
#[ApiResource]
attribute during the build of the container instead of scanning directories at runtime.The same feature was implemented in Symfony for the
#[JsonEncodable]
attribute: symfony/symfony#59401