Problem/Motivation

Content entities may support weights and may want to use a list builder with drag-and-drop capabilities. Unfortunately DraggableListBuilder is only available for config entities.

While it probably doesn't make sense to add a draggable list builder for content entities in core without actually having an example implementation, a lot of the logic is not really specific to config entities so it would be unfortunate to duplicate it.

Proposed resolution

Extract the common logic into a trait. The only config-entity specific bits are extracted into public function getWeight($entity) and public function setWeight($entity, $weight) which DraggableListBuilder implements for config entities. This will ease adding a draggable content entity list builder in contrib. In fact I hope to add it Entity API.

Issue fork drupal-2989889

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

tstoeckler created an issue. See original summary.

tstoeckler’s picture

Status: Active » Needs review
StatusFileSize
new10.23 KB

Here we go. Clicked around a bit on a couple draggable list builders and didn't seem to break anything.

Status: Needs review » Needs work

The last submitted patch, 2: 2989889-2.patch, failed testing. View results

tstoeckler’s picture

Status: Needs work » Needs review
StatusFileSize
new2.69 KB
new10.06 KB

Hehe, vocabularies were not among those I tested. So thought the $this->hasWeight was a nice cleanup because we don't actually need the weight key in the generic code, but I didn't realize that I accidentally introduced a BC-break. This one should be better.

tstoeckler’s picture

Now added a patch for Entity API over at #2990784-2: Add a draggable list builder for content entities so you can see how this would help.

joachim’s picture

How is that going to work when subclasses need to

+++ b/core/lib/Drupal/Core/Entity/DraggableListBuilderTrait.php
@@ -0,0 +1,183 @@
+   * Name of the entity's weight field or FALSE if no field is provided.

Does it make sense to allow FALSE here?

tstoeckler’s picture

I'm not actually sure why the current supports setting this to FALSE that has always seemed pretty pointless to me. However, in order to not break BC, I think we need to keep supporting this.

bojanz’s picture

Thank you tstoeckler, this is a great idea.

I first reviewed #4, and had the thought of "but wait, $this->weightKey isn't actually used".
I do prefer the approach of #2, but realize that it's too risky. Even Commerce uses the unset($this->weightKey) trick which caused the VocabularyListBuilder breakage.

My only remaining question is here:

+  protected function formBuilder() {
+    if (!$this->formBuilder) {
+      $this->formBuilder = \Drupal::formBuilder();
+    }
+    return $this->formBuilder;
+  }

Is it odd for a trait to reach into \Drupal?
If this was a Commerce trait I'd just expect the parent class to set $this->formBuilder in the constructor, with no fallback or method, but core is usually more tolerant.

andypost’s picture

+++ b/core/lib/Drupal/Core/Config/Entity/DraggableListBuilder.php
@@ -61,123 +35,17 @@ public function __construct(EntityTypeInterface $entity_type, EntityStorageInter
+  protected function setWeight(EntityInterface $entity, $weight) {
+    /* @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */
+    $entity->set($this->weightKey, $weight);
   }

Maybe return $this in setter?

dww’s picture

+1 to this issue overall.

+1 to #7. The cost of possible BC breakage outweighs the tech debt of keeping this API.

+1 to #8. I agree that if you use this trait, you should properly set $this->formBuilder in your constructor via good DI, not this. However, the existing code "does it wrong", so I'm not sure if fixing this is scope creep here. I'd probably just try to fix it now, but maybe a follow-up is better.

+1 to #9.

Thanks,
-Derek

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

idebr’s picture

StatusFileSize
new1.17 KB
new8.78 KB

#8 I went with the smallest change possible to make it easier to get this issue committed.

#9 The setter now does return $this

idebr’s picture

StatusFileSize
new1.05 KB
new10.04 KB

Fixed code style

joachim’s picture

Status: Needs review » Reviewed & tested by the community

LGTM, though follow-ups need to be filed for the various suggestions for follow-ups in the comments.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 17: 2989889-17.patch, failed testing. View results

spokje’s picture

Status: Needs work » Reviewed & tested by the community

Back to RTBC per #18 after #3255836: Test fails due to Composer 2.2 solved the unrelated test failure.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 17: 2989889-17.patch, failed testing. View results

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

andrew answer’s picture

Status: Needs work » Reviewed & tested by the community

+1 to release.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/lib/Drupal/Core/Entity/DraggableListBuilderTrait.php
    @@ -0,0 +1,185 @@
    +  abstract protected function getWeight(EntityInterface $entity);
    

    Can use a return tyephint.

  2. +++ b/core/lib/Drupal/Core/Entity/DraggableListBuilderTrait.php
    @@ -0,0 +1,185 @@
    +  abstract protected function setWeight(EntityInterface $entity, $weight);
    

    We can and should use scalar typehints - plus we can use return typehints too ...not sure what it would be.

  3. +++ b/core/lib/Drupal/Core/Entity/DraggableListBuilderTrait.php
    @@ -0,0 +1,185 @@
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public function buildHeader() {
    ...
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public function buildRow(EntityInterface $entity) {
    ...
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public function render() {
    

    These inheritdocs are from \Drupal\Core\Entity\EntityListBuilder and it's interface

  4. +++ b/core/lib/Drupal/Core/Entity/DraggableListBuilderTrait.php
    @@ -0,0 +1,185 @@
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public function buildForm(array $form, FormStateInterface $form_state) {
    ...
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public function validateForm(array &$form, FormStateInterface $form_state) {
    ...
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public function submitForm(array &$form, FormStateInterface $form_state) {
    

    These are from \Drupal\Core\Form\FormInterface

    ... not sure what to do but @inheritdoc here is incorrect. We're not inheriting any docs.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

tstoeckler’s picture

Status: Needs work » Needs review

Converted the patch into a MR now, with #17 as the initial commit so my changes are easily reviewable. Went ahead and implemented #8 now with a tiny change in EntityListBuilder (to set $this->formBuilder) (but not changes required in any sub-classes). And also fixed #26. Verified that everything still works and also verified that adding more property or return type hints causes breakage because that would require sub-classes to also specify those.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Seems points #26 have been addressed in MR 5154. Since this was previously RTBC before that going to restore

catch’s picture

Status: Reviewed & tested by the community » Fixed

Started leaving comments about adding more type hints on the MR, then I realised I should have read #29 properly, of course it will affect subclasses.

Committed a993304 and pushed to 11.x (which will also become 10.3.x). Thanks!

  • catch committed 8c084d06 on 11.x
    Issue #2989889 by tstoeckler, idebr, joachim, bojanz, dww, alexpott:...
joachim’s picture

I was going to file a follow-up for the injection of formBuilder, but #3123209: Replace non-test usages of \Drupal::formBuilder() with IoC injection should cover it.

andypost’s picture

Status: Fixed » Needs work
Issue tags: +Needs change record

It missing change notice

andypost’s picture

jurgenhaas’s picture

The commit from #33 expects a return value int|float for the getWeight method in DraggableListBuilder. I just came across a config entity, that has a weight property, but that may be NULL. In that case, this throws an exception.

Should the getWeight method maybe fall back to 0, if the weight property has no value?

tstoeckler’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record

Re #35: fair enough, makes sense. Added a draft change notice: https://www.drupal.org/node/3425054. Feel free to publish if you think it's alright. (And then ideally set the issue back to fixed)

Re #37: Wow, never thought of that possibility, but yeah, totally makes sense to not blow up in that case, doesn't really cost much to add that fallback: Opened #3425058: [regression] Add a fallback in DraggableListBuilder::getWeight() to support entities with a NULL weight Sorry for the trouble and thanks for reporting it.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Marking RTBC for the CR. Would like a committer to also see before publishing it.

alexpott’s picture

Version: 11.x-dev » 10.3.x-dev
Status: Reviewed & tested by the community » Fixed

CR looks great. Publishing.

joachim’s picture

> The commit from #33 expects a return value int|float for the getWeight method in DraggableListBuilder. I just came across a config entity, that has a weight property, but that may be NULL. In that case, this throws an exception.

Similar issue -- I've just tried to use DraggableListBuilder on a config entity, and got a crash because the weight is a string not an int.

joachim’s picture

tstoeckler’s picture

Re #41: Interesting, that didn't come up here because that would be fixed as soon as you add config schema to your entity type. But I guess it wouldn't hurt to add a (float) type-cast to getWeight(). I can open a follow-up for that, if people think that makes sense.

joachim’s picture

Ah yeah, the bug is that environment_indicator has declared this incorrectly:

    weight:
      type: string
      label: 'Name'

> But I guess it wouldn't hurt to add a (float) type-cast to getWeight(). I can open a follow-up for that, if people think that makes sense.

On second thoughts, we shouldn't babysit that, but we should instead add something to the trait docs to say the weight field must be an int.

Status: Fixed » Closed (fixed)

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