"Fossies" - the Fresh Open Source Software Archive

Member "drupal-8.9.9/core/profiles/demo_umami/modules/demo_umami_content/src/InstallHelper.php" (18 Nov 2020, 26919 Bytes) of package /linux/www/drupal-8.9.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "InstallHelper.php" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.0.8_vs_9.1.0-rc1.

    1 <?php
    2 
    3 namespace Drupal\demo_umami_content;
    4 
    5 use Drupal\Component\Utility\Html;
    6 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
    7 use Drupal\Core\Entity\EntityTypeManagerInterface;
    8 use Drupal\Core\Extension\ModuleHandlerInterface;
    9 use Drupal\Core\File\Exception\FileException;
   10 use Drupal\Core\File\FileSystemInterface;
   11 use Drupal\path_alias\AliasManagerInterface;
   12 use Drupal\Core\State\StateInterface;
   13 use Symfony\Component\DependencyInjection\ContainerInterface;
   14 
   15 /**
   16  * Defines a helper class for importing default content.
   17  *
   18  * @internal
   19  *   This code is only for use by the Umami demo: Content module.
   20  */
   21 class InstallHelper implements ContainerInjectionInterface {
   22 
   23   /**
   24    * The path alias manager.
   25    *
   26    * @var \Drupal\path_alias\AliasManagerInterface
   27    */
   28   protected $aliasManager;
   29 
   30   /**
   31    * Entity type manager.
   32    *
   33    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   34    */
   35   protected $entityTypeManager;
   36 
   37   /**
   38    * Module handler.
   39    *
   40    * @var \Drupal\Core\Extension\ModuleHandlerInterface
   41    */
   42   protected $moduleHandler;
   43 
   44   /**
   45    * State.
   46    *
   47    * @var \Drupal\Core\State\StateInterface
   48    */
   49   protected $state;
   50 
   51   /**
   52    * The file system.
   53    *
   54    * @var \Drupal\Core\File\FileSystemInterface
   55    */
   56   protected $fileSystem;
   57 
   58   /**
   59    * Enabled languages.
   60    *
   61    * List of all enabled languages.
   62    *
   63    * @var array
   64    */
   65   protected $enabledLanguages;
   66 
   67   /**
   68    * Term ID map.
   69    *
   70    * Used to store term IDs created in the import process against
   71    * vocabulary and row in the source CSV files. This allows the created terms
   72    * to be cross referenced when creating articles and recipes.
   73    *
   74    * @var array
   75    */
   76   protected $termIdMap;
   77 
   78   /**
   79    * Media Image CSV ID map.
   80    *
   81    * Used to store media image CSV IDs created in the import process.
   82    * This allows the created media images to be cross referenced when creating
   83    * article, recipes and blocks.
   84    *
   85    * @var array
   86    */
   87   protected $mediaImageIdMap;
   88 
   89   /**
   90    * Node CSV ID map.
   91    *
   92    * Used to store node CSV IDs created in the import process. This allows the
   93    * created nodes to be cross referenced when creating blocks.
   94    *
   95    * @var array
   96    */
   97   protected $nodeIdMap;
   98 
   99   /**
  100    * Constructs a new InstallHelper object.
  101    *
  102    * @param \Drupal\path_alias\AliasManagerInterface $aliasManager
  103    *   The path alias manager.
  104    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
  105    *   Entity type manager.
  106    * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
  107    *   Module handler.
  108    * @param \Drupal\Core\State\StateInterface $state
  109    *   State service.
  110    * @param \Drupal\Core\File\FileSystemInterface $fileSystem
  111    *   The file system.
  112    */
  113   public function __construct(AliasManagerInterface $aliasManager, EntityTypeManagerInterface $entityTypeManager, ModuleHandlerInterface $moduleHandler, StateInterface $state, FileSystemInterface $fileSystem) {
  114     $this->aliasManager = $aliasManager;
  115     $this->entityTypeManager = $entityTypeManager;
  116     $this->moduleHandler = $moduleHandler;
  117     $this->state = $state;
  118     $this->fileSystem = $fileSystem;
  119     $this->termIdMap = [];
  120     $this->mediaImageIdMap = [];
  121     $this->nodeIdMap = [];
  122     $this->enabledLanguages = array_keys(\Drupal::languageManager()->getLanguages());
  123   }
  124 
  125   /**
  126    * {@inheritdoc}
  127    */
  128   public static function create(ContainerInterface $container) {
  129     return new static(
  130       $container->get('path_alias.manager'),
  131       $container->get('entity_type.manager'),
  132       $container->get('module_handler'),
  133       $container->get('state'),
  134       $container->get('file_system')
  135     );
  136   }
  137 
  138   /**
  139    * Imports default contents.
  140    *
  141    * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
  142    * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
  143    * @throws \Drupal\Core\Entity\EntityStorageException
  144    */
  145   public function importContent() {
  146     $this->getModulePath()
  147       ->importEditors()
  148       ->importContentFromFile('taxonomy_term', 'tags')
  149       ->importContentFromFile('taxonomy_term', 'recipe_category')
  150       ->importContentFromFile('media', 'image')
  151       ->importContentFromFile('node', 'recipe')
  152       ->importContentFromFile('node', 'article')
  153       ->importContentFromFile('node', 'page')
  154       ->importContentFromFile('block_content', 'disclaimer_block')
  155       ->importContentFromFile('block_content', 'footer_promo_block')
  156       ->importContentFromFile('block_content', 'banner_block');
  157   }
  158 
  159   /**
  160    * Set module_path variable.
  161    *
  162    * @return $this
  163    */
  164   protected function getModulePath() {
  165     $this->module_path = $this->moduleHandler->getModule('demo_umami_content')->getPath();
  166     return $this;
  167   }
  168 
  169   /**
  170    * Read multilingual content.
  171    *
  172    * @param string $filename
  173    *   Filename to import.
  174    *
  175    * @return array
  176    *   An array of two items:
  177    *     1. All multilingual content that was read from the files.
  178    *     2. List of language codes that need to be imported.
  179    */
  180   protected function readMultilingualContent($filename) {
  181     $default_content_path = $this->module_path . "/default_content/languages/";
  182 
  183     // Get all enabled languages.
  184     $translated_languages = $this->enabledLanguages;
  185 
  186     // Load all the content from any CSV files that exist for enabled languages.
  187     foreach ($translated_languages as $language) {
  188       if (file_exists($default_content_path . "$language/$filename") &&
  189       ($handle = fopen($default_content_path . "$language/$filename", 'r')) !== FALSE) {
  190         $header = fgetcsv($handle);
  191         $line_counter = 0;
  192         while (($content = fgetcsv($handle)) !== FALSE) {
  193           $keyed_content[$language][$line_counter] = array_combine($header, $content);
  194           $line_counter++;
  195         }
  196         fclose($handle);
  197       }
  198       else {
  199         // Language directory exists, but the file in this language was not found,
  200         // remove that language from list list of languages to be translated.
  201         $key = array_search($language, $translated_languages);
  202         unset($translated_languages[$key]);
  203       }
  204     }
  205     return [$keyed_content, $translated_languages];
  206   }
  207 
  208   /**
  209    * Retrieves the Term ID of a term saved during the import process.
  210    *
  211    * @param string $vocabulary
  212    *   Machine name of vocabulary to which it was saved.
  213    * @param int $term_csv_id
  214    *   The term's ID from the CSV file.
  215    *
  216    * @return int
  217    *   Term ID, or 0 if Term ID could not be found.
  218    */
  219   protected function getTermId($vocabulary, $term_csv_id) {
  220     if (array_key_exists($vocabulary, $this->termIdMap) && array_key_exists($term_csv_id, $this->termIdMap[$vocabulary])) {
  221       return $this->termIdMap[$vocabulary][$term_csv_id];
  222     }
  223     return 0;
  224   }
  225 
  226   /**
  227    * Saves a Term ID generated when saving a taxonomy term.
  228    *
  229    * @param string $vocabulary
  230    *   Machine name of vocabulary to which it was saved.
  231    * @param int $term_csv_id
  232    *   The term's ID from the CSV file.
  233    * @param int $tid
  234    *   Term ID generated when saved in the Drupal database.
  235    */
  236   protected function saveTermId($vocabulary, $term_csv_id, $tid) {
  237     $this->termIdMap[$vocabulary][$term_csv_id] = $tid;
  238   }
  239 
  240   /**
  241    * Retrieves the Media Image ID of a media image saved during the import process.
  242    *
  243    * @param int $media_image_csv_id
  244    *   The media image's ID from the CSV file.
  245    *
  246    * @return int
  247    *   Media Image ID, or 0 if Media Image ID could not be found.
  248    */
  249   protected function getMediaImageId($media_image_csv_id) {
  250     if (array_key_exists($media_image_csv_id, $this->mediaImageIdMap)) {
  251       return $this->mediaImageIdMap[$media_image_csv_id];
  252     }
  253     return 0;
  254   }
  255 
  256   /**
  257    * Saves a Media Image ID generated when saving a media image.
  258    *
  259    * @param int $media_image_csv_id
  260    *   The media image's ID from the CSV file.
  261    * @param int $media_image_id
  262    *   Media Image ID generated when saved in the Drupal database.
  263    */
  264   protected function saveMediaImageId($media_image_csv_id, $media_image_id) {
  265     $this->mediaImageIdMap[$media_image_csv_id] = $media_image_id;
  266   }
  267 
  268   /**
  269    * Retrieves the node path of node CSV ID saved during the import process.
  270    *
  271    * @param string $langcode
  272    *   Current language code.
  273    * @param string $content_type
  274    *   Current content type.
  275    * @param string $node_csv_id
  276    *   The node's ID from the CSV file.
  277    *
  278    * @return string
  279    *   Node path, or 0 if node CSV ID could not be found.
  280    */
  281   protected function getNodePath($langcode, $content_type, $node_csv_id) {
  282     if (array_key_exists($langcode, $this->nodeIdMap) &&
  283         array_key_exists($content_type, $this->nodeIdMap[$langcode]) &&
  284         array_key_exists($node_csv_id, $this->nodeIdMap[$langcode][$content_type])) {
  285       return $this->nodeIdMap[$langcode][$content_type][$node_csv_id];
  286     }
  287     return 0;
  288   }
  289 
  290   /**
  291    * Saves a node CSV ID generated when saving content.
  292    *
  293    * @param string $langcode
  294    *   Current language code.
  295    * @param string $content_type
  296    *   Current content type.
  297    * @param string $node_csv_id
  298    *   The node's ID from the CSV file.
  299    * @param string $node_url
  300    *   Node's URL alias when saved in the Drupal database.
  301    */
  302   protected function saveNodePath($langcode, $content_type, $node_csv_id, $node_url) {
  303     $this->nodeIdMap[$langcode][$content_type][$node_csv_id] = $node_url;
  304   }
  305 
  306   /**
  307    * Imports editors.
  308    *
  309    * Other users are created as their content is imported. However, editors
  310    * don't have their own content so are created here instead.
  311    *
  312    * @return $this
  313    */
  314   protected function importEditors() {
  315     $user_storage = $this->entityTypeManager->getStorage('user');
  316     $editors = [
  317       'Margaret Hopper',
  318       'Grace Hamilton',
  319     ];
  320     foreach ($editors as $name) {
  321       $user = $user_storage->create([
  322         'name' => $name,
  323         'status' => 1,
  324         'roles' => ['editor'],
  325         'mail' => mb_strtolower(str_replace(' ', '.', $name)) . '@example.com',
  326       ]);
  327       $user->enforceIsNew();
  328       $user->save();
  329       $this->storeCreatedContentUuids([$user->uuid() => 'user']);
  330     }
  331     return $this;
  332   }
  333 
  334   /**
  335    * Process terms for a given vocabulary and filename.
  336    *
  337    * @param array $data
  338    *   Data of line that was read from the file.
  339    * @param string $vocabulary
  340    *   Machine name of vocabulary to which we should save terms.
  341    *
  342    * @return array
  343    *   Data structured as a term.
  344    */
  345   protected function processTerm(array $data, $vocabulary) {
  346     $term_name = trim($data['term']);
  347 
  348     // Prepare content.
  349     $values = [
  350       'name' => $term_name,
  351       'vid' => $vocabulary,
  352       'path' => ['alias' => '/' . Html::getClass($vocabulary) . '/' . Html::getClass($term_name)],
  353       'langcode' => 'en',
  354     ];
  355     return $values;
  356   }
  357 
  358   /**
  359    * Process images into media entities.
  360    *
  361    * @param array $data
  362    *   Data of line that was read from the file.
  363    *
  364    * @return array
  365    *   Data structured as a image.
  366    */
  367   protected function processImage(array $data) {
  368     // Set article author.
  369     if (!empty($data['author'])) {
  370       $values['uid'] = $this->getUser($data['author']);
  371     }
  372 
  373     $image_path = $this->module_path . '/default_content/images/' . $data['image'];
  374     // Prepare content.
  375     $values = [
  376       'name' => $data['title'],
  377       'bundle' => 'image',
  378       'langcode' => 'en',
  379       'field_media_image' => [
  380         'target_id' => $this->createFileEntity($image_path),
  381         'alt' => $data['alt'],
  382       ],
  383     ];
  384     return $values;
  385   }
  386 
  387   /**
  388    * Process pages data into page node structure.
  389    *
  390    * @param array $data
  391    *   Data of line that was read from the file.
  392    * @param string $langcode
  393    *   Current language code.
  394    *
  395    * @return array
  396    *   Data structured as a page node.
  397    */
  398   protected function processPage(array $data, $langcode) {
  399     // Prepare content.
  400     $values = [
  401       'type' => 'page',
  402       'title' => $data['title'],
  403       'moderation_state' => 'published',
  404       'langcode' => 'en',
  405     ];
  406     // Fields mapping starts.
  407     // Set body field.
  408     if (!empty($data['body'])) {
  409       $values['body'] = [['value' => $data['body'], 'format' => 'basic_html']];
  410     }
  411     // Set node alias if exists.
  412     if (!empty($data['slug'])) {
  413       $values['path'] = [['alias' => '/' . $data['slug']]];
  414     }
  415     // Save node alias
  416     $this->saveNodePath($langcode, 'page', $data['id'], $data['slug']);
  417 
  418     // Set article author.
  419     if (!empty($data['author'])) {
  420       $values['uid'] = $this->getUser($data['author']);
  421     }
  422     return $values;
  423   }
  424 
  425   /**
  426    * Process recipe data into recipe node structure.
  427    *
  428    * @param array $data
  429    *   Data of line that was read from the file.
  430    *
  431    * @return array
  432    *   Data structured as a recipe node.
  433    */
  434   protected function processRecipe(array $data, $langcode) {
  435     $values = [
  436       'type' => 'recipe',
  437       // Title field.
  438       'title' => $data['title'],
  439       'moderation_state' => 'published',
  440       'langcode' => 'en',
  441     ];
  442     // Set article author.
  443     if (!empty($data['author'])) {
  444       $values['uid'] = $this->getUser($data['author']);
  445     }
  446     // Set node alias if exists.
  447     if (!empty($data['slug'])) {
  448       $values['path'] = [['alias' => '/' . $data['slug']]];
  449     }
  450     // Save node alias
  451     $this->saveNodePath($langcode, 'recipe', $data['id'], $data['slug']);
  452     // Set field_media_image field.
  453     if (!empty($data['image_reference'])) {
  454       $values['field_media_image'] = [
  455         'target_id' => $this->getMediaImageId($data['image_reference']),
  456       ];
  457     }
  458     // Set field_summary field.
  459     if (!empty($data['summary'])) {
  460       $values['field_summary'] = [['value' => $data['summary'], 'format' => 'basic_html']];
  461     }
  462     // Set field_recipe_category if exists.
  463     if (!empty($data['recipe_category'])) {
  464       $values['field_recipe_category'] = [];
  465       $tags = array_filter(explode(',', $data['recipe_category']));
  466       foreach ($tags as $tag_id) {
  467         if ($tid = $this->getTermId('recipe_category', $tag_id)) {
  468           $values['field_recipe_category'][] = ['target_id' => $tid];
  469         }
  470       }
  471     }
  472     // Set field_preparation_time field.
  473     if (!empty($data['preparation_time'])) {
  474       $values['field_preparation_time'] = [['value' => $data['preparation_time']]];
  475     }
  476     // Set field_cooking_time field.
  477     if (!empty($data['cooking_time'])) {
  478       $values['field_cooking_time'] = [['value' => $data['cooking_time']]];
  479     }
  480     // Set field_difficulty field.
  481     if (!empty($data['difficulty'])) {
  482       $values['field_difficulty'] = $data['difficulty'];
  483     }
  484     // Set field_number_of_servings field.
  485     if (!empty($data['number_of_servings'])) {
  486       $values['field_number_of_servings'] = [['value' => $data['number_of_servings']]];
  487     }
  488     // Set field_ingredients field.
  489     if (!empty($data['ingredients'])) {
  490       $ingredients = explode(',', $data['ingredients']);
  491       $values['field_ingredients'] = [];
  492       foreach ($ingredients as $ingredient) {
  493         $values['field_ingredients'][] = ['value' => $ingredient];
  494       }
  495     }
  496     // Set field_recipe_instruction field.
  497     if (!empty($data['recipe_instruction'])) {
  498       $recipe_instruction_path = $this->module_path . '/default_content/languages/' . $langcode . '/recipe_instructions/' . $data['recipe_instruction'];
  499       $recipe_instructions = file_get_contents($recipe_instruction_path);
  500       if ($recipe_instructions !== FALSE) {
  501         $values['field_recipe_instruction'] = [['value' => $recipe_instructions, 'format' => 'basic_html']];
  502       }
  503     }
  504     // Set field_tags if exists.
  505     if (!empty($data['tags'])) {
  506       $values['field_tags'] = [];
  507       $tags = array_filter(explode(',', $data['tags']));
  508       foreach ($tags as $tag_id) {
  509         if ($tid = $this->getTermId('tags', $tag_id)) {
  510           $values['field_tags'][] = ['target_id' => $tid];
  511         }
  512       }
  513     }
  514     return $values;
  515   }
  516 
  517   /**
  518    * Process article data into article node structure.
  519    *
  520    * @param array $data
  521    *   Data of line that was read from the file.
  522    * @param string $langcode
  523    *   Current language code.
  524    *
  525    * @return array
  526    *   Data structured as an article node.
  527    */
  528   protected function processArticle(array $data, $langcode) {
  529     // Prepare content.
  530     $values = [
  531       'type' => 'article',
  532       'title' => $data['title'],
  533       'moderation_state' => 'published',
  534       'langcode' => 'en',
  535     ];
  536     // Fields mapping starts.
  537     // Set body field.
  538     if (!empty($data['body'])) {
  539       $body_path = $this->module_path . '/default_content/languages/' . $langcode . '/article_body/' . $data['body'];
  540       $body = file_get_contents($body_path);
  541       if ($body !== FALSE) {
  542         $values['body'] = [['value' => $body, 'format' => 'basic_html']];
  543       }
  544     }
  545 
  546     // Set node alias if exists.
  547     if (!empty($data['slug'])) {
  548       $values['path'] = [['alias' => '/' . $data['slug']]];
  549     }
  550     // Save node alias
  551     $this->saveNodePath($langcode, 'article', $data['id'], $data['slug']);
  552     // Set article author.
  553     if (!empty($data['author'])) {
  554       $values['uid'] = $this->getUser($data['author']);
  555     }
  556     // Set field_media_image field.
  557     if (!empty($data['image_reference'])) {
  558       $values['field_media_image'] = [
  559         'target_id' => $this->getMediaImageId($data['image_reference']),
  560       ];
  561     }
  562     // Set field_tags if exists.
  563     if (!empty($data['tags'])) {
  564       $values['field_tags'] = [];
  565       $tags = explode(',', $data['tags']);
  566       foreach ($tags as $tag_id) {
  567         if ($tid = $this->getTermId('tags', $tag_id)) {
  568           $values['field_tags'][] = ['target_id' => $tid];
  569         }
  570       }
  571     }
  572     return $values;
  573   }
  574 
  575   /**
  576    * Process block_banner data into block_banner block structure.
  577    *
  578    * @param array $data
  579    *   Data of line that was read from the file.
  580    * @param string $langcode
  581    *   Current language code.
  582    *
  583    * @return array
  584    *   Data structured as a block.
  585    */
  586   protected function processBannerBlock(array $data, $langcode) {
  587     $node_url = $this->getNodePath($langcode, $data['content_type'], $data['node_id']);
  588     $values = [
  589       'uuid' => $data['uuid'],
  590       'info' => $data['info'],
  591       'type' => $data['type'],
  592       'langcode' => 'en',
  593       'field_title' => [
  594         'value' => $data['field_title'],
  595       ],
  596       'field_content_link' => [
  597         'uri' => 'internal:/' . $langcode . '/' . $node_url,
  598         'title' => $data['field_content_link_title'],
  599       ],
  600       'field_summary' => [
  601         'value' => $data['field_summary'],
  602       ],
  603       'field_media_image' => [
  604         'target_id' => $this->getMediaImageId($data['image_reference']),
  605       ],
  606     ];
  607     return $values;
  608   }
  609 
  610   /**
  611    * Process disclaimer_block data into disclaimer_block block structure.
  612    *
  613    * @param array $data
  614    *   Data of line that was read from the file.
  615    *
  616    * @return array
  617    *   Data structured as a block.
  618    */
  619   protected function processDisclaimerBlock(array $data) {
  620     $values = [
  621       'uuid' => $data['uuid'],
  622       'info' => $data['info'],
  623       'type' => $data['type'],
  624       'langcode' => 'en',
  625       'field_disclaimer' => [
  626         'value' => $data['field_disclaimer'],
  627         'format' => 'basic_html',
  628       ],
  629       'field_copyright' => [
  630         'value' => '&copy; ' . date("Y") . ' ' . $data['field_copyright'],
  631         'format' => 'basic_html',
  632       ],
  633     ];
  634     return $values;
  635   }
  636 
  637   /**
  638    * Process footer_block data into footer_block block structure.
  639    *
  640    * @param array $data
  641    *   Data of line that was read from the file.
  642    * @param string $langcode
  643    *   Current language code.
  644    *
  645    * @return array
  646    *   Data structured as a block.
  647    */
  648   protected function processFooterPromoBlock(array $data, $langcode) {
  649     $node_url = $this->getNodePath($langcode, $data['content_type'], $data['node_id']);
  650     $values = [
  651       'uuid' => $data['uuid'],
  652       'info' => $data['info'],
  653       'type' => $data['type'],
  654       'langcode' => 'en',
  655       'field_title' => [
  656         'value' => $data['field_title'],
  657       ],
  658       'field_content_link' => [
  659         'uri' => 'internal:/' . $node_url,
  660         'title' => $data['field_content_link_title'],
  661       ],
  662       'field_summary' => [
  663         'value' => $data['field_summary'],
  664       ],
  665       'field_media_image' => [
  666         'target_id' => $this->getMediaImageId($data['image_reference']),
  667       ],
  668     ];
  669     return $values;
  670   }
  671 
  672   /**
  673    * Process content into a structure that can be saved into Drupal.
  674    *
  675    * @param string $bundle_machine_name
  676    *   Current bundle's machine name.
  677    * @param array $content
  678    *   Current content array that needs to be structured.
  679    * @param string $langcode
  680    *   Current language code.
  681    *
  682    * @return array
  683    *   Structured content.
  684    */
  685   protected function processContent($bundle_machine_name, array $content, $langcode) {
  686     switch ($bundle_machine_name) {
  687       case 'recipe':
  688         $structured_content = $this->processRecipe($content, $langcode);
  689         break;
  690 
  691       case 'article':
  692         $structured_content = $this->processArticle($content, $langcode);
  693         break;
  694 
  695       case 'page':
  696         $structured_content = $this->processPage($content, $langcode);
  697         break;
  698 
  699       case 'banner_block':
  700         $structured_content = $this->processBannerBlock($content, $langcode);
  701         break;
  702 
  703       case 'disclaimer_block':
  704         $structured_content = $this->processDisclaimerBlock($content);
  705         break;
  706 
  707       case 'footer_promo_block':
  708         $structured_content = $this->processFooterPromoBlock($content, $langcode);
  709         break;
  710 
  711       case 'image':
  712         $structured_content = $this->processImage($content);
  713         break;
  714 
  715       case 'recipe_category':
  716       case 'tags':
  717         $structured_content = $this->processTerm($content, $bundle_machine_name);
  718         break;
  719 
  720       default:
  721         break;
  722     }
  723     return $structured_content;
  724   }
  725 
  726   /**
  727    * Imports content.
  728    *
  729    * @param string $entity_type
  730    *   Entity type to be imported
  731    * @param string $bundle_machine_name
  732    *   Bundle machine name to be imported.
  733    *
  734    * @return $this
  735    */
  736   protected function importContentFromFile($entity_type, $bundle_machine_name) {
  737     $filename = $entity_type . '/' . $bundle_machine_name . '.csv';
  738 
  739     // Read all multilingual content from the file.
  740     list($all_content, $translated_languages) = $this->readMultilingualContent($filename);
  741 
  742     // English is no longer needed in the list of languages to translate.
  743     $key = array_search('en', $translated_languages);
  744     unset($translated_languages[$key]);
  745 
  746     // Start the loop with English (default) recipes.
  747     foreach ($all_content['en'] as $current_content) {
  748       // Process data into its relevant structure.
  749       $structured_content = $this->processContent($bundle_machine_name, $current_content, 'en');
  750 
  751       // Save Entity.
  752       $entity = $this->entityTypeManager->getStorage($entity_type)->create($structured_content);
  753       $entity->save();
  754       $this->storeCreatedContentUuids([$entity->uuid() => $entity_type]);
  755 
  756       // Save taxonomy entity Drupal ID, so we can reference it in nodes.
  757       if ($entity_type == 'taxonomy_term') {
  758         $this->saveTermId($bundle_machine_name, $current_content['id'], $entity->id());
  759       }
  760 
  761       // Save media entity Drupal ID, so we can reference it in nodes & blocks.
  762       if ($entity_type == 'media') {
  763         $this->saveMediaImageId($current_content['id'], $entity->id());
  764       }
  765 
  766       // Go through all the languages that have translations.
  767       foreach ($translated_languages as $translated_language) {
  768 
  769         // Find the translated content ID that corresponds to original content.
  770         $translation_id = array_search($current_content['id'], array_column($all_content[$translated_language], 'id'));
  771 
  772         // Check if translation was found.
  773         if ($translation_id !== FALSE) {
  774 
  775           // Process that translation.
  776           $translated_entity = $all_content[$translated_language][$translation_id];
  777           $structured_content = $this->processContent($bundle_machine_name, $translated_entity, $translated_language);
  778 
  779           // Save entity's translation.
  780           $entity->addTranslation(
  781             $translated_language,
  782             $structured_content
  783           );
  784           $entity->save();
  785         }
  786       }
  787     }
  788     return $this;
  789   }
  790 
  791   /**
  792    * Deletes any content imported by this module.
  793    *
  794    * @return $this
  795    */
  796   public function deleteImportedContent() {
  797     $uuids = $this->state->get('demo_umami_content_uuids', []);
  798     $by_entity_type = array_reduce(array_keys($uuids), function ($carry, $uuid) use ($uuids) {
  799       $entity_type_id = $uuids[$uuid];
  800       $carry[$entity_type_id][] = $uuid;
  801       return $carry;
  802     }, []);
  803     foreach ($by_entity_type as $entity_type_id => $entity_uuids) {
  804       $storage = $this->entityTypeManager->getStorage($entity_type_id);
  805       $entities = $storage->loadByProperties(['uuid' => $entity_uuids]);
  806       $storage->delete($entities);
  807     }
  808     return $this;
  809   }
  810 
  811   /**
  812    * Looks up a user by name, if it is missing the user is created.
  813    *
  814    * @param string $name
  815    *   Username.
  816    *
  817    * @return int
  818    *   User ID.
  819    */
  820   protected function getUser($name) {
  821     $user_storage = $this->entityTypeManager->getStorage('user');
  822     $users = $user_storage->loadByProperties(['name' => $name]);
  823     if (empty($users)) {
  824       // Creating user without any password.
  825       $user = $user_storage->create([
  826         'name' => $name,
  827         'status' => 1,
  828         'roles' => ['author'],
  829         'mail' => mb_strtolower(str_replace(' ', '.', $name)) . '@example.com',
  830       ]);
  831       $user->enforceIsNew();
  832       $user->save();
  833       $this->storeCreatedContentUuids([$user->uuid() => 'user']);
  834       return $user->id();
  835     }
  836     $user = reset($users);
  837     return $user->id();
  838   }
  839 
  840   /**
  841    * Creates a file entity based on an image path.
  842    *
  843    * @param string $path
  844    *   Image path.
  845    *
  846    * @return int
  847    *   File ID.
  848    */
  849   protected function createFileEntity($path) {
  850     $filename = basename($path);
  851     try {
  852       $uri = $this->fileSystem->copy($path, 'public://' . $filename, FileSystemInterface::EXISTS_REPLACE);
  853     }
  854     catch (FileException $e) {
  855       $uri = FALSE;
  856     }
  857     $file = $this->entityTypeManager->getStorage('file')->create([
  858       'uri' => $uri,
  859       'status' => 1,
  860     ]);
  861     $file->save();
  862     $this->storeCreatedContentUuids([$file->uuid() => 'file']);
  863     return $file->id();
  864   }
  865 
  866   /**
  867    * Stores record of content entities created by this import.
  868    *
  869    * @param array $uuids
  870    *   Array of UUIDs where the key is the UUID and the value is the entity
  871    *   type.
  872    */
  873   protected function storeCreatedContentUuids(array $uuids) {
  874     $uuids = $this->state->get('demo_umami_content_uuids', []) + $uuids;
  875     $this->state->set('demo_umami_content_uuids', $uuids);
  876   }
  877 
  878 }