Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
Drupal core provides field handlers per entity operation, but no handlers that can render all available operations at the same time. This means that any module that introduces a new operation must also provide a handler plugin, which is more work.
Proposed resolution
Add a reusable handler that renders all available operations for an entity.
Remaining tasks
Write tests.DoneUse the handler for at least one entity type in Drupal core (node?)Done
User interface changes
None.
API changes
none.
Beta phase evaluation
Issue category | Bug because this fixes a regression from Drupal 7 where contrib could add operations to admin/content and admin/people. Also the operation links displayed currently in views might show operations that user has not access to |
---|---|
Issue priority | Not critical |
Prioritized changes | Adds an operations links handler for views which displays the entity operations that an user might have access to. Fixes a regression on admin/content and admin/people displaying the right links |
Disruption | Non disruptive, core and contrib can use now the handler but no need to as the dropbutton will still be operative. |
Comment | File | Size | Author |
---|---|---|---|
#129 | drupal_2165989-129.patch | 25.38 KB | pcambra |
Comments
Comment #1
XanoI have to run now, but I will continue working on the tests and integration tomorrow.
Comment #2
dawehnerCan't you always pull the entity type/entity ID from the actual metadata available on the running view?
Comment #3
damiankloip CreditAttribution: damiankloip commentedCool, nice start! I meant to open this issue but obviously forgot...
You can remove a few things from the handler, like the storage controller, and do something more like this. Sorry, this was quicker/easier than explaining.
Handlers also have a getEntityType() method, which might be what Daniel means in #2? So maybe just pass in the EntityManager instead too.
I guess you also didn't get round to doing the destination stuff. How were you planning on implementing that?
Comment #7
XanobuildOperations()
is not part ofEntityListControllerInterface
, so we can't depend on it.Comment #9
dawehnerNo docs are better than these docs.
$this->t()
Nice description +! i think it is pointless to require getInfo on unit tests.
Any reason why we don't extend the class as in other tests?
Comment #10
damiankloip CreditAttribution: damiankloip commentedI'm not seeing the point of this change? Just a wasted additional line of code. Can you revert or just assume that an entity will be loaded (we do both)?
Yeah, I think we should extend the class instead, not test using a mock.
This is not that useful. We're not really testing anything.
Maybe we should also override the query method here aswell, same as the Links handler.
Have you tested this yet? I guess not as there is no views data implementation :)
Comment #11
XanoI have bad experiences with doing assignments in conditions. This keeps it more readable for me and prevents me from accidentally writing assignments instead of comparisons.
We'll still have to mock, as
getEntity()
must return our mocked entity, and we need to set expectations on the methods.At the very least, this tests method execution and whether the return value is partly correct.
Sure. Is this just a small performance gain, or something else?
I haven't. There is just the unit test. I wanted to get the approach agreed on first, before adding an implementation to core.
Done.
Done.
This patch addresses the test failure and updates the admin/content view to use this new handler rather than the existing per-link handlers.
Comment #12
damiankloip CreditAttribution: damiankloip commentedWe already had a chat on IRc, but ...
This can't/shouldn't really live in here. render() will get called for every row. That's a call to getEntityType, getListController(), getOperations(), and getEntity() on every row. You can add the entityType and ListController to an init method.
We can probably do a similar thing to destination aswell? This is not going to change per row, so better to not call drupal_get_destination() every time.
Comment #13
XanoComment #14
XanoNote that this issue should probably not be committed before #2165725: Introduce hook_entity_operation(), as without that issue, the handler will not be able to render links for operations that are defined in entity operations hooks.
Comment #16
XanoComment #17
damiankloip CreditAttribution: damiankloip commentedAlso, just adding this ad hoc for node is not what we want. we need to add this for entity types generally. We don't have to use it yet, but we want to be able to.
Comment #18
XanoAlright. This exposes the operations for all entity types at the same time. Do we still want to convert the administrative content view as an example and proof of this solution?
Comment #20
dawehner@Xano
This sounds like a great idea.
Comment #22
XanoThe failure looks like it was caused by
hook_entity_operation_alter()
operations not being picked up. This is as expected and will be fixed in #2165725: Introduce hook_entity_operation().Comment #23
XanoKeeping on needs work per the previous comment.
I extended the tests a little bit based on @damiankloip's feedback over IRC.
Thanks to you and @damiankloip for proposing this to me.
Comment #24
XanoComment #26
XanoRe-roll, and #2165725: Introduce hook_entity_operation() has been fixed.
Comment #28
XanoComment #29
damiankloip CreditAttribution: damiankloip commentedOverall, I do love what this patch is trying to achieve. Being able to remove x number of field handlers and replace with one is a win for sure.
oops
parameter in the link to return the user to the original view upon completing the link action.'),
Not sure why this needs to be wrapped in code tags? Can we remove those?
Why do we need to get the list builder every time? I think we could just store it.
Nitpick: empty line after query() closing brace.
"The mock entity manager"? - We know this will be used in the test :)
Not a good name. Should be "Field: Entity operations" I think.
These still don't really test much :(
'Operation links' instead? 'Operations links' sounds weird. Maybe that's just me.
Comment #30
dawehnerI do hate it that you cannot longer choose the visual representation, which you could do before with the dropbutton.
TRAILING SLASH!
We should do something different. the getLinks on Links.php should be able to retrieve all the entity operations, so you can use dropbutton etc. This would basically be one field for the operations and one for the actual rendering.
Comment #32
dawehnerComment #33
XanoIf we're going this way, can we split it up into two separate issues? We'll need to let EntityOperations render operations links as
'#type' => 'operations'
anyway, because DropButton renders them as'#type' => 'dropbutton'
.Comment #35
XanoThis is unblocked again as #2165725: Introduce hook_entity_operation() was just committed.
Comment #36
dawehnerWell sure, we can implement the API support first and then get the dropbutton in.
Comment #37
XanoRe-roll, and addressed some feedback.
The code tags are to emphasize the parameter is a coding thing and that it must not be translated.
Done.
Pffft :+ Done.
@sun, @dawehner, and I agree that this is how (unit) tests should be named for the most clarity. We've done this for a while now.
Full coverage now.
A missing
false
, actually. Fixed.Comment #39
XanoComment #41
Xano39: drupal_2165989_39.patch queued for re-testing.
Comment #43
Xano39: drupal_2165989_39.patch queued for re-testing.
Comment #45
XanoThis should pass.
Comment #46
dawehnerThank you for ignoring my previous suggestion.
Comment #47
XanoWhich one? The one you said was okay to postpone in #36?
Comment #48
dawehnerYeah you are so right.
Comment #49
XanoI interpreted that post as agreement with #33, which was about letting entity operations be rendered. While your additional approach opens up many possibilities, it does not directly solve the issue, and because it doesn't let operations be rendered as operations (we have a special render element for those), I don't think this solution is the most semantical one we can choose from right now.
If you feel like I am ignoring you, please just talk to me in person on IRC, but the sarcasm in your last two posts is not really motivating or constructive.
Comment #50
dawehnerWell, having two total different ways in views to provide links and render them in some ways is odd.
I don't really get why my approach does not directly solve the issue? Is it because there are test failures at the moment or does not include your parts?
I can't join IRC during the day.
Comment #51
XanoSo is being able to render operation links using the dropbutton element, but not the operations element. If we're going to go with just one, we should be consistent with list builders and use the semantically correct operations render element.
Your approach is much more generic, and while it is useful, it doesn't let us render entity operations as we render entity operations anywhere else: using the operations element.
Comment #52
dawehnerNot sure what you talk about. Views is not an entity list and will never be. It is a broken concept and should have been kept to only work with config entities. On the other hand views shipped with this kind of link support at least since D7, so you can easily argue that support the views way is more semantic correct.
Comment #53
XanoIf we are going to use Views to display entity operation links, then we should display those links like we do everywhere else, which is using the
operations
renderable element that is defined insystem.module
. Anything else (including the way core currently does) is not a proper rendering of entity operations. Your approach does not aid in this, and therefore belongs in another issue.Comment #54
Xano45: drupal_2165989_45.patch queued for re-testing.
Comment #55
Xano45: drupal_2165989_45.patch queued for re-testing.
Comment #56
Xano45: drupal_2165989_45.patch queued for re-testing.
Comment #58
XanoComment #60
XanoRe-roll because of the move to PSR-4.
Can we please use this approach? The
operations
element was added to core last year exactly for this purpose. Let's add more generic link handling in a follow-up.Comment #61
Xano60: drupal_2165989_60.patch queued for re-testing.
Comment #62
andypostIn context of related issue it makes sense to expose operations for all entities by unified plugin
Comment #65
XanoRe-roll.
Comment #66
andypostlet's check first that entity type has list builder
Comment #67
XanoComment #68
andypostsuppose it makes sense to add the same check additionally to base table
Comment #70
XanoComment #75
XanoComment #77
XanoComment #78
dawehnerAs written in march #2165989-32: Add a Views field handler for multiple entity operations we want to be able to implement things nicely. Therefore I created an issue which does it the views way,
which then would make this handler redundant again: #2324961: Allow field handlers to return multiple links
@Xano
I know you disagree and this is fine, but at least once both issues are in we can share a hell lot of code.
Comment #79
XanoI only disagree because we have a render element dedicated to displaying entity operations. As long as we can deal with that, I'm fine with any solution, such as
It's senseless to ship with an entity operations render element that is only used in one single situation where we need to display operations. I personally haven't really seen the need for that element yet. My only concern is that we need to be consistent throughout core. Any consistent solution is fine with me.
Comment #80
andypostI d like to see both abilities in core:
1) operations as dropdown - like most of admin forms are
2) separate links, because I used a lot special UIs when only single 'edit' or 'change' is needed
Comment #83
Xano@dawehner and I discussed this at DrupalCon Amsterdam and we reached the conclusion that we should continue adding this handler that is just for operations, and use #2324961: Allow field handlers to return multiple links to allow handlers to return multiple links and handlers to render these links.
Comment #85
XanoCould you make an issue for that? I think we should be able to write a reusable base class for this.
Comment #87
XanoComment #88
XanoAnd now exposing the operations in entity types' views handlers.
Comment #89
dawehnerTo be honest I think we actually want to have some basic integration test here as well.
It feels kinda wrong, but yeah this is for some reasons the "official" ""API"" at the moment.
don't we need a group here?
Comment #90
damiankloip CreditAttribution: damiankloip commentedCouldn't we just call
$this->entityType->hasHandlerClass(..)
instead?Maybe we should add a comment in the empty body here that we don't want to ensure anything/create any aliases.
I think we can just remove this now and add @group instead.
This is bordering on pointless, but I guess it's there now :)
Comment #91
dawehnerOh yeah, so much work is needed.
Comment #92
Xano#1839516: Introduce entity operation providers was our chance to change this ;-)
I found something even better!
Comment #95
damiankloip CreditAttribution: damiankloip commentedThat was just a general suggestion, so yes, using that looks great.
Sorry, can you add to this and say we purposely are not calling parent or something?
Otherwise, this is RTBC.
Comment #96
XanoComment #97
bojanz CreditAttribution: bojanz commentedI've tested this patch manually.
The operations list has the correct links, and the dropbutton renders correctly in Views preview.
But when I go to my actually page (admin/products in this case), the list is rendered bare, without the dropbutton, even though it has the necessary classes.
The top div has class="dropbutton-wrapper", but no dropbutton-processed, so maybe the required JS just wasn't included / ran?
Comment #98
XanoDid you try clearing the cache? Maybe the aggregated JavaScript has not been rebuilt yet.
Comment #99
bojanz CreditAttribution: bojanz commentedYes. Also tried disabling the aggregation completely. It's not that.
Comment #100
XanoIt seems this is a bug in core, as it happens with the current default views as well.
Comment #101
Xano#2350551: Views fields that have attached assets are lost when Views output caching is enabled is the culprit.
Comment #102
dawehnerI still think that we should have a dedicated integration test here because what we actually do here is not complex logic
but rather an integration between various bits.
Comment #103
XanoNote to self: see
\Drupal\views\Tests\Handler\FieldBooleanTest
for an example of a Views field handler integration test.Comment #104
pcambraRe rolled the patch as the content view has changed.
The interdiff contains the test I've added for this.
Comment #105
dawehnerAre we sure that this
if()
makes really sense here? I could easily imagine that entity types don't want to use entity list classes at all, but instead always use views, in which case they would not have the operations available.Just in case you want to, please split it up into multiple lines, as it makes things easier to read / adapt in the future.
no need for bool TRUE anymore.
Comment #107
pcambraThanks for the review @dawehner
Fixed comments in #105 and the failing test.
Comment #108
dawehnerSome nitpicks :(
Contains ... and wrong classname :(
new line after @file
Comment #109
pcambraSorry about those, fixed comments in #108
Comment #110
dawehnerThank you, especially for fixing this annoying things, which are kind of a Drupalism.
Comment #111
alexpottThis issue introduces a new feature, so per https://www.drupal.org/core/beta-changes, we should postpone it to 8.1.x or later.
Any reasons why we shouldn't postpone this?
Comment #112
bojanz CreditAttribution: bojanz commented@alexpott
A handler that includes all possible operations for an entity is one of the most common needed handlers for entity listings done via views, and the one most frequently reinvented in D7 contrib. Sure, the end result can be faked by declaring a bunch of individual link handlers, then merging their results together, but this puts the pressure and boilerplate on the contrib authors.
Comment #113
dawehner@alexpott
Yeah this for sure improves the development experience, but it also fixes for example
admin/content
You don't see the translation link on there (remember all those optional handlers discussion?). Instead it just provides all exposed operations the user has access to.
Comment #114
alexpott#113 suggest that this is actually a regression fix then :)
Comment #115
alexpottAs per #113/#114 reclassifying as a regression fix. Aren't there other admin views we should update?
Plus can someone add the beta evaluation template to the IS.
Comment #116
dawehnerAgreed the following views has to be updated:
Comment #117
pcambraModified admin/people to use operation links as for #116
Comment #118
pcambraComment #119
pcambraAdded beta evaluation summary table
Comment #120
dawehnerAwesome!
Comment #121
bojanz CreditAttribution: bojanz commentedRTBC if green.
EDIT: dawehner beat me to it.
Comment #122
alexpottThis issue should not be considered to be unfrozen. We are choosing to proceed because it fixes a regression and it fixes a bug.
Looking at the tests it appears that the
is not actually tested. Let's add a test to NodeAdminTest that users don't get operations they don't have access to.
Can we add a assertion somewhere in content_translation that the expected operation link is available.
Comment #123
pcambraHere's a test on content translation that shows the operations and that users with not enough permissions will not get them displayed.
Comment #125
bojanz CreditAttribution: bojanz commentedAnd we're back. Thanks, Pedro.
Comment #129
pcambraComment #130
bojanz CreditAttribution: bojanz commentedJust in time to miss beta5...
Comment #131
ArlaIn that case the operations field should not be available, because the list builder is used to generate the operations links, and a fatal error occurs when trying to access the undfined list builder.
I tested this on an entity without a list builder. To make it work, I specified EntityListBuilder as list builder. It is indeed strange that I need to specify a list builder to avoid using a list builder... but I gather from #92 that the idea of moving the operations definition to a concept on its own has already been lengthily discussed and eventually discarded.
TL;DR: I think the hasListBuilderClass() check should remain.
Otherwise: nice!
Comment #132
XanoCorrect. The current coupling is not ideal, but nothing we can clean up in Drupal 8. It is easy to provide a list builder for operations without having to use it for an entity listing: don't provide a route (although other modules might depend on your list builder).
Setting back to RTBC, as it seems all concerns have been addressed and there are no actual failures.
Comment #133
dawehnerNot a blocker at all, just given a hint for the future: There is a thing called
->willReturn
exists as a shortcut.Comment #134
dawehner+1 for the RTBC though.
Comment #135
alexpottCommitted 3f29fd9 and pushed to 8.0.x. Thanks!
Thank you for adding the beta evaluation to the issue summary.
Comment #137
ArlaI think this should be
$operation['query']
? Otherwise the destination option does not have any effect.Comment #138
andypost@Arla please file follow-up
Comment #139
ArlaCreated followup: #2419905: Views field 'Operations links' fails to set destination