Problem/Motivation
Entity browser will currently allow widgets to select just any entity. If it is an entity it can be selected. We need a mechanism that will allow users to define conditions that entities need to meet in order to be selected with a given entity browser. Examples of this conditions would be:
- Entity must be of type A
- Entity must belong to bundles X,Y,Z
- Entity must be older than 1 year
- At most N entities can be selected
- At least M entities must be selected
- Entity must have field "foo" and it's value needs to be "bar"
This seems like a very hard problem. In reality we'll need basic checks most of the time (entity, type, bundle, cardinality), but it would be nice to come with a system that would be extensible enough to allow people to do nice things in the future.
It would be great if we could use APIs that come with core.
Proposed resolution
There are many things to figure out here, but I think there are two main issues to resolve:
Where are conditions enforced?
- Widgets: leave responsibility entirely on entity browser widgets which need to be sure entities they are selecting meet all conditions. This would be optimal from UX point of view, but is very hard to do it right. Imagine a View widget that would need to check entity type it operates on, make sure all filters to meet conditions are set on the view, ...
- Before entity is added to current selection: This happens after an entity has been selected. We check all conditions and let through only those that meet all conditions. Easier to implement but not very nice from UX perspective (imagine how frustrating it is after you created something and EB rejects it).
- Combination of both: Propagate conditions to widgets which do their best to meet them. Once entities are selected check them once again and reject the ones that might not meet all the conditions.
What to use to define conditions?
- Core Contexts/Conditions: Currently used with blocks to limit visibility. It seems that Context concept won't fit in our use-case very well.
- Core Constraints: Allows us to re-use existing constraints and to write new ones that work better for us. It will most likely be hard for widgets to check for conditions before entities are created/selected (optimal from UX perspective).
- Rules: Might be useful? We can probably implement this in a way that allows us to plug rules in the future.
- Custom solution: Most flexible but definitely not desired.
Remaining tasks
- brainstorm and decide on architecture
- write patch
- write test coverage
- review
Comment | File | Size | Author |
---|---|---|---|
#35 | interdiff.txt | 7.04 KB | slashrsm |
#35 | 2366335_35.patch | 39.66 KB | slashrsm |
#34 | entity_browser-2366335-34.patch | 41.04 KB | samuel.mortenson |
#34 | interdiff-2366335-31-34.txt | 430 bytes | samuel.mortenson |
Comments
Comment #1
slashrsm CreditAttribution: slashrsm commentedComment #2
slashrsm CreditAttribution: slashrsm commentedComment #3
slashrsm CreditAttribution: slashrsm commentedComment #4
slashrsm CreditAttribution: slashrsm commentedComment #5
slashrsm CreditAttribution: slashrsm commentedComment #6
Primsi CreditAttribution: Primsi at Examiner.com for Examiner.com commentedA gave this a thought and imo the most elegant solution would be working constraints that we use to validate on widget submission.
Let's try that on an example workflow:
Comment #7
Primsi CreditAttribution: Primsi at Examiner.com for Examiner.com commentedInitial stab at this: https://github.com/drupal-media/entity_browser/pull/117/files
Still needs:
- a way to specify conditions
- cleanup
- tests
Comment #8
BerdirOne important thing that we discussed is how we send those conditions/requirements to the entity browser.
My suggestion was to use the same as the EntityAutocomplete element. Hash the settings, store them by that hash in key value then pass along the hash in the URL or so.
Comment #9
Primsi CreditAttribution: Primsi at Examiner.com for Examiner.com commentedFinally found time to continue working on this. Only Upload widget uses this validation for now- views widget runs it's own validation thing.
Also, as the patch stands now, it would require other widgets to follow.
Comment #10
slashrsm CreditAttribution: slashrsm at Examiner.com commentedThanks! This looks very good. Few comments on pull. Also needs reroll and @file blocks can be removed.
Comment #11
samuel.mortensonHere's a vanilla re-base on top of 8.x-1.x, no notes addressed and no manual testing yet.
Comment #12
samuel.mortensonLast patch was no good, no idea why.
Comment #13
samuel.mortensonSo after (visually) reviewing the current code and reading up on Symfony Constraints, I understand that the reason we're adding a new plugin is that we need to mock the typical use of Core's field validation. It's a pretty cool concept! Just need to do cleanup work on comments and inject more dependencies into the validator plugins, then test that it's working.
Comment #14
samuel.mortensonUpdated patch which addresses all notes from https://github.com/drupal-media/entity_browser/pull/117 except the note on
WidgetValidationBase::setConfiguration
"We need to call this function from the constructor and respect default configuration before setting.". Not sure what is required for that.Moving into manual testing now.
Comment #15
samuel.mortensonFixed fatals, cleaned up more code, and made the Cardinality and EntityType WidgetValidators actually work. I believe this is ready for some form of review.
Comment #18
samuel.mortensonRe-roll.
Comment #21
samuel.mortensonAnother huge re-roll, with a lot of code removed now that we have a generic way to pass information down to the Entity Browser.
Comment #24
samuel.mortensonHopefully fixed tests.
Comment #25
samuel.mortensonExisting tests pass, writing new test coverage now.
Comment #26
samuel.mortensonAdded a new test for the entity_type validator, I think this should be enough coverage for this patch unless we want to test every validator we have individually.
Comment #27
phenaproximaNeeds a type hint.
Should be type hinted.
I think this should say "Gets the selection storage values." Otherwise it sounds like we're getting the actual storage handler.
IMHO this should be $options['maximum'], for clarity's sake.
s/Entities/entities
This sentence doesn't seem complete :)
Should be protected.
This is quite dangerous, IMHO. It's entirely possible that someone will have an element parent named 'submit', and then things will blow up for them. Can we find a better way of determining whether validation should occur? How about #limit_validation_errors?
$violations is an object, so it will never be empty. This should be $violations->count() > 0.
I'm not sure we need the if check here -- won't the plugin manager throw PluginNotFoundException if the constraint does not exist?
Shouldn't this be EntityInterface[]?
Comment #28
samuel.mortenson#27.1/#27.2 - It looks like core doesn't use type hints for
hook_*_info_alter()
implementations, I'm not sure why. I cleaned up the whole api.php file.#27.3 - Done
#27.4 - We use "cardinality" in a number of locations (entity_browser.common.js, entity_browser_entity_form.module), and so do some dependent contrib modules. I would be open to changing this across the board in a new issue if we choose to also support cardinality minimums.
#27.5/#27.6/#27.7 - Done
#27.8/#27.9 - Nice catches, done
#27.10 - Since the WidgetValidationManager extends DefaultPluginManager, we get the benefits of FallbackPluginManagerInterface and this function will not throw exceptions if a fallback plugin is available. See
\Drupal\Component\Plugin\PluginManagerBase::createInstance()
for details.#27.11 - Done
Comment #29
slashrsm CreditAttribution: slashrsm at MD Systems GmbH for Acquia commentedDo we need to implement this function in all other widgets too? Can we come up with a sane default implementation. I think that we should declare it as abstract if not. Maybe even make it protected?
s/validation/validate
Why additional? These are validators.
Can be removed. Applies to the entire patch.
s/null/NULL
Comment #30
Primsi CreditAttribution: Primsi at MD Systems GmbH commented#29,1
I think I remember that I every plugin needs to implement it because entities must exist if we want to reference them. We need to load them or create them. I am not sure if we can create a default. See upload widget example in patch.
Comment #31
samuel.mortensonThis should address all concerns in #29, implementing prepareEntities() for the View widget actually abstracted some logic out of the submit handler, which is good too.
Comment #32
samuel.mortensonComment #33
samuel.mortensonThe Views widget implements its own validate() method, so we need to make sure it also calls the validators. I'll manually test as well.
Comment #34
samuel.mortensonAlright, the Views widget now calls the normal WidgetBase validate() method. I manually verified that cardinality and entity_type work with the Views widget as well.
Comment #35
slashrsm CreditAttribution: slashrsm at MD Systems GmbH for Acquia commentedSome last minute refactoring.
Comment #37
slashrsm CreditAttribution: slashrsm at MD Systems GmbH for Acquia commentedYay! One big step towards beta.
Comment #39
Gábor Hojtsy