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