0

I need to iterate through the article nodes that have enabled the layout builder and replace the content block in the layout builder section with a new content block. I need to do this via migration script. But it's not working as expected.

yaml file

uuid: 599162cc-ba3b-4c4d-98c9-404958545305
langcode: en-gb
status: true
dependencies: {  }
_core:
  default_config_hash: lzIn3Lnhv-Efq1Lry7b0-99zKIaAiawY_AHBy_OJPxM
id: migrate_node
class: null
field_plugin_method: null
cck_plugin_method: null
migration_tags: null
migration_group: NAS
label: null
source:
  plugin: get_article_nodes
  key: default
process:
  nid: nid
  uid: uid
  uuid: uuid
  title: title
  status: status
  created: created
  changed: changed
  block_type_temp:
    plugin: migrate_node
    source_field: layout_builder_value
  layout_builder__layout:
    plugin: get
    source:
      - '@block_type_temp'
destination:
  plugin: 'entity:node'
  default_bundle: article
migration_dependencies: { }

Source plugin

<?php


namespace Drupal\my_custom_module\Plugin\migrate\source;

use Drupal\Core\Database\Query\SelectInterface;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
use Drupal\migrate\Row;

/**
 * Source plugin for article content.
 *
 * @MigrateSource(
 *   id = "get_article_nodes"
 * )
 */
final class GetArticleNodes extends SqlBase
{

  /**
   * {@inheritdoc}
   */
  public function query(): SelectInterface
  {
    $query = $this->select('node_field_data', 'n');
    $query->fields('n', [
      'nid',
      'vid',
      'type',
      'title',
      'uid',
      'langcode',
      'created',
      'changed',
      'status'
    ]);
    // $query->fields('nlbl', [
    //   'layout_builder__layout_section',
    // ]);
    // $query->leftJoin('node__layout_builder__layout', 'nlbl', 'nlbl.entity_id=n.nid');
    $query->condition('n.type', 'article', '=');
    return $query;
  }

  /**
   * {@inheritdoc}
   */
  public function fields(): array
  {
    $fields = [
      'nid' => $this->t('Node ID'),
      'vid' => $this->t('Vid'),
      'uid' => $this->t('Uid'),
      'title' => $this->t('Title'),
      'type' => $this->t('Type'),
      'created' => $this->t('Created timestamp'),
      'changed' => $this->t('Modified timestamp'),
      'status' => $this->t('Published'),
      'layout_builder__layout_section' => $this->t('Layout builder section'),
    ];

    return $fields;
  }

  /**
   * {@inheritdoc}
   */
  public function getIds(): array
  {
    return [
      'nid' => [
        'type' => 'integer',
        'alias' => 'n',
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row): bool
  {
    $nid = $row->getSourceProperty('nid');
    $row->setSourceProperty('nid', $nid);

    $result = $this->getDatabase()->query(
      "SELECT bundle , entity_id, layout_builder__layout_section  FROM  node__layout_builder__layout 
      WHERE  entity_id = $nid"
    );
    $layoutbuilder_data = [];
    foreach($result as $record ){
      $layoutbuilder_data[] = $record->layout_builder__layout_section;
    }
    $row->setSourceProperty('layout_builder_value', $layoutbuilder_data);
    return parent::prepareRow($row);
  }
}

Process plugin

<?php

namespace Drupal\my_custom_module\Plugin\migrate\process;

use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
use Drupal\node\Entity\Node;
use Drupal\layout_builder\Section;
use Drupal\layout_builder\SectionComponent;
use Drupal\migrate\MigrateException;
use Drupal\my_custom_module\LayoutBase;
use Drupal\my_custom_module\LayoutMigrationItem;
use Drupal\my_custom_module\LayoutMigrationMissingBlockException;


/**
 * Custom process plugin for updating layout builder section.
 *
 * @MigrateProcessPlugin(
 *   id = "migrate_node"
 * )
 */
class MigrateNode extends LayoutBase{

    /**
     * {@inheritdoc}
     */
    public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property)
    {
        $nid = $row->getSourceProperty('nid');
        if (!isset($this->configuration['source_field'])) {
            throw new MigrateException('Missing source_field for layout builder process plugin.');
        }
        if($nid == '1429'){ // testing for a single node
          $values = $row->getSourceProperty($this->configuration['source_field']);
          if(isset($values) && is_array($values)){
            foreach($values as $key => $value){
              $sectionComponents = unserialize($value);// am geting section components here
              if ($sectionComponents instanceof Section) {
                $components = $sectionComponents->getComponents();
                foreach ($components as $key => $component) {
                  print_r($component->get('configuration'));
                  // $sectionComponents->insertComponent(1, $component);
                  $configurations = $component->get('configuration');
                  $configurations['id'] = "block_content:3208e4a9-24a2-489c-a0c2-122bcc9c5395"; // this is not working :(
                  $component->setConfiguration($configurations);
                }
              }
            }
          }
        }
        return $value;
    }
}

Can somebody help me pls?

2 Answers 2

1

You return $value but you do not modify it, also please be aware that you use $value as a method argument and as a part of foreach.

You must return a value that is compatible with layout_builder__layout field

e.g. $section in an instance of \Drupal\layout_builder\Section that contains updated components configuration.

return [
  'section' => $section,
]

or multiple sections

return $sections;

where $sections is an array that contains multiple sections in the following format:

$sections[] = [
  'section' => $section,
];
0

Thanks @alex. I think i was not sending the correct value, as well as not returning the sections as you said. I resolved it as follows:

   /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    // Return early if $value is not an array.
    if (!is_array($value)) {
      return NULL;
    }
    foreach ($value as $serializedData) {
      // Unserialize the data.
      $sections = unserialize($serializedData);
      // Check if unserialized data is an instance of Section.
      if ($sections instanceof Section) {
        // Update section components if necessary.
        $this->updateSectionComponents($sections);
      }
      $final_data[] = $sections;
    }
    return $final_data;
  }
    /**
       * Updates section components.
       *
       * @param \Drupal\layout_builder\Section $section
       *   The section object.
       */
      protected function updateSectionComponents(Section $section): void {
        $components = $section->getComponents();
        foreach ($components as $component) {
          // Check if values are instance of SectionComponent.
          if ($component instanceof SectionComponent) {
            // Update the configuration of each component.
            $this->updateComponentConfiguration($component, $section);
          }
        }
      }
    
      /**
       * Updates the configuration of a section component.
       *
       * @param \Drupal\layout_builder\SectionComponent $component
       *   The section component object.
       * @param \Drupal\layout_builder\Section $section
       *   The parent section object.
       */
      protected function updateComponentConfiguration(SectionComponent $component, Section $section): void {
        // Get component configuration.
        $configuration = $component->get('configuration');
        // Query to get new block content (id and uuid) based on revision_id.
        $newBlockIdData = $this->getNewBlockId($configuration['block_revision_id']); // helper function to get old block details
        if (!empty($newBlockIdData)) {
          $attached_block_id = $newBlockIdData[0]->id;
          $old_block_type = $newBlockIdData[0]->type;
          // Old block region.
          $region = $component->get('region');
          // Get new block id.
          $oldBlockData = $this->getOldBlockData($attached_block_id); // helper function to get new block (migrated earlier) from old block id
          if (!empty($oldBlockData) && $configuration['id'] == "inline_block:$old_block_type") {
            // Get new block type.
            $new_block_type = $oldBlockData[0]->bundle;
            // Set the new block id configuration.
            $configuration['id'] = "inline_block:$new_block_type";
            // Create new component.
            $newComponent = (new SectionComponent($this->uuid->generate(), $region, $configuration));
            // Append the new component within the section.
            $section->appendComponent($newComponent);
          }
        }
      }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.