PageRenderTime 27ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/web/core/modules/media_library/src/MediaLibraryUiBuilder.php

https://gitlab.com/mohamed_hussein/prodt
PHP | 353 lines | 178 code | 36 blank | 139 comment | 11 complexity | 3600964bfb2b1a7455833e9c27921cb6 MD5 | raw file
  1. <?php
  2. namespace Drupal\media_library;
  3. use Drupal\Core\Access\AccessResult;
  4. use Drupal\Core\Form\FormBuilderInterface;
  5. use Drupal\Core\Form\FormState;
  6. use Drupal\Core\Entity\EntityTypeManagerInterface;
  7. use Drupal\Core\Session\AccountInterface;
  8. use Drupal\Core\StringTranslation\StringTranslationTrait;
  9. use Drupal\Core\Url;
  10. use Drupal\views\ViewExecutableFactory;
  11. use Symfony\Component\HttpFoundation\RequestStack;
  12. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  13. /**
  14. * Service which builds the media library.
  15. *
  16. * @internal
  17. * This service is an internal part of the modal media library dialog and
  18. * does not provide any extension points.
  19. */
  20. class MediaLibraryUiBuilder {
  21. use StringTranslationTrait;
  22. /**
  23. * The form builder.
  24. *
  25. * @var \Drupal\Core\Form\FormBuilderInterface
  26. */
  27. protected $formBuilder;
  28. /**
  29. * The entity type manager.
  30. *
  31. * @var \Drupal\Core\Entity\EntityTypeManagerInterface
  32. */
  33. protected $entityTypeManager;
  34. /**
  35. * The currently active request object.
  36. *
  37. * @var \Symfony\Component\HttpFoundation\Request
  38. */
  39. protected $request;
  40. /**
  41. * The views executable factory.
  42. *
  43. * @var \Drupal\views\ViewExecutableFactory
  44. */
  45. protected $viewsExecutableFactory;
  46. /**
  47. * The media library opener resolver.
  48. *
  49. * @var \Drupal\media_library\OpenerResolverInterface
  50. */
  51. protected $openerResolver;
  52. /**
  53. * Constructs a MediaLibraryUiBuilder instance.
  54. *
  55. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
  56. * The entity type manager.
  57. * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
  58. * The request stack.
  59. * @param \Drupal\views\ViewExecutableFactory $views_executable_factory
  60. * The views executable factory.
  61. * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
  62. * The currently active request object.
  63. * @param \Drupal\media_library\OpenerResolverInterface $opener_resolver
  64. * The opener resolver.
  65. */
  66. public function __construct(EntityTypeManagerInterface $entity_type_manager, RequestStack $request_stack, ViewExecutableFactory $views_executable_factory, FormBuilderInterface $form_builder, OpenerResolverInterface $opener_resolver) {
  67. $this->entityTypeManager = $entity_type_manager;
  68. $this->request = $request_stack->getCurrentRequest();
  69. $this->viewsExecutableFactory = $views_executable_factory;
  70. $this->formBuilder = $form_builder;
  71. $this->openerResolver = $opener_resolver;
  72. }
  73. /**
  74. * Get media library dialog options.
  75. *
  76. * @return array
  77. * The media library dialog options.
  78. */
  79. public static function dialogOptions() {
  80. return [
  81. 'dialogClass' => 'media-library-widget-modal',
  82. 'title' => t('Add or select media'),
  83. 'height' => '75%',
  84. 'width' => '75%',
  85. ];
  86. }
  87. /**
  88. * Build the media library UI.
  89. *
  90. * @param \Drupal\media_library\MediaLibraryState $state
  91. * (optional) The current state of the media library, derived from the
  92. * current request.
  93. *
  94. * @return array
  95. * The render array for the media library.
  96. */
  97. public function buildUi(MediaLibraryState $state = NULL) {
  98. if (!$state) {
  99. $state = MediaLibraryState::fromRequest($this->request);
  100. }
  101. // When navigating to a media type through the vertical tabs, we only want
  102. // to load the changed library content. This is not only more efficient, but
  103. // also provides a more accessible user experience for screen readers.
  104. if ($state->get('media_library_content') === '1') {
  105. return $this->buildLibraryContent($state);
  106. }
  107. else {
  108. return [
  109. '#theme' => 'media_library_wrapper',
  110. '#attributes' => [
  111. 'id' => 'media-library-wrapper',
  112. ],
  113. 'menu' => $this->buildMediaTypeMenu($state),
  114. 'content' => $this->buildLibraryContent($state),
  115. // Attach the JavaScript for the media library UI. The number of
  116. // available slots needs to be added to make sure users can't select
  117. // more items than allowed.
  118. '#attached' => [
  119. 'library' => ['media_library/ui'],
  120. 'drupalSettings' => [
  121. 'media_library' => [
  122. 'selection_remaining' => $state->getAvailableSlots(),
  123. ],
  124. ],
  125. ],
  126. ];
  127. }
  128. }
  129. /**
  130. * Build the media library content area.
  131. *
  132. * @param \Drupal\media_library\MediaLibraryState $state
  133. * The current state of the media library, derived from the current request.
  134. *
  135. * @return array
  136. * The render array for the media library.
  137. */
  138. protected function buildLibraryContent(MediaLibraryState $state) {
  139. return [
  140. '#type' => 'container',
  141. '#theme_wrappers' => [
  142. 'container__media_library_content',
  143. ],
  144. '#attributes' => [
  145. 'id' => 'media-library-content',
  146. ],
  147. 'form' => $this->buildMediaTypeAddForm($state),
  148. 'view' => $this->buildMediaLibraryView($state),
  149. ];
  150. }
  151. /**
  152. * Check access to the media library.
  153. *
  154. * @param \Drupal\Core\Session\AccountInterface $account
  155. * Run access checks for this account.
  156. * @param \Drupal\media_library\MediaLibraryState $state
  157. * (optional) The current state of the media library, derived from the
  158. * current request.
  159. *
  160. * @return \Drupal\Core\Access\AccessResult
  161. * The access result.
  162. */
  163. public function checkAccess(AccountInterface $account, MediaLibraryState $state = NULL) {
  164. if (!$state) {
  165. try {
  166. $state = MediaLibraryState::fromRequest($this->request);
  167. }
  168. catch (BadRequestHttpException $e) {
  169. return AccessResult::forbidden($e->getMessage());
  170. }
  171. catch (\InvalidArgumentException $e) {
  172. return AccessResult::forbidden($e->getMessage());
  173. }
  174. }
  175. // Deny access if the view or display are removed.
  176. $view = $this->entityTypeManager->getStorage('view')->load('media_library');
  177. if (!$view) {
  178. return AccessResult::forbidden('The media library view does not exist.')
  179. ->setCacheMaxAge(0);
  180. }
  181. if (!$view->getDisplay('widget')) {
  182. return AccessResult::forbidden('The media library widget display does not exist.')
  183. ->addCacheableDependency($view);
  184. }
  185. // The user must at least be able to view media in order to access the media
  186. // library.
  187. $can_view_media = AccessResult::allowedIfHasPermission($account, 'view media')
  188. ->addCacheableDependency($view);
  189. // Delegate any further access checking to the opener service nominated by
  190. // the media library state.
  191. return $this->openerResolver->get($state)->checkAccess($state, $account)
  192. ->andIf($can_view_media);
  193. }
  194. /**
  195. * Get the media type menu for the media library.
  196. *
  197. * @param \Drupal\media_library\MediaLibraryState $state
  198. * The current state of the media library, derived from the current request.
  199. *
  200. * @return array
  201. * The render array for the media type menu.
  202. */
  203. protected function buildMediaTypeMenu(MediaLibraryState $state) {
  204. // Add the menu for each type if we have more than 1 media type enabled for
  205. // the field.
  206. $allowed_type_ids = $state->getAllowedTypeIds();
  207. if (count($allowed_type_ids) <= 1) {
  208. return [];
  209. }
  210. // @todo Add a class to the li element.
  211. // https://www.drupal.org/project/drupal/issues/3029227
  212. $menu = [
  213. '#theme' => 'links__media_library_menu',
  214. '#links' => [],
  215. '#attributes' => [
  216. 'class' => ['js-media-library-menu'],
  217. ],
  218. ];
  219. $allowed_types = $this->entityTypeManager->getStorage('media_type')->loadMultiple($allowed_type_ids);
  220. $selected_type_id = $state->getSelectedTypeId();
  221. foreach ($allowed_types as $allowed_type_id => $allowed_type) {
  222. $link_state = MediaLibraryState::create($state->getOpenerId(), $state->getAllowedTypeIds(), $allowed_type_id, $state->getAvailableSlots(), $state->getOpenerParameters());
  223. // Add the 'media_library_content' parameter so the response will contain
  224. // only the updated content for the tab.
  225. // @see self::buildUi()
  226. $link_state->set('media_library_content', 1);
  227. $title = $allowed_type->label();
  228. $display_title = [
  229. '#markup' => $this->t('<span class="visually-hidden">Show </span>@title<span class="visually-hidden"> media</span>', ['@title' => $title]),
  230. ];
  231. if ($allowed_type_id === $selected_type_id) {
  232. $display_title = [
  233. '#markup' => $this->t('<span class="visually-hidden">Show </span>@title<span class="visually-hidden"> media</span><span class="active-tab visually-hidden"> (selected)</span>', ['@title' => $title]),
  234. ];
  235. }
  236. $menu['#links']['media-library-menu-' . $allowed_type_id] = [
  237. 'title' => $display_title,
  238. 'url' => Url::fromRoute('media_library.ui', [], [
  239. 'query' => $link_state->all(),
  240. ]),
  241. 'attributes' => [
  242. 'role' => 'button',
  243. 'data-title' => $title,
  244. ],
  245. ];
  246. }
  247. // Set the active menu item.
  248. $menu['#links']['media-library-menu-' . $selected_type_id]['attributes']['class'][] = 'active';
  249. return $menu;
  250. }
  251. /**
  252. * Get the add form for the selected media type.
  253. *
  254. * @param \Drupal\media_library\MediaLibraryState $state
  255. * The current state of the media library, derived from the current request.
  256. *
  257. * @return array
  258. * The render array for the media type add form.
  259. */
  260. protected function buildMediaTypeAddForm(MediaLibraryState $state) {
  261. $selected_type_id = $state->getSelectedTypeId();
  262. $access_handler = $this->entityTypeManager->getAccessControlHandler('media');
  263. $context = [
  264. 'media_library_state' => $state,
  265. ];
  266. if (!$access_handler->createAccess($selected_type_id, NULL, $context)) {
  267. return [];
  268. }
  269. $selected_type = $this->entityTypeManager->getStorage('media_type')->load($selected_type_id);
  270. $plugin_definition = $selected_type->getSource()->getPluginDefinition();
  271. if (empty($plugin_definition['forms']['media_library_add'])) {
  272. return [];
  273. }
  274. // After the form to add new media is submitted, we need to rebuild the
  275. // media library with a new instance of the media add form. The form API
  276. // allows us to do that by forcing empty user input.
  277. // @see \Drupal\Core\Form\FormBuilder::doBuildForm()
  278. $form_state = new FormState();
  279. if ($state->get('_media_library_form_rebuild')) {
  280. $form_state->setUserInput([]);
  281. $state->remove('_media_library_form_rebuild');
  282. }
  283. $form_state->set('media_library_state', $state);
  284. return $this->formBuilder->buildForm($plugin_definition['forms']['media_library_add'], $form_state);
  285. }
  286. /**
  287. * Get the media library view.
  288. *
  289. * @param \Drupal\media_library\MediaLibraryState $state
  290. * The current state of the media library, derived from the current request.
  291. *
  292. * @return array
  293. * The render array for the media library view.
  294. */
  295. protected function buildMediaLibraryView(MediaLibraryState $state) {
  296. // @todo Make the view configurable in
  297. // https://www.drupal.org/project/drupal/issues/2971209
  298. $view = $this->entityTypeManager->getStorage('view')->load('media_library');
  299. $view_executable = $this->viewsExecutableFactory->get($view);
  300. $display_id = $state->get('views_display_id', 'widget');
  301. // Make sure the state parameters are set in the request so the view can
  302. // pass the parameters along in the pager, filters etc.
  303. $view_request = $view_executable->getRequest();
  304. $view_request->query->add($state->all());
  305. $view_executable->setRequest($view_request);
  306. $args = [$state->getSelectedTypeId()];
  307. // Make sure the state parameters are set in the request so the view can
  308. // pass the parameters along in the pager, filters etc.
  309. $request = $view_executable->getRequest();
  310. $request->query->add($state->all());
  311. $view_executable->setRequest($request);
  312. $view_executable->setDisplay($display_id);
  313. $view_executable->preExecute($args);
  314. $view_executable->execute($display_id);
  315. return $view_executable->buildRenderable($display_id, $args, FALSE);
  316. }
  317. }