【问题标题】:Drupal 8 orphan paragraphsDrupal 8 孤儿段落
【发布时间】:2018-10-05 13:40:24
【问题描述】:

我注意到段落实体没有从数据库中删除。他们宁愿取消与父节点的链接。

如果您创建一个视图,列出段落并附加上下文过滤器(按Parent ID 过滤),这一点会很明显。

目前,我找到了一种解决方法,即创建一个列出内容的视图。将关系附加到段落。这样可以确保只显示链接的段落。

数据库中仍然存在数百个孤立段落和字段数据的问题。有没有办法清理它们?

编辑: 这显然是一个重大错误,可以在段落模块的问题跟踪器中找到:Removed paragraph entities are not deleted from database

【问题讨论】:

标签: drupal drupal-8 paragraph


【解决方案1】:

现在我发现这是一个错误并且尚未修复,我的主要目标是清理孤立段落。

有人创建了这个模块:Paragraph clean,但我不喜欢将模块用于此类目的。

所以,下面我将发布我第一次成功尝试解决它。我必须警告这不安全,因为它会删除段落!

该解决方案未针对使用修订、内容翻译等进行测试。因此,这可能会毁了您的一天。 备份您的网站

使用Devel 模块,转到Development > Execute PHP Code。粘贴并执行以下代码:

// get all paragraphs
$deleted = [];
$paragraph_ids = \Drupal::entityQuery('paragraph')->execute();
$paragraphs = \Drupal::entityTypeManager()->getStorage('paragraph')->loadMultiple($paragraph_ids);
foreach ($paragraphs as $target_id => $paragraph) {
  // get parent entity (node, taxonomy, paragraph, etc.)
  $parent = $paragraph->getParentEntity();
  $field_name = $paragraph->parent_field_name->value;

  // Check if current paragraph exists in parent entity field values
  $exists = FALSE;
  $values = is_null($parent) ? [] : $parent->get($field_name)->getValue();
  foreach($values as $value) {
    if ($value['target_id'] == $target_id) {
      $exists = TRUE;
    }
  }

  // Delete paragraphs that aren't linked to an entity they claim as a parent
  if (!$exists) {
    $paragraph->delete();
    $deleted[] = $target_id;
  }
}

print "Deleted paragraph IDs: " . implode(', ', $deleted);

【讨论】:

  • 我发现 Paragraphs Clean 模块只删除新删除的段落,因此如果您有现有的孤立段落,您也需要使用此解决方案。此外,“执行 PHP”功能现已从 Devel 模块中删除,但您可以通过安装 Devel PHP (devel_php) 将其恢复。
【解决方案2】:

我们创建了一个名为paragraphs_clean 的模块,它实现了hook_entity_update()(注意:模块名称必须与entity_update() 挂钩函数的前缀相同)获得灵感从这里:https://www.drupal.org/project/paragraphs/issues/2741937#comment-13181377

如前所述,即使有修订和翻译,它似乎也能很好地工作。此外,我们还必须调整原始 php 代码以在段落也有段落(即嵌套段落)的情况下运行。

这段代码比上面的更高效,因为它只会从上下文中加载实体的孤立段落。

代码如下:

<?php


/**
* @file
* Paragraphs clean module.
*/

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\field\Entity\FieldConfig;

/**
* Implements hook_entity_update().
* 
* When form updates, delete any paragraph entities that were removed.
* 
* @param \Drupal\Core\Entity\EntityInterface $entity
*/
function paragraphs_clean_entity_update(EntityInterface $entity) {

  // Only act on content entities.
  if (!($entity instanceof FieldableEntityInterface)) {
    return;
  }

  $fieldManager = \Drupal::service('entity_field.manager');
  $parentEntities = $fieldManager->getFieldMapByFieldType('entity_reference_revisions');

  if (!array_key_exists($entity->getEntityTypeId(), $parentEntities)) {
    return;
  }

  $paragraph_definitions = [];

  // loop through all paragraph types
  foreach ($parentEntities[$entity->getEntityTypeId()] as $field_id => $settings) {
    if ($configField = FieldConfig::loadByName($entity->getEntityTypeId(), $entity->bundle(), $field_id)) {
      $paragraph_definitions[] = $configField;
    }
  }

  if (empty($paragraph_definitions)) {
    return;
  }

  foreach ($paragraph_definitions as $paragraph_definition) {

    //get entity type name to make it work with any kind of parent entity (node, paragraph, etc.)
    $entityTypeName = $entity->getEntityTypeId();

    // Remove orphaned paragraphs.
    $query = \Drupal::database()->select('paragraphs_item_field_data', 'pfd')
      ->fields('pfd', ['id'])
      ->condition('pfd.parent_type', $entityTypeName) 
      ->condition('pfd.parent_id', $entity->id())
      ->condition('pfd.parent_field_name', $paragraph_definition->getName());

    $query->addJoin('left', $entityTypeName.'__'.$paragraph_definition->getName(),'nt','pfd.id=nt.'.$paragraph_definition->getName().'_target_id');
    $query->isNull('nt.'.$paragraph_definition->getName().'_target_id');
    $query->distinct();

    $paragraph_ids = $query->execute()->fetchCol();

    if ($paragraph_ids) {
      $para_storage = \Drupal::entityTypeManager()->getStorage('paragraph');
      foreach ($paragraph_ids as $paragraph_id) {

        if ($para = $para_storage->load($paragraph_id)) {
          $para->delete();
          drupal_set_message(t('Paragraph of type "%type" has been deleted: %id', ['%id' => $paragraph_id, '%type' => $paragraph_definition->getName()]));
        }

      }
    }   

  }

}

【讨论】:

    猜你喜欢
    • 2011-05-21
    • 1970-01-01
    • 2021-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 2022-06-21
    • 1970-01-01
    相关资源
    最近更新 更多