blacksmith-8.x-1.x-dev/src/Blacksmith/EntityImporter/EntityImporter.php
src/Blacksmith/EntityImporter/EntityImporter.php
<?php namespace Drupal\blacksmith\Blacksmith\EntityImporter; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Logger\LoggerChannelTrait; use Drupal\Core\Messenger\MessengerTrait; use Drupal\blacksmith\Exception\BlacksmithImportSkip; use Drupal\blacksmith\Blacksmith\EntityImporter\FieldFormatter\FieldFormatterFactory; use Drupal\blacksmith\BlacksmithItem; use Drupal\blacksmith\BlacksmithTranslation; /** * Class EntityImporter. * * @package Drupal\blacksmith\Blacksmith\EntityImporter */ abstract class EntityImporter implements EntityImporterInterface { use LoggerChannelTrait; use MessengerTrait; /** * Entity storage used to create the entities. * * @var \Drupal\Core\Entity\EntityStorageInterface */ protected $entityStorage; /** * Entity field manager service. * * @var \Drupal\Core\Entity\EntityFieldManagerInterface */ protected $entityFieldManager; /** * Field formatter factory service. * * @var \Drupal\blacksmith\Blacksmith\EntityImporter\FieldFormatter\FieldFormatterFactory */ protected $fieldFormatterFactory; /** * Entity type manager service. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * Entity importer factory service. * * @var \Drupal\blacksmith\Blacksmith\EntityImporter\EntityImporterFactory */ protected $entityImporterFactory; /** * NodeEntityImporter constructor. * * @param \Drupal\Core\Entity\EntityStorageInterface $entityStorage * Node entity storage. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager * Entity type manager service. * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entityFieldManager * Entity field manager service. * @param \Drupal\blacksmith\Blacksmith\EntityImporter\EntityImporterFactory $entityImporterFactory * Entity importer factory service. */ public function __construct(EntityStorageInterface $entityStorage, EntityTypeManagerInterface $entityTypeManager, EntityFieldManagerInterface $entityFieldManager, EntityImporterFactory $entityImporterFactory) { $this->entityStorage = $entityStorage; $this->entityTypeManager = $entityTypeManager; $this->entityFieldManager = $entityFieldManager; $this->entityImporterFactory = $entityImporterFactory; $this->fieldFormatterFactory = new FieldFormatterFactory($entityTypeManager); } /** * {@inheritdoc} */ public function import(BlacksmithItem $item) : EntityInterface { $values = $this->presetValues($item); foreach ($this->getFieldDefinitions($item) as $fieldDefinition) { $fieldName = $fieldDefinition->getName(); // Properly format the value from the Yaml file. if ($item->hadField($fieldName)) { $fieldFormatter = $this->fieldFormatterFactory->create($fieldDefinition); $values[$fieldName] = $fieldFormatter->format($item->get($fieldName)); } // Get the default value. elseif ($defaults = $this->getDefaultValues($fieldDefinition)) { $values[$fieldName] = $defaults; } // Throw an error if the field is supposed to have a value. elseif (!array_key_exists($fieldName, $values) && $fieldDefinition->isRequired()) { $entityTypeName = $this->entityStorage->getEntityType()->getLabel(); throw new BlacksmithImportSkip("The entity type '$entityTypeName' needs the field : '$fieldName'.", $item); } } // Create the entity and save it to the database. $entity = $this->createEntity($values); $entity = $this->addEntityTranslations($entity, $item); return $entity; } /** * Generates an new entity and saves it in the database. * * @param array $values * Keyed array of values used to generated an entity. * * @return \Drupal\Core\Entity\EntityInterface * The created entity. * * @throws \Drupal\Core\Entity\EntityStorageException */ protected function createEntity(array $values) : EntityInterface { $entity = $this->entityStorage->create($values); $entity->save(); return $entity; } /** * Generates all translations of the entity based on the Blacksmith item. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity to which we add translations. * @param \Drupal\blacksmith\BlacksmithItem $item * The Blacksmith item used to generate the translations. * * @return \Drupal\Core\Entity\EntityInterface * The entity with additional translations. * * @throws \Drupal\Core\Entity\EntityStorageException */ protected function addEntityTranslations(EntityInterface $entity, BlacksmithItem $item) : EntityInterface { if ($entity instanceof ContentEntityBase && $entity->isTranslatable()) { foreach ($item->getTranslations() as $langcode => $translation) { $translationValues = $this->presentTranslationValues($translation); foreach ($this->getFieldDefinitions($item) as $fieldDefinition) { $fieldName = $fieldDefinition->getName(); if (!$fieldDefinition->isTranslatable()) { if ($translation->get($fieldName)) { $this->messenger()->addWarning("$fieldName is not translatable"); } continue; } // Properly format the value from the Yaml file. if ($fieldValue = $translation->get($fieldName)) { $fieldFormatter = $this->fieldFormatterFactory->create($fieldDefinition); $translationValues[$fieldName] = $fieldFormatter->format($translation->get($fieldName)); } } // Create the translation if any. $entity->addTranslation($langcode, $translationValues); $entity->save(); } } return $entity; } /** * Prepares some values that have a specific key and/or value. * * @param \Drupal\blacksmith\BlacksmithItem $item * Blacksmith item used to build the entity. * * @return array * The keyed values that will be set in the entity. */ protected function presetValues(BlacksmithItem $item) : array { return [ $this->entityStorage->getEntityType()->getKey('label') => $item->label(), $this->entityStorage->getEntityType()->getKey('bundle') => $item->bundle(), ]; } /** * Prepares some values that have a specific key and/or value. * * @param \Drupal\blacksmith\BlacksmithTranslation $translations * Blacksmith translation used to build the entity translation. * * @return array * The keyed values that will be set in the entity. */ protected function presentTranslationValues(BlacksmithTranslation $translations) : array { return [ $this->entityStorage->getEntityType()->getKey('label') => $translations->label(), ]; } /** * Get all fields of a specific entity type with bundle. * * @param \Drupal\blacksmith\BlacksmithItem $item * The Blacksmith item about to be imported. * * @return \Drupal\Core\Field\FieldDefinitionInterface[] * The list of fields. */ protected function getFieldDefinitions(BlacksmithItem $item) : array { return $this->entityFieldManager->getFieldDefinitions($this->entityStorage->getEntityTypeId(), $item->bundle()); } /** * Finds the default values of a field. * * @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition * The field that is about to be saved in the entity. * * @return array * Raw default values. */ protected function getDefaultValues(FieldDefinitionInterface $fieldDefinition) : array { $defaultValues = []; foreach ($fieldDefinition->getDefaultValueLiteral() as $value) { $defaultValues[] = $value['value']; } return $defaultValues; } }