SimpleSource.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. namespace Drupal\reinstall\Plugin\migrate\source;
  3. use Drupal\Core\Entity\EntityFieldManagerInterface;
  4. use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
  5. use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
  6. use Drupal\migrate\MigrateException;
  7. use Drupal\migrate\Plugin\migrate\source\SourcePluginBase;
  8. use Drupal\migrate\Plugin\MigrationInterface;
  9. use Drupal\migrate\Row;
  10. use Symfony\Component\DependencyInjection\ContainerInterface;
  11. use Symfony\Component\Yaml\Exception\ParseException;
  12. use Symfony\Component\Yaml\Yaml;
  13. /**
  14. * Class SimpleSource provides the basic mechanisms to load a YML entity dump.
  15. */
  16. abstract class SimpleSource extends SourcePluginBase implements ContainerFactoryPluginInterface {
  17. /**
  18. * The source records.
  19. *
  20. * @var array
  21. */
  22. protected $records;
  23. /**
  24. * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
  25. */
  26. protected $entityTypeBundleInfo;
  27. /**
  28. * @var \Drupal\Core\Entity\EntityFieldManagerInterface
  29. */
  30. protected $entityFieldManager;
  31. /**
  32. * Constructor.
  33. */
  34. public function __construct(
  35. array $configuration,
  36. string $pluginId,
  37. array $pluginDefinition,
  38. MigrationInterface $migration,
  39. EntityTypeBundleInfoInterface $ebi,
  40. EntityFieldManagerInterface $efm
  41. ) {
  42. parent::__construct($configuration, $pluginId, $pluginDefinition, $migration);
  43. $this->entityTypeBundleInfo = $ebi;
  44. $this->entityFieldManager = $efm;
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. public static function create(
  50. ContainerInterface $container,
  51. array $configuration,
  52. $pluginId,
  53. $pluginDefinition,
  54. MigrationInterface $migration = NULL
  55. ) {
  56. $importPath = $container->getParameter('reinstall.path');
  57. $configuration['importPath'] = $importPath;
  58. $ebi = $container->get('entity_type.bundle.info');
  59. $efm = $container->get('entity_field.manager');
  60. return new static($configuration, $pluginId, $pluginDefinition, $migration, $ebi, $efm);
  61. }
  62. /**
  63. * {@inheritdoc}
  64. */
  65. public function doCount() {
  66. return count($this->records);
  67. }
  68. /**
  69. * {@inheritdoc}
  70. */
  71. public function fields() {
  72. $bundles = $this->entityTypeBundleInfo->getBundleInfo(static::ENTITY_TYPE);
  73. $rows = [];
  74. foreach ($bundles as $bundleName => $bundle) {
  75. $fieldDefinitions = $this->entityFieldManager->getFieldDefinitions(static::ENTITY_TYPE,
  76. $bundleName);
  77. foreach ($fieldDefinitions as $fieldName => $fieldDefinition) {
  78. $rows[$fieldName][$bundleName] = $fieldDefinition->getLabel();
  79. }
  80. }
  81. $fields = [];
  82. $singleBundle = count($bundles) === 1;
  83. foreach ($rows as $fieldName => $labels) {
  84. if ($singleBundle) {
  85. $fields[$fieldName] = reset($labels);
  86. continue;
  87. }
  88. if (count(array_unique($labels)) === 1) {
  89. $fields[$fieldName] = reset($labels);
  90. continue;
  91. }
  92. $ret = [];
  93. ksort($labels);
  94. foreach ($labels as $ct => $label) {
  95. $ret[] = $this->t('@ct: @label', ['@ct' => $ct, '@label' => $label]);
  96. }
  97. $fields[$fieldName] = implode(', ', $ret);
  98. }
  99. ksort($fields);
  100. return $fields;
  101. }
  102. /**
  103. * Flatten the field hierarchy. Not correct for all cases.
  104. *
  105. * @param array $record
  106. * The raw source values.
  107. *
  108. * @return array
  109. * The flattened values.
  110. *
  111. * @see \Drupal\reinstall\Plugin\migrate\process\TermParent
  112. */
  113. protected function flattenRecord(array $record) {
  114. $row = new Row($record);
  115. $this->flattenRow($row);
  116. return $row->getSource();
  117. }
  118. /**
  119. * Flatten a typical Drupal 8 field array to a 1-level array.
  120. */
  121. protected function flattenRow(Row $row) {
  122. $source = $row->getSource();
  123. foreach ($source as $key => &$item_list) {
  124. if (is_scalar($item_list)) {
  125. continue;
  126. }
  127. if (count($item_list) > 1) {
  128. $item = $item_list;
  129. }
  130. else {
  131. $item = reset($item_list);
  132. }
  133. if (isset($item['target_id'])) {
  134. $value = $item['target_id'];
  135. }
  136. elseif (is_scalar($item) || (count($item) != 1 && !isset($item['width']) && !isset($item['pid']))) {
  137. $value = $item;
  138. }
  139. elseif (isset($item['value'])) {
  140. $value = $item['value'];
  141. }
  142. // Handle bundle['target_id']
  143. // Exclude image field to keep metadata (alt / title)
  144. elseif (isset($item['target_id']) && !isset($item['alt']) && !isset($item['title'])) {
  145. $value = $item['target_id'];
  146. }
  147. elseif (isset($item['pid'])) {
  148. $value = $item['alias'];
  149. }
  150. else {
  151. $value = $item;
  152. }
  153. if (empty($item)) {
  154. $value = NULL;
  155. }
  156. $row->setSourceProperty($key, $value);
  157. }
  158. }
  159. /**
  160. * {@inheritdoc}
  161. */
  162. protected function initializeIterator() {
  163. return new \ArrayIterator($this->records);
  164. }
  165. /**
  166. * Load then parse the file requested in configuration and return its records.
  167. *
  168. * @param array $configuration
  169. * The source configuration from the migration source section.
  170. * @param string $key
  171. * Optional. A top-level key for the source document. If empty, items will
  172. * be parsed from the root of the source document.
  173. *
  174. * @return array
  175. * An array of entity descriptions.
  176. *
  177. * @throws \Drupal\migrate\MigrateException
  178. */
  179. protected function initialParse(array $configuration, string $key = NULL) {
  180. $baseFilePath = $configuration['file'] ?? NULL;
  181. $importPath = $configuration['importPath'] ?? NULL;
  182. $filePath = realpath("$importPath/$baseFilePath");
  183. if (!is_file($filePath) || !is_readable($filePath)) {
  184. throw new MigrateException("${filePath} is not a readable file.");
  185. }
  186. try {
  187. $raw = file_get_contents($filePath);
  188. $data = Yaml::parse($raw);
  189. }
  190. catch (ParseException $e) {
  191. throw new MigrateException("Cannot parse the contents of ${filePath}.");
  192. }
  193. if ($key) {
  194. return $data[$key] ?? [];
  195. }
  196. return $data ?? [];
  197. }
  198. /**
  199. * {@inheritdoc}
  200. */
  201. public function __toString() {
  202. $current = $this->getIterator()->current();
  203. $ret = json_encode($current, JSON_PRETTY_PRINT);
  204. return $ret;
  205. }
  206. }