Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / field_layout / src / FieldLayoutBuilder.php
1 <?php
2
3 namespace Drupal\field_layout;
4
5 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
6 use Drupal\Core\Entity\EntityFieldManagerInterface;
7 use Drupal\Core\Field\FieldDefinitionInterface;
8 use Drupal\field_layout\Display\EntityDisplayWithLayoutInterface;
9 use Drupal\Core\Layout\LayoutPluginManagerInterface;
10 use Symfony\Component\DependencyInjection\ContainerInterface;
11
12 /**
13  * Builds a field layout.
14  */
15 class FieldLayoutBuilder implements ContainerInjectionInterface {
16
17   /**
18    * The layout plugin manager.
19    *
20    * @var \Drupal\Core\Layout\LayoutPluginManagerInterface
21    */
22   protected $layoutPluginManager;
23
24   /**
25    * The entity field manager.
26    *
27    * @var \Drupal\Core\Entity\EntityFieldManagerInterface
28    */
29   protected $entityFieldManager;
30
31   /**
32    * Constructs a new FieldLayoutBuilder.
33    *
34    * @param \Drupal\Core\Layout\LayoutPluginManagerInterface $layout_plugin_manager
35    *   The layout plugin manager.
36    * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
37    *   The entity field manager.
38    */
39   public function __construct(LayoutPluginManagerInterface $layout_plugin_manager, EntityFieldManagerInterface $entity_field_manager) {
40     $this->layoutPluginManager = $layout_plugin_manager;
41     $this->entityFieldManager = $entity_field_manager;
42   }
43
44   /**
45    * {@inheritdoc}
46    */
47   public static function create(ContainerInterface $container) {
48     return new static(
49       $container->get('plugin.manager.core.layout'),
50       $container->get('entity_field.manager')
51     );
52   }
53
54   /**
55    * Applies the layout to an entity build.
56    *
57    * @param array $build
58    *   A renderable array representing the entity content or form.
59    * @param \Drupal\field_layout\Display\EntityDisplayWithLayoutInterface $display
60    *   The entity display holding the display options configured for the entity
61    *   components.
62    */
63   public function buildView(array &$build, EntityDisplayWithLayoutInterface $display) {
64     $layout_definition = $this->layoutPluginManager->getDefinition($display->getLayoutId(), FALSE);
65     if ($layout_definition && $fields = $this->getFields($build, $display, 'view')) {
66       // Add the regions to the $build in the correct order.
67       $regions = array_fill_keys($layout_definition->getRegionNames(), []);
68
69       foreach ($fields as $name => $field) {
70         // If the region is controlled by the layout, move the field from the
71         // top-level of $build into a region-specific section. Custom regions
72         // could be set by other code at run-time; these should be ignored.
73         // @todo Ideally the array structure would remain unchanged, see
74         //   https://www.drupal.org/node/2846393.
75         if (isset($regions[$field['region']])) {
76           $regions[$field['region']][$name] = $build[$name];
77           unset($build[$name]);
78         }
79       }
80       // Ensure this will not conflict with any existing array elements by
81       // prefixing with an underscore.
82       $build['_field_layout'] = $display->getLayout()->build($regions);
83     }
84   }
85
86   /**
87    * Applies the layout to an entity form.
88    *
89    * @param array $build
90    *   A renderable array representing the entity content or form.
91    * @param \Drupal\field_layout\Display\EntityDisplayWithLayoutInterface $display
92    *   The entity display holding the display options configured for the entity
93    *   components.
94    */
95   public function buildForm(array &$build, EntityDisplayWithLayoutInterface $display) {
96     $layout_definition = $this->layoutPluginManager->getDefinition($display->getLayoutId(), FALSE);
97     if ($layout_definition && $fields = $this->getFields($build, $display, 'form')) {
98       $fill = [];
99       $fill['#process'][] = '\Drupal\Core\Render\Element\RenderElement::processGroup';
100       $fill['#pre_render'][] = '\Drupal\Core\Render\Element\RenderElement::preRenderGroup';
101       // Add the regions to the $build in the correct order.
102       $regions = array_fill_keys($layout_definition->getRegionNames(), $fill);
103
104       foreach ($fields as $name => $field) {
105         // As this is a form, #group can be used to relocate the fields. This
106         // avoids breaking hook_form_alter() implementations by not actually
107         // moving the field in the form structure. If a #group is already set,
108         // do not overwrite it.
109         if (isset($regions[$field['region']]) && !isset($build[$name]['#group'])) {
110           $build[$name]['#group'] = $field['region'];
111         }
112       }
113       // Ensure this will not conflict with any existing array elements by
114       // prefixing with an underscore.
115       $build['_field_layout'] = $display->getLayout()->build($regions);
116     }
117   }
118
119   /**
120    * Gets the fields that need to be processed.
121    *
122    * @param array $build
123    *   A renderable array representing the entity content or form.
124    * @param \Drupal\field_layout\Display\EntityDisplayWithLayoutInterface $display
125    *   The entity display holding the display options configured for the entity
126    *   components.
127    * @param string $display_context
128    *   The display context, either 'form' or 'view'.
129    *
130    * @return array
131    *   An array of configurable fields present in the build.
132    */
133   protected function getFields(array $build, EntityDisplayWithLayoutInterface $display, $display_context) {
134     $components = $display->getComponents();
135
136     // Ignore any extra fields from the list of field definitions. Field
137     // definitions can have a non-configurable display, but all extra fields are
138     // always displayed.
139     $field_definitions = array_diff_key(
140       $this->entityFieldManager->getFieldDefinitions($display->getTargetEntityTypeId(), $display->getTargetBundle()),
141       $this->entityFieldManager->getExtraFields($display->getTargetEntityTypeId(), $display->getTargetBundle())
142     );
143
144     $fields_to_exclude = array_filter($field_definitions, function (FieldDefinitionInterface $field_definition) use ($display_context) {
145       // Remove fields with a non-configurable display.
146       return !$field_definition->isDisplayConfigurable($display_context);
147     });
148     $components = array_diff_key($components, $fields_to_exclude);
149
150     // Only include fields present in the build.
151     $components = array_intersect_key($components, $build);
152
153     return $components;
154   }
155
156 }