Problem/Motivation
If en entity reference field is using a ViewsSelection handler, the underlying view is not initialised with the request of the page where the field is exposed. This is because the view is built in a subsequent request of the autocomplete widget. This is bad because that view cannot use default arguments from the original request (like path arguments or query parameters). We can imagine a lot of use-cases where the autocomplete list needs to be narrowed by a parameter from the URL.
There's a "test only" patch showing this bug.
Proposed resolution
Ideally we should store the entire original Symfony request when exposing the ER field and pass it later to the view. But this would lead to a very big variance that would had flood the storage, so I went with the next proposal:
- In
EntityAutocomplete
: save the request URI in expirable key/value store, keyed by a hash built from URI. - Pass the hashed key along the URL of autocomplete request to
EntityAutocompleteController::handleAutocomplete()
- In
EntityAutocompleteController::handleAutocomplete()
retrieve the original URI from the key/value expirable store. - Pass the original URI to the matcher (
EntityAutocompleteMatcher::getMatches()
). - The selection handler plugin will be instantiated also with the original URI.
- In
ViewsSelection::initializeView()
(right now only this handler has a legitimate interest on using this value) create a mock of the original request based only on the URI and pass is as request context to the view.
Remaining tasks
None.
User interface changes
None.
API changes
- The route
system.entity_autocomplete
takes an additional, optional parameter{original_uri_key}
EntityAutocompleteController::handleAutocomplete
accepts an additional, optional argument$original_uri_key
EntityAutocompleteMatcher::getMatches
accepts an additional, optional argument$original_uri
Data model changes
SelectionInterface
plugins receive also the original URI as original_uri
config.
Comment | File | Size | Author |
---|---|---|---|
#64 | 2776571-nr-bot.txt | 144 bytes | needs-review-queue-bot |
#62 | 2776571-59.patch | 17.84 KB | cgrader |
#58 | interdiff_57-58.txt | 844 bytes | ranjith_kumar_k_u |
#58 | 2776571-58.patch | 17.77 KB | ranjith_kumar_k_u |
#57 | 2776571-57.patch | 17.82 KB | aludescher |
Comments
Comment #2
claudiu.cristeaAnd the fix.
Comment #3
claudiu.cristeaComment #6
claudiu.cristeaObvious. Now all tests involving entity reference require the keyvalue.expirable service in KernelTestBase container... and it's not there. I added the parameter in KernelTestBase but the table schema is only created on demand. Also I temporary stole #2623568: Config schema of argument_default plugins is incorrect just to see this passing.
Comment #7
claudiu.cristeaAnd for 8.1.x.
Comment #9
claudiu.cristeaComment #10
claudiu.cristeaComment #12
claudiu.cristeaThe "test only" patch failed, the other is green. So, back to NR.
Comment #13
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedJust a question for now, why don't we pass the original URI as part of the existing selection settings entry from k/v?
Comment #14
claudiu.cristea@amateescu, that was my first impulse. But on normal site, the actual implementation, will produce a reasonable variance in
\Drupal::keyValue('entity_autocomplete')
. How many specific autocomplete configurations you might have on a site? Dozens is already too much. But if we put there also the URI you can end up with hundreds or even thousands of items in\Drupal::keyValue('entity_autocomplete')
(or even more). This is because we cannot predict on how many URIs with the same autocomplete will be displayed. Just imagine a page with an autocomplete where the URI has a node id as query parameter (e.g./node/add/page?catalog={node}
. For each{node}
you'll have a new entry.But adding the URI to
\Drupal::service('keyvalue.expirable')->get('entity_autocomplete')
with a 24 hrs expiry time can work as the garbage collection will keep a reasonable number of entries there. Of course the TTL we have to discuss and it's now an arbitrary value.Comment #15
claudiu.cristea@amateescu,
alternative solution:We pack everything (selection settings + entire original symfony Request object) in a single array.Build a hash on that packageStore the package keyed with the hash in session.Pass the hash in the URL (as we do now)Retrieve on the other side, in EntityAutocompleteController::handleAutocomplete(), the whole packageClear the session entry.What about that?EDIT: Ignore the whole comment, this doesn't work.
Comment #16
claudiu.cristeaThis is another approach that doesn't require Expirable Key/Value. The URI is sent with a POST, instead of GET, in autocomplete.js. If it's reasonable we can expand and send also all the selection settings through the same post an drop completely the \Drupal::keyValue('entity_autocomplete') storage. What about that?
Comment #17
dawehnerWhat blocks you from sending the URI also as query parameter and don't change it from a GET to a POST request.
Comment #18
claudiu.cristea@dawehner, that was my first thought. But now I think I can extend the POST by adding also the $selection_settings to be posted. In this way we can get rid of the 'entity_autocomplete' Key/Value storage. That key/value stuff seem to me a little bit weird because has no mechanism for garbage collection. For example when the settings of a field are changed, a dead entry will still remain in the storage. And conceptually, I don't think that the key/value is for passing data between requests. But GET or POST are exactly for passing data across the requests.
Comment #19
dawehnerWell the problem is that GET requests are cacheable, while POST requests arent'
Comment #20
claudiu.cristea@dawehner, that counts!
In this case what is your opinion, should I:
Comment #21
BerdirWe changed this to key value on purpose, don't change that. The reason is that the client/browser should *not* be able to change those settings. We had a security issue there that was fixed before 8.0.0.
Comment #22
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedI still think we should pass the URI as part of the selection settings, and maybe make it use the expirable one and set the expire time to match the Drupal form expiration time.
Comment #23
claudiu.cristeaChanged back to use GET request. Now the original URI is passed as query parameter.
@amateescu, why cluttering key/value storage, even the expirable one, when we can pass it along with a very light GET request?
Comment #24
claudiu.cristeaCredits.
Comment #25
claudiu.cristeaSmall improvements and doc fixes.
Comment #26
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedBecause we're trading cluttering the key/value storage for cluttering cache-able GET requests :)
Comment #27
dawehnerCan we somehow make that an opt in behaviour for some form elements? By that we would not have to clutter up
key_value
nor change the GET url by default.Another idea I just had, we could store the URI in session, if needed. This is by far still not ideal, but at least something.
Comment #28
claudiu.cristea@amateescu,
You're right. But personally I like more to store them in the cache for 2 reasons: it has better invalidation mechanism and it benefits for faster storages (Redis, Memcache, etc)
@dawehner,
Sure we can. But that means we need to add also an UI option in entity reference autocomplete widget so that we can take the benefit. There is the first place where this would be used.
I had also this idea in #15 but the values should live in the session till the end. The session data can increase dramatically for a single user.
Comment #29
claudiu.cristeaHow about storing a flag "pass_original_uri" in selection handler settings? Then we do the whole logic only if a specific selection handler will require that. ViewsSelection will require the original uri while DefaultSelection not.
EDIT: At least this narrows the cases to the selection handlers that requires it. But adding also the opt-in could narrow more.
Comment #30
claudiu.cristeaIf we let selection handlers to declare if they want to get the original URI (idea from #29) then we need a base class for all selection handlers in order to assure BC compatibility. I opened #2787873: Add a base class for entity reference selection handlers and fix the structure of their configuration also to deal with #2786841: Entity reference fields should add selection handler config dependencies. That will provide the foundation to add a method such as needsOriginalUri() to all selection handlers. Then we implement that method in the base class returning FALSE and we are covered as BC.
Comment #32
jibranComment #33
BerdirSee #2280479: Add setting to EntityReferenceSelection plugins to prevent references to referencing entity for an alternative suggestion on how to solve this.
Comment #35
tacituseu CreditAttribution: tacituseu commentedComment #36
bircherre-roll of #25 without any of the improvements in subsequent comments.
I agree that this would be best tackled together with the mentioned #2787873: Add a base class for entity reference selection handlers and fix the structure of their configuration.
Comment #37
birchersorry for forgetting the test class in the patch.
Comment #43
hchonovA simple re-roll for 8.9.x.
Comment #44
hchonovI've updated the "Taxonomy tid default argument" to check also the parameters for the origin URI request. This makes it possible to use a contextual filter on a view reference selection on an entity reference field and filter by the current term ID.
Comment #47
nikitagupta CreditAttribution: nikitagupta at Srijan | A Material+ Company for Drupal India Association commentedworked on deprecation in EntityReferenceAutocompleteTest.
Comment #48
nikitagupta CreditAttribution: nikitagupta at Srijan | A Material+ Company for Drupal India Association commentedComment #50
raman.b CreditAttribution: raman.b at OpenSense Labs commentedRe-rolling for the latest dev branch
Comment #51
raman.b CreditAttribution: raman.b at OpenSense Labs commentedResolving failed test cases from #48
Comment #53
raman.b CreditAttribution: raman.b at OpenSense Labs commentedComment #56
hchonov9.3.x reroll.
Comment #57
aludescher CreditAttribution: aludescher at drunomics for Porsche Informatik Gesellschaft m.b.H. commentedCurrent 9.3.x reroll.
Comment #58
ranjith_kumar_k_u CreditAttribution: ranjith_kumar_k_u at Zyxware Technologies commentedComment #60
yogeshmpawarMarking Needs Review again because test failures are unrelated.
Getting above test failures in most of the issues.
Comment #62
cgrader CreditAttribution: cgrader at Porsche Informatik Gesellschaft m.b.H. commentedUpdate patch from #58 so that it fits to 9.3.15
Comment #64
needs-review-queue-bot CreditAttribution: needs-review-queue-bot as a volunteer commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.