Problem/Motivation

In #2957425: Allow the inline creation of non-reusable Custom Blocks in the layout builder we are having to get all the revision IDs for entity that we just know is revisionable.

We have generic code

   $entity_type = $this->entityTypeManager->getDefinition($entity->getEntityTypeId());
    if ($revision_table = $entity_type->getRevisionTable()) {
      $query = $this->database->select($revision_table);
      $query->condition($entity_type->getKey('id'), $entity->id());
      $query->fields($revision_table, [$entity_type->getKey('revision')]);
      $query->orderBy($entity_type->getKey('revision'), 'DESC');
      return $query->execute()->fetchCol();
    }
    return [];

Proposed resolution

See Comment #43: we decided to deprecate this function instead of moving it to the parent class. That comment updated the issue title but not the issue summary. (It did add the tag for an issue summary update.)

See Comment #46: the deprecation was done as part of #3396062: Deprecate most methods on NodeStorage.

That should work for any revisionable entity. Can we move NodeStorageInterface::revisionIds on up to RevisionableStorageInterface and then implement this generic logic in \Drupal\Core\Entity\Sql\SqlContentEntityStorage?

Remaining tasks

Is this ok with BC policy.
Write patch
Tests

User interface changes

None

API changes

RevisionableStorageInterface would have ::revisionIds()

Data model changes

NOne

Issue fork drupal-2986027

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

tedbow created an issue. See original summary.

tedbow’s picture

Status: Active » Needs review
Issue tags: +Needs tests
StatusFileSize
new3.94 KB

Here is initial patch. I noticed that NodeStorageInterface::revisionIds() hard codes the order so I added this as an option argument.

Status: Needs review » Needs work

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

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new502 bytes
new4.43 KB

Fixed ContentEntityNullStorage

Status: Needs review » Needs work

The last submitted patch, 4: 2986027-4.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new881 bytes
new5.29 KB

Fixed KeyValueContentEntityStorage

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

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

joachim’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/Entity/RevisionableStorageInterface.php
@@ -65,4 +65,17 @@ public function deleteRevision($revision_id);
+   * @return int[]
+   *   Entity revision IDs.

+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -1692,4 +1692,18 @@ protected function storageDefinitionIsDeleted(FieldStorageDefinitionInterface $s
+    return NULL;

@return docs don't match the possible NULL return.

Would an empty array here not be better DX, so you always have something iterable?

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new563 bytes
new5.31 KB

@joachim good catch. changed to return [].

gabesullice’s picture

Status: Needs review » Needs work
Issue tags: +API-First Initiative
Related issues: +#2992833: Add a version negotiation to revisionable resource types

This is will help JSON API achieve solid support for the content_moderation module.


+++ b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
@@ -60,4 +61,11 @@ public function getLatestTranslationAffectedRevisionId($entity_id, $langcode) {
+  public function revisionIds(EntityInterface $entity, $order = 'ASC') {
+    return NULL;
+  }

Shouldn't this also be []?

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new5.3 KB
new1.06 KB

#10 yep fixed and also in ContentEntityNullStorage

This is will help JSON API achieve solid support for the content_moderation module.

Bonus!

joachim’s picture

Status: Needs review » Needs work

One last thing, I hope:

  1. +++ b/core/modules/node/src/NodeStorageInterface.php
    @@ -11,17 +11,6 @@
    -   *   Node revision IDs (in ascending order).
    

    We've lost the bit about them being in ascending order.

    We need to keep that aspect to preserve BC.

  2. +++ b/core/lib/Drupal/Core/Entity/RevisionableStorageInterface.php
    @@ -65,4 +65,17 @@ public function deleteRevision($revision_id);
    +   *   Entity revision IDs.
    

    So this should read something like:

    > An array of the entity revision IDs, in ascending order.

longwave’s picture

> An array of the entity revision IDs, in ascending order.

This isn't strictly true as the $order argument defines this, but why do we even need the $order argument anyway? Is there really a use case for returning them in reverse order? The caller can just use array_reverse(), can't they?

joachim’s picture

Status: Needs work » Reviewed & tested by the community

> This isn't strictly true as the $order argument defines this

Oh DUH you're right. So the Node docs are actually incorrect, and the new docs are better.

> but why do we even need the $order argument anyway? Is there really a use case for returning them in reverse order? The caller can just use array_reverse(), can't they?

Also a good point, but we need to keep it for BC and deprecating it should be a separate issue.

Though isn't it quicker to order in SQL than PHP?

Based on that I'm going to say this is RTBC.

The last submitted patch, 6: 2986027-6.patch, failed testing. View results

longwave’s picture

Status: Reviewed & tested by the community » Needs work

The $order argument is new in this patch. NodeStorageInterface::revisionIds() always returns in ascending order (which is why the previous comment exists). It was added in #2 but with no real reason given, but to me this is technically a new feature and out of scope here, at least until we have a use for it.

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.

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.

capysara’s picture

I'm looking to get revision ids from entities other than nodes. Is there still interest in this patch? If so, it would have to be re-rolled and the comments in #16 need to be addressed.

To address #16, do we just need to remove the $order argument that was added? Or is it more complicated than that?

joachim’s picture

> just need to remove the $order argument that was added

Yup.

And copy the bit from the node docs about the @return being in ascending order.

ravi.shankar’s picture

StatusFileSize
new5.31 KB
new2.92 KB

Added reroll of patch #11 on Drupal 9.4.x.

capysara’s picture

StatusFileSize
new5.19 KB
new2.93 KB

Thanks! That was fast on the re-roll! I updated the re-roll in #25 to remove the $order argument and add back in the docs about ascending order.

I tested this manually. For my use case, I created a custom views field that uses revisionIds to get the previous content moderation state for nodes, blocks, and media entities.

  • Cloned a clean 9.4.x-dev site.
  • Added patch.
  • Enabled modules: workflows, content_moderation, media, media_library.
  • Configured default workflow to apply to All custom block types, All media types, and All content types /admin/config/workflow/workflows/manage/editorial.
  • Added custom blocks of type Basic block, media of type Image, and content of type Basic in various states of content moderation.
  • Created views--Custom Block revisions, Media revision, and Content revisions--added my custom views field.

All 3 entity types worked as expected: I was able to use revisionIds to get a list of revision IDs for the block_content, media, and nodes.

capysara’s picture

Status: Needs work » Needs review
joachim’s picture

Status: Needs review » Reviewed & tested by the community

LGTM.

catch’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Entity/ContentEntityNullStorage.php
@@ -147,4 +147,11 @@ public function hasData() {
 
+  /**
+   * {@inheritdoc}
+   */
+  public function revisionIds(EntityInterface $entity) {
+    return [];
+  }

Since this will be new code on the interface, could we add a return type hint?

Also looks like we still need some explicit test coverage here.

capysara’s picture

What do we need for "explicit test coverage"? Do we need another function like testPendingRevisions(), but for blocks (and/or other entity types?)? Or should testPending Revisions be more generic so it covers other revisionable entities?

catch’s picture

@capysara there should be some existing test coverage of SqlContentEntityStorage to add to, Drupal\KernelTests\Core\Entity\EntityRevisionsTest is probably a good place.

berdir’s picture

Why do we need this method, can't this be done with an entity query?

tedbow’s picture

referencing the original issue.

@Berdir good point. I am not sure. Here is how did this without the public
function

$storage = \Drupal::entityTypeManager()->getStorage('node');
    $node = $storage->load(1);
    // Assume you already have the load entity. so just below counts.
    /** @var \Drupal\Core\Entity\Query\Sql\Query $q */
    $q = \Drupal::entityQuery('node');
    $q->allRevisions();
    $q->accessCheck(FALSE);
    $q->condition($node->getEntityType()->getKey('id'), $node->id());
    $revisions_ids = array_keys($q->execute());

for what is it is worth I made this issue in the middle of #2957425: Allow the inline creation of non-reusable Custom Blocks in the layout builder but by the end we didn't actually end up needing it

but I would say if we are going to leave `\Drupal\node\NodeStorage::revisionIds` it makes it much more sense to move it to \Drupal\Core\Entity\Sql\SqlContentEntityStorage::revisionIds() because there shouldn't be anything special for nodes in this case. Other if we are not going to move it I think it would make sense to deprecate and remove \Drupal\node\NodeStorage::revisionIds()

berdir’s picture

Yes, exactly, like that. Although I remember some issues with that in entity reference revisions.

But the revision ui issue also doesn't seem to need this.

Deprecating without direct replacement is definitely an option. This method likely predates entity query revision support

berdir’s picture

Right, the issue I had was this: #2766135: EntityQuery with condition on the revision field leads to wrong results, this has been fixed. I'm sure there are other issues, one of the most important ones is entity query performance, but I think for this, using an entity query should be OK. I'd suggest we verify that by deprecating the method and replacing all calls to it with such an entity query.

tedbow’s picture

Counter argument to removing the current method....

It looks like people do call it https://git.drupalcode.org/search?group_id=2&page=2&repository_ref=&scop...

and in some of the results you also see other Entity storage classes that are writting their own versions that they would not need if actually moved it

https://git.drupalcode.org/project/open_badges/-/blob/8.x-1.x/modules/is...

https://git.drupalcode.org/project/carousel_block/-/blob/8.x-1.x/src/Car...
many other examples

berdir’s picture

The search doesn't seem to work too well (getting a lot of endpoint requested too many times errors).

But almost all of those seem to be 1:1 copies of NodeStorage, and many callers (http://grep.xnddx.ru/search?text=-%3ErevisionIds%28) are 1:1 copies of the revision page controller.

And all custom methods won't be affected by deprecating the node storage method.

berdir’s picture

I'd say if those results prove one thing, then that it would be good to get #2350939: Implement a generic revision UI into core, with a generic revision UI, most of that code wouldn't need to exist at all.

capysara’s picture

FWIW, I'm using this patch to replace some code like this, which (I believe) was borrowed from Media revisions UI.

function getNonNodeEntityRevisionIds($entity) {
  $entityTypeManager = \Drupal::entityTypeManager();
  $entityStorage = $entityTypeManager->getStorage($entity->getEntityTypeId());
  $id_column = ($entity->getEntityTypeId() == 'media') ? 'mid' : 'id';
  $revision_column = ($entity->getEntityTypeId() == 'media') ? 'vid' : 'revision_id';
  $result = $entityStorage->getQuery()
    ->allRevisions()
    ->condition($id_column, $entity->id())
    ->sort($revision_column, 'DESC')
    ->pager(50)
    ->execute();

  return array_keys($result);
}

I would be happy to see this patch move forward (and was planning to try to write some tests). I would also love to see #2350939: Implement a generic revision UI get into core! :)

Thoughts on the path forward for this one?

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.

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.

acbramley’s picture

Title: Move NodeStorageInterface::revisionIds on up to RevisionableStorageInterface » Deprecate NodeStorageInterface::revisionIds in favor of entity query
Issue tags: +Needs issue summary update

Came up in slack and the advice from @berdir was to deprecate instead. I agree as it's minimal code to get a list of revision IDs using an entity query.

benjifisher made their first commit to this issue’s fork.

benjifisher changed the visibility of the branch 2986027-deprecate-nodestorageinterface-revisionids to hidden.

benjifisher’s picture

Issue summary: View changes
Status: Needs work » Closed (outdated)
Related issues: +#3396062: Deprecate most methods on NodeStorage

This issue was fixed as part of #3396062: Deprecate most methods on NodeStorage. The change record is https://www.drupal.org/node/3519187.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.