Skip to content

Instantly share code, notes, and snippets.

@mattschaff
Created December 12, 2019 22:48
Show Gist options
  • Save mattschaff/deff8de71fde7f757331ed38094da731 to your computer and use it in GitHub Desktop.
Save mattschaff/deff8de71fde7f757331ed38094da731 to your computer and use it in GitHub Desktop.
Drupal 8: Drush 9 command to migrate an entity reference from a paragraph field to a node field
services:
example.migrate_entity_reference:
class: Drupal\example\Commands\MigrateEntityReference
arguments:
- '@entity_type.manager'
- '@entity_type.bundle.info'
- '@entity_field.manager'
tags:
- { name: drush.command }
<?php
/*
* Place this file at src/Commands/MigrateEntityReference.php in your custom module directory.
*/
namespace Drupal\exmample\Commands;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drush\Commands\DrushCommands;
/**
* Migrates an entity reference from a paragraph field to a node field
*/
class MigrateEntityReference extends DrushCommands {
/**
* Entity type manager
*
* @var EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Entity type bundle info
*
* @var EntityTypeBundleInfoInterface
*/
protected $entityTypeBundeInfo;
/**
* Entity field manager
*
* @var EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* MigrateEntityReference constructor.
*
* @param EntityTypeManagerInterface $EntityTypeManager
* @param EntityTypeBundleInfoInterface $EntityTypeBundeInfo
* @param EntityFieldManagerInterface $EntityFieldManager
*/
public function __construct(EntityTypeManagerInterface $EntityTypeManager, EntityTypeBundleInfoInterface $EntityTypeBundeInfo, EntityFieldManagerInterface $EntityFieldManager) {
$this->entityTypeManager = $EntityTypeManager;
$this->entityTypeBundeInfo = $EntityTypeBundeInfo;
$this->entityFieldManager = $EntityFieldManager;
}
/**
* Performs the migration
*
* @param string $paragraph_name
* @param string $paragraph_field_name
* @param string $node_paragraph_field_name
* @param string $node_field_name
*
* @command example:migrate-entity-reference
* @aliases mfwc,migrate-fwcta
* @usage mfwc test_paragraph field_para_cta field_test_paragraph field_node_cta
*/
public function migrate($paragraph_name, $paragraph_field_name, $node_paragraph_field_name, $node_field_name) {
// Get bundle types with both $node_paragraph_field_name and $node_field_name.
$bundles = array_keys($this->entityTypeBundeInfo->getBundleInfo('node'));
$content_types_to_search = [];
foreach ($bundles as $bundle) {
$fields = $this->entityFieldManager->getFieldDefinitions('node', $bundle);
if (array_key_exists($node_paragraph_field_name, $fields) && array_key_exists($node_field_name, $fields)) {
$content_types_to_search[] = $bundle;
}
}
// Get all $paragraph_name IDs.
$paragraph_ids = $this->entityTypeManager
->getStorage('paragraph')
->getQuery()
->condition('type', $paragraph_name)
->execute();
// Get all relevant nodes that target $node_paragraph_field_name
$nids = $this->entityTypeManager
->getStorage('node')
->getQuery()
->condition('type', $content_types_to_search, 'IN')
->condition($node_paragraph_field_name, $paragraph_ids, 'IN')
->execute();
$this->output()->writeln(dt("Migrating the reference from @para_name paragraphs to
the @node_field_name field for (@num) nodes.", ['@num' => count($nids), '@para_name' => $paragraph_name, '@node_field_name' => $node_field_name]));
$count = 0;
foreach ($nids as $nid) {
$node = $this->entityTypeManager->getStorage('node')->load($nid);
$values = $node->get($node_paragraph_field_name)->getValue();
foreach ($values as $key => $value) {
if (in_array($value['target_id'], $paragraph_ids)) {
// Remove that paragraph from the values of that field.
unset($values[$key]);
$values = array_values($values);
$node->set($node_paragraph_field_name, $values);
// Switch the reference from the paragraph to the node.
$paragraph = $this->entityTypeManager->getStorage('paragraph')->load($value['target_id']);
if (isset($paragraph->get($paragraph_field_name)->target_id)) {
$node->set($node_field_name, ['target_id' => $paragraph->get($paragraph_field_name)->target_id]);
};
// Delete paragraph & save node.
$paragraph->delete();
unset($paragraph);
$node->save();
break;
}
}
unset($node);
// Get values.
$count++;
$this->showStatus($count, count($nids));
}
}
/**
* Show a status bar in the console
*
* Source: https://stackoverflow.com/questions/2124195/command-line-progress-bar-in-php
*
* @param int $done how many items are completed
* @param int $total how many items are to be done total
* @param int $size optional size of the status bar
* @return void
*
*/
protected function showStatus($done, $total, $size=30) {
static $start_time;
// if we go over our bound, just ignore it
if($done > $total) return;
if(empty($start_time)) $start_time=time();
$now = time();
$perc=(double)($done/$total);
$bar=floor($perc*$size);
$status_bar="\r[";
$status_bar.=str_repeat("=", $bar);
if($bar<$size){
$status_bar.=">";
$status_bar.=str_repeat(" ", $size-$bar);
} else {
$status_bar.="=";
}
$disp=number_format($perc*100, 0);
$status_bar.="] $disp% $done/$total";
$rate = ($now-$start_time)/$done;
$left = $total - $done;
$eta = round($rate * $left, 2);
$elapsed = $now - $start_time;
$status_bar.= " remaining: ".number_format($eta)." sec. elapsed: ".number_format($elapsed)." sec.";
echo "$status_bar ";
flush();
// when done, send a newline
if($done == $total) {
echo "\n";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment