Chris@17
|
1 <?php
|
Chris@17
|
2
|
Chris@17
|
3 namespace Drupal\layout_builder\EventSubscriber;
|
Chris@17
|
4
|
Chris@17
|
5 use Drupal\block_content\BlockContentEvents;
|
Chris@17
|
6 use Drupal\block_content\BlockContentInterface;
|
Chris@17
|
7 use Drupal\block_content\Event\BlockContentGetDependencyEvent;
|
Chris@17
|
8 use Drupal\Core\Database\Connection;
|
Chris@17
|
9 use Drupal\Core\Entity\EntityInterface;
|
Chris@17
|
10 use Drupal\Core\Entity\EntityTypeManagerInterface;
|
Chris@18
|
11 use Drupal\layout_builder\InlineBlockUsageInterface;
|
Chris@17
|
12 use Drupal\layout_builder\LayoutEntityHelperTrait;
|
Chris@18
|
13 use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
|
Chris@17
|
14 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
Chris@17
|
15
|
Chris@17
|
16 /**
|
Chris@17
|
17 * An event subscriber that returns an access dependency for inline blocks.
|
Chris@17
|
18 *
|
Chris@17
|
19 * When used within the layout builder the access dependency for inline blocks
|
Chris@17
|
20 * will be explicitly set but if access is evaluated outside of the layout
|
Chris@17
|
21 * builder then the dependency may not have been set.
|
Chris@17
|
22 *
|
Chris@17
|
23 * A known example of when the access dependency will not have been set is when
|
Chris@17
|
24 * determining 'view' or 'download' access to a file entity that is attached
|
Chris@17
|
25 * to a content block via a field that is using the private file system. The
|
Chris@17
|
26 * file access handler will evaluate access on the content block without setting
|
Chris@17
|
27 * the dependency.
|
Chris@17
|
28 *
|
Chris@17
|
29 * @internal
|
Chris@18
|
30 * Tagged services are internal.
|
Chris@17
|
31 *
|
Chris@17
|
32 * @see \Drupal\file\FileAccessControlHandler::checkAccess()
|
Chris@17
|
33 * @see \Drupal\block_content\BlockContentAccessControlHandler::checkAccess()
|
Chris@17
|
34 */
|
Chris@17
|
35 class SetInlineBlockDependency implements EventSubscriberInterface {
|
Chris@17
|
36
|
Chris@17
|
37 use LayoutEntityHelperTrait;
|
Chris@17
|
38
|
Chris@17
|
39 /**
|
Chris@17
|
40 * The entity type manager.
|
Chris@17
|
41 *
|
Chris@17
|
42 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
Chris@17
|
43 */
|
Chris@17
|
44 protected $entityTypeManager;
|
Chris@17
|
45
|
Chris@17
|
46 /**
|
Chris@17
|
47 * The database connection.
|
Chris@17
|
48 *
|
Chris@17
|
49 * @var \Drupal\Core\Database\Connection
|
Chris@17
|
50 */
|
Chris@17
|
51 protected $database;
|
Chris@17
|
52
|
Chris@17
|
53 /**
|
Chris@17
|
54 * The inline block usage service.
|
Chris@17
|
55 *
|
Chris@18
|
56 * @var \Drupal\layout_builder\InlineBlockUsageInterface
|
Chris@17
|
57 */
|
Chris@17
|
58 protected $usage;
|
Chris@17
|
59
|
Chris@17
|
60 /**
|
Chris@17
|
61 * Constructs SetInlineBlockDependency object.
|
Chris@17
|
62 *
|
Chris@17
|
63 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
Chris@17
|
64 * The entity type manager.
|
Chris@17
|
65 * @param \Drupal\Core\Database\Connection $database
|
Chris@17
|
66 * The database connection.
|
Chris@18
|
67 * @param \Drupal\layout_builder\InlineBlockUsageInterface $usage
|
Chris@17
|
68 * The inline block usage service.
|
Chris@18
|
69 * @param \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface $section_storage_manager
|
Chris@18
|
70 * The section storage manager.
|
Chris@17
|
71 */
|
Chris@18
|
72 public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, InlineBlockUsageInterface $usage, SectionStorageManagerInterface $section_storage_manager) {
|
Chris@17
|
73 $this->entityTypeManager = $entity_type_manager;
|
Chris@17
|
74 $this->database = $database;
|
Chris@17
|
75 $this->usage = $usage;
|
Chris@18
|
76 $this->sectionStorageManager = $section_storage_manager;
|
Chris@17
|
77 }
|
Chris@17
|
78
|
Chris@17
|
79 /**
|
Chris@17
|
80 * {@inheritdoc}
|
Chris@17
|
81 */
|
Chris@17
|
82 public static function getSubscribedEvents() {
|
Chris@17
|
83 return [
|
Chris@17
|
84 BlockContentEvents::BLOCK_CONTENT_GET_DEPENDENCY => 'onGetDependency',
|
Chris@17
|
85 ];
|
Chris@17
|
86 }
|
Chris@17
|
87
|
Chris@17
|
88 /**
|
Chris@17
|
89 * Handles the BlockContentEvents::INLINE_BLOCK_GET_DEPENDENCY event.
|
Chris@17
|
90 *
|
Chris@17
|
91 * @param \Drupal\block_content\Event\BlockContentGetDependencyEvent $event
|
Chris@17
|
92 * The event.
|
Chris@17
|
93 */
|
Chris@17
|
94 public function onGetDependency(BlockContentGetDependencyEvent $event) {
|
Chris@17
|
95 if ($dependency = $this->getInlineBlockDependency($event->getBlockContentEntity())) {
|
Chris@17
|
96 $event->setAccessDependency($dependency);
|
Chris@17
|
97 }
|
Chris@17
|
98 }
|
Chris@17
|
99
|
Chris@17
|
100 /**
|
Chris@17
|
101 * Get the access dependency of an inline block.
|
Chris@17
|
102 *
|
Chris@17
|
103 * If the block is used in an entity that entity will be returned as the
|
Chris@17
|
104 * dependency.
|
Chris@17
|
105 *
|
Chris@17
|
106 * For revisionable entities the entity will only be returned if it is used in
|
Chris@17
|
107 * the latest revision of the entity. For inline blocks that are not used in
|
Chris@17
|
108 * the latest revision but are used in a previous revision the entity will not
|
Chris@17
|
109 * be returned because calling
|
Chris@17
|
110 * \Drupal\Core\Access\AccessibleInterface::access() will only check access on
|
Chris@17
|
111 * the latest revision. Therefore if the previous revision of the entity was
|
Chris@17
|
112 * returned as the dependency access would be granted to inline block
|
Chris@17
|
113 * regardless of whether the user has access to the revision in which the
|
Chris@17
|
114 * inline block was used.
|
Chris@17
|
115 *
|
Chris@17
|
116 * @param \Drupal\block_content\BlockContentInterface $block_content
|
Chris@17
|
117 * The block content entity.
|
Chris@17
|
118 *
|
Chris@17
|
119 * @return \Drupal\Core\Entity\EntityInterface|null
|
Chris@17
|
120 * Returns the layout dependency.
|
Chris@17
|
121 *
|
Chris@17
|
122 * @see \Drupal\block_content\BlockContentAccessControlHandler::checkAccess()
|
Chris@17
|
123 * @see \Drupal\layout_builder\EventSubscriber\BlockComponentRenderArray::onBuildRender()
|
Chris@17
|
124 */
|
Chris@17
|
125 protected function getInlineBlockDependency(BlockContentInterface $block_content) {
|
Chris@17
|
126 $layout_entity_info = $this->usage->getUsage($block_content->id());
|
Chris@17
|
127 if (empty($layout_entity_info)) {
|
Chris@17
|
128 // If the block does not have usage information then we cannot set a
|
Chris@17
|
129 // dependency. It may be used by another module besides layout builder.
|
Chris@17
|
130 return NULL;
|
Chris@17
|
131 }
|
Chris@17
|
132 $layout_entity_storage = $this->entityTypeManager->getStorage($layout_entity_info->layout_entity_type);
|
Chris@17
|
133 $layout_entity = $layout_entity_storage->load($layout_entity_info->layout_entity_id);
|
Chris@17
|
134 if ($this->isLayoutCompatibleEntity($layout_entity)) {
|
Chris@17
|
135 if ($this->isBlockRevisionUsedInEntity($layout_entity, $block_content)) {
|
Chris@17
|
136 return $layout_entity;
|
Chris@17
|
137 }
|
Chris@17
|
138
|
Chris@17
|
139 }
|
Chris@17
|
140 return NULL;
|
Chris@17
|
141 }
|
Chris@17
|
142
|
Chris@17
|
143 /**
|
Chris@17
|
144 * Determines if a block content revision is used in an entity.
|
Chris@17
|
145 *
|
Chris@17
|
146 * @param \Drupal\Core\Entity\EntityInterface $layout_entity
|
Chris@17
|
147 * The layout entity.
|
Chris@17
|
148 * @param \Drupal\block_content\BlockContentInterface $block_content
|
Chris@17
|
149 * The block content revision.
|
Chris@17
|
150 *
|
Chris@17
|
151 * @return bool
|
Chris@17
|
152 * TRUE if the block content revision is used as an inline block in the
|
Chris@17
|
153 * layout entity.
|
Chris@17
|
154 */
|
Chris@17
|
155 protected function isBlockRevisionUsedInEntity(EntityInterface $layout_entity, BlockContentInterface $block_content) {
|
Chris@17
|
156 $sections_blocks_revision_ids = $this->getInlineBlockRevisionIdsInSections($this->getEntitySections($layout_entity));
|
Chris@17
|
157 return in_array($block_content->getRevisionId(), $sections_blocks_revision_ids);
|
Chris@17
|
158 }
|
Chris@17
|
159
|
Chris@17
|
160 }
|