Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[DoctrineBridge][Form] Introducing newLazyChoiceLoader class andchoice_lazy option forChoiceType#52503

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged

Conversation

@yceruto
Copy link
Member

@ycerutoyceruto commentedNov 8, 2023
edited
Loading

QA
Branch?7.2
Bug fix?no
New feature?yes
Deprecations?no
Issues#57724
LicenseMIT

It's quite usual to work with forms that process large datasets. In Symfony Form + Doctrine ORM, if you define anEntityType, it typically loads all choices/entities fully into memory, and this can lead to serious performance problems if your entity table contain several hundred or thousands of records.

The newLazyChoiceLoader class addresses this performance issue by implementing an on-demand choice loading strategy. This class is integrated with anyChoiceType subtype by using a new boolean option namedchoice_lazy, which activates the feature.

Basic usage in a Symfony form looks like this:

$formBuilder->add('user', EntityType::class, ['class' => User::class,// a ton of users...'choice_lazy' =>true,]);

How does it work?

The loader operates by keeping the choice list empty until values are needed (avoiding unnecessary database queries). When form values are provided or submitted, it retrieves and caches only the necessary choices.

As you can see in the code, all this happens behind theLazyChoiceLoader class, which delegates the loading of choices to a wrappedChoiceLoaderInterface adapter (in this case, theDoctrineChoiceLoader).

Frontend Considerations

Certainly, you may need a JavaScript component for dynamically loading<select> options, aka autocomplete plugins. You'll need to develop the endpoint/controller to fetch this data on your own, ensuring it corresponds to the form field data source. This aspect is not included in this project.

As a point of reference, theAutocomplete UX Component now uses this choice loading strategy, simplifying its autocomplete form type to a single field:

A Handy Use Case without Javascript?

Thedisabled option renders anEntityType form field read-only, and when combined with thechoice_lazy option, it prevents the loading of unnecessary entities in your choice list (only the pre-selected entities will be loaded), thereby enhancing performance.


Hope this helps to create simpler autocomplete components for Symfony forms.

Cheers!

norkunas, Seb33300, Pixelshaped, ging-dev, andreybolonin, spackmat, Crovitche-1623, and rynhndrcksn reacted with thumbs up emoji
@carsonbot

This comment was marked as outdated.

@ycerutoyceruto modified the milestones:7.0,7.1Nov 8, 2023
@ycerutoyceruto changed the title[Form] Introducing new ExtraLazyChoiceLoader class and extra_lazy option for DoctrineType[Form][DoctrineBridge] Introducing new ExtraLazyChoiceLoader class and extra_lazy option for DoctrineTypeNov 8, 2023
@OskarStarkOskarStark changed the title[Form][DoctrineBridge] Introducing new ExtraLazyChoiceLoader class and extra_lazy option for DoctrineType[Form][DoctrineBridge] Introducing newExtraLazyChoiceLoader class andextra_lazy option forDoctrineTypeNov 8, 2023
@carsonbotcarsonbot changed the title[Form][DoctrineBridge] Introducing newExtraLazyChoiceLoader class andextra_lazy option forDoctrineType[DoctrineBridge][Form] Introducing newExtraLazyChoiceLoader class andextra_lazy option forDoctrineTypeNov 8, 2023
@yceruto
Copy link
MemberAuthor

yceruto commentedNov 8, 2023
edited
Loading

Over there, there should be other special use cases, such as using API payloads against forms where the choice lists are not really necessary, so people work around with custom form types and specialEntityToIdDataTransformer. Now they can use theEntityType directly with thechoice_lazy option activated.

@Seb33300
Copy link
Contributor

Over there, there should be other special use cases, such as using API payloads against forms where the choice lists are not really necessary, so people work around with custom form types and specialEntityToIdDataTransformer. Now they can use theEntityType directly with theextra_lazy option activated.

+1

I had a similar case few years ago with an API relying on a Symfony form with an EntityType loading thousands of choices.
I ended by adding the EntityType field to the form with an event on submit and filtering the SQL query to select only the items submitted by the user.

yceruto reacted with rocket emoji

@Pixelshaped
Copy link

Pixelshaped commentedNov 9, 2023
edited
Loading

Thank you I was already using this code from UX Autocomplete and I think it's the right move to make it part of Doctrine Bridge as this is a very common use case, even if part of the solution is front end (one would still need to implement a route to get a paginated list of entities and pass it to Select2 or whatever solution you're using).

I had duplicated the ExtraLazyChoiceLoader in my project to not require UX Autocomplete (as I'm using Select2 already everywhere), and now I can use this and stay updated.

Nice job.

yceruto and sstok reacted with heart emoji

@stof
Copy link
Member

stof commentedNov 9, 2023

I'm not sure thisextra_lazy option in the existing type extending ChoiceType is the right option. Such autocomplete type requires a totally different rendering than a choice type (and this autocomplete rendering might make sense with data sources that are not from doctrine).

@yceruto
Copy link
MemberAuthor

yceruto commentedNov 9, 2023
edited
Loading

@stof certainly there's additional work required to create a fully-autocomplete type, which is not the goal of this PR btw. However, it does streamline implementations that previously needed custom/complex solutions. Thechoice_lazy option facilitates this forDoctrineType although its use is not restricted to that purpose alone.

I believe theLazyChoiceLoader is the main feature here. It's compatible with anyChoiceType and you can wrap any data source (Local Storage, External APIs, ...) allowing it to load those data efficiently by following this "on-demand" approach.

@ycerutoyceruto changed the base branch from7.0 to7.1November 15, 2023 18:04
@ycerutoycerutoforce-pushed thefeature/lazy_choice_loader branch from4d42789 to87afdeaCompareNovember 15, 2023 18:04
@ycerutoycerutoforce-pushed thefeature/lazy_choice_loader branch from87afdea to53463a2CompareDecember 4, 2023 21:42
@norkunas

This comment was marked as off-topic.

@ycerutoycerutoforce-pushed thefeature/lazy_choice_loader branch from53463a2 toe933246CompareJanuary 6, 2024 11:47
@ycerutoyceruto modified the milestones:7.1,7.2May 2, 2024
@ycerutoycerutoforce-pushed thefeature/lazy_choice_loader branch frome933246 to33b2f3dCompareJuly 3, 2024 19:25
@ycerutoycerutoforce-pushed thefeature/lazy_choice_loader branch 3 times, most recently from4016846 tofae0d67CompareJuly 3, 2024 22:59
@ycerutoycerutoforce-pushed thefeature/lazy_choice_loader branch fromfae0d67 to2953bcfCompareJuly 17, 2024 13:35
@yceruto
Copy link
MemberAuthor

Thanks@xabbuh for your review! I also added two test cases more aboutmultiple option combined withchoice_lazy.

@carsonbotcarsonbot changed the title[Form] Introducing newLazyChoiceLoader class andchoice_lazy option forChoiceType[DoctrineBridge][Form] Introducing newLazyChoiceLoader class andchoice_lazy option forChoiceTypeJul 19, 2024
@ycerutoycerutoforce-pushed thefeature/lazy_choice_loader branch from2953bcf to97ddd62CompareAugust 4, 2024 01:13
@yceruto
Copy link
MemberAuthor

Just rebased to fix conflicts.

Copy link
Member

@nicolas-grekasnicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Maybe stupid comment: can't we always behave lazily when choice_loader is set and get rid of the option altogether?

@stof
Copy link
Member

@nicolas-grekas this lazy mode assumes that you have a form rendering that does not need the list of available choices (and sonot rendering it as a<select> like the default rendering of a ChoiceType).

This is the reason why I suggested that it may fit better as aseparate form type instead (which would have a separate rendering).

Making all choice loaders wrapped in this LazyChoiceLoader in ChoiceType itself would break it.

nicolas-grekas reacted with thumbs up emoji

@ycerutoycerutoforce-pushed thefeature/lazy_choice_loader branch from97ddd62 tod73b5eeCompareAugust 23, 2024 01:42
@yceruto
Copy link
MemberAuthor

yceruto commentedAug 23, 2024
edited
Loading

@nicolas-grekas this lazy mode assumes that you have a form rendering that does not need the list of available choices (and so not rendering it as a<select> like the default rendering of a ChoiceType).

I can add that if there is data bound to that field (either default or submitted), it will render the choices as usual, rendering only the selected ones in this case.

This is the reason why I suggested that it may fit better as a separate form type instead (which would have a separate rendering).

I might be missing your point here. Still wondering how it could be different from the current one and why... you can currently have different renderings for the same form type usingblock_prefix option.

Making all choice loaders wrapped in this LazyChoiceLoader in ChoiceType itself would break it.

Sorry, I'm confused by this comment. Is it related to Nicolas' comment? Otherwise, could you please elaborate 🙏

@yceruto
Copy link
MemberAuthor

Maybe stupid comment: can't we always behave lazily when choice_loader is set and get rid of the option altogether?

You might still want to use achoice_loader even without lazy loading.

@ycerutoyceruto added the ❄️ Feature FreezeImportant Pull Requests to finish before the next Symfony "feature freeze" labelOct 3, 2024
@yceruto
Copy link
MemberAuthor

This is ready on my side.@stof any blocker on your side?

@nicolas-grekas
Copy link
Member

Thank you@yceruto.

yceruto and andreybolonin reacted with hooray emoji

@nicolas-grekasnicolas-grekas merged commit5763273 intosymfony:7.2Oct 9, 2024
@ycerutoyceruto deleted the feature/lazy_choice_loader branchOctober 9, 2024 16:14
javiereguiluz added a commit to javiereguiluz/symfony-docs that referenced this pull requestOct 14, 2024
This PR was merged into the 7.2 branch.Discussion----------[Form] Documenting ``choice_lazy`` optionClosessymfony#20311Code PR*symfony/symfony#52503Commits-------e55e7cd documenting choice_lazy option
@fabpotfabpot mentioned this pull requestOct 27, 2024
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@nicolas-grekasnicolas-grekasnicolas-grekas approved these changes

@xabbuhxabbuhxabbuh approved these changes

@chalasrchalasrchalasr approved these changes

@weaverryanweaverryanAwaiting requested review from weaverryan

+1 more reviewer

@ro0NLro0NLro0NL left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

DoctrineBridgeFeatureForm❄️ Feature FreezeImportant Pull Requests to finish before the next Symfony "feature freeze"Status: Reviewed

Projects

None yet

Milestone

7.2

Development

Successfully merging this pull request may close these issues.

10 participants

@yceruto@carsonbot@Seb33300@Pixelshaped@stof@norkunas@nicolas-grekas@ro0NL@xabbuh@chalasr

[8]ページ先頭

©2009-2025 Movatter.jp