Problem/Motivation
When adding variants to a page, we add fill the Page::$variants array. If the variants haven't already been initialised via Page::getVariants() then Page::getVariant(), Page::getVariants() and Page::removeVariant() will never get any other variants that exist on the page and therefore return incomplete lists of variants for Page::getVariants() or throw UnexpectedValueException for the other methods.
In addition to this, even if we have already initialised Page::$variants, the addition could leave them out of order which wont get corrected until a fresh copy of the page is retrieved and the variants are loaded fresh from the database.
When removing a variant, the variant is deleted, but never removed from Page::$variants which could also cause similar problems.
Proposed resolution
- Abstract sorting variants into a separate method
- Always initiate the variants before adding
- Always sort the variants after adding
- Unset the removed variant from
Page::$variants
| Comment | File | Size | Author |
|---|---|---|---|
| #11 | fix_add_remove-2692397-8.patch | 5 KB | andrewbelcher |
| #11 | fix_add_remove-2692397-8-test_only.patch | 3.58 KB | andrewbelcher |
Comments
Comment #2
andrewbelcher commentedFixing title...
Comment #3
andrewbelcher commentedThere is also a similar issue with removing (see #2692347: removeVariant() should remove variant from page and not just delete the variant. which I've merged into this). Updated issue summary accordingly.
Here are a couple patches, one test only which demonstrates the problem and one with a fix that abstracts the sorting into
Page::sortVariants()so it can be called fromPage::addVariant.Comment #4
andrewbelcher commentedComment #6
andrewbelcher commentedThere is also a question of whether we should switch over to using
PageVariant::sort()(which is actually\Drupal\Core\Config\Entity\ConfigEntityBase::sort) as our sorting callback, which means we can dropPage::variantSortHelper.This adds in label as a secondary sorting mechanism. It's possible this may not actually be desirable. If it isn't, I would still suggest the change I've made, but overriding
PageVariant::sort()to not check the label as that seems a better design pattern.I've uploaded patches that switch to using
PageVariant::sort()including testing the addition sort based on label.Comment #8
juampynr commentedI tested this patch in conjunction with #2550879: Use CTools Wizard API to add/edit Pages (and move plugin UI using PluginWizardInterface) and it works fine, plus all tests pass.
Comment #9
tim.plunkettPageVariant::sort and variantSortHelper have different logic. If you want to remove this helper, then please move this logic (getWeight() calls only) to override PageVariant::sort()
I finally understand this (still wrong) change. It's because \Drupal\Core\Config\Entity\ConfigEntityBase::sort() uses ->weight directly, we want to use getWeight().
Comment #10
tim.plunkettComment #11
andrewbelcher commentedOk, based on an IRC conversation, sounds like the consensus is to not deal with changing the way we actually do the sort here, but rather in a follow up which I'll post shortly.
In the light of that, here is the patch from #3 with a minor fix and I'll hide everything else.
Comment #13
andrewbelcher commentedHave opened #2693165: Move variant sort callback into PageVariant as a follow up for moving our sort helper.
Comment #14
andrewbelcher commentedComment #15
juampynr commentedGood job @andrewbelcher!
Comment #17
eclipsegc commentedI concur. Fixed