web-dev-qa-db-fra.com

Recherche du nœud hôte d'un paragraphe

J'essaie de trouver toutes les URL absolues dans un site (dans le contenu wysiwyg, les champs d'URL, la configuration) pour les convertir en URL relatives plus tard via une administration manuelle. Toutes les URL en question se trouvent dans le même site Drupal. J'ai réussi à utiliser PHPMyAdmin pour trouver et enregistrer des entités facilement accessibles contenant des URL absolues (nœuds - /node/NID/edit, éléments de menu - /admin/structure/menu/item/MLID/edit, etc.). Cependant, j'ai du mal avec les paragraphes.

  • L'ID d'une ligne de champ de paragraphe correspond à une instance spécifique du paragraphe.
  • Sans connaissance du champ hébergeant le paragraphe, l'instance pourrait être n'importe où.
  • Le paragraphe pourrait être imbriqué dans un autre paragraphe.

Comment pourrait-on résoudre ce problème? Comment trouver le nœud hôte des paragraphes contenant un lien absolu?

2
Joseph

Il pourrait être un peu plus facile d'utiliser l'API plutôt que SQL pour cela. Je serais tenté de charger tous les nœuds, de parcourir tous leurs champs et de vérifier les valeurs de cette façon. Si vous frappez un champ de paragraphe, répétez et vérifiez également ses champs.

Il s'agit d'un exemple de fonction très approximatif, mais il devrait vous permettre de continuer:

function entityHasFieldWithAbsUrl(\Drupal\Core\Entity\ContentEntityInterface $entity, array $types) {
  foreach ($entity->getFields() as $key => $field) {
    $field_type = $field->getFieldDefinition()->getType();
    $field_settings = $field->getSettings();
    if ($field_type == 'entity_reference_revisions' && $field_settings['target_type'] == 'paragraph') {
      foreach ($field as $item) {
        if ($item->entity instanceof \Drupal\paragraphs\ParagraphInterface) {
          if (entityHasFieldWithAbsUrl($item->entity, $types)) {
            return TRUE;
          }
        }
      }
    }
    elseif (in_array($field_type, $types)) {
      foreach ($field as $item) {
        // Change this to something better...
        if (strpos($item->value, 'https://www.example.com/') !== FALSE) {
          return TRUE;
        }
      }
    }
  }

  return FALSE;
}

Et vous l'utiliseriez quelque chose comme ceci:

$nodes_with_abs_urls = [];
$nodes = \Drupal::entityTypeManager()->getStorage('node')->loadMultiple();
$types = ['text', 'text_long', 'text_with_summary', 'string'];
foreach ($nodes as $node) {
  if (entityHasFieldWithAbsUrl($node, $types)) {
    $nodes_with_abs_urls[] = $node->id();
  }
}

Vous devrez probablement modifier les types en fonction de votre installation, mais cela devrait fonctionner au niveau de base.

2
Clive

Donc, ce que j'ai fini par faire était de rechercher les URL dans PHPMyAdmin, de sélectionner toutes les tables qui appartiennent aux champs de paragraphe (elles étaient préfixées paragraph__) Et de rassembler toutes leurs entity_id. Ensuite, en utilisant une commande Drush temporaire, j'ai chargé tous ces paragraphes et pour chacun, _ récursivement chargé $paragraph->getParentEntity() jusqu'à ce qu'il atteigne le type d'entité souhaité (dans ce cas, nœuds). Ensuite, j'ai enregistré les identifiants des nœuds.

function mymodule_drush_command() {
  $items = [];
  $items['mycommand'] = [
    'description' => 'Find the nids of the pids',
    'arguments' => [],
    'drupal dependencies' => ['mymodule'],
    'aliases' => [],
  ];
  return $items;
}

function drush_mymodule_mycommand() {
  // Could be improved by retrieving ids via query.
  $pids = [/* paragraph entity_ids */];

  // For each, recursively search ancestors.
  $nids = array_unique(array_filter(array_map(function($pid) {
    return _mymodule_find_node(\Drupal\paragraphs\Entity\Paragraph::load($pid));
  }, $pids)));

  // Print results
  drush_print_r(array_map(function($nid) {
    return '/node/' . $nid . '/edit';
  }, $nids));
}

function _mymodule_find_node($entity){
  // Could be improved by handling more than just nodes
  if ($entity instanceof \Drupal\node\NodeInterface) return $entity->id();
  // If still a paragraph, climb
  if ($entity instanceof \Drupal\paragraphs\ParagraphInterface) return _mymodule_find_node($entity->getParentEntity());
  // Otherwise, this is an entity we didn't want.
  return null;
}

La masse de cette opération aurait pu être automatisée. Il aurait pu être amélioré pour récupérer les identifiants d'entité via une requête au lieu de PHPMyAdmin et gérer différents types de racines comme les blocs, les termes, etc. Il pourrait également être plus performant en ne chargeant pas chaque paragraphe. Mais ce qui précède a fait ce dont j'avais besoin pour le moment, alors je l'ai laissé tel quel.

1
Joseph