comparison core/modules/field_layout/src/FieldLayoutBuilder.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 7a779792577d
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
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 // Move the field from the top-level of $build into a region-specific
71 // section.
72 // @todo Ideally the array structure would remain unchanged, see
73 // https://www.drupal.org/node/2846393.
74 $regions[$field['region']][$name] = $build[$name];
75 unset($build[$name]);
76 }
77 // Ensure this will not conflict with any existing array elements by
78 // prefixing with an underscore.
79 $build['_field_layout'] = $display->getLayout()->build($regions);
80 }
81 }
82
83 /**
84 * Applies the layout to an entity form.
85 *
86 * @param array $build
87 * A renderable array representing the entity content or form.
88 * @param \Drupal\field_layout\Display\EntityDisplayWithLayoutInterface $display
89 * The entity display holding the display options configured for the entity
90 * components.
91 */
92 public function buildForm(array &$build, EntityDisplayWithLayoutInterface $display) {
93 $layout_definition = $this->layoutPluginManager->getDefinition($display->getLayoutId(), FALSE);
94 if ($layout_definition && $fields = $this->getFields($build, $display, 'form')) {
95 $fill = [];
96 $fill['#process'][] = '\Drupal\Core\Render\Element\RenderElement::processGroup';
97 $fill['#pre_render'][] = '\Drupal\Core\Render\Element\RenderElement::preRenderGroup';
98 // Add the regions to the $build in the correct order.
99 $regions = array_fill_keys($layout_definition->getRegionNames(), $fill);
100
101 foreach ($fields as $name => $field) {
102 // As this is a form, #group can be used to relocate the fields. This
103 // avoids breaking hook_form_alter() implementations by not actually
104 // moving the field in the form structure. If a #group is already set,
105 // do not overwrite it.
106 if (!isset($build[$name]['#group'])) {
107 $build[$name]['#group'] = $field['region'];
108 }
109 }
110 // Ensure this will not conflict with any existing array elements by
111 // prefixing with an underscore.
112 $build['_field_layout'] = $display->getLayout()->build($regions);
113 }
114 }
115
116 /**
117 * Gets the fields that need to be processed.
118 *
119 * @param array $build
120 * A renderable array representing the entity content or form.
121 * @param \Drupal\field_layout\Display\EntityDisplayWithLayoutInterface $display
122 * The entity display holding the display options configured for the entity
123 * components.
124 * @param string $display_context
125 * The display context, either 'form' or 'view'.
126 *
127 * @return array
128 * An array of configurable fields present in the build.
129 */
130 protected function getFields(array $build, EntityDisplayWithLayoutInterface $display, $display_context) {
131 $components = $display->getComponents();
132
133 // Ignore any extra fields from the list of field definitions. Field
134 // definitions can have a non-configurable display, but all extra fields are
135 // always displayed.
136 $field_definitions = array_diff_key(
137 $this->entityFieldManager->getFieldDefinitions($display->getTargetEntityTypeId(), $display->getTargetBundle()),
138 $this->entityFieldManager->getExtraFields($display->getTargetEntityTypeId(), $display->getTargetBundle())
139 );
140
141 $fields_to_exclude = array_filter($field_definitions, function (FieldDefinitionInterface $field_definition) use ($display_context) {
142 // Remove fields with a non-configurable display.
143 return !$field_definition->isDisplayConfigurable($display_context);
144 });
145 $components = array_diff_key($components, $fields_to_exclude);
146
147 // Only include fields present in the build.
148 $components = array_intersect_key($components, $build);
149
150 return $components;
151 }
152
153 }