web-dev-qa-db-ja.com

段落のホストノードを見つける

私はサイト内のすべての絶対URL(wysiwygコンテンツ、URLフィールド、構成)を見つけて、後で手動管理によって相対URLに変換しようとしています。問題のすべてのURLが同じDrupalサイト内にあります。私はPHPMyAdminを使用して、絶対URL(ノード-/node/NID/edit、メニュー項目-/admin/structure/menu/item/MLID/editなど)。しかし、私は段落で苦労しています。

  • 段落フィールド行のIDは、段落の特定のインスタンス用です。
  • 段落をホストしているフィールドの知識がなければ、インスタンスはanywhereになる可能性があります。
  • 段落は別の段落にネストすることができます。

この問題を解決するにはどうすればよいですか?絶対リンクを含む段落のホストノードを見つけるにはどうすればよいですか?

2
Joseph

これには、SQLよりもAPIを使用する方が少し簡単かもしれません。私はすべてのノードをロードし、すべてのフィールドをループし、そのように値をチェックしたくなるでしょう。段落フィールドをヒットした場合は、再帰してそのフィールドも確認してください。

これは非常に大まかな例の関数ですが、次のようになります。

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;
}

そして、あなたはそれをこのように使うでしょう:

$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();
  }
}

おそらく、インストールに合わせてタイプを微調整する必要がありますが、基本的なレベルで機能するはずです。

2
Clive

つまり、PHPMyAdminでURLを検索し、段落フィールドに属するすべてのテーブル(それらには_paragraph___というプレフィックスが付いています)を選択して、それらのすべての_entity_id_ sを収集していました。次に、一時的なDrushコマンドを使用して、これらの段落をすべてロードし、目的のエンティティタイプ(この場合はノード)に到達するまで、再帰的に$paragraph->getParentEntity()をロードしました。次に、ノードIDを記録しました。

_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;
}
_

この操作の大部分は自動化されている可能性があります。 PHPMyAdminの代わりにクエリを介してエンティティIDを取得し、ブロックや用語などのさまざまなルートタイプを処理するように改善されている可能性があります。すべての段落を読み込まないことで、パフォーマンスが向上する可能性もあります。しかし、上記は現時点で必要なことを行っていたので、そのままにしておきました。

1
Joseph