Пример #1
0
 /**
  * {@inheritdoc}
  */
 public function getVisibleBlocksPerRegion(array &$cacheable_metadata = [])
 {
     $active_theme = $this->themeManager->getActiveTheme();
     // Build an array of the region names in the right order.
     $empty = array_fill_keys($active_theme->getRegions(), array());
     $full = array();
     foreach ($this->blockStorage->loadByProperties(array('theme' => $active_theme->getName())) as $block_id => $block) {
         /** @var \Drupal\block\BlockInterface $block */
         $access = $block->access('view', NULL, TRUE);
         $region = $block->getRegion();
         if (!isset($cacheable_metadata[$region])) {
             $cacheable_metadata[$region] = CacheableMetadata::createFromObject($access);
         } else {
             $cacheable_metadata[$region] = $cacheable_metadata[$region]->merge(CacheableMetadata::createFromObject($access));
         }
         // Set the contexts on the block before checking access.
         if ($access->isAllowed()) {
             $full[$region][$block_id] = $block;
         }
     }
     // Merge it with the actual values to maintain the region ordering.
     $assignments = array_intersect_key(array_merge($empty, $full), $empty);
     foreach ($assignments as &$assignment) {
         // Suppress errors because PHPUnit will indirectly modify the contents,
         // triggering https://bugs.php.net/bug.php?id=50688.
         @uasort($assignment, 'Drupal\\block\\Entity\\Block::sort');
     }
     return $assignments;
 }
Пример #2
0
 /**
  * Creates a bubbleable metadata object from a depended object.
  *
  * @param \Drupal\Core\Cache\CacheableDependencyInterface|mixed $object
  *   The object whose cacheability metadata to retrieve. If it implements
  *   CacheableDependencyInterface, its cacheability metadata will be used,
  *   otherwise, the passed in object must be assumed to be uncacheable, so
  *   max-age 0 is set.
  *
  * @return static
  */
 public static function createFromObject($object)
 {
     $meta = parent::createFromObject($object);
     if ($object instanceof AttachmentsInterface) {
         $meta->attachments = $object->getAttachments();
     }
     return $meta;
 }
 /**
  * {@inheritdoc}
  */
 public function buildSelectorForm(array $form, FormStateInterface $form_state)
 {
     $form = parent::buildSelectorForm($form, $form_state);
     $available_plugins = [];
     $cacheability_metadata = CacheableMetadata::createFromRenderArray($form);
     foreach (array_keys($this->selectablePluginDiscovery->getDefinitions()) as $plugin_id) {
         $available_plugin = $this->selectablePluginFactory->createInstance($plugin_id);
         $available_plugins[] = $available_plugin;
         $cacheability_metadata = $cacheability_metadata->merge(CacheableMetadata::createFromObject($available_plugin));
     }
     $cacheability_metadata->applyTo($form);
     $plugin_selector_form_state_key = static::setPluginSelector($form_state, $this);
     $form['container'] = array('#attributes' => array('class' => array('plugin-selector-' . Html::getClass($this->getPluginId()))), '#available_plugins' => $available_plugins, '#plugin_selector_form_state_key' => $plugin_selector_form_state_key, '#process' => [[get_class(), 'processBuildSelectorForm']], '#tree' => TRUE, '#type' => 'container');
     return $form;
 }
 /**
  * Returns the referenced entities for display.
  *
  * The method takes care of:
  * - checking entity access,
  * - placing the entities in the language expected for display.
  * It is thus strongly recommended that formatters use it in their
  * implementation of viewElements($items) rather than dealing with $items
  * directly.
  *
  * For each entity, the EntityReferenceItem by which the entity is referenced
  * is available in $entity->_referringItem. This is useful for field types
  * that store additional values next to the reference itself.
  *
  * @param \Drupal\Core\Field\EntityReferenceFieldItemListInterface $items
  *   The item list.
  * @param string $langcode
  *   The language code of the referenced entities to display.
  *
  * @return \Drupal\Core\Entity\EntityInterface[]
  *   The array of referenced entities to display, keyed by delta.
  *
  * @see ::prepareView()
  */
 protected function getEntitiesToView(EntityReferenceFieldItemListInterface $items, $langcode)
 {
     $entities = array();
     foreach ($items as $delta => $item) {
         // Ignore items where no entity could be loaded in prepareView().
         if (!empty($item->_loaded)) {
             $entity = $item->entity;
             // Set the entity in the correct language for display.
             if ($entity instanceof TranslatableInterface) {
                 $entity = \Drupal::entityManager()->getTranslationFromContext($entity, $langcode);
             }
             $access = $this->checkAccess($entity);
             // Add the access result's cacheability, ::view() needs it.
             $item->_accessCacheability = CacheableMetadata::createFromObject($access);
             if ($access->isAllowed()) {
                 // Add the referring item, in case the formatter needs it.
                 $entity->_referringItem = $items[$delta];
                 $entities[$delta] = $entity;
             }
         }
     }
     return $entities;
 }
Пример #5
0
 /**
  * @covers ::createFromObject
  * @dataProvider providerTestCreateFromObject
  */
 public function testCreateFromObject($object, CacheableMetadata $expected)
 {
     $this->assertEquals($expected, CacheableMetadata::createFromObject($object));
 }
Пример #6
0
 /**
  * Builds the #items property for a menu tree's renderable array.
  *
  * Helper function for ::build().
  *
  * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
  *   A data structure representing the tree, as returned from
  *   MenuLinkTreeInterface::load().
  * @param \Drupal\Core\Cache\CacheableMetadata &$tree_access_cacheability
  *   Internal use only. The aggregated cacheability metadata for the access
  *   results across the entire tree. Used when rendering the root level.
  * @param \Drupal\Core\Cache\CacheableMetadata &$tree_link_cacheability
  *   Internal use only. The aggregated cacheability metadata for the menu
  *   links across the entire tree. Used when rendering the root level.
  *
  * @return array
  *   The value to use for the #items property of a renderable menu.
  *
  * @throws \DomainException
  */
 protected function buildItems(array $tree, CacheableMetadata &$tree_access_cacheability, CacheableMetadata &$tree_link_cacheability)
 {
     $items = array();
     foreach ($tree as $data) {
         /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
         $link = $data->link;
         // Generally we only deal with visible links, but just in case.
         if (!$link->isEnabled()) {
             continue;
         }
         if ($data->access !== NULL && !$data->access instanceof AccessResultInterface) {
             throw new \DomainException('MenuLinkTreeElement::access must be either NULL or an AccessResultInterface object.');
         }
         // Gather the access cacheability of every item in the menu link tree,
         // including inaccessible items. This allows us to render cache the menu
         // tree, yet still automatically vary the rendered menu by the same cache
         // contexts that the access results vary by.
         // However, if $data->access is not an AccessResultInterface object, this
         // will still render the menu link, because this method does not want to
         // require access checking to be able to render a menu tree.
         if ($data->access instanceof AccessResultInterface) {
             $tree_access_cacheability = $tree_access_cacheability->merge(CacheableMetadata::createFromObject($data->access));
         }
         // Gather the cacheability of every item in the menu link tree. Some links
         // may be dynamic: they may have a dynamic text (e.g. a "Hi, <user>" link
         // text, which would vary by 'user' cache context), or a dynamic route
         // name or route parameters.
         $tree_link_cacheability = $tree_link_cacheability->merge(CacheableMetadata::createFromObject($data->link));
         // Only render accessible links.
         if ($data->access instanceof AccessResultInterface && !$data->access->isAllowed()) {
             continue;
         }
         $element = [];
         // Set a variable for the <li> tag. Only set 'expanded' to true if the
         // link also has visible children within the current tree.
         $element['is_expanded'] = FALSE;
         $element['is_collapsed'] = FALSE;
         if ($data->hasChildren && !empty($data->subtree)) {
             $element['is_expanded'] = TRUE;
         } elseif ($data->hasChildren) {
             $element['is_collapsed'] = TRUE;
         }
         // Set a helper variable to indicate whether the link is in the active
         // trail.
         $element['in_active_trail'] = FALSE;
         if ($data->inActiveTrail) {
             $element['in_active_trail'] = TRUE;
         }
         // Note: links are rendered in the menu.html.twig template; and they
         // automatically bubble their associated cacheability metadata.
         $element['attributes'] = new Attribute();
         $element['title'] = $link->getTitle();
         $element['url'] = $link->getUrlObject();
         $element['url']->setOption('set_active_class', TRUE);
         $element['below'] = $data->subtree ? $this->buildItems($data->subtree, $tree_access_cacheability, $tree_link_cacheability) : array();
         if (isset($data->options)) {
             $element['url']->setOptions(NestedArray::mergeDeep($element['url']->getOptions(), $data->options));
         }
         $element['original_link'] = $link;
         // Index using the link's unique ID.
         $items[$link->getPluginId()] = $element;
     }
     return $items;
 }
Пример #7
0
 /**
  * {@inheritdoc}
  */
 public function addCacheableDependency(array &$elements, $dependency)
 {
     $meta_a = CacheableMetadata::createFromRenderArray($elements);
     $meta_b = CacheableMetadata::createFromObject($dependency);
     $meta_a->merge($meta_b)->applyTo($elements);
 }
 /**
  * Embeds a Response object in a render array so that RenderCache can cache it.
  *
  * @param \Drupal\Core\Cache\CacheableResponseInterface $response
  *   A cacheable response.
  *
  * @return array
  *   A render array that embeds the given cacheable response object, with the
  *   cacheability metadata of the response object present in the #cache
  *   property of the render array.
  *
  * @see renderArrayToResponse()
  *
  * @todo Refactor/remove once https://www.drupal.org/node/2551419 lands.
  */
 protected function responseToRenderArray(CacheableResponseInterface $response)
 {
     $response_as_render_array = $this->dynamicPageCacheRedirectRenderArray + ['#response' => $response, '#cache_properties' => ['#response'], '#markup' => '', '#attached' => ''];
     // Merge the response's cacheability metadata, so that RenderCache can take
     // care of cache redirects for us.
     CacheableMetadata::createFromObject($response->getCacheableMetadata())->merge(CacheableMetadata::createFromRenderArray($response_as_render_array))->applyTo($response_as_render_array);
     return $response_as_render_array;
 }
Пример #9
0
 /**
  * {@inheritdoc}
  */
 public function process($text, $langcode)
 {
     $result = new FilterProcessResult($text);
     if (strpos($text, 'data-entity-type') !== FALSE && (strpos($text, 'data-entity-embed-display') !== FALSE || strpos($text, 'data-view-mode') !== FALSE)) {
         $dom = Html::load($text);
         $xpath = new \DOMXPath($dom);
         foreach ($xpath->query('//drupal-entity[@data-entity-type and (@data-entity-uuid or @data-entity-id) and (@data-entity-embed-display or @data-view-mode)]') as $node) {
             /** @var \DOMElement $node */
             $entity_type = $node->getAttribute('data-entity-type');
             $entity = NULL;
             $entity_output = '';
             try {
                 // Load the entity either by UUID (preferred) or ID.
                 $id = $node->getAttribute('data-entity-uuid') ?: $node->getAttribute('data-entity-id');
                 $entity = $this->loadEntity($entity_type, $id);
                 if ($entity) {
                     // Protect ourselves from recursive rendering.
                     static $depth = 0;
                     $depth++;
                     if ($depth > 20) {
                         throw new RecursiveRenderingException(sprintf('Recursive rendering detected when rendering embedded %s entity %s.', $entity_type, $entity->id()));
                     }
                     // If a UUID was not used, but is available, add it to the HTML.
                     if (!$node->getAttribute('data-entity-uuid') && ($uuid = $entity->uuid())) {
                         $node->setAttribute('data-entity-uuid', $uuid);
                     }
                     $access = $entity->access('view', NULL, TRUE);
                     $access_metadata = CacheableMetadata::createFromObject($access);
                     $entity_metadata = CacheableMetadata::createFromObject($entity);
                     $result = $result->merge($entity_metadata)->merge($access_metadata);
                     $context = $this->getNodeAttributesAsArray($node);
                     $context += array('data-langcode' => $langcode);
                     $entity_output = $this->renderEntityEmbed($entity, $context);
                     $depth--;
                 } else {
                     throw new EntityNotFoundException(sprintf('Unable to load embedded %s entity %s.', $entity_type, $id));
                 }
             } catch (\Exception $e) {
                 watchdog_exception('entity_embed', $e);
             }
             $this->replaceNodeContent($node, $entity_output);
         }
         $result->setProcessedText(Html::serialize($dom));
     }
     return $result;
 }
Пример #10
0
 /**
  * {@inheritdoc}
  */
 public function calculateCacheMetadata()
 {
     $cache_metadata = new CacheableMetadata();
     // Iterate over ordinary views plugins.
     foreach (Views::getPluginTypes('plugin') as $plugin_type) {
         $plugin = $this->getPlugin($plugin_type);
         if ($plugin instanceof CacheableDependencyInterface) {
             $cache_metadata = $cache_metadata->merge(CacheableMetadata::createFromObject($plugin));
         }
     }
     // Iterate over all handlers. Note that at least the argument handler will
     // need to ask all its subplugins.
     foreach (array_keys(Views::getHandlerTypes()) as $handler_type) {
         $handlers = $this->getHandlers($handler_type);
         foreach ($handlers as $handler) {
             if ($handler instanceof CacheableDependencyInterface) {
                 $cache_metadata = $cache_metadata->merge(CacheableMetadata::createFromObject($handler));
             }
         }
     }
     /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */
     if ($cache_plugin = $this->getPlugin('cache')) {
         $cache_plugin->alterCacheMetadata($cache_metadata);
     }
     return $cache_metadata;
 }
Пример #11
0
 /**
  * {@inheritdoc}
  */
 public function build()
 {
     /** @var $entity \Drupal\Core\Entity\EntityInterface */
     $entity = $this->getContextValue('entity');
     $view_builder = $this->entityManager->getViewBuilder($entity->getEntityTypeId());
     $build = $view_builder->view($entity, $this->configuration['view_mode']);
     CacheableMetadata::createFromObject($this->getContext('entity'))->applyTo($build);
     return $build;
 }
Пример #12
0
 /**
  * Asserts \Drupal\Core\Routing\UrlGenerator::generateFromRoute()'s output.
  *
  * @param $route_name
  *   The route name to test.
  * @param array $route_parameters
  *   The route parameters to test.
  * @param array $options
  *   The options to test.
  * @param $expected_url
  *   The expected generated URL string.
  * @param \Drupal\Core\Cache\CacheableMetadata $expected_cacheability
  *   The expected generated cacheability metadata.
  */
 protected function assertGenerateFromRoute($route_name, array $route_parameters, array $options, $expected_url, CacheableMetadata $expected_cacheability)
 {
     // First, test with $collect_cacheability_metadata set to the default value.
     $url = $this->generator->generateFromRoute($route_name, $route_parameters, $options);
     $this->assertSame($expected_url, $url);
     // Second, test with it set to TRUE.
     $generated_url = $this->generator->generateFromRoute($route_name, $route_parameters, $options, TRUE);
     $this->assertSame($expected_url, $generated_url->getGeneratedUrl());
     $this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
 }
Пример #13
0
 /**
  * {@inheritdoc}
  */
 public function addCacheableDependency($dependency)
 {
     $this->cacheabilityMetadata = $this->cacheabilityMetadata->merge(CacheableMetadata::createFromObject($dependency));
     return $this;
 }
Пример #14
0
 /**
  * {@inheritdoc}
  */
 protected function doLoadMultiple(array $ids = NULL)
 {
     $prefix = $this->getPrefix();
     // Get the names of the configuration entities we are going to load.
     if ($ids === NULL) {
         $names = $this->configFactory->listAll($prefix);
     } else {
         $names = array();
         foreach ($ids as $id) {
             // Add the prefix to the ID to serve as the configuration object name.
             $names[] = $prefix . $id;
         }
     }
     // Load all of the configuration entities.
     /** @var \Drupal\Core\Config\Config[] $configs */
     $configs = [];
     $records = [];
     foreach ($this->configFactory->loadMultiple($names) as $config) {
         $id = $config->get($this->idKey);
         $records[$id] = $this->overrideFree ? $config->getOriginal(NULL, FALSE) : $config->get();
         $configs[$id] = $config;
     }
     $entities = $this->mapFromStorageRecords($records, $configs);
     // Config entities wrap config objects, and therefore they need to inherit
     // the cacheability metadata of config objects (to ensure e.g. additional
     // cacheability metadata added by config overrides is not lost).
     foreach ($entities as $id => $entity) {
         // But rather than simply inheriting all cacheability metadata of config
         // objects, we need to make sure the self-referring cache tag that is
         // present on Config objects is not added to the Config entity. It must be
         // removed for 3 reasons:
         // 1. When renaming/duplicating a Config entity, the cache tag of the
         //    original config object would remain present, which would be wrong.
         // 2. Some Config entities choose to not use the cache tag that the under-
         //    lying Config object provides by default (For performance and
         //    cacheability reasons it may not make sense to have a unique cache
         //    tag for every Config entity. The DateFormat Config entity specifies
         //    the 'rendered' cache tag for example, because A) date formats are
         //    changed extremely rarely, so invalidating all render cache items is
         //    fine, B) it means fewer cache tags per page.).
         // 3. Fewer cache tags is better for performance.
         $self_referring_cache_tag = ['config:' . $configs[$id]->getName()];
         $config_cacheability = CacheableMetadata::createFromObject($configs[$id]);
         $config_cacheability->setCacheTags(array_diff($config_cacheability->getCacheTags(), $self_referring_cache_tag));
         $entity->addCacheableDependency($config_cacheability);
     }
     return $entities;
 }
Пример #15
0
  /**
   * {@inheritdoc}
   */
  protected function valueForm(&$form, FormStateInterface $form_state) {
    parent::valueForm($form, $form_state);
    // Apply cacheability metadata, because the parent class does not.
    // @todo Remove this once https://www.drupal.org/node/2754103 is fixed.
    $cacheability_metdata = CacheableMetadata::createFromObject($this);
    $cacheability_metdata->applyTo($form);

    return $form;
  }
 /**
  * Build the render array for a single panelized entity.
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  * @param \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant $panels_display
  * @param string $view_mode
  * @param string $langcode
  *
  * @return array
  */
 protected function buildPanelized(EntityInterface $entity, PanelsDisplayVariant $panels_display, $view_mode, $langcode)
 {
     $contexts = $panels_display->getContexts();
     $entity_context = new Context(new ContextDefinition('entity:' . $this->entityTypeId, NULL, TRUE), $entity);
     $contexts['@panelizer.entity_context:' . $this->entityTypeId] = $entity_context;
     $panels_display->setContexts($contexts);
     $build = $panels_display->build();
     // @todo: I'm sure more is necessary to get the cache contexts right...
     CacheableMetadata::createFromObject($entity)->applyTo($build);
     $this->getPanelizerPlugin()->alterBuild($build, $entity, $panels_display, $view_mode);
     return $build;
 }
Пример #17
0
 /**
  * Iterates over all items in the tree to prepare the parents select options.
  *
  * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
  *   The menu tree.
  * @param string $menu_name
  *   The menu name.
  * @param string $indent
  *   The indentation string used for the label.
  * @param array $options
  *   The select options.
  * @param string $exclude
  *   An excluded menu link.
  * @param int $depth_limit
  *   The maximum depth of menu links considered for the select options.
  * @param \Drupal\Core\Cache\CacheableMetadata|NULL &$cacheability
  *   The object to add cacheability metadata to, if not NULL.
  */
 protected function parentSelectOptionsTreeWalk(array $tree, $menu_name, $indent, array &$options, $exclude, $depth_limit, CacheableMetadata &$cacheability = NULL)
 {
     foreach ($tree as $element) {
         if ($element->depth > $depth_limit) {
             // Don't iterate through any links on this level.
             break;
         }
         // Collect the cacheability metadata of the access result, as well as the
         // link.
         if ($cacheability) {
             $cacheability = $cacheability->merge(CacheableMetadata::createFromObject($element->access))->merge(CacheableMetadata::createFromObject($element->link));
         }
         // Only show accessible links.
         if (!$element->access->isAllowed()) {
             continue;
         }
         $link = $element->link;
         if ($link->getPluginId() != $exclude) {
             $title = $indent . ' ' . Unicode::truncate($link->getTitle(), 30, TRUE, FALSE);
             if (!$link->isEnabled()) {
                 $title .= ' (' . $this->t('disabled') . ')';
             }
             $options[$menu_name . ':' . $link->getPluginId()] = $title;
             if (!empty($element->subtree)) {
                 $this->parentSelectOptionsTreeWalk($element->subtree, $menu_name, $indent . '--', $options, $exclude, $depth_limit, $cacheability);
             }
         }
     }
 }
Пример #18
0
 /**
  * {@inheritdoc}
  */
 public function buildRow(EntityInterface $entity)
 {
     $row['username']['data'] = array('#theme' => 'username', '#account' => $entity);
     $row['status'] = $entity->isActive() ? $this->t('active') : $this->t('blocked');
     $roles = user_role_names(TRUE);
     unset($roles[RoleInterface::AUTHENTICATED_ID]);
     $users_roles = array();
     foreach ($entity->getRoles() as $role) {
         if (isset($roles[$role])) {
             $users_roles[] = $roles[$role];
         }
     }
     asort($users_roles);
     $row['roles']['data'] = array('#theme' => 'item_list', '#items' => $users_roles);
     $options = ['return_as_object' => TRUE];
     $row['member_for']['data'] = $this->dateFormatter->formatTimeDiffSince($entity->getCreatedTime(), $options)->toRenderable();
     $last_access = $this->dateFormatter->formatTimeDiffSince($entity->getLastAccessedTime(), $options);
     if ($entity->getLastAccessedTime()) {
         $row['access']['data']['#markup'] = $last_access->getString();
         CacheableMetadata::createFromObject($last_access)->applyTo($row['access']['data']);
     } else {
         $row['access']['data']['#markup'] = t('never');
     }
     return $row + parent::buildRow($entity);
 }
Пример #19
0
 /**
  * {@inheritdoc}
  */
 public function build()
 {
     $config = $this->getConfiguration();
     if (empty($config['required_configuration'])) {
         throw new \Exception('Required configuration is missing!');
     }
     $contexts = $this->getContexts();
     if (!isset($contexts['context'])) {
         throw new \Exception('Required context is missing!');
     }
     $build = [];
     $build['content']['default'] = ['#markup' => $config['required_configuration'] . ' ' . $contexts['context']->getContextValue()];
     CacheableMetadata::createFromObject($this)->applyTo($build);
     return $build;
 }
Пример #20
0
 /**
  * Formats a date/time as a time interval.
  *
  * @param \Drupal\Core\Datetime\DrupalDateTime|object $date
  *   A date/time object.
  *
  * @return array
  *   The formatted date/time string using the past or future format setting.
  */
 protected function formatDate(DrupalDateTime $date)
 {
     $granularity = $this->getSetting('granularity');
     $timestamp = $date->getTimestamp();
     $options = ['granularity' => $granularity, 'return_as_object' => TRUE];
     if ($this->request->server->get('REQUEST_TIME') > $timestamp) {
         $result = $this->dateFormatter->formatTimeDiffSince($timestamp, $options);
         $build = ['#markup' => SafeMarkup::format($this->getSetting('past_format'), ['@interval' => $result->getString()])];
     } else {
         $result = $this->dateFormatter->formatTimeDiffUntil($timestamp, $options);
         $build = ['#markup' => SafeMarkup::format($this->getSetting('future_format'), ['@interval' => $result->getString()])];
     }
     CacheableMetadata::createFromObject($result)->applyTo($build);
     return $build;
 }
Пример #21
0
 /**
  * Recursive helper function for buildOverviewForm().
  *
  * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
  *   The tree retrieved by \Drupal\Core\Menu\MenuLinkTreeInterface::load().
  * @param int $delta
  *   The default number of menu items used in the menu weight selector is 50.
  *
  * @return array
  *   The overview tree form.
  */
 protected function buildOverviewTreeForm($tree, $delta)
 {
     $form =& $this->overviewTreeForm;
     $tree_access_cacheability = new CacheableMetadata();
     foreach ($tree as $element) {
         $tree_access_cacheability = $tree_access_cacheability->merge(CacheableMetadata::createFromObject($element->access));
         // Only render accessible links.
         if (!$element->access->isAllowed()) {
             continue;
         }
         /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
         $link = $element->link;
         if ($link) {
             $id = 'menu_plugin_id:' . $link->getPluginId();
             $form[$id]['#item'] = $element;
             $form[$id]['#attributes'] = $link->isEnabled() ? array('class' => array('menu-enabled')) : array('class' => array('menu-disabled'));
             $form[$id]['title'] = Link::fromTextAndUrl($link->getTitle(), $link->getUrlObject())->toRenderable();
             if (!$link->isEnabled()) {
                 $form[$id]['title']['#suffix'] = ' (' . $this->t('disabled') . ')';
             } elseif (($url = $link->getUrlObject()) && $url->isRouted() && $url->getRouteName() == 'user.page') {
                 $form[$id]['title']['#suffix'] = ' (' . $this->t('logged in users only') . ')';
             }
             $form[$id]['enabled'] = array('#type' => 'checkbox', '#title' => $this->t('Enable @title menu link', array('@title' => $link->getTitle())), '#title_display' => 'invisible', '#default_value' => $link->isEnabled());
             $form[$id]['weight'] = array('#type' => 'weight', '#delta' => $delta, '#default_value' => $link->getWeight(), '#title' => $this->t('Weight for @title', array('@title' => $link->getTitle())), '#title_display' => 'invisible');
             $form[$id]['id'] = array('#type' => 'hidden', '#value' => $link->getPluginId());
             $form[$id]['parent'] = array('#type' => 'hidden', '#default_value' => $link->getParent());
             // Build a list of operations.
             $operations = array();
             $operations['edit'] = array('title' => $this->t('Edit'));
             // Allow for a custom edit link per plugin.
             $edit_route = $link->getEditRoute();
             if ($edit_route) {
                 $operations['edit']['url'] = $edit_route;
                 // Bring the user back to the menu overview.
                 $operations['edit']['query'] = $this->getDestinationArray();
             } else {
                 // Fall back to the standard edit link.
                 $operations['edit'] += array('url' => Url::fromRoute('menu_ui.link_edit', ['menu_link_plugin' => $link->getPluginId()]));
             }
             // Links can either be reset or deleted, not both.
             if ($link->isResettable()) {
                 $operations['reset'] = array('title' => $this->t('Reset'), 'url' => Url::fromRoute('menu_ui.link_reset', ['menu_link_plugin' => $link->getPluginId()]));
             } elseif ($delete_link = $link->getDeleteRoute()) {
                 $operations['delete']['url'] = $delete_link;
                 $operations['delete']['query'] = $this->getDestinationArray();
                 $operations['delete']['title'] = $this->t('Delete');
             }
             if ($link->isTranslatable()) {
                 $operations['translate'] = array('title' => $this->t('Translate'), 'url' => $link->getTranslateRoute());
             }
             $form[$id]['operations'] = array('#type' => 'operations', '#links' => $operations);
         }
         if ($element->subtree) {
             $this->buildOverviewTreeForm($element->subtree, $delta);
         }
     }
     $tree_access_cacheability->merge(CacheableMetadata::createFromRenderArray($form))->applyTo($form);
     return $form;
 }
Пример #22
0
 /**
  * Provide the administration overview page.
  *
  * @param string $link_id
  *   The ID of the administrative path link for which to display child links.
  *
  * @return array
  *   A renderable array of the administration overview page.
  */
 public function overview($link_id)
 {
     // Check for status report errors.
     if ($this->systemManager->checkRequirements() && $this->currentUser()->hasPermission('administer site configuration')) {
         drupal_set_message($this->t('One or more problems were detected with your Drupal installation. Check the <a href="@status">status report</a> for more information.', array('@status' => $this->url('system.status'))), 'error');
     }
     // Load all menu links below it.
     $parameters = new MenuTreeParameters();
     $parameters->setRoot($link_id)->excludeRoot()->setTopLevelOnly()->onlyEnabledLinks();
     $tree = $this->menuLinkTree->load(NULL, $parameters);
     $manipulators = array(array('callable' => 'menu.default_tree_manipulators:checkAccess'), array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'));
     $tree = $this->menuLinkTree->transform($tree, $manipulators);
     $tree_access_cacheability = new CacheableMetadata();
     $blocks = array();
     foreach ($tree as $key => $element) {
         $tree_access_cacheability = $tree_access_cacheability->merge(CacheableMetadata::createFromObject($element->access));
         // Only render accessible links.
         if (!$element->access->isAllowed()) {
             continue;
         }
         $link = $element->link;
         $block['title'] = $link->getTitle();
         $block['description'] = $link->getDescription();
         $block['content'] = array('#theme' => 'admin_block_content', '#content' => $this->systemManager->getAdminBlock($link));
         if (!empty($block['content']['#content'])) {
             $blocks[$key] = $block;
         }
     }
     if ($blocks) {
         ksort($blocks);
         $build = ['#theme' => 'admin_page', '#blocks' => $blocks];
         $tree_access_cacheability->applyTo($build);
         return $build;
     } else {
         $build = ['#markup' => $this->t('You do not have any administrative items.')];
         $tree_access_cacheability->applyTo($build);
         return $build;
     }
 }
 /**
  * Builds the translations overview page.
  *
  * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
  *   The route match.
  * @param string $entity_type_id
  *   (optional) The entity type ID.
  * @return array Array of page elements to render.
  * Array of page elements to render.
  */
 public function overview(RouteMatchInterface $route_match, $entity_type_id = NULL)
 {
     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
     $entity = $route_match->getParameter($entity_type_id);
     $account = $this->currentUser();
     $handler = $this->entityManager()->getHandler($entity_type_id, 'translation');
     $manager = $this->manager;
     $entity_type = $entity->getEntityType();
     // Start collecting the cacheability metadata, starting with the entity and
     // later merge in the access result cacheability metadata.
     $cacheability = CacheableMetadata::createFromObject($entity);
     $languages = $this->languageManager()->getLanguages();
     $original = $entity->getUntranslated()->language()->getId();
     $translations = $entity->getTranslationLanguages();
     $field_ui = $this->moduleHandler()->moduleExists('field_ui') && $account->hasPermission('administer ' . $entity_type_id . ' fields');
     $rows = array();
     $show_source_column = FALSE;
     if ($this->languageManager()->isMultilingual()) {
         // Determine whether the current entity is translatable.
         $translatable = FALSE;
         foreach ($this->entityManager->getFieldDefinitions($entity_type_id, $entity->bundle()) as $instance) {
             if ($instance->isTranslatable()) {
                 $translatable = TRUE;
                 break;
             }
         }
         // Show source-language column if there are non-original source langcodes.
         $additional_source_langcodes = array_filter(array_keys($translations), function ($langcode) use($entity, $original, $manager) {
             $source = $manager->getTranslationMetadata($entity->getTranslation($langcode))->getSource();
             return $source != $original && $source != LanguageInterface::LANGCODE_NOT_SPECIFIED;
         });
         $show_source_column = !empty($additional_source_langcodes);
         foreach ($languages as $language) {
             $language_name = $language->getName();
             $langcode = $language->getId();
             $add_url = new Url("entity.{$entity_type_id}.content_translation_add", array('source' => $original, 'target' => $language->getId(), $entity_type_id => $entity->id()), array('language' => $language));
             $edit_url = new Url("entity.{$entity_type_id}.content_translation_edit", array('language' => $language->getId(), $entity_type_id => $entity->id()), array('language' => $language));
             $delete_url = new Url("entity.{$entity_type_id}.content_translation_delete", array('language' => $language->getId(), $entity_type_id => $entity->id()), array('language' => $language));
             $operations = array('data' => array('#type' => 'operations', '#links' => array()));
             /**
              * allow translator to translate those content that languages are assign to him
              */
             $user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());
             foreach ($user->get('field_language') as $lang) {
                 $access_lang[] = $lang->value;
             }
             foreach ($user->get('roles') as $roles) {
                 $current_user_roles[] = $roles->target_id;
             }
             $isaplied = 0;
             $nolink = 0;
             if (in_array('translator', $current_user_roles) && !in_array('administrator', $current_user_roles)) {
                 $isaplied = 1;
             }
             if (!in_array($langcode, $access_lang)) {
                 $nolink = 1;
             }
             /*
              * end here
              */
             $links =& $operations['data']['#links'];
             if (array_key_exists($langcode, $translations)) {
                 // Existing translation in the translation set: display status.
                 $translation = $entity->getTranslation($langcode);
                 $metadata = $manager->getTranslationMetadata($translation);
                 $source = $metadata->getSource() ?: LanguageInterface::LANGCODE_NOT_SPECIFIED;
                 $is_original = $langcode == $original;
                 $label = $entity->getTranslation($langcode)->label();
                 $link = isset($links->links[$langcode]['url']) ? $links->links[$langcode] : array('url' => $entity->urlInfo());
                 if (!empty($link['url'])) {
                     $link['url']->setOption('language', $language);
                     $row_title = $this->l($label, $link['url']);
                 }
                 if (empty($link['url'])) {
                     $row_title = $is_original ? $label : $this->t('n/a');
                 }
                 // If the user is allowed to edit the entity we point the edit link to
                 // the entity form, otherwise if we are not dealing with the original
                 // language we point the link to the translation form.
                 $update_access = $entity->access('update', NULL, TRUE);
                 $translation_access = $handler->getTranslationAccess($entity, 'update');
                 $cacheability = $cacheability->merge(CacheableMetadata::createFromObject($update_access))->merge(CacheableMetadata::createFromObject($translation_access));
                 if ($update_access->isAllowed() && $entity_type->hasLinkTemplate('edit-form')) {
                     $links['edit']['url'] = $entity->urlInfo('edit-form');
                     $links['edit']['language'] = $language;
                 } elseif (!$is_original && $translation_access->isAllowed()) {
                     $links['edit']['url'] = $edit_url;
                 }
                 if (isset($links['edit'])) {
                     $links['edit']['title'] = $this->t('Edit');
                 }
                 $status = array('data' => array('#type' => 'inline_template', '#template' => '<span class="status">{% if status %}{{ "Published"|t }}{% else %}{{ "Not published"|t }}{% endif %}</span>{% if outdated %} <span class="marker">{{ "outdated"|t }}</span>{% endif %}', '#context' => array('status' => $metadata->isPublished(), 'outdated' => $metadata->isOutdated())));
                 if ($is_original) {
                     $language_name = $this->t('<strong>@language_name (Original language)</strong>', array('@language_name' => $language_name));
                     $source_name = $this->t('n/a');
                 } else {
                     $source_name = isset($languages[$source]) ? $languages[$source]->getName() : $this->t('n/a');
                     $delete_access = $entity->access('delete', NULL, TRUE);
                     $translation_access = $handler->getTranslationAccess($entity, 'delete');
                     $cacheability = $cacheability->merge(CacheableMetadata::createFromObject($delete_access))->merge(CacheableMetadata::createFromObject($translation_access));
                     if ($entity->access('delete') && $entity_type->hasLinkTemplate('delete-form')) {
                         $links['delete'] = array('title' => $this->t('Delete'), 'url' => $entity->urlInfo('delete-form'), 'language' => $language);
                     } elseif ($translation_access->isAllowed()) {
                         $links['delete'] = array('title' => $this->t('Delete'), 'url' => $delete_url);
                     }
                 }
                 /**
                  * empty the translation link for language that are not assign to translator role users
                  */
                 if ($isaplied == 1 && $nolink == 1) {
                     $links = array();
                 }
                 /**
                  *  end here
                  */
             } else {
                 // No such translation in the set yet: help user to create it.
                 $row_title = $source_name = $this->t('n/a');
                 $source = $entity->language()->getId();
                 $create_translation_access = $handler->getTranslationAccess($entity, 'create');
                 $cacheability = $cacheability->merge(CacheableMetadata::createFromObject($create_translation_access));
                 if ($source != $langcode && $create_translation_access->isAllowed()) {
                     if ($translatable) {
                         $links['add'] = array('title' => $this->t('Add'), 'url' => $add_url);
                     } elseif ($field_ui) {
                         $url = new Url('language.content_settings_page');
                         // Link directly to the fields tab to make it easier to find the
                         // setting to enable translation on fields.
                         $links['nofields'] = array('title' => $this->t('No translatable fields'), 'url' => $url);
                     }
                 }
                 /**
                  * empty the translation link for language that are not assign to translator role users
                  */
                 if ($isaplied == 1 && $nolink == 1) {
                     $links = array();
                 }
                 /**
                  * end here
                  */
                 $status = $this->t('Not translated');
             }
             if ($show_source_column) {
                 $rows[] = array($language_name, $row_title, $source_name, $status, $operations);
             } else {
                 $rows[] = array($language_name, $row_title, $status, $operations);
             }
         }
     }
     if ($show_source_column) {
         $header = array($this->t('Language'), $this->t('Translation'), $this->t('Source language'), $this->t('Status'), $this->t('Operations'));
     } else {
         $header = array($this->t('Language'), $this->t('Translation'), $this->t('Status'), $this->t('Operations'));
     }
     $build['#title'] = $this->t('Translations of %label', array('%label' => $entity->label()));
     // Add metadata to the build render array to let other modules know about
     // which entity this is.
     $build['#entity'] = $entity;
     $cacheability->addCacheTags($entity->getCacheTags())->applyTo($build);
     $build['content_translation_overview'] = array('#theme' => 'table', '#header' => $header, '#rows' => $rows);
     return $build;
 }
Пример #24
0
 /**
  * Tests FormattedDateDiff.
  *
  * @covers \Drupal\Core\Datetime\FormattedDateDiff::toRenderable
  * @covers \Drupal\Core\Datetime\FormattedDateDiff::getString
  * @covers \Drupal\Core\Datetime\FormattedDateDiff::getCacheMaxAge
  */
 public function testFormattedDateDiff()
 {
     $string = '10 minutes';
     $max_age = 60;
     $object = new FormattedDateDiff($string, $max_age);
     // Test conversion to a render array.
     $expected = ['#markup' => $string, '#cache' => ['max-age' => $max_age]];
     $this->assertArrayEquals($expected, $object->toRenderable());
     // Test retrieving the formatted time difference string.
     $this->assertEquals($string, $object->getString());
     // Test applying cacheability data to an existing build.
     $build = [];
     CacheableMetadata::createFromObject($object)->applyTo($build);
     $this->assertEquals($max_age, $build['#cache']['max-age']);
     // Test the BC layer.
     $this->assertSame($object->getCacheMaxAge(), $object->getMaxAge());
 }