Problem/Motivation

When running import on my local machine, I get one order of import. When run on github pipeline, the content import runs in a different order. This causes my expectations of the same nid being assigned to not be what I expect.

Steps to reproduce

Proposed resolution

Add a sort to make the order of scanned files always the same order, regardless of the underlying system.

Remaining tasks

User interface changes

API changes

Data model changes

CommentFileSizeAuthor
#2 3175870.patch384 bytesheddn

Comments

heddn created an issue. See original summary.

heddn’s picture

Status: Active » Needs review
StatusFileSize
new384 bytes
heddn’s picture

Title: Reproducible order of import » Predictable order of content import
Phil Wolstenholme’s picture

This looks really useful, thanks for posting it @heddn.

I'm trying to make it so my default content node that represents the homepage is always node 1 as we set the value of page.front in system.site.yml to be '/node/1'.

What does asort sort by? I tried renaming my homepage YML file to have a UUID that started with 00000000 to bring it to the top of the list but that didn't seem to work.

----

Edit: Hmm, when I run print_r(ContentFileStorage::scan('modules/custom/rocket_example_content/content/node')); my node YML file 00000000-12f0-4087-a490-644a3dfd6894.yml is at the top of the list, but it's not being created as NID 1, so maybe I've misunderstood what this patch will do. I'll try to do a bit more digging into how the module works out what order to create things in.

Edit edit: Ah, they're sorted by dependencies and then created. Looks like I'll give up on my nice idea of NID 1 always being the homepage and use a hook to set my frontpage config value by loading the homepage node by its UUID then getting its ID.

Here's what I ended up going with:

use Drupal\Core\Entity\EntityInterface;

/**
 * Implements hook_ENTITY_TYPE_insert() for node entities.
 */
function rocket_example_content_node_insert(EntityInterface $entity) {
  $homepage_uuid = '2adabba1-12f0-4087-a490-644a3dfd6894';
  $page_not_found_uuid = '755a057d-edea-42e9-8276-4b45a2488e12';

  switch ($entity->uuid()) {
    case $homepage_uuid:
      \Drupal::configFactory()
        ->getEditable('system.site')
        ->set('page.front', '/node/' . $entity->id())
        ->save();

      \Drupal::logger('rocket_example_content')->notice('Homepage path has been set to the example content node #%nid', [
        '%nid' => $entity->id(),
      ]);
      break;

    case $page_not_found_uuid:
      \Drupal::configFactory()
        ->getEditable('system.site')
        ->set('page.404', '/node/' . $entity->id())
        ->save();

      \Drupal::logger('rocket_example_content')->notice('Page not found path has been set to the example content node #%nid', [
        '%nid' => $entity->id(),
      ]);
      break;
  }
}
berdir’s picture

you should avoid relying on ids, we by design build a dependency tree and that can change completely as if you add more content.

I guess the file sort might make it more predictable but it can still vary, also between different PHP versions for example as PHP likes to change its sort algorithms.

And yes, for places that need the ID like frontpage setting, you want to set it in an install hook or alternatively on the import event that we trigger. check if UUID x is being installed and then set that as as frontpage. I think that's a very common scenario, so I'm also open to supporting something like that specifically (also for 403/404 pages).

shelane’s picture

In version 1.x, the entity ID was exported with the data. So for taxonomy terms, there was a tid with a value and then that value would be the tid when the content was imported. For taxonomy terms in a multisite, this is a must. They must all be the same so that when we do content sharing, the defined terms will all use the same IDs. I'm not sure why this is not an option in version 2.x.

Phil Wolstenholme’s picture

@shelane exporting entity IDs in version 1 caused issues including things like #2969631: NID / VID / TID conflicts in branches, so the option was removed from version 2.

I wonder if https://www.drupal.org/project/entity_share might be more useful for your use case? Default content is primarily designed for providing default/example content for a single site, whereas Entity share is designed for content sharing between sites, I believe.

shelane’s picture

We set up default taxonomy terms and menu items as each new multisite is installed so that they’re all consistent. It’s a one and done deal. We are currently adding about 2 sites per month.

jonketo’s picture

I have noticed that in some instances of imports when pages link to and reference each other they do not get set. Is this expected because the import can save pages in different orders?

karlshea’s picture

you should avoid relying on ids

In many cases this is impossible. I'm trying to use this module to add default block content and menu items that are required for config import before a D7 migration. When the migration runs it will only map block content by ID, since that was the only identifier in D7.

Hilariously with this patch applied the content is all created in the wrong order due to the array_reverse in Importer::sortTree.

omarlopesino’s picture

This patch solves the problem for me, the content is always created in the same order. However, I agree with the sorting method's limitations as commented in #5. Until there is an agreement on a solid solution the patch proposed at #2 is completely recommended.

delacosta456’s picture

hi
i was also having Nid constantly changing on import and would like to know if this issue and https://www.drupal.org/project/default_content/issues/3277477 are related

daniel.bosen’s picture

Another positive effect of this patch is, that lists that are ordered by creation or change date are predictable. This is not as easily fixable as forntpage and 40x settings.