Problem/Motivation
Views allows you to render a specific entity for example in the header/footer of a view.
This functionality is for example used for "taxonomy/term/..." but is especially helpful for custom help texts above a view.
Sadly it uses the entity ID, for referencing to the entity, so deployment of the view is problematic.
On top of that it is not straightforward to find the UUID
Proposed resolution
ER and Views (and probably other modules) have a shared usecase here to:
- Store a deployable reference in their configuration to a specific entity.
- Reference either a content or configuration entity with the same API.
- For content entities, allow the user enter a serial ID that is then converted to a deployable ID (UUID).
We agreed that the best way to address all of the use cases would be to actually add some methods in the Entity API that ER, Views, or whatever other implementing code can rely on:
EntityInterface::getConfigTarget()
Will provide the the correct way to store the value of a target entity--i.e. the UUID for content entities, or the config ID for configuration entities. As elsewhere, the Entity base class will provide the default implementation, and ConfigEntity will override it.
EntityManagerInterface::loadByConfigTarget()
Loads the entity from the string provided by getConfigTarget() (both for rendering and for preparing the form?). Would include this check:
$key = $target_entity_type instanceof ConfigEntityType ? 'config' : 'content'
currently found in EntityReferenceItem::calculateDependencies()
For this issue, we'll:
- Add the two methods.
- Rename the Views key to 'target'.
- Convert the logic in
Drupal\views\Plugin\views\area\Entity::render()
(and::buildOptionsForm()
) to use the new load by target method. Somehow-or-other allow the View to get the target for the entity during pre-save (instead of inEdit: see #63.submitOptionsForm()
as in the current patch).
Once we add these methods, there will also be some followup in ER (see #2390729: Update ER's ID to UUID default value conversion code to use the new "getTarget()" API) to use them there as well.
Remaining tasks
#111 needs review.
Followups
- #2392833: Entity area handler input is not validated
- #2396607: Allow Views token matching for validation (and remove dead code)
- #2390729: Update ER's ID to UUID default value conversion code to use the new "getTarget()" API
- #2412983: Consider adding a method to indicate the entity type's target identifier key
- #2416109: Validate configuration dependencies before importing configuration
- Possible followup: Add a generic autocomplete implementation which works beyond fields (entity reference)
User interface changes
None yet; the patch just changes what is stored when the user enters valid input.
API changes
- New methods
Comment | File | Size | Author |
---|---|---|---|
#111 | interdiff-105-111.txt | 6.49 KB | xjm |
#111 | vdc-entityarea-2341357-111.patch | 38.27 KB | xjm |
#105 | interdiff-101-104.txt | 6.65 KB | xjm |
#105 | vdc-entityarea-2341357-104.patch | 37.82 KB | xjm |
#101 | interdiff-target-bug.txt | 1.06 KB | xjm |
Comments
Comment #1
dawehnerHere is a first try. Let's call it major as it helps to deploy views.
Comment #3
dawehner.
Comment #4
dawehnerAlright, here we go.
Comment #5
dawehnerUpdate the IS.
Comment #6
Wim LeersLooking good :) Manually tested, works perfectly.
Also: is there a reason we must support IDs at all? Why can't this support UUIDs only? Because users might know the ID by heart and might want to enter that?
s/autocompletion/entity autocompletion/
s/,/./
Why not
QueryFactoryInterface
?(We encountered this same problem in #2278017: When a content entity type providing module is uninstalled, the entities are not fully deleted, leaving broken reference also, so this is more a genuine question than a review remark.)
s/UserAutocomplete/EntityAutocomplete/
AFAIK we generally prefix such routes with
/system
?Missing the matching protected property for this.
I wonder if we can't figure out whether the value is a UUID and then not try both anymore?
s/Specific/Specify/
What about "Entity ID or UUID"
I think we can omit this description, with the slight title change, it seems entirely redundant?
Comment #7
dawehnerWell yeah, we know that the QueryFactoryInterface is the factory for each entity type. In order
to reduce the amount of work done in the constructor, let's store the generic factory.
I don't care, changed it.
Fixed.
Good idea, let's check first run a UUID validation.
We can't do that, because we allow to use IDs for usecases like "/taxonomy/term/{taxonomy_term}". We use tokens there to fetch the argument from the URL.
True.
Comment #8
Wim LeersOnly one nit left now:
The comment now no longer matches the logic.
Comment #10
dawehner... given that I introduced a logic error in the last patch I decided to write a unit test for that file.
Comment #11
Wim LeersComment #12
amateescu CreditAttribution: amateescu commentedI hope you realize that this
1) is a security vulnerability (it will return entities a user doesn't have access to because
->accessCheck(TRUE)
doesn't actually do anything)and 2) it will return incomplete results (it won't return the anonymous user for example).
If doing a generic entity autocomplete system would've been this simple, don't you think we would've removed all those ER selection plugins by now?
Can we rename this class to something more than EntityTest? It will be quite annoying to bump into it in an IDE autocompletion when you're actually looking for the entity_test class.
And some constructive feedback (replying to the "Proposed resolution" in the IS):
For this you need to do a ID <-> UUID mapping like
EntityReferenceFieldItemList
is doing inprocessDefaultValue()
anddefaultValuesFormSubmit()
.We have #2107243: Decouple entity reference selection plugins from field definitions and #1959806: Provide a generic 'entity_autocomplete' Form API element for that.
Comment #13
alexpottUUID :)
And can we have a content dependency added to the view too? Thanks.
Comment #14
jibranHere are some minor issue.
Gets
type missing.
Is this even possible?
I don't think this is enough. Yeah see #12.1. I think we should postpone this on #2107243: Decouple entity reference selection plugins from field definitions and #1959806: Provide a generic 'entity_autocomplete' Form API element
It should be above and it should be for $entities like this.
/** @var \Drupal\Core\Entity\EntityInterface[] $entities */
I have a question, will it become /taxonomy/term/{uuid}?
Comment #15
dawehner@amateescu
Okay, I do see your point. Let's remove the autocompletion from this issue then. The UX in HEAD is not worse.
... No I won't. The class is called Entity, so the test should simply be EntityTest, so you can easily switch between class and test. If someone doesn't get namespaces,
we have other problems.
See #2353611: Make it possible to link to an entity by UUID
Comment #16
amateescu CreditAttribution: amateescu commented@dawehner, apparently you're implying that I don't get namespaces? Well, I don't have any answer for that, do what you want.
What exactly needs review here?
Comment #17
jibranNW because
Comment #18
olli CreditAttribution: olli commentedIs it possible to use the entity type label here instead of "Entity"?
Comment #19
dawehnerOh damn, I forgot to upload the patch.
Good idea!
Comment #20
Wim LeersTiny nitpick that can be fixed on commit:
s/as/by/
But what about this more important part, that Alex Pott remarked in #13:
Comment #21
dawehnerSure.
Comment #22
Wim LeersThe interdiff is wrong, but the patch is right. Here's the right interdiff for #21.
So close, just one remark left:
We don't have test coverage for this yet.
Comment #23
dawehnerThank you for the quick review ... no idea what happened with the interdiff ...
Alright, let's complete the test coverage ...
Comment #24
Wim LeersSplendid!
Comment #25
amateescu CreditAttribution: amateescu commentedI still don't understand why we're going with this "it can be either an ID or an UUID" (based on what? phase of the moon?) approach instead of doing it properly like I suggested in #12.
Comment #26
Wim LeersSorry, I forgot about that.
So this is the part that needs either to be answered or resolved:
Comment #27
dawehnerWell, because I just simply don't see the big advantage. Why is loading by UUID a bad idea?
Comment #28
dawehnerSeriously, ... we don't always have the UUID, in case loading UUID is a problem this should be handled internally by the entity system.
Comment #29
amateescu CreditAttribution: amateescu commentedIs consistency too much to ask for?
Who said loading by UUID is a bad idea? What I'm saying is that we need to enter only IDs in the UI and automatically convert and store them as UUID in config.
When do we not have a UUID for an entity, either content or config? That would be a bug.
Again, there's no problem with loading by UUID, the only problem is being consistent with that we enter in the UI and with what gets stored in config.
Comment #30
amateescu CreditAttribution: amateescu commentedOh, wait, maybe I don't understand the current approach because I don't get namespaces.
Comment #31
dawehner@amateescu
The thing is that views allows you to input "!1" which points to the first argument of the view. The argument will be the ID most of the time anyway.
So entity_id_uuid is kinda a good name.
Given that we need code on runtime to handle the converted ID directly.
Comment #32
amateescu CreditAttribution: amateescu commentedOk, I don't have anything else to add to this discussion.
Comment #33
dawehnerSo do we really just talk about the following change?
Comment #34
amateescu CreditAttribution: amateescu commentedI'm talking about never storing an entity ID in config, only the UUID. I can't tell from a quick look at the patch if that interdiff is the only thing needed.
In any case, the
!<arg>
case needs to be handled separately somewhere and if what we get from config doesn't start with '!', it must to be an UUID and handled as such.This also means that the name should be more like entity_uuid_or_param.
Comment #35
Wim LeersThis is a good point. The current patch essentially is
entity_id_or_uuid_or_arg
("param" is wrong, "arg" is what you mean). If we'd only support UUIDs, then it'd indeed becomeentity_uuid_or_arg
.Comment #36
dawehnerWell, just to be clear, this parameter is the usecase for which this currently is useful (taxonomy/term/%). The UUID here is an addition, so I would argue that adding the UUID should not drop the existing feature.
I still don't get why it has to be an UUID and why the current implementation is so horrible.
Comment #37
amateescu CreditAttribution: amateescu commentedWhere did I say anything about dropping the existing feature? I just said that we should only store UUIDs or the current
!<arg>
thing in config and process them differently on load/runtime if config gives us something that starts with "!" or not.I also didn't say the current implementation is horrible, not sure where you got this impression? Maybe it's because that "I don't get namespaces" stuff really stepped on my tail.
Comment #38
effulgentsia CreditAttribution: effulgentsia commentedI think not being able to do a config deployment is a critical bug. And since the fix requires changing the config structure, that makes it an upgrade path blocker. I haven't yet gotten up to speed with the patch to provide a meaningful review, but am hoping to do so when I get a chance, unless this gets fixed before then.
Comment #39
xjmI think we should only store UUIDs in Views, anywhere, because every content dependency in a view needs to be deployable and so storing a serial entity ID breaks the principles of the configuration system. However, whether the user enters a serial ID, UUID, entity label, or whatever when configuring their view is probably worth discussing. I think the minimum to do here is to ensure that all serial IDs get converted to the UUIDs of the current site when the View is configured (are there others remaining beside the entity area handlers?). Then, we can look into usability improvements to how the user chooses the referenced entity in separate issues if needed.
Comment #40
dawehnerThank you for summarizing exactly what the patch is doing.
We convert IDs to UUIDs, in case possible. In case we can't know, because its a placeholder, we load the entity using the placeholder resolves ID/UUID.
Comment #41
dawehnerHad a bit of a discussion with xjm:
To be clear, let's all forgot about this issue first.
HEAD supports you specify "!1" which will pull the UID which is part of the URL, "/foo/{entity_test}" and use it in the area,
to render an entity at the top of a view. This functionality is used for the taxonomy/term/{} view in order to render the entity description at the top.
This patch adds support to also reference an entity by UUID, as you want to have proper deployment functionality.
Comment #42
xjm(This is a crosspost with #41)
So I'm a little slow on the uptake apparently, but @dawehner just explained this to me. Apologies to everyone who already understood this -- the
!1
placeholder has nothing to do with any particular serial ID; rather, it's a placeholder for a views argument available at runtime (e.g. for the taxonomy/term/% pages as @dawehner points out above). The reason that it's a!
and not a%
is so that it's run throughstrip_tags()
(see in ViewExecutable::_buildArguments().)I can see the case for renaming the key since the current name confused me too. And yeah the interdiff in #33 seems to make sense, if the goal is to ensure only a UUID get saved. But OTOH my brain cannot parse what the old code was doing. ;)
Per @dawehner the fact that this was still a
1
was simply a bug in the patch. It is fixed in #41. I wonder why no tests failed in #23?Comment #43
xjmComment #44
olli CreditAttribution: olli commentedThese need to go too.
$options is not passed here, you need &form_state->getValue('options') or something.
Move the comment inside loadEntityByIdOrUuid()?
Comment #45
dawehnerThank you for your review!
Good catch.
Fixed
Interesting, I wasn't sure and just looked it up in the argument default plugins, and indeed they are still special here.
Comment #46
effulgentsia CreditAttribution: effulgentsia commentedWith this approach, the behavior of the patch is that:
- Edit a View, add a "Global: Rendered entity - Custom Block" to the Header, type in the ID (e.g., "1").
- Submit the form, and then go back to edit that header item. Now, what's visible in the UI is the UUID.
I think I agree with @amateescu that that's not desired, and that a possible way of fixing that is to have two separate keys in $options: 'entity_id' and 'entity_uuid', just as we do in the schema of
field.value.entity_reference
within core.data_types.schema.yml. Even if the UI problem becomes moot once we use an autocomplete element, I think the code flow would be easier to follow with two separate keys.Comment #47
effulgentsia CreditAttribution: effulgentsia commentedAdditionally, the patch does the ID to UUID conversion for config entities as well. For example, do the example from #46 with a "Global: Rendered entity - Block" and "bartik_powered". Do we need/want that, or is it better for config references to stick to ID?
Comment #48
effulgentsia CreditAttribution: effulgentsia commentedBuilding on that idea,
What if we changed this to:
So $options would look like
$options['entity_reference']['target_id']
and$options['entity_reference']['target_uuid']
. Or, if we don't like a non-field using a field value's schema type, we could make a new core data type (e.g.,entity_reference
) and have both field.value.entity_reference and views.area.entity.entity_reference extend it.I wonder if doing that would also assist with the issues linked at the bottom of #12 and using those elements for this use case.
Comment #49
effulgentsia CreditAttribution: effulgentsia commentedPer #47, this can be either a config dependency or a content dependency; we can't assume only content.
Comment #50
amateescu CreditAttribution: amateescu commented@effulgentsia, I'm sorry but I don't think that will be of much help here and neither for the two issues linked in #12, one is about the implementation of ER's selection plugins, which don't have any knowledge of entity IDs or UUIDs, and the other one is just about code (Form API), so config is not involved in neither of them. It seems that my point didn't quite get across so I'll try to explain again how I see a good resolution for this issue.
Let's start with (what I hope is) the desired outcome:
- in the "entity area thingy" the user can enter
1) an entity ID
2) an entity UUID
3) an "argument placeholder" (
!<arg>
)- when the view is saved in config, for the cases above we need to
1) convert the entity ID to its UUID
2) and 3) do nothing (pass-through)
Now, when the user comes back to edit the view/header area, they will see
1) an entity ID, which can be different from the initial one if the view is edited on a different environment
2) an entity ID, converted from the UUID entered initially
3) the same argument placeholder
Note that in point 2) above, there is a change like the one you noticed, but reversed (UUID -> ID) since we store both 1) and 2) as UUIDs and we cannot know if the user entered an ID or UUID in the first place.
Therefore, since the desired outcome is to never store an ID in config, but only a UUID or an argument placeholder, I still think a single config entry named
entity_uuid_or_arg
is enough for this use case.Also, we can decide that the user can not enter a UUID at all since we don't have that possibility anywhere else in D8's user interface as far as I know, so the possibly confusing outcome of 2) is no longer a problem.
Does that explanation make sense?
We will also need a validation step to ensure that the ID (or UUID if we decide we want 2)) is actually valid for the given entity type (I have no idea if this is already implemented, I just thought it needs to be mentioned).
Comment #51
effulgentsia CreditAttribution: effulgentsia commentedPer #47, is that true in the case that we're referencing a config entity?
Comment #52
amateescu CreditAttribution: amateescu commentedYes, I think that #47 will complicate things without adding any benefit. The user will only see the ID in the UI anyway.
Comment #53
effulgentsia CreditAttribution: effulgentsia commentedWhat about default config, shipped for example with an install profile? For example, let's say the Standard profile wants to ship with a View that puts a block into one of its areas? That block doesn't have a UUID yet.
If we want a single entry, then I would change that to
entity_uuid_or_token
, since tokenizeValue() can handle more than just URL arguments. However, per above, that name wouldn't cover the case of referencing a config entity by ID. So, what about simplyentity
?Comment #54
amateescu CreditAttribution: amateescu commentedThe same case can be made for a content entity as well, for example the 'Home' menu link, so I'd say in this case the view will need to go through the same "when the view is saved in config" step from #50, which means the implementation will have to be somewhere else than a form submit handler.
That sounds fine, what I'm really against here is having 'id' in the name, based on the premise that we'll never store IDs.
Comment #55
effulgentsia CreditAttribution: effulgentsia commentedSorry to bring up old wounds, but the Standard profile's 'Home' menu link is not a content entity.
There's no support in core to ship default content. A profile can add some content entities in its hook_install(), in which case it then has a UUID to work with and can update its installed config accordingly. But nowhere else where config references config do we require it to deal with a UUID and the resulting need for programmatic interaction as part of default config.
So, I still think that the config key we're discussing in this issue needs to be able to support the following value types:
- a string with tokens (e.g., "!1")
- a UUID when referencing a content entity
- an ID when referencing a config entity (I could be convinced against this, but haven't been yet)
Therefore, if we want a single key that can be any of the above, I propose we name it
entity
.Yes, I agree with this. I don't think we should ever display a UUID in the UI, except in places like the config diff modal.
Yes, so then the question becomes where in the code to do that conversion. In the form? Or somewhere within the onLoad() flow? I think the conversion should be symmetrical. So, if we do ID -> UUID during form submit, then we should do UUID -> ID during form build. But, if we do ID -> UUID during config save, then we should do UUID -> ID during config load.
Comment #56
dawehnerJust in general, I do see your pursuit of semanticness for what we actually store in the configuration and how we describe it.
Given that I would certainly like to separate storing the placeholder, from storing the ID/UUID. Using placeholders
here is a separate concept in my point of view, one you would probably not be able to describe properly in generic schema information.
At the moment we don't have any semanticness about UUID being something special, compared to just an arbitrary string.
Given that though I really ask myself, whether describing more, than a pure string is a requirement to get the bug fixed, which is,
that you cannot deploy those views. Adding a proper schema and making the storage more sane seems major for me.
Well, sure, but I think making the UI nice to use, is not and should not be part of this issue, given that you would
always have to start with some form of autocompletion anyway, otherwise finding the IDs is too hard anyway.
Talking about usecase for config entities:
I could really easy imagine usecases like the following, on which we want to point to a config entity: You have config entities which
represent some kind of help text, which should be shown above the view.
Even not directly related, but this reminds me of #2353611: Make it possible to link to an entity by UUID, we often want to have ID and OR UUID.
Comment #57
pfrenssenSummarizing #46-#55:
There is consensus on the following next steps to take for this patch:
entity_id_uuid
toentity
- proposed in #53, confirmed in #54.Still to be discussed:
edit: this does not include @dawehner's input from comment #56.
Comment #58
xjmComment #59
xjmWe discussed #57 with @amateescu, @alexpott, @dawehner, @bircher, and myself. Writing up now what we concluded...
Comment #60
xjmComment #61
xjmDiscussed with @alexpott, @amateescu, @dawehner, myself, and intermittently @bircher. ER and Views (and probably other modules) have a shared usecase here to:
Currently, ER handles this in
EntityReferenceFieldItemList::defaultValuesFormSubmit()
like so:So the
target_id
key is used in the user-facing form to provide the entity ID, and then converted to a UUID before it is saved via the Entity API. @alexpott noted that this doesn't support default configuration (which does not have a UUID) -- i.e., a module cannot provide both an entity reference field and a default value for it in its configuration.To fix that, we can move this logic into the pre-save operation.Edit: see #63 and #2390729: Update ER's ID to UUID default value conversion code to use the new "getTarget()" API.@alexpott also pointed out that in general it's much better to store and rely on the config ID for configuration entities (rather than the UUID). Since it can be a UUID ID or a config ID, we decided it would make the most sense to just name the key it
target
(rather thanentity
,entity_id_or_uuid
,target_uuid
,target_id
... or whatever).We agreed that the best way to address all of the above would be to actually add some methods in the Entity API that ER, Views, or whatever other implementing code can rely on:
EntityInterface::getConfigTarget()
Will provide the the correct way to store the value of a target entity--i.e. the UUID for content entities, or the config ID for configuration entities. As elsewhere, the Entity base class will provide the default implementation, and ConfigEntity will override it.
EntityManagerInterface::loadByConfigTarget()
Loads the entity from the string provided by getConfigTarget() (both for rendering and for preparing the form?). Would include this check:
$key = $target_entity_type instanceof ConfigEntityType ? 'config' : 'content'
currently found inEntityReferenceItem::calculateDependencies()
Related issue: #2390615: Add method to determine config dependency key depending on entity type
For this issue, we'll:
Drupal\views\Plugin\views\area\Entity::render()
(and::buildOptionsForm()
?) to use the new load by target method.Somehow-or-other allow the View to get the target for the entity during pre-save (instead of inEdit: see #63.submitOptionsForm()
as in the current patch).Once we add these methods, there will also be some followup in ER (see #2390729: Update ER's ID to UUID default value conversion code to use the new "getTarget()" API) to use them there as well.
For another followup issue: There appears to be no validation for the value of the taxonomy term ID field. You can enter term IDs that don't exist. You can enter placeholders that aren't available. It happily accepted
elephant
as a taxonomy term ID. It accepted !this%is!not%legit
. Etc. :) This is an existing bug in HEAD (so out of scope here), and probably pervasive elsewhere in Views.I'll start incorporating this in the patch.
Comment #62
dawehnerThis is a no-followup: #2390773: Bubble up View::preSave
Comment #63
xjmAdditional discussion with @dawehner, @alexpott, @amateescu -- the bit about moving functionality into
preSave()
instead of submit handlers actually becomes a non-issue once we store the config ID instead of UUIDs. So #2390773: Bubble up View::preSave is no longer related, and #2390729: Update ER's ID to UUID default value conversion code to use the new "getTarget()" API becomes about simply converting to the new methods rather than also moving the logic out of the submit handlers.Comment #64
xjmHere are initial implementations for the new methods. One thing that occurred to me is that it doesn't feel quite right to hard-code the instanceof check in the entity manager -- we could instead supply a method gets the entity key for the target ID--UUID key in the content entity base implementation, and ID key in the config entity base implementation. Then load by that key regardless. But I've not incorporated that here yet--want to get it working first. :)
Comment #65
xjmWorking patch (in that it worked when I tested it in the UI, and the integration tests pass). Still to do:
Comment #66
xjmOops, forgot the interdiff.
Comment #68
xjmFixes the silly ViewUI fail.
Comment #69
Wim LeersComment #71
larowlanwork on phpunit fails, still not quite there
Comment #73
larowlanComment #74
dawehnerThat is a bit misleaading if you think about content entitites. What about using "in configuration" instead of "in other configuration"?
Why do we not use the interface here? $entity_type instanceof ConfigEntityTypeInterface ...
We can do the validation in another isue, given that we did not applied any kind of validation in HEAD as well.
Follow up? :P
Its actually kinda sad that loadEntityByConfigTarget does not work if you specify the entity ID of an content entity and you need to special case it here.
Comment #75
xjmThanks @larowlan and @dawehner.
Filed #2392823: [meta] Much Views UI input is not validated and #2392833: Entity area handler input is not validated as followups for validation. Also updated the issue summary a bit (still could use some work).
I'll improve the patch some more.
Comment #76
xjmSome work. Addresses #74 points 1-3, and one of the @todo. I also broke a unit test. Might have actually broken the functionality; didn't test it manually yet.
Comment #77
xjmComment #79
dawehnerYeah, somehow ideally I think this should be part of the entity storage ... but given that this would be an API change for itself, moving along and not do that here, seems fine for me.
It would be great to file a follow up to get rid of that 'bypass_access' checking. This got introduced when we had an SA, which added access checking but still allow people to opt out, to not introduce regressions.
Does those methods really have to be public?
Can we use
$this->view->getStyle()
instead?it is a little bit odd to have singular here, but meh
Note: We could reuse the regex used by token itself:
Absolutely!
Its kinda odd that we return TRUE for strings like "you say hello, [ and we say goodbye"
Poor ViewUI, nobody likes oyu :) ... shouldn't that be
return $this->getConfigTarget()
... ?Btw. this should fail the ViewUI unit test automatically.
Comment #80
xjmRe: #74.4, I discussed this with both @alexpott and @amateescu, and they said they were comfortable with the behavior, so I've just removed the @todo.
Re: #74.5:
I actually don't think that the entity system should support that; it'd be a bit magical. The load method should match what's returned from the getter, and calling code can be explicit about what it expects and what it doesn't. Discussed with @alexpott and he agreed. So I've left this as is.
Re: #79.5:
I actually think the singular is correct -- we are checking that it has at least one token, and the method can also check that it has only one token. So I've left these with singular names.
Re: #79.9:
Fixed. There are also a couple other config-related methods on ViewUI that do this in HEAD (which is what I was copying). I'll file a followup to fix those.
Attached also addresses #79.4, which additionally actually solved another bug on form build similar to the one in the dependency calculation with the style plugin not being initialized. (@alexpott helped me fix the unit tests.) Still to do: the various @todo, file followups for #79.1-2 and the stuff related to #79.9. For #79.3 and 6-8, I may actually spin these new methods out into their own separate patch so that we aren't creeping scope quite so much. For now, though, here's a working patch. I'll work on this more later.
Comment #81
dawehnerSo what should we do with all these @todos ... We do alread have one follow up to have a broader test coverage for the itself.
Comment #82
dawehnerWell anyway, let's just ship it :)
Comment #83
catchSorry this issue took multiple different directions and needs an issue summary update.
Comment #84
xjmYeah it's also not done yet. Sorry... should have set it NW. Haven't had time to finish this past week.
Comment #85
xjmSpun out #2396607: Allow Views token matching for validation (and remove dead code) as per #80.
Comment #86
xjmThis will need an update for #2342287: Allow Twig in Views token replacement but doing so in #2396607: Allow Views token matching for validation (and remove dead code).
Comment #87
xjmDiscussed with @alexpott, @effulgentsia, @catch, and @webchick. This issue is critical because of the missing configuration dependencies for this handler. The content reference problem by itself is not critical, per #2248369-20: [meta] Deploying configuration that depends on content, but needs to have a compatible solution (which this issue will provide).
Comment #88
xjmHere's the patch rerolled on top of the current patch in #2396607: Allow Views token matching for validation (and remove dead code). The
-do-not-test.patch
contains the patch for this issue. Working on #80 (and #83) now.Comment #89
xjmThe rock that is #2396607: Allow Views token matching for validation (and remove dead code) has turned out to have many creepy-crawlies underneath, so removing the soft block on that issue and adding a @todo to remove 12
strpos()
later. :PComment #91
xjmFiled #2412891: Let config entity methods be tested on ViewUI per #80 and fixing a silly logic error.
Comment #92
xjmFixing another bug in the patch. Looks like we definitely need to expand the integration tests here...
Comment #93
xjmComment #94
xjmOkay, so here is what needs to be done on this issue still:
One usability question from the patch to test as part of that:
.
Comment #95
larowlanIS update
Putting my hand up for the integration tests, but won't likely be until Monday 26th before I get a chance to start them.
Comment #96
dawehnerAdded a bit of a test coverage.
Comment #98
xjmWebTestBase and KernelTestBase both already have the trait (thanks @alexpott).
Comment #99
xjmI did a bunch of manual testing and... dah dah DUNH... found a bug.
1
in the "taxonomy term ID field.entityarea-test
. You should see your term displayed at the top of the content listing.admin/config/development/configuration/single/export
and select your view. You should see that the "target" is properly the UUID of the entity.!1
. in the header's taxonomy term ID configuration instead. Save the view.entityarea-test
. There should be no taxonomy term rendered at the top of the view, because there is no argument to match the placeholder.admin/config/development/configuration/single/export
and select your view. You should see that the "target" is properly!1
.1
in the header's taxonomy term ID configuration instead.entityarea-test
Expected behavior: Rendered taxonomy term at the top of the listing. Actual behavior: No rendered taxonomy term at the top of the listing.admin/config/development/configuration/single/export
and select your view. Expected behavior: The target is the UUID of the term. Actual behavior: The target is the serial ID 1.So far I've only reproduced this when changing from an argument placeholder to a term ID, not when changing between different term IDs. So something in the view is stale or something when saving... needs further debugging. And then a test for whatever the underlying bug is, and then a fix for said bug. ;)
Comment #100
xjmComment #101
xjmAttached resolves #99. The bug was that the submit method was checking the previous value of the target field, not the new one in form state, and so failing to load the entity in that case when the previous value had a token.
So to add test coverage the test view could simply save first with a token value, then resave with an existing content entity ID, and assert that the correct value is then saved to the view. The test would fail with the attached interdiff reverted, and pass with it included.
Comment #102
dawehnerI think we can drop this todo now.
This todo can be dropped now as well
Comment #103
xjmAlrighty, I've done thorough testing adding, editing, and deploying a content entity area handler using both the term ID and an argument placeholder. The dependency management works like it is supposed to. For example, if I first create a view on the test site referencing a taxonomy term that exists only on the dev site:
The term is properly displayed at the top of the view.
Then deploy it to prod:
No term at the top of the view, and it correctly falls back to displaying nothing in that area handler.
Then, if I create a term with a matching UUID on prod:
And then the matching prod term is displayed at the top of the view.
This works fine for core and will support content deployment in contrib. The question is whether or not we want to display the UUID to the user there when it is not available on the site, or something else. I'll filed a followup issue for that. (It's surely going to apply elsewhere in Views where we have content entity dependencies.)
Argument placeholders are also handled correctly. I didn't test global tokens. Invalid term IDs fall back to the same behavior as unavailable UUIDs:
Next I'm going to manually test config entities. Also expanding the test coverage a bit and removing @todos that are no longer needed.
Comment #104
dawehnerDidn't we totally agreed that we don't want to think about the UI representation in this issue?
If you are shocked by a UUID but not by the entirety of a views UI, you have quite a good life.
Comment #105
xjmAttached expands the UI test coverage to catch all the clever ways I broke the options form during the course of this issue. I've also confirmed the calculateDependencies() test coverage is sufficient to catch the previous bugs, removed various no-longer-relevant @todos, filed #2392833: Entity area handler input is not validated, and updated the issue summary. I plan to do a bit more manual testing for config entities and maybe for non-argument tokens, but I think this is close and probably ready for a final round of review.
Comment #106
xjm@dawehner, re: #104, yes, that's why I said I was filing a followup. :) Just posting screenshots to prove, well, that it actually works. You can, actually for real, deploy the view, and then add the content entity to the target site with the same UUID but a different serial ID, and it works.
lol
Comment #107
xjmNote to self: Add this issue to the summary.
Oops, forgot to check whether this was still the case or not. This @todo can probably go as well. I'll test this tomorrow. Edit: Or we might need to add a tidbit to a unit test.
Comment #108
xjmComment #109
larowlan@xjm - so does that mean the 'remaining tasks' in the IS can be updated to remove the manual testing?
Thanks
Comment #110
xjm@larowlan, I updated the manual testing to list what I still haven't done (and will do on my flight today). Cheers!
Comment #111
xjmI thoroughly tested config entity targets, field tokens, and global tokens. I found a couple bugs, which are fixed in the attached:
Drupal\Tests\views\Unit\Plugin\area\EntityTest
doesn't cover rendering and calculating dependencies with a config ID, but the integration test inDrupal\views\Tests\Handler\AreaEntityTest
does. Good enough, so I've removed that @todo.{{ title }}
) instead of what's suggested in the UI, both HEAD and this patch work fine. I added unit test coverage for the render tokens as well.I also tested deploying with config entity targets. So far as I can tell, a missing config dependency for the view... has no effect whatsoever on the deployment. ??
Comment #112
xjmComment #113
alexpottThere is no checking (yet) that all dependencies exist during configuration import - we only use dependencies to order the import. If the dependency does not exist it has no effect on ordering.
Comment #114
alexpottCreated #2416109: Validate configuration dependencies before importing configuration to do #113
Comment #115
xjmHooray, thanks @alexpott. That means everything for this patch has been very thoroughly tested and appears to be in working order. :)
Comment #116
xjmComment #117
dawehnerI'm certainly fine with the patch as it is ...
Comment #118
amateescu CreditAttribution: amateescu commentedI can't speak for the views part, but I found a couple of small issues on the entity side :/
We could use Drupal\Component\Uuid\Uuid::isValid() here instead of the hardcoded check.
Why do we return FALSE instead of NULL? Also, the $target param is not always a UUID :)
Same for the exception below.
Comment #119
jibran+1 for views changes :)
Comment #120
dawehnerThe reason for that is that we inherit the behaviour from
EntityManager::loadEntityByUuid()
Well, the idea was more to distinct between config and content entities, not about UUID vs. not UUID. At least this is how I can explain it.
Comment #121
webchickSounds like amateescu's feedback was addressed? Assigning to alexpott for sign-off because it looks like he's been pretty involved here.
Comment #122
alexpottThis issue addresses a critical bug and is allowed per https://www.drupal.org/core/beta-changes. Committed 9a5eb86 and pushed to 8.0.x. Thanks!
Remove unused variable on commit.
Comment #124
xjmRe: #118, right, the idea is to ensure that config entities use their ID rather than their UUID. Because they have valid UUIDs too. That's why I suggested an API to make it up to the entity type to indicate what key corresponds to its target identifier. We can discuss more in #2412983: Consider adding a method to indicate the entity type's target identifier key?
Comment #125
amateescu CreditAttribution: amateescu commented@dawehner, you told me a couple of weeks ago in a different issue that if HEAD has some bad code, it doesn't mean new code has to be bad too (in this case, documentation). I suppose this principle got lost somewhere on the way? :P
Opened #2417339: Fix @return documentation for EntityManagerInterface::loadEntityByConfigTarget() to fix the docs.
@xjm, I'm not sure we actually want to enforce that behavior, but you're right, let's continue over there.