Chris@14
|
1 <?php
|
Chris@14
|
2
|
Chris@14
|
3 namespace Drupal\layout_builder;
|
Chris@14
|
4
|
Chris@14
|
5 use Drupal\Component\Plugin\Exception\PluginException;
|
Chris@14
|
6 use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
Chris@14
|
7 use Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent;
|
Chris@14
|
8
|
Chris@14
|
9 /**
|
Chris@14
|
10 * Provides a value object for a section component.
|
Chris@14
|
11 *
|
Chris@14
|
12 * A component represents the smallest part of a layout (for example, a block).
|
Chris@14
|
13 * Components wrap a renderable plugin, currently using
|
Chris@14
|
14 * \Drupal\Core\Block\BlockPluginInterface, and contain the layout region
|
Chris@14
|
15 * within the section layout where the component will be rendered.
|
Chris@14
|
16 *
|
Chris@14
|
17 * @internal
|
Chris@14
|
18 * Layout Builder is currently experimental and should only be leveraged by
|
Chris@14
|
19 * experimental modules and development releases of contributed modules.
|
Chris@14
|
20 * See https://www.drupal.org/core/experimental for more information.
|
Chris@14
|
21 *
|
Chris@14
|
22 * @see \Drupal\Core\Layout\LayoutDefinition
|
Chris@14
|
23 * @see \Drupal\layout_builder\Section
|
Chris@14
|
24 * @see \Drupal\layout_builder\SectionStorageInterface
|
Chris@14
|
25 *
|
Chris@14
|
26 * @todo Determine whether to retain the name 'component' in
|
Chris@14
|
27 * https://www.drupal.org/project/drupal/issues/2929783.
|
Chris@14
|
28 * @todo Determine whether an interface will be provided for this in
|
Chris@14
|
29 * https://www.drupal.org/project/drupal/issues/2930334.
|
Chris@14
|
30 */
|
Chris@14
|
31 class SectionComponent {
|
Chris@14
|
32
|
Chris@14
|
33 /**
|
Chris@14
|
34 * The UUID of the component.
|
Chris@14
|
35 *
|
Chris@14
|
36 * @var string
|
Chris@14
|
37 */
|
Chris@14
|
38 protected $uuid;
|
Chris@14
|
39
|
Chris@14
|
40 /**
|
Chris@14
|
41 * The region the component is placed in.
|
Chris@14
|
42 *
|
Chris@14
|
43 * @var string
|
Chris@14
|
44 */
|
Chris@14
|
45 protected $region;
|
Chris@14
|
46
|
Chris@14
|
47 /**
|
Chris@14
|
48 * An array of plugin configuration.
|
Chris@14
|
49 *
|
Chris@14
|
50 * @var mixed[]
|
Chris@14
|
51 */
|
Chris@14
|
52 protected $configuration;
|
Chris@14
|
53
|
Chris@14
|
54 /**
|
Chris@14
|
55 * The weight of the component.
|
Chris@14
|
56 *
|
Chris@14
|
57 * @var int
|
Chris@14
|
58 */
|
Chris@14
|
59 protected $weight = 0;
|
Chris@14
|
60
|
Chris@14
|
61 /**
|
Chris@14
|
62 * Any additional properties and values.
|
Chris@14
|
63 *
|
Chris@14
|
64 * @var mixed[]
|
Chris@14
|
65 */
|
Chris@14
|
66 protected $additional = [];
|
Chris@14
|
67
|
Chris@14
|
68 /**
|
Chris@14
|
69 * Constructs a new SectionComponent.
|
Chris@14
|
70 *
|
Chris@14
|
71 * @param string $uuid
|
Chris@14
|
72 * The UUID.
|
Chris@14
|
73 * @param string $region
|
Chris@14
|
74 * The region.
|
Chris@14
|
75 * @param mixed[] $configuration
|
Chris@14
|
76 * The plugin configuration.
|
Chris@14
|
77 * @param mixed[] $additional
|
Chris@14
|
78 * An additional values.
|
Chris@14
|
79 */
|
Chris@14
|
80 public function __construct($uuid, $region, array $configuration = [], array $additional = []) {
|
Chris@14
|
81 $this->uuid = $uuid;
|
Chris@14
|
82 $this->region = $region;
|
Chris@14
|
83 $this->configuration = $configuration;
|
Chris@14
|
84 $this->additional = $additional;
|
Chris@14
|
85 }
|
Chris@14
|
86
|
Chris@14
|
87 /**
|
Chris@14
|
88 * Returns the renderable array for this component.
|
Chris@14
|
89 *
|
Chris@14
|
90 * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
Chris@14
|
91 * An array of available contexts.
|
Chris@14
|
92 * @param bool $in_preview
|
Chris@14
|
93 * TRUE if the component is being previewed, FALSE otherwise.
|
Chris@14
|
94 *
|
Chris@14
|
95 * @return array
|
Chris@14
|
96 * A renderable array representing the content of the component.
|
Chris@14
|
97 */
|
Chris@14
|
98 public function toRenderArray(array $contexts = [], $in_preview = FALSE) {
|
Chris@14
|
99 $event = new SectionComponentBuildRenderArrayEvent($this, $contexts, $in_preview);
|
Chris@14
|
100 $this->eventDispatcher()->dispatch(LayoutBuilderEvents::SECTION_COMPONENT_BUILD_RENDER_ARRAY, $event);
|
Chris@14
|
101 $output = $event->getBuild();
|
Chris@14
|
102 $event->getCacheableMetadata()->applyTo($output);
|
Chris@14
|
103 return $output;
|
Chris@14
|
104 }
|
Chris@14
|
105
|
Chris@14
|
106 /**
|
Chris@14
|
107 * Gets any arbitrary property for the component.
|
Chris@14
|
108 *
|
Chris@14
|
109 * @param string $property
|
Chris@14
|
110 * The property to retrieve.
|
Chris@14
|
111 *
|
Chris@14
|
112 * @return mixed
|
Chris@14
|
113 * The value for that property, or NULL if the property does not exist.
|
Chris@14
|
114 */
|
Chris@14
|
115 public function get($property) {
|
Chris@14
|
116 if (property_exists($this, $property)) {
|
Chris@14
|
117 $value = isset($this->{$property}) ? $this->{$property} : NULL;
|
Chris@14
|
118 }
|
Chris@14
|
119 else {
|
Chris@14
|
120 $value = isset($this->additional[$property]) ? $this->additional[$property] : NULL;
|
Chris@14
|
121 }
|
Chris@14
|
122 return $value;
|
Chris@14
|
123 }
|
Chris@14
|
124
|
Chris@14
|
125 /**
|
Chris@14
|
126 * Sets a value to an arbitrary property for the component.
|
Chris@14
|
127 *
|
Chris@14
|
128 * @param string $property
|
Chris@14
|
129 * The property to use for the value.
|
Chris@14
|
130 * @param mixed $value
|
Chris@14
|
131 * The value to set.
|
Chris@14
|
132 *
|
Chris@14
|
133 * @return $this
|
Chris@14
|
134 */
|
Chris@14
|
135 public function set($property, $value) {
|
Chris@14
|
136 if (property_exists($this, $property)) {
|
Chris@14
|
137 $this->{$property} = $value;
|
Chris@14
|
138 }
|
Chris@14
|
139 else {
|
Chris@14
|
140 $this->additional[$property] = $value;
|
Chris@14
|
141 }
|
Chris@14
|
142 return $this;
|
Chris@14
|
143 }
|
Chris@14
|
144
|
Chris@14
|
145 /**
|
Chris@14
|
146 * Gets the region for the component.
|
Chris@14
|
147 *
|
Chris@14
|
148 * @return string
|
Chris@14
|
149 * The region.
|
Chris@14
|
150 */
|
Chris@14
|
151 public function getRegion() {
|
Chris@14
|
152 return $this->region;
|
Chris@14
|
153 }
|
Chris@14
|
154
|
Chris@14
|
155 /**
|
Chris@14
|
156 * Sets the region for the component.
|
Chris@14
|
157 *
|
Chris@14
|
158 * @param string $region
|
Chris@14
|
159 * The region.
|
Chris@14
|
160 *
|
Chris@14
|
161 * @return $this
|
Chris@14
|
162 */
|
Chris@14
|
163 public function setRegion($region) {
|
Chris@14
|
164 $this->region = $region;
|
Chris@14
|
165 return $this;
|
Chris@14
|
166 }
|
Chris@14
|
167
|
Chris@14
|
168 /**
|
Chris@14
|
169 * Gets the weight of the component.
|
Chris@14
|
170 *
|
Chris@14
|
171 * @return int
|
Chris@14
|
172 * The zero-based weight of the component.
|
Chris@14
|
173 *
|
Chris@14
|
174 * @throws \UnexpectedValueException
|
Chris@14
|
175 * Thrown if the weight was never set.
|
Chris@14
|
176 */
|
Chris@14
|
177 public function getWeight() {
|
Chris@14
|
178 return $this->weight;
|
Chris@14
|
179 }
|
Chris@14
|
180
|
Chris@14
|
181 /**
|
Chris@14
|
182 * Sets the weight of the component.
|
Chris@14
|
183 *
|
Chris@14
|
184 * @param int $weight
|
Chris@14
|
185 * The zero-based weight of the component.
|
Chris@14
|
186 *
|
Chris@14
|
187 * @return $this
|
Chris@14
|
188 */
|
Chris@14
|
189 public function setWeight($weight) {
|
Chris@14
|
190 $this->weight = $weight;
|
Chris@14
|
191 return $this;
|
Chris@14
|
192 }
|
Chris@14
|
193
|
Chris@14
|
194 /**
|
Chris@14
|
195 * Gets the component plugin configuration.
|
Chris@14
|
196 *
|
Chris@14
|
197 * @return mixed[]
|
Chris@14
|
198 * The component plugin configuration.
|
Chris@14
|
199 */
|
Chris@14
|
200 protected function getConfiguration() {
|
Chris@14
|
201 return $this->configuration;
|
Chris@14
|
202 }
|
Chris@14
|
203
|
Chris@14
|
204 /**
|
Chris@14
|
205 * Sets the plugin configuration.
|
Chris@14
|
206 *
|
Chris@14
|
207 * @param mixed[] $configuration
|
Chris@14
|
208 * The plugin configuration.
|
Chris@14
|
209 *
|
Chris@14
|
210 * @return $this
|
Chris@14
|
211 */
|
Chris@14
|
212 public function setConfiguration(array $configuration) {
|
Chris@14
|
213 $this->configuration = $configuration;
|
Chris@14
|
214 return $this;
|
Chris@14
|
215 }
|
Chris@14
|
216
|
Chris@14
|
217 /**
|
Chris@14
|
218 * Gets the plugin ID.
|
Chris@14
|
219 *
|
Chris@14
|
220 * @return string
|
Chris@14
|
221 * The plugin ID.
|
Chris@14
|
222 *
|
Chris@14
|
223 * @throws \Drupal\Component\Plugin\Exception\PluginException
|
Chris@14
|
224 * Thrown if the plugin ID cannot be found.
|
Chris@14
|
225 */
|
Chris@14
|
226 public function getPluginId() {
|
Chris@14
|
227 if (empty($this->configuration['id'])) {
|
Chris@14
|
228 throw new PluginException(sprintf('No plugin ID specified for component with "%s" UUID', $this->uuid));
|
Chris@14
|
229 }
|
Chris@14
|
230 return $this->configuration['id'];
|
Chris@14
|
231 }
|
Chris@14
|
232
|
Chris@14
|
233 /**
|
Chris@14
|
234 * Gets the UUID for this component.
|
Chris@14
|
235 *
|
Chris@14
|
236 * @return string
|
Chris@14
|
237 * The UUID.
|
Chris@14
|
238 */
|
Chris@14
|
239 public function getUuid() {
|
Chris@14
|
240 return $this->uuid;
|
Chris@14
|
241 }
|
Chris@14
|
242
|
Chris@14
|
243 /**
|
Chris@14
|
244 * Gets the plugin for this component.
|
Chris@14
|
245 *
|
Chris@14
|
246 * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
Chris@14
|
247 * An array of contexts to set on the plugin.
|
Chris@14
|
248 *
|
Chris@14
|
249 * @return \Drupal\Component\Plugin\PluginInspectionInterface
|
Chris@14
|
250 * The plugin.
|
Chris@14
|
251 */
|
Chris@14
|
252 public function getPlugin(array $contexts = []) {
|
Chris@14
|
253 $plugin = $this->pluginManager()->createInstance($this->getPluginId(), $this->getConfiguration());
|
Chris@14
|
254 if ($contexts && $plugin instanceof ContextAwarePluginInterface) {
|
Chris@14
|
255 $this->contextHandler()->applyContextMapping($plugin, $contexts);
|
Chris@14
|
256 }
|
Chris@14
|
257 return $plugin;
|
Chris@14
|
258 }
|
Chris@14
|
259
|
Chris@14
|
260 /**
|
Chris@14
|
261 * Wraps the component plugin manager.
|
Chris@14
|
262 *
|
Chris@14
|
263 * @return \Drupal\Core\Block\BlockManagerInterface
|
Chris@14
|
264 * The plugin manager.
|
Chris@14
|
265 */
|
Chris@14
|
266 protected function pluginManager() {
|
Chris@14
|
267 // @todo Figure out the best way to unify fields and blocks and components
|
Chris@14
|
268 // in https://www.drupal.org/node/1875974.
|
Chris@14
|
269 return \Drupal::service('plugin.manager.block');
|
Chris@14
|
270 }
|
Chris@14
|
271
|
Chris@14
|
272 /**
|
Chris@14
|
273 * Wraps the context handler.
|
Chris@14
|
274 *
|
Chris@14
|
275 * @return \Drupal\Core\Plugin\Context\ContextHandlerInterface
|
Chris@14
|
276 * The context handler.
|
Chris@14
|
277 */
|
Chris@14
|
278 protected function contextHandler() {
|
Chris@14
|
279 return \Drupal::service('context.handler');
|
Chris@14
|
280 }
|
Chris@14
|
281
|
Chris@14
|
282 /**
|
Chris@14
|
283 * Wraps the event dispatcher.
|
Chris@14
|
284 *
|
Chris@14
|
285 * @return \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
Chris@14
|
286 * The event dispatcher.
|
Chris@14
|
287 */
|
Chris@14
|
288 protected function eventDispatcher() {
|
Chris@14
|
289 return \Drupal::service('event_dispatcher');
|
Chris@14
|
290 }
|
Chris@14
|
291
|
Chris@14
|
292 /**
|
Chris@14
|
293 * Returns an array representation of the section component.
|
Chris@14
|
294 *
|
Chris@16
|
295 * Only use this method if you are implementing custom storage for sections.
|
Chris@14
|
296 *
|
Chris@14
|
297 * @return array
|
Chris@14
|
298 * An array representation of the section component.
|
Chris@14
|
299 */
|
Chris@14
|
300 public function toArray() {
|
Chris@14
|
301 return [
|
Chris@14
|
302 'uuid' => $this->getUuid(),
|
Chris@14
|
303 'region' => $this->getRegion(),
|
Chris@14
|
304 'configuration' => $this->getConfiguration(),
|
Chris@14
|
305 'additional' => $this->additional,
|
Chris@14
|
306 'weight' => $this->getWeight(),
|
Chris@14
|
307 ];
|
Chris@14
|
308 }
|
Chris@14
|
309
|
Chris@16
|
310 /**
|
Chris@16
|
311 * Creates an object from an array representation of the section component.
|
Chris@16
|
312 *
|
Chris@16
|
313 * Only use this method if you are implementing custom storage for sections.
|
Chris@16
|
314 *
|
Chris@16
|
315 * @param array $component
|
Chris@16
|
316 * An array of section component data in the format returned by ::toArray().
|
Chris@16
|
317 *
|
Chris@16
|
318 * @return static
|
Chris@16
|
319 * The section component object.
|
Chris@16
|
320 */
|
Chris@16
|
321 public static function fromArray(array $component) {
|
Chris@16
|
322 return (new static(
|
Chris@16
|
323 $component['uuid'],
|
Chris@16
|
324 $component['region'],
|
Chris@16
|
325 $component['configuration'],
|
Chris@16
|
326 $component['additional']
|
Chris@16
|
327 ))->setWeight($component['weight']);
|
Chris@16
|
328 }
|
Chris@16
|
329
|
Chris@14
|
330 }
|