Chris@17
|
1 <?php
|
Chris@17
|
2
|
Chris@17
|
3 /**
|
Chris@17
|
4 * @file
|
Chris@17
|
5 * Contains hook implementations for the media_library module.
|
Chris@17
|
6 */
|
Chris@17
|
7
|
Chris@17
|
8 use Drupal\Component\Utility\UrlHelper;
|
Chris@18
|
9 use Drupal\Core\Access\AccessResult;
|
Chris@18
|
10 use Drupal\Core\Entity\EntityInterface;
|
Chris@18
|
11 use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
Chris@18
|
12 use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
Chris@17
|
13 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
Chris@17
|
14 use Drupal\Core\Form\FormStateInterface;
|
Chris@17
|
15 use Drupal\Core\Render\Element;
|
Chris@17
|
16 use Drupal\Core\Routing\RouteMatchInterface;
|
Chris@18
|
17 use Drupal\Core\Session\AccountInterface;
|
Chris@17
|
18 use Drupal\Core\Template\Attribute;
|
Chris@18
|
19 use Drupal\image\Entity\ImageStyle;
|
Chris@18
|
20 use Drupal\image\Plugin\Field\FieldType\ImageItem;
|
Chris@18
|
21 use Drupal\media\MediaTypeForm;
|
Chris@18
|
22 use Drupal\media\MediaTypeInterface;
|
Chris@18
|
23 use Drupal\media_library\Form\FileUploadForm;
|
Chris@18
|
24 use Drupal\media_library\Form\OEmbedForm;
|
Chris@18
|
25 use Drupal\media_library\MediaLibraryState;
|
Chris@17
|
26 use Drupal\views\Form\ViewsForm;
|
Chris@17
|
27 use Drupal\views\Plugin\views\cache\CachePluginBase;
|
Chris@17
|
28 use Drupal\views\ViewExecutable;
|
Chris@17
|
29
|
Chris@17
|
30 /**
|
Chris@17
|
31 * Implements hook_help().
|
Chris@17
|
32 *
|
Chris@17
|
33 * @todo Update in https://www.drupal.org/project/drupal/issues/2964789
|
Chris@17
|
34 */
|
Chris@17
|
35 function media_library_help($route_name, RouteMatchInterface $route_match) {
|
Chris@17
|
36 switch ($route_name) {
|
Chris@17
|
37 case 'help.page.media_library':
|
Chris@17
|
38 $output = '<h3>' . t('About') . '</h3>';
|
Chris@17
|
39 $output .= '<p>' . t('The Media library module overrides the /admin/content/media view to provide a rich visual interface for performing administrative operations on media. For more information, see the <a href=":media">online documentation for the Media library module</a>.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '</p>';
|
Chris@17
|
40 return $output;
|
Chris@17
|
41 }
|
Chris@17
|
42 }
|
Chris@17
|
43
|
Chris@17
|
44 /**
|
Chris@18
|
45 * Implements hook_media_source_info_alter().
|
Chris@18
|
46 */
|
Chris@18
|
47 function media_library_media_source_info_alter(array &$sources) {
|
Chris@18
|
48 $sources['audio_file']['forms']['media_library_add'] = FileUploadForm::class;
|
Chris@18
|
49 $sources['file']['forms']['media_library_add'] = FileUploadForm::class;
|
Chris@18
|
50 $sources['image']['forms']['media_library_add'] = FileUploadForm::class;
|
Chris@18
|
51 $sources['video_file']['forms']['media_library_add'] = FileUploadForm::class;
|
Chris@18
|
52 $sources['oembed:video']['forms']['media_library_add'] = OEmbedForm::class;
|
Chris@18
|
53 }
|
Chris@18
|
54
|
Chris@18
|
55 /**
|
Chris@17
|
56 * Implements hook_theme().
|
Chris@17
|
57 */
|
Chris@17
|
58 function media_library_theme() {
|
Chris@17
|
59 return [
|
Chris@17
|
60 'media__media_library' => [
|
Chris@17
|
61 'base hook' => 'media',
|
Chris@17
|
62 ],
|
Chris@17
|
63 ];
|
Chris@17
|
64 }
|
Chris@17
|
65
|
Chris@17
|
66 /**
|
Chris@17
|
67 * Implements hook_views_post_render().
|
Chris@17
|
68 */
|
Chris@17
|
69 function media_library_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
|
Chris@17
|
70 if ($view->id() === 'media_library') {
|
Chris@17
|
71 $output['#attached']['library'][] = 'media_library/view';
|
Chris@18
|
72 if (strpos($view->current_display, 'widget') === 0) {
|
Chris@18
|
73 $query = MediaLibraryState::fromRequest($view->getRequest())->all();
|
Chris@17
|
74 // If the current query contains any parameters we use to contextually
|
Chris@17
|
75 // filter the view, ensure they persist across AJAX rebuilds.
|
Chris@17
|
76 // The ajax_path is shared for all AJAX views on the page, but our query
|
Chris@17
|
77 // parameters are prefixed and should not interfere with any other views.
|
Chris@17
|
78 // @todo Rework or remove this in https://www.drupal.org/node/2983451
|
Chris@17
|
79 if (!empty($query)) {
|
Chris@17
|
80 $ajax_path = &$output['#attached']['drupalSettings']['views']['ajax_path'];
|
Chris@17
|
81 $parsed_url = UrlHelper::parse($ajax_path);
|
Chris@17
|
82 $query = array_merge($query, $parsed_url['query']);
|
Chris@17
|
83 $ajax_path = $parsed_url['path'] . '?' . UrlHelper::buildQuery($query);
|
Chris@17
|
84 }
|
Chris@17
|
85 }
|
Chris@17
|
86 }
|
Chris@17
|
87 }
|
Chris@17
|
88
|
Chris@17
|
89 /**
|
Chris@17
|
90 * Implements hook_preprocess_media().
|
Chris@17
|
91 */
|
Chris@17
|
92 function media_library_preprocess_media(&$variables) {
|
Chris@17
|
93 if ($variables['view_mode'] === 'media_library') {
|
Chris@17
|
94 /** @var \Drupal\media\MediaInterface $media */
|
Chris@17
|
95 $media = $variables['media'];
|
Chris@17
|
96 $variables['#cache']['contexts'][] = 'user.permissions';
|
Chris@17
|
97 $rel = $media->access('edit') ? 'edit-form' : 'canonical';
|
Chris@17
|
98 $variables['url'] = $media->toUrl($rel, [
|
Chris@17
|
99 'language' => $media->language(),
|
Chris@17
|
100 ]);
|
Chris@17
|
101 $variables['preview_attributes'] = new Attribute();
|
Chris@17
|
102 $variables['preview_attributes']->addClass('media-library-item__preview', 'js-media-library-item-preview', 'js-click-to-select-trigger');
|
Chris@17
|
103 $variables['metadata_attributes'] = new Attribute();
|
Chris@17
|
104 $variables['metadata_attributes']->addClass('media-library-item__attributes');
|
Chris@17
|
105 $variables['status'] = $media->isPublished();
|
Chris@17
|
106 }
|
Chris@17
|
107 }
|
Chris@17
|
108
|
Chris@17
|
109 /**
|
Chris@17
|
110 * Alter the bulk form to add a more accessible label.
|
Chris@17
|
111 *
|
Chris@17
|
112 * @param array $form
|
Chris@17
|
113 * An associative array containing the structure of the form.
|
Chris@17
|
114 * @param \Drupal\Core\Form\FormStateInterface $form_state
|
Chris@17
|
115 * The current state of the form.
|
Chris@17
|
116 *
|
Chris@17
|
117 * @todo Remove in https://www.drupal.org/node/2983454
|
Chris@17
|
118 */
|
Chris@17
|
119 function media_library_form_views_form_media_library_page_alter(array &$form, FormStateInterface $form_state) {
|
Chris@17
|
120 if (isset($form['media_bulk_form']) && isset($form['output'])) {
|
Chris@17
|
121 /** @var \Drupal\views\ViewExecutable $view */
|
Chris@17
|
122 $view = $form['output'][0]['#view'];
|
Chris@17
|
123 foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
|
Chris@17
|
124 if (isset($view->result[$key])) {
|
Chris@17
|
125 $media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
|
Chris@17
|
126 $form['media_bulk_form'][$key]['#title'] = t('Select @label', [
|
Chris@17
|
127 '@label' => $media->label(),
|
Chris@17
|
128 ]);
|
Chris@17
|
129 }
|
Chris@17
|
130 }
|
Chris@17
|
131 }
|
Chris@17
|
132 }
|
Chris@17
|
133
|
Chris@17
|
134 /**
|
Chris@17
|
135 * Implements hook_form_alter().
|
Chris@17
|
136 */
|
Chris@17
|
137 function media_library_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
|
Chris@17
|
138 $form_object = $form_state->getFormObject();
|
Chris@17
|
139 if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_media_library') === 0) {
|
Chris@17
|
140 $form['#attributes']['class'][] = 'media-library-views-form';
|
Chris@17
|
141 if (isset($form['header'])) {
|
Chris@17
|
142 $form['header']['#attributes']['class'][] = 'media-library-views-form__header';
|
Chris@17
|
143 $form['header']['media_bulk_form']['#attributes']['class'][] = 'media-library-views-form__bulk_form';
|
Chris@17
|
144 }
|
Chris@17
|
145 }
|
Chris@17
|
146
|
Chris@17
|
147 // Add after build to fix media library views exposed filter's submit button.
|
Chris@18
|
148 if ($form_id === 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-media-library-widget') === 0) {
|
Chris@17
|
149 $form['#after_build'][] = '_media_library_views_form_media_library_after_build';
|
Chris@17
|
150 }
|
Chris@18
|
151
|
Chris@18
|
152 // Configures media_library displays when a type is submitted.
|
Chris@18
|
153 if ($form_object instanceof MediaTypeForm) {
|
Chris@18
|
154 $form['actions']['submit']['#submit'][] = '_media_library_media_type_form_submit';
|
Chris@18
|
155 }
|
Chris@17
|
156 }
|
Chris@17
|
157
|
Chris@17
|
158 /**
|
Chris@17
|
159 * After build callback for views form media library.
|
Chris@17
|
160 */
|
Chris@17
|
161 function _media_library_views_form_media_library_after_build(array $form, FormStateInterface $form_state) {
|
Chris@17
|
162 // Remove .form-actions from media library views exposed filter actions
|
Chris@17
|
163 // and replace with .media-library-view--form-actions.
|
Chris@17
|
164 //
|
Chris@17
|
165 // This prevents the views exposed filter's 'Apply filter' submit button from
|
Chris@17
|
166 // being moved into the dialog's buttons.
|
Chris@17
|
167 // @see \Drupal\Core\Render\Element\Actions::processActions
|
Chris@17
|
168 // @see Drupal.behaviors.dialog.prepareDialogButtons
|
Chris@17
|
169 if (($key = array_search('form-actions', $form['actions']['#attributes']['class'])) !== FALSE) {
|
Chris@17
|
170 unset($form['actions']['#attributes']['class'][$key]);
|
Chris@17
|
171 }
|
Chris@17
|
172 $form['actions']['#attributes']['class'][] = 'media-library-view--form-actions';
|
Chris@17
|
173 return $form;
|
Chris@17
|
174 }
|
Chris@17
|
175
|
Chris@17
|
176 /**
|
Chris@18
|
177 * Submit callback for media type form.
|
Chris@17
|
178 */
|
Chris@18
|
179 function _media_library_media_type_form_submit(array &$form, FormStateInterface $form_state) {
|
Chris@18
|
180 $form_object = $form_state->getFormObject();
|
Chris@18
|
181 if ($form_object->getOperation() === 'add') {
|
Chris@18
|
182 $type = $form_object->getEntity();
|
Chris@18
|
183 $form_display_created = _media_library_configure_form_display($type);
|
Chris@18
|
184 $view_display_created = _media_library_configure_view_display($type);
|
Chris@18
|
185 if ($form_display_created || $view_display_created) {
|
Chris@18
|
186 \Drupal::messenger()->addStatus(t('Media Library form and view displays have been created for the %type media type.', [
|
Chris@18
|
187 '%type' => $type->label(),
|
Chris@18
|
188 ]));
|
Chris@17
|
189 }
|
Chris@17
|
190 }
|
Chris@17
|
191 }
|
Chris@17
|
192
|
Chris@17
|
193 /**
|
Chris@17
|
194 * Implements hook_field_ui_preconfigured_options_alter().
|
Chris@17
|
195 */
|
Chris@17
|
196 function media_library_field_ui_preconfigured_options_alter(array &$options, $field_type) {
|
Chris@17
|
197 // If the field is not an "entity_reference"-based field, bail out.
|
Chris@17
|
198 $class = \Drupal::service('plugin.manager.field.field_type')->getPluginClass($field_type);
|
Chris@17
|
199 if (!is_a($class, EntityReferenceItem::class, TRUE)) {
|
Chris@17
|
200 return;
|
Chris@17
|
201 }
|
Chris@17
|
202
|
Chris@17
|
203 // Set the default field widget for media to be the Media library.
|
Chris@17
|
204 if (!empty($options['media'])) {
|
Chris@17
|
205 $options['media']['entity_form_display']['type'] = 'media_library_widget';
|
Chris@17
|
206 }
|
Chris@17
|
207 }
|
Chris@17
|
208
|
Chris@17
|
209 /**
|
Chris@17
|
210 * Implements hook_local_tasks_alter().
|
Chris@17
|
211 *
|
Chris@17
|
212 * Removes tasks for the Media library if the view display no longer exists.
|
Chris@17
|
213 */
|
Chris@17
|
214 function media_library_local_tasks_alter(&$local_tasks) {
|
Chris@17
|
215 /** @var \Symfony\Component\Routing\RouteCollection $route_collection */
|
Chris@17
|
216 $route_collection = \Drupal::service('router')->getRouteCollection();
|
Chris@17
|
217 foreach (['media_library.grid', 'media_library.table'] as $key) {
|
Chris@17
|
218 if (isset($local_tasks[$key]) && !$route_collection->get($local_tasks[$key]['route_name'])) {
|
Chris@17
|
219 unset($local_tasks[$key]);
|
Chris@17
|
220 }
|
Chris@17
|
221 }
|
Chris@17
|
222 }
|
Chris@17
|
223
|
Chris@17
|
224 /**
|
Chris@18
|
225 * Implements hook_ENTITY_TYPE_access().
|
Chris@18
|
226 */
|
Chris@18
|
227 function media_library_image_style_access(EntityInterface $entity, $operation, AccountInterface $account) {
|
Chris@18
|
228 // Prevent the fallback 'media_library' image style from being deleted.
|
Chris@18
|
229 // @todo: Lock the image style instead of preventing delete access.
|
Chris@18
|
230 // https://www.drupal.org/project/drupal/issues/2247293
|
Chris@18
|
231 if ($operation === 'delete' && $entity->id() === 'media_library') {
|
Chris@18
|
232 return AccessResult::forbidden();
|
Chris@18
|
233 }
|
Chris@18
|
234 }
|
Chris@18
|
235
|
Chris@18
|
236 /**
|
Chris@18
|
237 * Ensures that the given media type has a media_library form display.
|
Chris@17
|
238 *
|
Chris@18
|
239 * @param \Drupal\media\MediaTypeInterface $type
|
Chris@18
|
240 * The media type to configure.
|
Chris@18
|
241 *
|
Chris@18
|
242 * @return bool
|
Chris@18
|
243 * Whether a form display has been created or not.
|
Chris@18
|
244 *
|
Chris@18
|
245 * @throws \Drupal\Core\Entity\EntityStorageException
|
Chris@17
|
246 */
|
Chris@18
|
247 function _media_library_configure_form_display(MediaTypeInterface $type) {
|
Chris@18
|
248 $display = EntityFormDisplay::load('media.' . $type->id() . '.media_library');
|
Chris@18
|
249
|
Chris@18
|
250 if ($display) {
|
Chris@18
|
251 return FALSE;
|
Chris@17
|
252 }
|
Chris@18
|
253
|
Chris@18
|
254 $values = [
|
Chris@18
|
255 'targetEntityType' => 'media',
|
Chris@18
|
256 'bundle' => $type->id(),
|
Chris@18
|
257 'mode' => 'media_library',
|
Chris@18
|
258 'status' => TRUE,
|
Chris@18
|
259 ];
|
Chris@18
|
260 $display = EntityFormDisplay::create($values);
|
Chris@18
|
261 // Remove all default components.
|
Chris@18
|
262 foreach (array_keys($display->getComponents()) as $name) {
|
Chris@18
|
263 $display->removeComponent($name);
|
Chris@18
|
264 }
|
Chris@18
|
265 // Expose the name field when it is not mapped.
|
Chris@18
|
266 $field_map = $type->getFieldMap();
|
Chris@18
|
267 if (empty($field_map['name'])) {
|
Chris@18
|
268 $display->setComponent('name', [
|
Chris@18
|
269 'type' => 'string_textfield',
|
Chris@18
|
270 'settings' => [
|
Chris@18
|
271 'size' => 60,
|
Chris@18
|
272 ],
|
Chris@18
|
273 ]);
|
Chris@18
|
274 }
|
Chris@18
|
275 // If the source field is an image field, expose it so that users can set alt
|
Chris@18
|
276 // and title text.
|
Chris@18
|
277 $source_field = $type->getSource()->getSourceFieldDefinition($type);
|
Chris@18
|
278 if ($source_field->isDisplayConfigurable('form') && is_a($source_field->getItemDefinition()->getClass(), ImageItem::class, TRUE)) {
|
Chris@18
|
279 $type->getSource()->prepareFormDisplay($type, $display);
|
Chris@18
|
280 }
|
Chris@18
|
281 return (bool) $display->save();
|
Chris@17
|
282 }
|
Chris@18
|
283
|
Chris@18
|
284 /**
|
Chris@18
|
285 * Ensures that the given media type has a media_library view display.
|
Chris@18
|
286 *
|
Chris@18
|
287 * @param \Drupal\media\MediaTypeInterface $type
|
Chris@18
|
288 * The media type to configure.
|
Chris@18
|
289 *
|
Chris@18
|
290 * @return bool
|
Chris@18
|
291 * Whether a view display has been created or not.
|
Chris@18
|
292 *
|
Chris@18
|
293 * @throws \Drupal\Core\Entity\EntityStorageException
|
Chris@18
|
294 */
|
Chris@18
|
295 function _media_library_configure_view_display(MediaTypeInterface $type) {
|
Chris@18
|
296 $display = EntityViewDisplay::load('media.' . $type->id() . '.media_library');
|
Chris@18
|
297
|
Chris@18
|
298 if ($display) {
|
Chris@18
|
299 return FALSE;
|
Chris@18
|
300 }
|
Chris@18
|
301
|
Chris@18
|
302 $values = [
|
Chris@18
|
303 'targetEntityType' => 'media',
|
Chris@18
|
304 'bundle' => $type->id(),
|
Chris@18
|
305 'mode' => 'media_library',
|
Chris@18
|
306 'status' => TRUE,
|
Chris@18
|
307 ];
|
Chris@18
|
308 $display = EntityViewDisplay::create($values);
|
Chris@18
|
309 // Remove all default components.
|
Chris@18
|
310 foreach (array_keys($display->getComponents()) as $name) {
|
Chris@18
|
311 $display->removeComponent($name);
|
Chris@18
|
312 }
|
Chris@18
|
313
|
Chris@18
|
314 // @todo: Remove dependency on 'medium' and 'thumbnail' image styles from
|
Chris@18
|
315 // media and media library modules.
|
Chris@18
|
316 // https://www.drupal.org/project/drupal/issues/3030437
|
Chris@18
|
317 $image_style = ImageStyle::load('medium');
|
Chris@18
|
318
|
Chris@18
|
319 // Expose the thumbnail component. If the medium image style doesn't exist,
|
Chris@18
|
320 // use the fallback 'media_library' image style.
|
Chris@18
|
321 $display->setComponent('thumbnail', [
|
Chris@18
|
322 'type' => 'image',
|
Chris@18
|
323 'label' => 'hidden',
|
Chris@18
|
324 'settings' => [
|
Chris@18
|
325 'image_style' => $image_style ? $image_style->id() : 'media_library',
|
Chris@18
|
326 'image_link' => '',
|
Chris@18
|
327 ],
|
Chris@18
|
328 ]);
|
Chris@18
|
329 return (bool) $display->save();
|
Chris@18
|
330 }
|