Skip to content

Instantly share code, notes, and snippets.

@acbramley
Created June 9, 2023 01:11
Show Gist options
  • Save acbramley/f5f48326cf43ab7338b6e31a51006f4a to your computer and use it in GitHub Desktop.
Save acbramley/f5f48326cf43ab7338b6e31a51006f4a to your computer and use it in GitHub Desktop.
Update child aliases Entity Hierarchy
<?php
declare(strict_types = 1);
namespace Drupal\some_module\Hooks;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\entity_hierarchy\Storage\EntityTreeNodeMapperInterface;
use Drupal\entity_hierarchy\Storage\NestedSetNodeKeyFactory;
use Drupal\entity_hierarchy\Storage\NestedSetStorageFactory;
use Drupal\hux\Attribute\Hook;
use Drupal\node\NodeInterface;
use Drupal\pathauto\PathautoGeneratorInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a class for reacting to entity events.
*/
final class SomeModuleHooks implements ContainerInjectionInterface {
/**
* Constructs a new SomeModuleHooks.
*/
public function __construct(
protected NestedSetStorageFactory $nestedSetStorageFactory,
protected NestedSetNodeKeyFactory $nodeKeyFactory,
protected EntityTreeNodeMapperInterface $entityTreeNodeMapper,
protected PathautoGeneratorInterface $pathautoGenerator,
) {
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): static {
return new static(
$container->get('entity_hierarchy.nested_set_storage_factory'),
$container->get('entity_hierarchy.nested_set_node_factory'),
$container->get('entity_hierarchy.entity_tree_node_mapper'),
$container->get('pathauto.generator'),
);
}
/**
* Implements hook_node_update().
*
* Uses the Hux module - swap to a normal hook using a class resolver if not
* using Hux.
*/
#[Hook('node_update')]
public function nodeInsertUpdate(NodeInterface $entity): void {
// Only update child aliases on default revisions.
if ($entity->isDefaultRevision()) {
$this->updateChildAliases($entity);
}
}
/**
* Update child aliases.
*
* PROTIP - use $node->original and compare things that would actually make
* the child's alias change (i.e compare $node->original->getTitle() to
* $node->getTitle() and only update the alias if they are different.
*/
protected function updateChildAliases(NodeInterface $node): void {
$field = 'PARENT_FIELD_MACHINE_NAME';
$storage = $this->nestedSetStorageFactory->get($field, $node->getEntityTypeId());
$children = $storage->findChildren($this->nodeKeyFactory->fromEntity($node));
$childEntities = $this->entityTreeNodeMapper->loadAndAccessCheckEntitysForTreeNodes($node->getEntityTypeId(), $children);
foreach ($children as $node) {
if (!$childEntities->contains($node)) {
// Doesn't exist or is access hidden.
continue;
}
/** @var \Drupal\Core\Entity\ContentEntityInterface $childEntity */
$childEntity = $childEntities->offsetGet($node);
$this->pathautoGenerator->updateEntityAlias($childEntity, 'update');
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment