Problem/Motivation

On a site that is using paragraphs fields on taxonomy terms the taxonomy_post_update_make_taxonomy_term_revisionable is taking hours. If the paragraphs fields are removed the update is quick.

I think this is a bug because the currently in HEAD updates can take hours. This is happened because all the paragraphs entities are loaded during every save. The problem seems to be coming from the line

$needs_save = $this->entity instanceof EntityNeedsSaveInterface && $this->entity->needsSave();

In \Drupal\entity_reference_revisions\Plugin\Field\FieldType\EntityReferenceRevisionsItem::preSave() this causes the paragraph entity to be loaded. So your taxonomy terms have lots of paragraphs then this results in many many additional entity loads.

Proposed resolution

Stop calling preSave methods from \Drupal\Core\Entity\Sql\SqlContentEntityStorage::restore(). Generally these are not necessary. If they are then you can override the restore implementation in the entity's storage class. For example in TermStorage we do:

  /**
   * {@inheritdoc}
   */
  public function restore(EntityInterface $entity) {
    $entity->preSave($this);
    parent::restore($entity);
  }

Remaining tasks

User interface changes

None

API changes

None. There is a behaviour change to an @internal method. \Drupal\Core\Entity\Sql\SqlContentEntityStorage::restore() no longer does

$entity->preSave($this);
$this->invokeFieldMethod('preSave', $entity);

Data model changes

None

Release notes snippet

@tbd - I don't think this needs one because we're changing the behaviour of a method marked @internal and there is a change record.

CommentFileSizeAuthor
#62 3066439-follow-up.patch1.05 KBalexpott
#58 3066439-2-58.patch13.11 KBalexpott
#58 56-58-interdiff.txt756 bytesalexpott
#56 3066439-2-55.patch13.11 KBalexpott
#55 53-55-interdiff.txt2.58 KBalexpott
#53 3066439-2-53.patch13.06 KBalexpott
#53 50-53-interdiff.txt1.87 KBalexpott
#50 3066439-2-50.patch12.94 KBalexpott
#50 49-50-interdiff.txt1.17 KBalexpott
#49 3066439-2-49.patch12.85 KBalexpott
#49 48-49-interdiff.txt3.31 KBalexpott
#49 3066439-49.test-only.patch4.84 KBalexpott
#2 3066439-2.patch2.11 KBalexpott
#5 2-5-interdiff.txt4.14 KBalexpott
#5 3066439-5.patch4.1 KBalexpott
#10 5-10-interdiff.txt3.93 KBalexpott
#10 3066439-10.patch8.03 KBalexpott
#11 3066439-test.patch729 bytesalexpott
#12 3066439-test-nopresave-atall.patch1.37 KBalexpott
#14 3066439-2-14.patch5.82 KBalexpott
#16 14-16-interdiff.txt1.46 KBalexpott
#16 3066439-2-16.patch6.66 KBalexpott
#18 16-18-interdiff.txt5.17 KBalexpott
#18 3066439-2-18.patch5.2 KBalexpott
#19 18-19-interdiff.txt789 bytesalexpott
#19 3066439-2-19.patch5.2 KBalexpott
#23 19-23-interdiff.txt1.54 KBalexpott
#23 3066439-2-23.patch5.24 KBalexpott
#29 23-29-interdiff.txt660 bytesalexpott
#29 3066439-2-29.patch5.41 KBalexpott
#37 29-37-interdiff.txt1.64 KBalexpott
#37 3066439-2-37.patch5.62 KBalexpott
#38 37-38-interdiff.txt2.31 KBalexpott
#38 3066439-2-38.patch6.02 KBalexpott
#39 38-39-interdiff.txt1.73 KBalexpott
#39 3066439-2-39.patch7.07 KBalexpott
#48 39-48-interdiff.txt5.61 KBalexpott
#48 3066439-2-48.test-only.patch2.44 KBalexpott
#48 3066439-2-48.patch10.45 KBalexpott
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

alexpott created an issue. See original summary.

alexpott’s picture

Status: Active » Needs review
Issue tags: +Needs tests, +Needs change record
FileSize
2.11 KB
alexpott’s picture

alexpott’s picture

Status: Needs review » Needs work

Silly me. That is not going to work. I changed approaches to minimise API change last moment and forgot to test locally. We can't just add that to the interface without breaking the world.

alexpott’s picture

Status: Needs work » Needs review
FileSize
4.14 KB
4.1 KB

So this shouldn't break the world.

daniel.bosen’s picture

Status: Needs review » Reviewed & tested by the community

I tested this patch in conjunction with #3066440: Taxonomy update to revisionable is taking hours with paragraphs fields on our installation with about 6000 terms and 15000 paragraphs and the update took a minute instead of 5 hours, as it did before.
This is quite nice indeed!

Ghost of Drupal Past’s picture

Might not be part of this patch but EntityStorageInterface::restore probably needs better documentation and probably tests too because I can't find adequate documentation or test either but it might be just me. What is a "restore"? How is it different from save, when should it be called instead of save? I filed #3066674: Missing typehints in SqlFieldableEntityTypeListenerTrait to begin travelling the road to understanding.

catch’s picture

Status: Reviewed & tested by the community » Needs work
Related issues: +#3056540: taxonomy_post_update_make_taxonomy_term_revisionable() timeouts with large numbers of terms

This might be the same root cause as #3056540: taxonomy_post_update_make_taxonomy_term_revisionable() timeouts with large numbers of terms.

Still needs tests and a change record but otherwise looks good.

alexpott’s picture

Issue summary: View changes
alexpott’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
3.93 KB
8.03 KB

Here's a test for the restore method and the calling of the field methods including the new preRestore.

alexpott’s picture

Been discussing with @amateescu about why are we invoking preSave on the fields. Maybe it is not necessary.

alexpott’s picture

@amateescu asked me to file this as well. This will fail...

Not sure about #11.

Status: Needs review » Needs work

The last submitted patch, 12: 3066439-test-nopresave-atall.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
FileSize
5.82 KB

Discussed with @amateescu. We agreed that removing all calls to pre-save is the right thing to do as only removing the call to field presave but leaving the entity presave in felt inconsistent and unexpected. This means that it is on the entity type to ensure it is restorable before any restore is done. So for taxonomy terms we can call preSave() in the its storage class's implementation of restore. This is similar to https://git.drupalcode.org/project/entityqueue/blob/e099b13506f664afe46e...

Now we've move the preSave to taxonomy term storage it feels like some special for taxonomy terms to set up the parent term ID in the following situation]

    // Terms with no parents are mandatory children of <root>.
    if (!$this->get('parent')->count()) {
      $this->parent->target_id = 0;
    }

and its okay that field preSave is not being called.

alexpott’s picture

Issue summary: View changes

I've updated the change record.

alexpott’s picture

Some docs updates.

amateescu’s picture

  1. +++ b/core/modules/system/tests/modules/entity_test/src/EntityUpdateTestStorage.php
    @@ -0,0 +1,23 @@
    +class EntityUpdateTestStorage extends SqlContentEntityStorage {
    

    This storage class should be named EntityTestUpdateStorage :)

  2. +++ b/core/modules/system/tests/modules/entity_test/src/EntityUpdateTestStorage.php
    @@ -0,0 +1,23 @@
    +    $entity->preSave($this);
    +    parent::restore($entity);
    

    Let's throw the exception here directly instead of calling the entity's preSave() method. The goal of that exception is to test for something going wrong while calling $storage->restore(), so it doesn't matter if it's thrown by the entity class or the storage handler.

  3. +++ b/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php
    @@ -415,11 +415,13 @@ protected function deleteEntityType() {
    +   * @param string $storage_class
    +   *   (optional) Use a custom storage class.
    

    I'm not sure about this, why don't we set the custom storage class directly in the entity type definition?

alexpott’s picture

@amateescu good points! Fixed them all.

alexpott’s picture

Commas are nice.

amateescu’s picture

Status: Needs review » Reviewed & tested by the community

Nice! I think this is ready to go, hoping that the testbot agrees as well.

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

Status: Reviewed & tested by the community » Needs work

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

alexpott’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record
FileSize
1.54 KB
5.24 KB

Whoops. Too many entity_test modules.

amateescu’s picture

Title: Taxonomy update to revisionable is taking hours with paragraphs fields » Stop invoking pre-save methods in EntityStorageInterface::restore()
Status: Needs review » Reviewed & tested by the community

Yay, all green :)

casey’s picture

Great, we just had an issue while upgrading a site to D8.7 caused by these calls to preSave (without calling presave hooks).

Not sure if I should open a separate issue, so I just give some background here:

* The site implements a hook_ENTITY_TYPE_presave that overrides the behavior of MenuLinkContent::preSave() always setting $entity->setRequiresRediscovery(FALSE) for non-"internal:" links.
* The post update menu_link_content_post_update_make_menu_link_content_revisionable() calls this new ::restore() method which in turn calls $entity->preSave() for any menu link content.
* Our hook_ENTITY_TYPE_presave is never called, and thus our rediscover override is not called.
* Now that the rediscover flag was not set for the menu links we want to be rediscovered (so we can programatically attach children links to it) the menu_tree was totally broken.

Calling $entity->preSave (without invoking hooks) in ::restore() is not only slow, it can destroy your data!

amateescu’s picture

Priority: Normal » Critical
Issue tags: +8.7.0 update

@casey, thanks for sharing that use case, it's super useful! And I think it makes this issue critical.

amateescu’s picture

@casey, just to clarify my understanding of the problem described in #25, I think the current patch fixes it because we stop calling MenuLinkContent::preSave() during restore() so the discoverability and the menu tree are not impacted anymore by the conversion to revisionable, right?

catch’s picture

Status: Reviewed & tested by the community » Needs work

It's possible that this will result in a custom/contrib entity type running into the same issue as taxonomy module, but I think the risk of that is outweighed by the criticality of the bug and the number of cases we know are affected. So +1 on the general approach.

One point though:

+++ b/core/modules/taxonomy/src/TermStorage.php
@@ -441,6 +441,14 @@ public function getVocabularyHierarchyType($vid) {
 
+  /**
+   * {@inheritdoc}
+   */
+  public function restore(aa
EntityInterface $entity) {
+    $entity->preSave($this);
+    parent::restore($entity);
+  }
+
   /**

This is only saving three lines of code, why not copy it? It runs the potentially of running additional code that could be added to Term::preSave() as it currently is. Or at least add a clear comment explaining why it needs to be called here.

alexpott’s picture

Status: Needs work » Needs review
FileSize
660 bytes
5.41 KB

@catch yeah I ummed and ahhed on that when I posted #23 but now given #25 I think I now prefer copying the code. It makes it explicit and sets a good example for contrib & custom and means that the docs are adhered too - i.e. no presave is called during a restore.

amateescu’s picture

Status: Needs review » Reviewed & tested by the community

I also considered pointing out that we could copy that code, so I'm glad both of you think it's better this way :)

casey’s picture

@amateescu #27, correct

Ghost of Drupal Past’s picture

If I understand correctly the goals of restore then TermStorage::restore is wrong -- my understanding is you have the entity coming from somewhere else but it's a entity previously saved in D8 (perhaps in another Drupal instance, of course) and as such the target_id was zeroed on a previous (presumed) save(). If this mental model is correct then restore should be declared final so you can't break the assumption.

Berdir’s picture

I was wondering about that too. Term parents used to be very special as it was only a half-field, but that has been changed a while ago and I think that is there (and not only a default value for the field) to make it impossible to break the tree by having no value at all.

However, it should never have no value in a restore situation. So I think this method isn't needed. I'm not quite sure yet if there *are* use cases for overriding that method and if it should be final or not.

amateescu’s picture

If this mental model is correct then restore should be declared final so you can't break the assumption.

I'm not quite sure yet if there *are* use cases for overriding that method and if it should be final or not.

Here's at least one use case for being able to "massage" the data before the restore process: https://git.drupalcode.org/project/entityqueue/blob/e099b13506f664afe46e...

If we want to be able to remove the restore() override from the latest patch, we need to look into and fix the failures from the patch in #12.

alexpott’s picture

So here's a clue about what';s going on. It appears making the term parent field revisionable has a problem.

Backup data - will be the same for both runs

mysql> select * from test45832490old_c21e01taxonomy_term__parent;
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| bundle          | deleted | entity_id | revision_id | langcode | delta | parent_target_id |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| forums          |       0 |         1 |           1 | en       |     0 |                0 |
| test_vocabulary |       0 |         2 |           2 | es       |     0 |                0 |
| test_vocabulary |       0 |         3 |           3 | en       |     0 |                2 |
| forums          |       0 |         4 |           4 | en       |     0 |                0 |
| tags            |       0 |         5 |           5 | en       |     0 |                0 |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
5 rows in set (0.00 sec)

Broken - without the taxonomy storage restore override

mysql> select * from test45832490taxonomy_term_revision__parent;
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| bundle          | deleted | entity_id | revision_id | langcode | delta | parent_target_id |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| forums          |       0 |         1 |           1 | en       |     0 |                0 |
| test_vocabulary |       0 |         3 |           3 | en       |     0 |                2 |
| forums          |       0 |         4 |           4 | en       |     0 |                0 |
| tags            |       0 |         5 |           5 | en       |     0 |                0 |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
4 rows in set (0.00 sec)

Works - with the taxonomy storage restore override

mysql> select * from test60345999taxonomy_term_revision__parent;
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| bundle          | deleted | entity_id | revision_id | langcode | delta | parent_target_id |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| forums          |       0 |         1 |           1 | en       |     0 |                0 |
| test_vocabulary |       0 |         2 |           2 | en       |     0 |                0 |
| test_vocabulary |       0 |         3 |           3 | en       |     0 |                2 |
| forums          |       0 |         4 |           4 | en       |     0 |                0 |
| tags            |       0 |         5 |           5 | en       |     0 |                0 |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
5 rows in set (0.00 sec)
alexpott’s picture

Oh and it's not just the revision table...

mysql> select * from test60345999taxonomy_term__parent;
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| bundle          | deleted | entity_id | revision_id | langcode | delta | parent_target_id |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| forums          |       0 |         1 |           1 | en       |     0 |                0 |
| test_vocabulary |       0 |         2 |           2 | en       |     0 |                0 |
| test_vocabulary |       0 |         3 |           3 | en       |     0 |                2 |
| forums          |       0 |         4 |           4 | en       |     0 |                0 |
| tags            |       0 |         5 |           5 | en       |     0 |                0 |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
5 rows in set (0.01 sec)

mysql> select * from test45832490taxonomy_term__parent;
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| bundle          | deleted | entity_id | revision_id | langcode | delta | parent_target_id |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
| forums          |       0 |         1 |           1 | en       |     0 |                0 |
| test_vocabulary |       0 |         3 |           3 | en       |     0 |                2 |
| forums          |       0 |         4 |           4 | en       |     0 |                0 |
| tags            |       0 |         5 |           5 | en       |     0 |                0 |
+-----------------+---------+-----------+-------------+----------+-------+------------------+
4 rows in set (0.00 sec)

It looks like we have a multilingual issue

alexpott’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
1.64 KB
5.62 KB

So #2543726: Make $term->parent behave like any other entity reference field, to fix REST and Migrate support and de-customize its Views integration did an incorrect update. It used the wrong langcode for the langcode of the parent reference. These fields are not translatable and therefore, I think, though it'd be good for an entity translation expert to confirm, should use the site's default langcode. Here's a fix that proves it - can't be the final fix though :(

alexpott’s picture

So something like...

alexpott’s picture

And now with some commentary and protections against custom and contrib code.

amateescu’s picture

Excellent find and fix!

  1. +++ b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
    @@ -168,6 +168,11 @@ public function save(EntityInterface $entity);
    +   *   This method should never be used to perform a regular entity save. It's
    

    It's -> Its :)

  2. +++ b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
    @@ -168,6 +168,11 @@ public function save(EntityInterface $entity);
    +   *   overriding this method to fix data prior to restoring is a sign that the
    

    "is a sign" -> "could be a sign"?

  3. +++ b/core/modules/taxonomy/taxonomy.install
    @@ -70,7 +69,7 @@ function taxonomy_update_8502(&$sandbox) {
    -      'langcode' => $default_langcode,
    +      'langcode' => $row->langcode,
    

    We should add some test coverage for this in \Drupal\Tests\taxonomy\Functional\Update\TaxonomyParentUpdateTest::testTaxonomyUpdateParents().

catch’s picture

+++ b/core/modules/taxonomy/taxonomy.install
@@ -195,3 +195,32 @@ function taxonomy_update_8701() {
+function taxonomy_update_8702() {

This is a content change, could it go in a post update instead?

Also very nice find this is a lot better.

alexpott’s picture

Re #41 - nope unfortunately it can't - it has to come before the revisionable post update. And the post updates are by definition not in any guaranteed order.

Berdir’s picture

+++ b/core/modules/taxonomy/taxonomy.install
@@ -195,3 +195,32 @@ function taxonomy_update_8701() {
+  if (!$field_storage_definition->isTranslatable()) {
+    $default_langcode = \Drupal::languageManager()
+      ->getDefaultLanguage()
+      ->getId();
+    // taxonomy_update_8502() populated the langcode field of
+    // 'taxonomy_term__parent' using the term's langcode but the field is not
+    // translatable. If taxonomy_post_update_make_taxonomy_term_revisionable()
+    // has already run prior to
+    // https://www.drupal.org/project/drupal/issues/3066439 then this will have
+    // already fixed the field. However on sites that have not run that update
+    // yet we need to run this update the langcode as calling
+    // \Drupal\Core\Entity\Sql\SqlContentEntityStorage::restore() no longer
+    // calls \Drupal\taxonomy\Entity\Term::preSave().
+    \Drupal::database()->update('taxonomy_term__parent')
+      ->fields(['langcode' => $default_langcode])
+      ->execute();
+  }

what about terms whose default langcode isn't the site default langcode?

I think it should be the default langcode of the entitty, not the site.

alexpott’s picture

@Berdir is of course correct... @Berdir was who I had in mind when I wrote

though it'd be good for an entity translation expert to confirm

:)

It needs to be what we do in \Drupal\Core\Entity\Sql\SqlContentEntityStorage::saveToDedicatedTables() ie...

$default_langcode = $entity->getUntranslated()->language()->getId();
//... 
$langcodes = $field_definition->isTranslatable() ? $translation_langcodes : [$default_langcode];
Ghost of Drupal Past’s picture

> Note that overriding this method to fix data prior to restoring is a sign that the current data is corrupt.

My primary language is not English (it's PHP :P ) but wouldn't "Do not override this method unless fixing corrupt data prior to restoring is necessary" be better? And if this is what it is, is it the role of restore to fix corrupted data, isn't that the role of the caller? I still would love to see restore as final. The test could override doSave instead ; by making restore final we could remove this note altogether and send a strong message about how it should be used. Sorry I am a bit stubborn here, I am mostly just scared of what we are getting into again, we had special saves for the update path before and it ended up in tears and very slightly corrupted data which eventually caused the weirdest migration faults...

amateescu’s picture

Re #41 - nope unfortunately it can't - it has to come before the revisionable post update. And the post updates are by definition not in any guaranteed order.

The documentation of hook_post_update_NAME() says that ordering is possible:

 * NAME can be arbitrary machine names. In contrast to hook_update_N() the
 * alphanumeric naming of functions in the file is the only thing which ensures
 * the execution order of those functions. If update order is mandatory,
 * you should add numerical prefix to NAME or make it completely numerical.
alexpott’s picture

Re #46 - I still don't think that this is a post update function. It's fixing a data corruption.

alexpott’s picture

Here's a patch that addresses @Berdir's point in #43. The update get considerably more complex :(

Also here's a test against 8.6.x that shows we have a data corruption issue. Note it will not fail against 8.7.x as the new revisionable update is fixing things (atm in HEAD).

alexpott’s picture

Given we've got complex batching going on in the update let's test it.

alexpott’s picture

@chx's suggestion of not overriding restore for the exception test is a good one. It allows us to revisit the final discussion in the future and makes us adhere to the docs better. Ie. there are no examples of overriding in core.

The last submitted patch, 49: 3066439-49.test-only.patch, failed testing. View results

amateescu’s picture

+++ b/core/modules/system/tests/fixtures/update/drupal-8.taxonomy-parent-multilingual-3066439.php
@@ -0,0 +1,51 @@
+for ($i = 0; $i < 60; $i++) {

+++ b/core/modules/taxonomy/taxonomy.install
@@ -195,3 +195,53 @@ function taxonomy_update_8701() {
+      if ($sandbox['current'] >= Settings::get('entity_update_batch_size', 50)) {

+++ b/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermParentMultilingualTest.php
@@ -0,0 +1,82 @@
+    // There are 5 terms in the db already and we create an extra 60 so the last
+    // term is 65. Ensure that taxonomy_update_8702() has fixed its parent data.

Note that we are setting entity_update_batch_size to 1 since #3007606: Force all update path tests to only run one entity per batch, so we're executing 65 batch process for this update test :)

alexpott’s picture

@amateescu we're not executing 65 batch process - that's not how it works. It means we looping in _batch_process() more and checking resources more often.

Anyhow let's bump the number to 30 and I also noticed a bug in my update function :).

amateescu’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/taxonomy/taxonomy.install
    @@ -195,3 +195,55 @@ function taxonomy_update_8701() {
    +  if (!$field_storage_definition->isTranslatable() && !$entity_type->isRevisionable()) {
    ...
    +    $select = $database->select('taxonomy_term__parent', 'tp');
    

    Since we're doing straight db queries, we need to ensure that the entity type is using core's default SQL content entity storage.

  2. +++ b/core/modules/taxonomy/taxonomy.install
    @@ -195,3 +195,55 @@ function taxonomy_update_8701() {
    +    // revisionable. However on sites that have not run that update yet we need
    +    // to run update taxonomy_term__parent.langcode as calling
    +    // \Drupal\Core\Entity\Sql\SqlContentEntityStorage::restore() no longer
    +    // calls \Drupal\taxonomy\Entity\Term::preSave().
    

    I don't think we should document how code used to work :)

  3. +++ b/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermParentMultilingualTest.php
    @@ -0,0 +1,88 @@
    +  public function testMultilingualTermParentUpdate() {
    

    How about adding this test method to the existing TaxonomyParentUpdateTest test class?

alexpott’s picture

Status: Needs work » Needs review
FileSize
2.58 KB

Thanks for the review @amateescu.
Re #54
1. Fixed
2. Rewrote the docs
3. We can't do this. We're using different database dumps.

alexpott’s picture

Here's the patch

amateescu’s picture

Status: Needs review » Reviewed & tested by the community

Nice! I think this patch is good to go now :)

alexpott’s picture

@chx pondered the difference between is_a() and is_subclass_of() - as far as I can see there's only really the third param difference is this case. Core prefers is_subclass_of() - so swapping the patch to use that.

  • catch committed 01013ed on 8.8.x
    Issue #3066439 by alexpott, amateescu, Charlie ChX Negyesi, catch, casey...

  • catch committed a863de1 on 8.7.x
    Issue #3066439 by alexpott, amateescu, Charlie ChX Negyesi, catch, casey...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Looks great now. Committed/pushed to 8.8.x and cherry-picked to 8.7.x, thanks!

alexpott’s picture

Status: Fixed » Reviewed & tested by the community
FileSize
1.05 KB

Very very small follow-up to fix PHP 5.5 on 8.7.x

Berdir’s picture

Looks good but is the first part really only for php 5.5/8.7?

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

@Berdir we can apply this to both branches... one less line of code for 8.8.x doesn't really matter.

Committed 19071a4 and pushed to 8.8.x and to 8.7.x.

  • alexpott committed dd26473 on 8.7.x
    Issue #3066439 follow-up by alexpott: Stop invoking pre-save methods in...

  • alexpott committed 19071a4 on 8.8.x
    Issue #3066439 follow-up by alexpott: Stop invoking pre-save methods in...

Status: Fixed » Closed (fixed)

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

heddn’s picture

Does the CR related here need to be updated or published? It is still in draft status.