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. Done
  • Use the handler for at least one entity type in Drupal core (node?) Done

User interface changes

None.

API changes

none.

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
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.
CommentFileSizeAuthor
#129 drupal_2165989-129.patch25.38 KBpcambra
#129 drupal_2165989-interdiff-123-129.txt1.83 KBpcambra
#123 drupal_2165989-123.patch25.27 KBpcambra
#123 drupal_2165989-interdiff-117-123.patch2.79 KBpcambra
#117 drupal_2165989_117.patch22.48 KBpcambra
#117 interdiff.txt3.06 KBpcambra
#109 drupal_2165989_109.patch19.42 KBpcambra
#109 interdiff.txt1.14 KBpcambra
#107 drupal_2165989_107.patch19.4 KBpcambra
#107 interdiff.txt2.83 KBpcambra
#104 drupal_2165989_104.patch19.44 KBpcambra
#104 interdiff.txt7.21 KBpcambra
#96 drupal_2165989_96.patch12.54 KBXano
#96 interdiff.txt644 bytesXano
#92 drupal_2165989_92.patch12.46 KBXano
#92 interdiff.txt1.95 KBXano
#88 drupal_2165989_88.patch12.65 KBXano
#88 interdiff.txt1.45 KBXano
#87 drupal_2165989_85.patch12.62 KBXano
#87 interdiff.txt842 bytesXano
#77 drupal_2165989_77.patch12.63 KBXano
#77 interdiff.txt1017 bytesXano
#75 drupal_2165989_75.patch12.57 KBXano
#75 interdiff.txt2.21 KBXano
#70 drupal_2165989_70.patch12.53 KBXano
#70 interdiff.txt1.4 KBXano
#67 drupal_2165989_67.patch12.64 KBXano
#67 interdiff.txt1.47 KBXano
#65 drupal_2165989_65.patch12.5 KBXano
#60 drupal_2165989_60.patch13.07 KBXano
#60 interdiff.txt17.14 KBXano
#58 drupal_2165989_58.patch13.15 KBXano
#45 drupal_2165989_45.patch13.29 KBXano
#45 interdiff.txt1.32 KBXano
#39 drupal_2165989_39.patch13.16 KBXano
#39 interdiff.txt1.1 KBXano
#37 drupal_2165989_37.patch12.7 KBXano
#32 views_entity_operations-2165989-31.patch16.38 KBdawehner
#28 interdiff.txt2.53 KBXano
#28 drupal_2165989_28.patch11.39 KBXano
#26 drupal_2165989_26.patch11.32 KBXano
#23 drupal_2165989_23.patch11.15 KBXano
#23 interdiff.txt1.13 KBXano
#18 drupal_2165989_18.patch11.14 KBXano
#18 interdiff.txt983 bytesXano
#13 drupal_2165989_12.patch11.1 KBXano
#13 interdiff.txt1.49 KBXano
#11 drupal_2165989_11.patch11.01 KBXano
#11 interdiff.txt8.85 KBXano
#7 drupal_2165989_7.patch6.94 KBXano
#7 interdiff.txt5.31 KBXano
#3 interdiff-2165989-3.txt3.59 KBdamiankloip
#3 2165989-3.patch3.11 KBdamiankloip
#1 drupal_2165989_1.patch4 KBXano
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Xano’s picture

Status: Active » Needs review
FileSize
4 KB

I have to run now, but I will continue working on the tests and integration tomorrow.

dawehner’s picture

Can't you always pull the entity type/entity ID from the actual metadata available on the running view?

damiankloip’s picture

FileSize
3.11 KB
3.59 KB

Cool, 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?

The last submitted patch, 1: drupal_2165989_1.patch, failed testing.

The last submitted patch, 3: 2165989-3.patch, failed testing.

The last submitted patch, 3: 2165989-3.patch, failed testing.

Xano’s picture

FileSize
5.31 KB
6.94 KB
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
@@ -0,0 +1,103 @@
+      return $this->entityList->buildOperations($entity);

buildOperations() is not part of EntityListControllerInterface, so we can't depend on it.

Status: Needs review » Needs work

The last submitted patch, 7: drupal_2165989_7.patch, failed testing.

dawehner’s picture

  1. +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,116 @@
    +   * Constructor.
    +   *
    +   * @param array $configuration
    +   * @param string $plugin_id
    +   * @param array $plugin_definition
    +   * @param \Drupal\Core\Entity\EntityListControllerInterface $entity_list
    +   *    The list controller of the entity type.
    +   */
    

    No docs are better than these docs.

  2. +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,116 @@
    +      '#title' => t('Include destination'),
    

    $this->t()

  3. +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,119 @@
    +      'description' => '',
    

    Nice description +! i think it is pointless to require getInfo on unit tests.

  4. +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,119 @@
    +    $this->plugin = $this->getMockBuilder('\Drupal\views\Plugin\views\field\EntityOperations')
    ...
    +      ->getMock();
    ...
    +      ->setMethods(array('drupalGetDestination', 'getEntity', 't'))
    ...
    +      ->setConstructorArgs(array($configuration, $plugin_id, $plugin_definition, $this->entityList))
    

    Any reason why we don't extend the class as in other tests?

damiankloip’s picture

  1. +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
    @@ -95,9 +90,27 @@ public function buildOptionsForm(&$form, &$form_state) {
    -    if ($entity = $this->getEntity($values)) {
    -      return $this->entityList->buildOperations($entity);
    +    $entity = $this->getEntity($values);
    +    if ($entity) {
    

    I'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)?

  2. +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,119 @@
    +    $this->plugin = $this->getMockBuilder('\Drupal\views\Plugin\views\field\EntityOperations')
    +      ->setConstructorArgs(array($configuration, $plugin_id, $plugin_definition, $this->entityList))
    +      ->setMethods(array('drupalGetDestination', 'getEntity', 't'))
    +      ->getMock();
    

    Yeah, I think we should extend the class instead, not test using a mock.

  3. +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,119 @@
    +    $this->assertInternalType('array', $this->plugin->buildOptionsForm($form, $form_state));
    ...
    +    $this->assertInternalType('array', $this->plugin->defineOptions());
    ...
    +    $this->assertInternalType('array', $build);
    ...
    +    $this->assertInternalType('array', $build);
    

    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 :)

Xano’s picture

FileSize
8.85 KB
11.01 KB

I'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)?

I 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.

Yeah, I think we should extend the class instead, not test using a mock.

We'll still have to mock, as getEntity() must return our mocked entity, and we need to set expectations on the methods.

This is not that useful. We're not really testing anything.

At the very least, this tests method execution and whether the return value is partly correct.

Maybe we should also override the query method here aswell, same as the Links handler.

Sure. Is this just a small performance gain, or something else?

Have you tested this yet? I guess not as there is no views data implementation :)

I haven't. There is just the unit test. I wanted to get the approach agreed on first, before adding an implementation to core.

$this->t()

Done.

No docs are better than these docs.

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.

damiankloip’s picture

We already had a chat on IRc, but ...

  1. +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,125 @@
    +      $operations = $this->entityManager->getListController($this->getEntityType())->getOperations($entity);
    

    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.

  2. +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,125 @@
    +          $operation['options']['query'] += $this->drupalGetDestination();
    

    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.

Xano’s picture

Status: Needs work » Needs review
FileSize
1.49 KB
11.1 KB
Xano’s picture

Note 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.

Status: Needs review » Needs work

The last submitted patch, 13: drupal_2165989_12.patch, failed testing.

Xano’s picture

damiankloip’s picture

+++ b/core/modules/node/node.views.inc
@@ -214,6 +214,14 @@ function node_views_data() {
+  $data['node']['operations'] = array(
+    'field' => array(
+      'title' => t('Operations links'),
+      'help' => t('Provide links to perform content operations.'),
+      'id' => 'entity_operations',
+    ),
+  );
+

Also, 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.

Xano’s picture

Status: Needs work » Needs review
FileSize
983 bytes
11.14 KB

Alright. 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?

The last submitted patch, 13: drupal_2165989_12.patch, failed testing.

dawehner’s picture

@Xano
This sounds like a great idea.

Status: Needs review » Needs work

The last submitted patch, 18: drupal_2165989_18.patch, failed testing.

Xano’s picture

The 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().

Xano’s picture

FileSize
1.13 KB
11.15 KB

Keeping on needs work per the previous comment.

I extended the tests a little bit based on @damiankloip's feedback over IRC.

@Xano
This sounds like a great idea.

Thanks to you and @damiankloip for proposing this to me.

Xano’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 23: drupal_2165989_23.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
11.32 KB

Re-roll, and #2165725: Introduce hook_entity_operation() has been fixed.

Status: Needs review » Needs work

The last submitted patch, 26: drupal_2165989_26.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
11.39 KB
2.53 KB
damiankloip’s picture

Status: Needs review » Needs work

Overall, 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.

  1. +++ b/core/modules/node/config/views.view.content.yml
    @@ -352,6 +304,57 @@ display:
    +          empty_zero: ¶
    

    oops

  2. +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,123 @@
    +      '#description' => $this->t('Include a <code>destination

    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?

  3. +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,123 @@
    +    $operations = $this->entityManager->getListBuilder($this->getEntityType())->getOperations($entity);
    

    Why do we need to get the list builder every time? I think we could just store it.

  4. +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,123 @@
    +  }
    

    Nitpick: empty line after query() closing brace.

  5. +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,123 @@
    +   * The entity manager used for testing.
    

    "The mock entity manager"? - We know this will be used in the test :)

  6. +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,123 @@
    +      'name' => '\Drupal\views\Plugin\views\field\EntityOperations',
    

    Not a good name. Should be "Field: Entity operations" I think.

  7. +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,123 @@
    +    $this->assertInternalType('array', $form);
    +    $this->assertArrayHasKey('destination', $form);
    ...
    +    $this->assertInternalType('array', $options);
    +    $this->assertArrayHasKey('destination', $options);
    ...
    +    $this->assertInternalType('array', $build);
    ...
    +    $this->assertInternalType('array', $build);
    

    These still don't really test much :(

  8. +++ b/core/modules/views/views.views.inc
    @@ -128,6 +128,16 @@ function views_views_data() {
    +          'title' => t('Operations links'),
    

    'Operation links' instead? 'Operations links' sounds weird. Maybe that's just me.

dawehner’s picture

  1. +++ b/core/modules/node/config/views.view.content.yml
    @@ -352,6 +304,57 @@ display:
    +        operations:
    +          id: operations
    +          table: node
    +          field: operations
    +          relationship: none
    +          group_type: group
    +          admin_label: ''
    +          label: Operations
    +          exclude: false
    

    I do hate it that you cannot longer choose the visual representation, which you could do before with the dropbutton.

  2. +++ b/core/modules/node/config/views.view.content.yml
    @@ -352,6 +304,57 @@ display:
    +          empty_zero: ¶
    

    TRAILING SLASH!

  3. +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,123 @@
    +  public function render(ResultRow $values) {
    +    $entity = $this->getEntity($values);
    +    $operations = $this->entityManager->getListBuilder($this->getEntityType())->getOperations($entity);
    +    if ($this->options['destination']) {
    +      foreach ($operations as &$operation) {
    +        if (!isset($operation['options']['query'])) {
    +          $operation['options']['query'] = array();
    +        }
    +        $operation['options']['query'] += $this->drupalGetDestination();
    +      }
    +    }
    +    $build = array(
    +      '#type' => 'operations',
    +      '#links' => $operations,
    +    );
    +
    +    return $build;
    +  }
    

    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.

The last submitted patch, 28: drupal_2165989_28.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
16.38 KB
Xano’s picture

If 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'.

Status: Needs review » Needs work

The last submitted patch, 32: views_entity_operations-2165989-31.patch, failed testing.

Xano’s picture

This is unblocked again as #2165725: Introduce hook_entity_operation() was just committed.

dawehner’s picture

Well sure, we can implement the API support first and then get the dropbutton in.

Xano’s picture

Status: Needs work » Needs review
FileSize
12.7 KB

Re-roll, and addressed some feedback.

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?

The code tags are to emphasize the parameter is a coding thing and that it must not be translated.

Nitpick: empty line after query() closing brace.

Done.

"The mock entity manager"? - We know this will be used in the test :)

Pffft :+ Done.

Not a good name. Should be "Field: Entity operations" I think.

@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.

These still don't really test much :(

Full coverage now.

TRAILING SLASH!

A missing false, actually. Fixed.

Status: Needs review » Needs work

The last submitted patch, 37: drupal_2165989_37.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
1.1 KB
13.16 KB

Status: Needs review » Needs work

The last submitted patch, 39: drupal_2165989_39.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review

39: drupal_2165989_39.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 39: drupal_2165989_39.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review

39: drupal_2165989_39.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 39: drupal_2165989_39.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
1.32 KB
13.29 KB

This should pass.

dawehner’s picture

Thank you for ignoring my previous suggestion.

Xano’s picture

Which one? The one you said was okay to postpone in #36?

dawehner’s picture

Well sure, we can implement the API support first

Yeah you are so right.

Xano’s picture

I 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.

dawehner’s picture

Well, 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.

Xano’s picture

Well, 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?

So 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.

dawehner’s picture

Not 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.

Xano’s picture

If 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 in system.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.

Xano’s picture

45: drupal_2165989_45.patch queued for re-testing.

Xano’s picture

45: drupal_2165989_45.patch queued for re-testing.

Xano’s picture

45: drupal_2165989_45.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 45: drupal_2165989_45.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
13.15 KB

Status: Needs review » Needs work

The last submitted patch, 58: drupal_2165989_58.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
17.14 KB
13.07 KB

Re-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.

Xano’s picture

60: drupal_2165989_60.patch queued for re-testing.

andypost’s picture

In context of related issue it makes sense to expose operations for all entities by unified plugin

Xano queued 60: drupal_2165989_60.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 60: drupal_2165989_60.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
12.5 KB

Re-roll.

andypost’s picture

+++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
@@ -0,0 +1,117 @@
+  public function render(ResultRow $values) {
+    $entity = $this->getEntity($values);
+    $operations = $this->entityManager->getListBuilder($entity->getEntityTypeId())->getOperations($entity);

let's check first that entity type has list builder

Xano’s picture

FileSize
1.47 KB
12.64 KB
andypost’s picture

+++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
@@ -0,0 +1,123 @@
+    // Skip rendering if the entity doesn't even have a list builder.
+    if (!$this->entityManager->hasController($entity->getEntityTypeId(), 'list_builder')) {
+      return array();

+++ b/core/modules/views/views.views.inc
@@ -136,6 +136,16 @@ function views_views_data() {
+    if ($entity_type->getBaseTable()) {
+      $data[$entity_type->getBaseTable()]['operations'] = array(

suppose it makes sense to add the same check additionally to base table

Status: Needs review » Needs work

The last submitted patch, 67: drupal_2165989_67.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
1.4 KB
12.53 KB

Xano queued 70: drupal_2165989_70.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 70: drupal_2165989_70.patch, failed testing.

Status: Needs work » Needs review

Xano queued 70: drupal_2165989_70.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 70: drupal_2165989_70.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
2.21 KB
12.57 KB

Status: Needs review » Needs work

The last submitted patch, 75: drupal_2165989_75.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
1017 bytes
12.63 KB
dawehner’s picture

As 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.

Xano’s picture

I 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

  1. Remove the render element and just display links in a generic way.
  2. Ship Drupal with both Views handlers.
  3. Something else...?

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.

andypost’s picture

I 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

Xano queued 77: drupal_2165989_77.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 77: drupal_2165989_77.patch, failed testing.

Xano’s picture

@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.

Status: Needs work » Needs review

Xano queued 77: drupal_2165989_77.patch for re-testing.

Xano’s picture

separate links, because I used a lot special UIs when only single 'edit' or 'change' is needed

Could you make an issue for that? I think we should be able to write a reusable base class for this.

Status: Needs review » Needs work

The last submitted patch, 77: drupal_2165989_77.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review
FileSize
842 bytes
12.62 KB
Xano’s picture

FileSize
1.45 KB
12.65 KB

And now exposing the operations in entity types' views handlers.

dawehner’s picture

To be honest I think we actually want to have some basic integration test here as well.

  1. +++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,118 @@
    +    $operations = $this->entityManager->getListBuilder($entity->getEntityTypeId())->getOperations($entity);
    

    It feels kinda wrong, but yeah this is for some reasons the "official" ""API"" at the moment.

  2. +++ b/core/modules/views/src/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,179 @@
    +/**
    + * @coversDefaultClass \Drupal\views\Plugin\views\field\EntityOperations
    + */
    +class EntityOperationsUnitTest extends UnitTestCase {
    +
    

    don't we need a group here?

damiankloip’s picture

  1. +++ b/core/modules/views/src/EntityViewsData.php
    @@ -147,6 +147,15 @@ public function getViewsData() {
    +    if ($this->entityManager->hasHandler($this->entityType->id(), 'list_builder')) {
    

    Couldn't we just call $this->entityType->hasHandlerClass(..) instead?

  2. +++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,118 @@
    +  public function query() {
    +  }
    

    Maybe we should add a comment in the empty body here that we don't want to ensure anything/create any aliases.

  3. +++ b/core/modules/views/src/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,179 @@
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public static function getInfo() {
    +    return array(
    +      'description' => '',
    +      'name' => '\Drupal\views\Plugin\views\field\EntityOperations',
    +      'group' => 'Views Plugins',
    +    );
    +  }
    

    I think we can just remove this now and add @group instead.

  4. +++ b/core/modules/views/src/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,179 @@
    +  public function testUsesGroupBy() {
    +    $this->assertFalse($this->plugin->usesGroupBy());
    +  }
    

    This is bordering on pointless, but I guess it's there now :)

dawehner’s picture

Status: Needs review » Needs work

Oh yeah, so much work is needed.

Xano’s picture

Status: Needs work » Needs review
FileSize
1.95 KB
12.46 KB

It feels kinda wrong, but yeah this is for some reasons the "official" ""API"" at the moment.

#1839516: Introduce entity operation providers was our chance to change this ;-)

Couldn't we just call $this->entityType->hasHandlerClass(..) instead?

I found something even better!

Status: Needs review » Needs work

The last submitted patch, 92: drupal_2165989_92.patch, failed testing.

Status: Needs work » Needs review

Xano queued 92: drupal_2165989_92.patch for re-testing.

damiankloip’s picture

  1. +++ b/core/modules/views/src/EntityViewsData.php
    @@ -147,7 +147,7 @@ public function getViewsData() {
    +    if ($this->entityType->hasListBuilderClass()) {
    

    That was just a general suggestion, so yes, using that looks great.

  2. +++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
    @@ -113,6 +113,7 @@ public function render(ResultRow $values) {
    +    // There is nothing to ensure or add for this handler.
    

    Sorry, can you add to this and say we purposely are not calling parent or something?

Otherwise, this is RTBC.

Xano’s picture

FileSize
644 bytes
12.54 KB
bojanz’s picture

Status: Needs review » Needs work

I'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?

Xano’s picture

Did you try clearing the cache? Maybe the aggregated JavaScript has not been rebuilt yet.

bojanz’s picture

Yes. Also tried disabling the aggregation completely. It's not that.

Xano’s picture

Status: Needs work » Needs review

It seems this is a bug in core, as it happens with the current default views as well.

dawehner’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

I 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.

Xano’s picture

Note to self: see \Drupal\views\Tests\Handler\FieldBooleanTest for an example of a Views field handler integration test.

pcambra’s picture

Status: Needs work » Needs review
FileSize
7.21 KB
19.44 KB

Re rolled the patch as the content view has changed.

The interdiff contains the test I've added for this.

dawehner’s picture

  1. +++ b/core/modules/views/src/EntityViewsData.php
    @@ -147,6 +147,15 @@ public function getViewsData() {
    +    if ($this->entityType->hasListBuilderClass()) {
    +      $data[$base_table]['operations'] = array(
    +        'field' => array(
    +          'title' => $this->t('Operations links'),
    +          'help' => $this->t('Provides links to perform entity operations.'),
    +          'id' => 'entity_operations',
    +        ),
    +      );
    +    }
    

    Are 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.

  2. +++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,120 @@
    +    return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity.manager'));
    

    Just in case you want to, please split it up into multiple lines, as it makes things easier to read / adapt in the future.

  3. +++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
    @@ -0,0 +1,120 @@
    +      'bool' => TRUE,
    

    no need for bool TRUE anymore.

Status: Needs review » Needs work

The last submitted patch, 104: drupal_2165989_104.patch, failed testing.

pcambra’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests +VDC
FileSize
2.83 KB
19.4 KB

Thanks for the review @dawehner
Fixed comments in #105 and the failing test.

dawehner’s picture

Some nitpicks :(

  1. +++ b/core/modules/views/src/Tests/Handler/FieldEntityOperationsTest.php
    @@ -0,0 +1,58 @@
    + * Definition of Drupal\views\Tests\Handler\EntityOperations.
    

    Contains ... and wrong classname :(

  2. +++ b/core/modules/views/src/Tests/Plugin/views/field/EntityOperationsUnitTest.php
    @@ -0,0 +1,169 @@
    +/**
    + * @file Contains \Drupal\views\Tests\Plugin\views\field\EntityOperationsUnitTest.
    

    new line after @file

pcambra’s picture

Assigned: Xano » Unassigned
FileSize
1.14 KB
19.42 KB

Sorry about those, fixed comments in #108

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you, especially for fixing this annoying things, which are kind of a Drupalism.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

This 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?

bojanz’s picture

@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.

dawehner’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: +DX (Developer Experience)

@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.

alexpott’s picture

#113 suggest that this is actually a regression fix then :)

alexpott’s picture

Category: Feature request » Bug report
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs issue summary update

As 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.

dawehner’s picture

Agreed the following views has to be updated:

  • user_admin_people
  • content (already covered)
pcambra’s picture

Status: Needs work » Needs review
FileSize
3.06 KB
22.48 KB

Modified admin/people to use operation links as for #116

pcambra’s picture

Issue summary: View changes
pcambra’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update

Added beta evaluation summary table

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Awesome!

bojanz’s picture

RTBC if green.

EDIT: dawehner beat me to it.

alexpott’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Needs work

This 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

Bug because the operation links displayed currently in views might show operations that user has not access to

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.

pcambra’s picture

Status: Needs work » Needs review
FileSize
2.79 KB
25.27 KB

Here's a test on content translation that shows the operations and that users with not enough permissions will not get them displayed.

The last submitted patch, 123: drupal_2165989-interdiff-117-123.patch, failed testing.

bojanz’s picture

Status: Needs review » Reviewed & tested by the community

And we're back. Thanks, Pedro.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 123: drupal_2165989-123.patch, failed testing.

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 123: drupal_2165989-123.patch, failed testing.

pcambra’s picture

Status: Needs work » Needs review
FileSize
1.83 KB
25.38 KB
bojanz’s picture

Status: Needs review » Reviewed & tested by the community

Just in time to miss beta5...

Arla’s picture

Status: Reviewed & tested by the community » Needs work
+    if ($this->entityType->hasListBuilderClass()) {

Are 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.

In 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!

Xano’s picture

Status: Needs work » Reviewed & tested by the community

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.

Correct. 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.

dawehner’s picture

+++ b/core/modules/views/src/Tests/Plugin/views/field/EntityOperationsUnitTest.php
@@ -0,0 +1,170 @@
+      ->will($this->returnValue($entity_type_id));
...
+      ->will($this->returnValue($operations));
...
+      ->will($this->returnValue($list_builder));
...
+      ->will($this->returnValue($entity_type_id));
...
+      ->will($this->returnValue($operations));
...
+      ->will($this->returnValue($list_builder));

Not a blocker at all, just given a hint for the future: There is a thing called ->willReturnexists as a shortcut.

dawehner’s picture

+1 for the RTBC though.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 3f29fd9 and pushed to 8.0.x. Thanks!

Thank you for adding the beta evaluation to the issue summary.

  • alexpott committed 3f29fd9 on 8.0.x
    Issue #2165989 by Xano, pcambra, damiankloip, dawehner: Add a Views...
Arla’s picture

Status: Fixed » Needs work
+++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
@@ -0,0 +1,124 @@
+        if (!isset($operation['options']['query'])) {
+          $operation['options']['query'] = array();
+        }
+        $operation['options']['query'] += drupal_get_destination();

I think this should be $operation['query']? Otherwise the destination option does not have any effect.

andypost’s picture

@Arla please file follow-up

Arla’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.