View source
<?php
namespace Drupal\layout_builder\Plugin\SectionStorage;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\EntityContext;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
use Drupal\layout_builder\OverridesSectionStorageInterface;
use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\RouteCollection;
class OverridesSectionStorage extends SectionStorageBase implements ContainerFactoryPluginInterface, OverridesSectionStorageInterface, SectionStorageLocalTaskProviderInterface {
const FIELD_NAME = 'layout_builder__layout';
protected $entityTypeManager;
protected $entityFieldManager;
protected $sectionStorageManager;
protected $entityRepository;
protected $currentUser;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, SectionStorageManagerInterface $section_storage_manager, EntityRepositoryInterface $entity_repository, AccountInterface $current_user) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
$this->sectionStorageManager = $section_storage_manager;
$this->entityRepository = $entity_repository;
$this->currentUser = $current_user;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('entity_type.manager'), $container
->get('entity_field.manager'), $container
->get('plugin.manager.layout_builder.section_storage'), $container
->get('entity.repository'), $container
->get('current_user'));
}
protected function getSectionList() {
return $this
->getEntity()
->get(static::FIELD_NAME);
}
protected function getEntity() {
return $this
->getContextValue('entity');
}
public function getStorageId() {
$entity = $this
->getEntity();
return $entity
->getEntityTypeId() . '.' . $entity
->id();
}
public function getTempstoreKey() {
$key = parent::getTempstoreKey();
$key .= '.' . $this
->getContextValue('view_mode');
$entity = $this
->getEntity();
if ($entity instanceof TranslatableInterface) {
$key .= '.' . $entity
->language()
->getId();
}
return $key;
}
public function deriveContextsFromRoute($value, $definition, $name, array $defaults) {
$contexts = [];
if ($entity = $this
->extractEntityFromRoute($value, $defaults)) {
$contexts['entity'] = EntityContext::fromEntity($entity);
$view_mode = 'full';
$view_mode = LayoutBuilderEntityViewDisplay::collectRenderDisplay($entity, $view_mode)
->getMode();
$contexts['view_mode'] = new Context(new ContextDefinition('string'), $view_mode);
}
return $contexts;
}
private function extractEntityFromRoute($value, array $defaults) {
if (strpos($value, '.') !== FALSE) {
list($entity_type_id, $entity_id) = explode('.', $value, 2);
}
elseif (isset($defaults['entity_type_id']) && !empty($defaults[$defaults['entity_type_id']])) {
$entity_type_id = $defaults['entity_type_id'];
$entity_id = $defaults[$entity_type_id];
}
else {
return NULL;
}
$entity = $this->entityRepository
->getActive($entity_type_id, $entity_id);
if ($entity instanceof FieldableEntityInterface && $entity
->hasField(static::FIELD_NAME)) {
return $entity;
}
}
public function buildRoutes(RouteCollection $collection) {
foreach ($this
->getEntityTypes() as $entity_type_id => $entity_type) {
if (!$collection
->get("entity.{$entity_type_id}.canonical")) {
continue;
}
$defaults = [];
$defaults['entity_type_id'] = $entity_type_id;
$requirements = $collection
->get("entity.{$entity_type_id}.canonical")
->getRequirements();
$options = [];
$options['parameters']['section_storage'] = [];
$options['parameters'][$entity_type_id]['type'] = 'entity:' . $entity_type_id;
$template = $entity_type
->getLinkTemplate('canonical') . '/layout';
$this
->buildLayoutRoutes($collection, $this
->getPluginDefinition(), $template, $defaults, $requirements, $options, $entity_type_id, $entity_type_id);
}
}
public function buildLocalTasks($base_plugin_definition) {
$local_tasks = [];
foreach ($this
->getEntityTypes() as $entity_type_id => $entity_type) {
$local_tasks["layout_builder.overrides.{$entity_type_id}.view"] = $base_plugin_definition + [
'route_name' => "layout_builder.overrides.{$entity_type_id}.view",
'weight' => 15,
'title' => $this
->t('Layout'),
'base_route' => "entity.{$entity_type_id}.canonical",
'cache_contexts' => [
'layout_builder_is_active:' . $entity_type_id,
],
];
}
return $local_tasks;
}
protected function hasIntegerId(EntityTypeInterface $entity_type) {
$field_storage_definitions = $this->entityFieldManager
->getFieldStorageDefinitions($entity_type
->id());
return $field_storage_definitions[$entity_type
->getKey('id')]
->getType() === 'integer';
}
protected function getEntityTypes() {
return array_filter($this->entityTypeManager
->getDefinitions(), function (EntityTypeInterface $entity_type) {
return $entity_type
->entityClassImplements(FieldableEntityInterface::class) && $entity_type
->hasHandlerClass('form', 'layout_builder') && $entity_type
->hasViewBuilderClass() && $entity_type
->hasLinkTemplate('canonical');
});
}
public function getDefaultSectionStorage() {
$display = LayoutBuilderEntityViewDisplay::collectRenderDisplay($this
->getEntity(), $this
->getContextValue('view_mode'));
return $this->sectionStorageManager
->load('defaults', [
'display' => EntityContext::fromEntity($display),
]);
}
public function getRedirectUrl() {
return $this
->getEntity()
->toUrl('canonical');
}
public function getLayoutBuilderUrl($rel = 'view') {
$entity = $this
->getEntity();
$route_parameters[$entity
->getEntityTypeId()] = $entity
->id();
return Url::fromRoute("layout_builder.{$this->getStorageType()}.{$this->getEntity()->getEntityTypeId()}.{$rel}", $route_parameters);
}
public function getContextsDuringPreview() {
$contexts = parent::getContextsDuringPreview();
if (isset($contexts['entity'])) {
$contexts['layout_builder.entity'] = $contexts['entity'];
unset($contexts['entity']);
}
return $contexts;
}
public function label() {
return $this
->getEntity()
->label();
}
public function save() {
return $this
->getEntity()
->save();
}
public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
if ($account === NULL) {
$account = $this->currentUser;
}
$entity = $this
->getEntity();
$any_access = AccessResult::allowedIfHasPermission($account, 'configure any layout');
$bundle_access = AccessResult::allowedIfHasPermission($account, "configure all {$entity->bundle()} {$entity->getEntityTypeId()} layout overrides");
$edit_only_bundle_access = AccessResult::allowedIfHasPermission($account, "configure editable {$entity->bundle()} {$entity->getEntityTypeId()} layout overrides");
$edit_only_bundle_access = $edit_only_bundle_access
->andIf($entity
->access('update', $account, TRUE));
$result = $any_access
->orIf($bundle_access)
->orIf($edit_only_bundle_access);
$result = $result
->andIf($this
->getDefaultSectionStorage()
->access($operation, $account, TRUE));
$result = $this
->handleTranslationAccess($result, $operation, $account);
return $return_as_object ? $result : $result
->isAllowed();
}
protected function handleTranslationAccess(AccessResult $result, $operation, AccountInterface $account) {
$entity = $this
->getEntity();
return $result
->andIf(AccessResult::allowedIf(!($entity instanceof TranslatableInterface && !$entity
->isDefaultTranslation())))
->addCacheableDependency($entity);
}
public function isApplicable(RefinableCacheableDependencyInterface $cacheability) {
$default_section_storage = $this
->getDefaultSectionStorage();
$cacheability
->addCacheableDependency($default_section_storage)
->addCacheableDependency($this);
return $default_section_storage
->isOverridable() && $this
->isOverridden();
}
public function isOverridden() {
return !empty($this
->getSections());
}
}