Further Drupal 8.6.4 changes. Some core files were not committed before a commit...
[yaffs-website] / web / core / modules / media / src / MediaSourceBase.php
1 <?php
2
3 namespace Drupal\media;
4
5 use Drupal\Component\Utility\NestedArray;
6 use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
7 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
8 use Drupal\Core\Entity\EntityFieldManagerInterface;
9 use Drupal\Core\Entity\EntityTypeManagerInterface;
10 use Drupal\Core\Field\FieldTypePluginManagerInterface;
11 use Drupal\Core\Form\FormStateInterface;
12 use Drupal\Core\Config\ConfigFactoryInterface;
13 use Drupal\Core\Plugin\PluginBase;
14 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
15 use Symfony\Component\DependencyInjection\ContainerInterface;
16
17 /**
18  * Base implementation of media source plugin.
19  */
20 abstract class MediaSourceBase extends PluginBase implements MediaSourceInterface, ContainerFactoryPluginInterface {
21
22   /**
23    * Plugin label.
24    *
25    * @var string
26    */
27   protected $label;
28
29   /**
30    * The entity type manager service.
31    *
32    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
33    */
34   protected $entityTypeManager;
35
36   /**
37    * The entity field manager service.
38    *
39    * @var \Drupal\Core\Entity\EntityFieldManagerInterface
40    */
41   protected $entityFieldManager;
42
43   /**
44    * The field type plugin manager service.
45    *
46    * @var \Drupal\Core\Field\FieldTypePluginManagerInterface
47    */
48   protected $fieldTypeManager;
49
50   /**
51    * The config factory service.
52    *
53    * @var \Drupal\Core\Config\ConfigFactoryInterface
54    */
55   protected $configFactory;
56
57   /**
58    * Constructs a new class instance.
59    *
60    * @param array $configuration
61    *   A configuration array containing information about the plugin instance.
62    * @param string $plugin_id
63    *   The plugin_id for the plugin instance.
64    * @param mixed $plugin_definition
65    *   The plugin implementation definition.
66    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
67    *   Entity type manager service.
68    * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
69    *   Entity field manager service.
70    * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
71    *   The field type plugin manager service.
72    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
73    *   The config factory service.
74    */
75   public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, ConfigFactoryInterface $config_factory) {
76     parent::__construct($configuration, $plugin_id, $plugin_definition);
77     $this->entityTypeManager = $entity_type_manager;
78     $this->entityFieldManager = $entity_field_manager;
79     $this->fieldTypeManager = $field_type_manager;
80     $this->configFactory = $config_factory;
81
82     // Add the default configuration of the media source to the plugin.
83     $this->setConfiguration($configuration);
84   }
85
86   /**
87    * {@inheritdoc}
88    */
89   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
90     return new static(
91       $configuration,
92       $plugin_id,
93       $plugin_definition,
94       $container->get('entity_type.manager'),
95       $container->get('entity_field.manager'),
96       $container->get('plugin.manager.field.field_type'),
97       $container->get('config.factory')
98     );
99   }
100
101   /**
102    * {@inheritdoc}
103    */
104   public function setConfiguration(array $configuration) {
105     $this->configuration = NestedArray::mergeDeep(
106       $this->defaultConfiguration(),
107       $configuration
108     );
109   }
110
111   /**
112    * {@inheritdoc}
113    */
114   public function getConfiguration() {
115     return $this->configuration;
116   }
117
118   /**
119    * {@inheritdoc}
120    */
121   public function defaultConfiguration() {
122     return [
123       'source_field' => '',
124     ];
125   }
126
127   /**
128    * {@inheritdoc}
129    */
130   public function getMetadata(MediaInterface $media, $attribute_name) {
131     switch ($attribute_name) {
132       case 'default_name':
133         return 'media:' . $media->bundle() . ':' . $media->uuid();
134
135       case 'thumbnail_uri':
136         $default_thumbnail_filename = $this->pluginDefinition['default_thumbnail_filename'];
137         return $this->configFactory->get('media.settings')->get('icon_base_uri') . '/' . $default_thumbnail_filename;
138     }
139
140     return NULL;
141   }
142
143   /**
144    * {@inheritdoc}
145    */
146   public function calculateDependencies() {
147     return [];
148   }
149
150   /**
151    * Get the source field options for the media type form.
152    *
153    * This returns all fields related to media entities, filtered by the allowed
154    * field types in the media source annotation.
155    *
156    * @return string[]
157    *   A list of source field options for the media type form.
158    */
159   protected function getSourceFieldOptions() {
160     // If there are existing fields to choose from, allow the user to reuse one.
161     $options = [];
162     foreach ($this->entityFieldManager->getFieldStorageDefinitions('media') as $field_name => $field) {
163       $allowed_type = in_array($field->getType(), $this->pluginDefinition['allowed_field_types'], TRUE);
164       if ($allowed_type && !$field->isBaseField()) {
165         $options[$field_name] = $field->getLabel();
166       }
167     }
168     return $options;
169   }
170
171   /**
172    * {@inheritdoc}
173    */
174   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
175     $options = $this->getSourceFieldOptions();
176     $form['source_field'] = [
177       '#type' => 'select',
178       '#title' => $this->t('Field with source information'),
179       '#default_value' => $this->configuration['source_field'],
180       '#empty_option' => $this->t('- Create -'),
181       '#options' => $options,
182       '#description' => $this->t('Select the field that will store essential information about the media item. If "Create" is selected a new field will be automatically created.'),
183     ];
184
185     if (!$options && $form_state->get('operation') === 'add') {
186       $form['source_field']['#access'] = FALSE;
187       $field_definition = $this->fieldTypeManager->getDefinition(reset($this->pluginDefinition['allowed_field_types']));
188       $form['source_field_message'] = [
189         '#markup' => $this->t('%field_type field will be automatically created on this type to store the essential information about the media item.', [
190           '%field_type' => $field_definition['label'],
191         ]),
192       ];
193     }
194     elseif ($form_state->get('operation') === 'edit') {
195       $form['source_field']['#access'] = FALSE;
196       $fields = $this->entityFieldManager->getFieldDefinitions('media', $form_state->get('type')->id());
197       $form['source_field_message'] = [
198         '#markup' => $this->t('%field_name field is used to store the essential information about the media item.', [
199           '%field_name' => $fields[$this->configuration['source_field']]->getLabel(),
200         ]),
201       ];
202     }
203
204     return $form;
205   }
206
207   /**
208    * {@inheritdoc}
209    */
210   public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
211   }
212
213   /**
214    * {@inheritdoc}
215    */
216   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
217     foreach (array_intersect_key($form_state->getValues(), $this->configuration) as $config_key => $config_value) {
218       $this->configuration[$config_key] = $config_value;
219     }
220
221     // If no source field is explicitly set, create it now.
222     if (empty($this->configuration['source_field'])) {
223       $field_storage = $this->createSourceFieldStorage();
224       $field_storage->save();
225       $this->configuration['source_field'] = $field_storage->getName();
226     }
227   }
228
229   /**
230    * Creates the source field storage definition.
231    *
232    * By default, the first field type listed in the plugin definition's
233    * allowed_field_types array will be the generated field's type.
234    *
235    * @return \Drupal\field\FieldStorageConfigInterface
236    *   The unsaved field storage definition.
237    */
238   protected function createSourceFieldStorage() {
239     return $this->entityTypeManager
240       ->getStorage('field_storage_config')
241       ->create([
242         'entity_type' => 'media',
243         'field_name' => $this->getSourceFieldName(),
244         'type' => reset($this->pluginDefinition['allowed_field_types']),
245       ]);
246   }
247
248   /**
249    * Returns the source field storage definition.
250    *
251    * @return \Drupal\Core\Field\FieldStorageDefinitionInterface|null
252    *   The field storage definition or NULL if it doesn't exists.
253    */
254   protected function getSourceFieldStorage() {
255     // Nothing to do if no source field is configured yet.
256     $field = $this->configuration['source_field'];
257     if ($field) {
258       // Even if we do know the name of the source field, there's no
259       // guarantee that it exists.
260       $fields = $this->entityFieldManager->getFieldStorageDefinitions('media');
261       return isset($fields[$field]) ? $fields[$field] : NULL;
262     }
263     return NULL;
264   }
265
266   /**
267    * {@inheritdoc}
268    */
269   public function getSourceFieldDefinition(MediaTypeInterface $type) {
270     // Nothing to do if no source field is configured yet.
271     $field = $this->configuration['source_field'];
272     if ($field) {
273       // Even if we do know the name of the source field, there is no
274       // guarantee that it already exists.
275       $fields = $this->entityFieldManager->getFieldDefinitions('media', $type->id());
276       return isset($fields[$field]) ? $fields[$field] : NULL;
277     }
278     return NULL;
279   }
280
281   /**
282    * {@inheritdoc}
283    */
284   public function createSourceField(MediaTypeInterface $type) {
285     $storage = $this->getSourceFieldStorage() ?: $this->createSourceFieldStorage();
286     return $this->entityTypeManager
287       ->getStorage('field_config')
288       ->create([
289         'field_storage' => $storage,
290         'bundle' => $type->id(),
291         'label' => $this->pluginDefinition['label'],
292         'required' => TRUE,
293       ]);
294   }
295
296   /**
297    * Determine the name of the source field.
298    *
299    * @return string
300    *   The source field name. If one is already stored in configuration, it is
301    *   returned. Otherwise, a new, unused one is generated.
302    */
303   protected function getSourceFieldName() {
304     // Some media sources are using a deriver, so their plugin IDs may contain
305     // a separator (usually ':') which is not allowed in field names.
306     $base_id = 'field_media_' . str_replace(static::DERIVATIVE_SEPARATOR, '_', $this->getPluginId());
307     $tries = 0;
308     $storage = $this->entityTypeManager->getStorage('field_storage_config');
309
310     // Iterate at least once, until no field with the generated ID is found.
311     do {
312       $id = $base_id;
313       // If we've tried before, increment and append the suffix.
314       if ($tries) {
315         $id .= '_' . $tries;
316       }
317       $field = $storage->load('media.' . $id);
318       $tries++;
319     } while ($field);
320
321     return $id;
322   }
323
324   /**
325    * {@inheritdoc}
326    */
327   public function getSourceFieldValue(MediaInterface $media) {
328     $source_field = $this->configuration['source_field'];
329     if (empty($source_field)) {
330       throw new \RuntimeException('Source field for media source is not defined.');
331     }
332
333     /** @var \Drupal\Core\Field\FieldItemInterface $field_item */
334     $field_item = $media->get($source_field)->first();
335     return $field_item->{$field_item->mainPropertyName()};
336   }
337
338   /**
339    * {@inheritdoc}
340    */
341   public function prepareViewDisplay(MediaTypeInterface $type, EntityViewDisplayInterface $display) {
342     $display->setComponent($this->getSourceFieldDefinition($type)->getName());
343   }
344
345   /**
346    * {@inheritdoc}
347    */
348   public function prepareFormDisplay(MediaTypeInterface $type, EntityFormDisplayInterface $display) {
349     // Make sure the source field is placed just after the "name" basefield.
350     $name_component = $display->getComponent('name');
351     $source_field_weight = ($name_component && isset($name_component['weight'])) ? $name_component['weight'] + 5 : -50;
352     $display->setComponent($this->getSourceFieldDefinition($type)->getName(), [
353       'weight' => $source_field_weight,
354     ]);
355   }
356
357 }