Created
December 12, 2019 22:48
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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