annotate core/modules/field_layout/src/FieldLayoutBuilder.php @ 19:fa3358dc1485 tip

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