X-Git-Url: http://www.aleph1.co.uk/gitweb/?a=blobdiff_plain;ds=sidebyside;f=web%2Fcore%2Fmodules%2Flayout_builder%2Fsrc%2FPlugin%2FBlock%2FFieldBlock.php;fp=web%2Fcore%2Fmodules%2Flayout_builder%2Fsrc%2FPlugin%2FBlock%2FFieldBlock.php;h=d32e71baa28f48c1c39daa93e23e186f108a4f08;hb=af6d1fb995500ae68849458ee10d66abbdcfb252;hp=0000000000000000000000000000000000000000;hpb=680c79a86e3ed402f263faeac92e89fb6d9edcc0;p=yaffs-website diff --git a/web/core/modules/layout_builder/src/Plugin/Block/FieldBlock.php b/web/core/modules/layout_builder/src/Plugin/Block/FieldBlock.php new file mode 100644 index 000000000..d32e71baa --- /dev/null +++ b/web/core/modules/layout_builder/src/Plugin/Block/FieldBlock.php @@ -0,0 +1,377 @@ +entityFieldManager = $entity_field_manager; + $this->formatterManager = $formatter_manager; + $this->moduleHandler = $module_handler; + + // Get the entity type and field name from the plugin ID. + list (, $entity_type_id, $bundle, $field_name) = explode(static::DERIVATIVE_SEPARATOR, $plugin_id, 4); + $this->entityTypeId = $entity_type_id; + $this->bundle = $bundle; + $this->fieldName = $field_name; + + parent::__construct($configuration, $plugin_id, $plugin_definition); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('entity_field.manager'), + $container->get('plugin.manager.field.formatter'), + $container->get('module_handler') + ); + } + + /** + * Gets the entity that has the field. + * + * @return \Drupal\Core\Entity\FieldableEntityInterface + * The entity. + */ + protected function getEntity() { + return $this->getContextValue('entity'); + } + + /** + * {@inheritdoc} + */ + public function build() { + $display_settings = $this->getConfiguration()['formatter']; + $entity = $this->getEntity(); + $build = $entity->get($this->fieldName)->view($display_settings); + if (!empty($entity->in_preview) && !Element::getVisibleChildren($build)) { + $build['content']['#markup'] = new TranslatableMarkup('Placeholder for the "@field" field', ['@field' => $this->getFieldDefinition()->getLabel()]); + } + CacheableMetadata::createFromObject($this)->applyTo($build); + return $build; + } + + /** + * {@inheritdoc} + */ + protected function blockAccess(AccountInterface $account) { + $entity = $this->getEntity(); + + // First consult the entity. + $access = $entity->access('view', $account, TRUE); + if (!$access->isAllowed()) { + return $access; + } + + // Check that the entity in question has this field. + if (!$entity instanceof FieldableEntityInterface || !$entity->hasField($this->fieldName)) { + return $access->andIf(AccessResult::forbidden()); + } + + // Check field access. + $field = $entity->get($this->fieldName); + $access = $access->andIf($field->access('view', $account, TRUE)); + if (!$access->isAllowed()) { + return $access; + } + + // Check to see if the field has any values. + if ($field->isEmpty()) { + return $access->andIf(AccessResult::forbidden()); + } + return $access; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return [ + 'label_display' => FALSE, + 'formatter' => [ + 'label' => 'above', + 'type' => $this->pluginDefinition['default_formatter'], + 'settings' => [], + 'third_party_settings' => [], + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function blockForm($form, FormStateInterface $form_state) { + $config = $this->getConfiguration(); + + $form['formatter'] = [ + '#tree' => TRUE, + '#process' => [ + [$this, 'formatterSettingsProcessCallback'], + ], + ]; + $form['formatter']['label'] = [ + '#type' => 'select', + '#title' => $this->t('Label'), + // @todo This is directly copied from + // \Drupal\field_ui\Form\EntityViewDisplayEditForm::getFieldLabelOptions(), + // resolve this in https://www.drupal.org/project/drupal/issues/2933924. + '#options' => [ + 'above' => $this->t('Above'), + 'inline' => $this->t('Inline'), + 'hidden' => '- ' . $this->t('Hidden') . ' -', + 'visually_hidden' => '- ' . $this->t('Visually Hidden') . ' -', + ], + '#default_value' => $config['formatter']['label'], + ]; + + $form['formatter']['type'] = [ + '#type' => 'select', + '#title' => $this->t('Formatter'), + '#options' => $this->getApplicablePluginOptions($this->getFieldDefinition()), + '#required' => TRUE, + '#default_value' => $config['formatter']['type'], + '#ajax' => [ + 'callback' => [static::class, 'formatterSettingsAjaxCallback'], + 'wrapper' => 'formatter-settings-wrapper', + ], + ]; + + // Add the formatter settings to the form via AJAX. + $form['formatter']['settings_wrapper'] = [ + '#prefix' => '
', + '#suffix' => '
', + ]; + + return $form; + } + + /** + * Render API callback: builds the formatter settings elements. + */ + public function formatterSettingsProcessCallback(array &$element, FormStateInterface $form_state, array &$complete_form) { + if ($formatter = $this->getFormatter($element['#parents'], $form_state)) { + $element['settings_wrapper']['settings'] = $formatter->settingsForm($complete_form, $form_state); + $element['settings_wrapper']['settings']['#parents'] = array_merge($element['#parents'], ['settings']); + $element['settings_wrapper']['third_party_settings'] = $this->thirdPartySettingsForm($formatter, $this->getFieldDefinition(), $complete_form, $form_state); + $element['settings_wrapper']['third_party_settings']['#parents'] = array_merge($element['#parents'], ['third_party_settings']); + + // Store the array parents for our element so that we can retrieve the + // formatter settings in our AJAX callback. + $form_state->set('field_block_array_parents', $element['#array_parents']); + } + return $element; + } + + /** + * Adds the formatter third party settings forms. + * + * @param \Drupal\Core\Field\FormatterInterface $plugin + * The formatter. + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The field definition. + * @param array $form + * The (entire) configuration form array. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return array + * The formatter third party settings form. + */ + protected function thirdPartySettingsForm(FormatterInterface $plugin, FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) { + $settings_form = []; + // Invoke hook_field_formatter_third_party_settings_form(), keying resulting + // subforms by module name. + foreach ($this->moduleHandler->getImplementations('field_formatter_third_party_settings_form') as $module) { + $settings_form[$module] = $this->moduleHandler->invoke($module, 'field_formatter_third_party_settings_form', [ + $plugin, + $field_definition, + EntityDisplayBase::CUSTOM_MODE, + $form, + $form_state, + ]); + } + return $settings_form; + } + + /** + * Render API callback: gets the layout settings elements. + */ + public static function formatterSettingsAjaxCallback(array $form, FormStateInterface $form_state) { + $formatter_array_parents = $form_state->get('field_block_array_parents'); + return NestedArray::getValue($form, array_merge($formatter_array_parents, ['settings_wrapper'])); + } + + /** + * {@inheritdoc} + */ + public function blockSubmit($form, FormStateInterface $form_state) { + $this->configuration['formatter'] = $form_state->getValue('formatter'); + } + + /** + * Gets the field definition. + * + * @return \Drupal\Core\Field\FieldDefinitionInterface + * The field definition. + */ + protected function getFieldDefinition() { + if (empty($this->fieldDefinition)) { + $field_definitions = $this->entityFieldManager->getFieldDefinitions($this->entityTypeId, $this->bundle); + $this->fieldDefinition = $field_definitions[$this->fieldName]; + } + return $this->fieldDefinition; + } + + /** + * Returns an array of applicable formatter options for a field. + * + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The field definition. + * + * @return array + * An array of applicable formatter options. + * + * @see \Drupal\field_ui\Form\EntityDisplayFormBase::getApplicablePluginOptions() + */ + protected function getApplicablePluginOptions(FieldDefinitionInterface $field_definition) { + $options = $this->formatterManager->getOptions($field_definition->getType()); + $applicable_options = []; + foreach ($options as $option => $label) { + $plugin_class = DefaultFactory::getPluginClass($option, $this->formatterManager->getDefinition($option)); + if ($plugin_class::isApplicable($field_definition)) { + $applicable_options[$option] = $label; + } + } + return $applicable_options; + } + + /** + * Gets the formatter object. + * + * @param array $parents + * The #parents of the element representing the formatter. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @return \Drupal\Core\Field\FormatterInterface + * The formatter object. + */ + protected function getFormatter(array $parents, FormStateInterface $form_state) { + // Use the processed values, if available. + $configuration = NestedArray::getValue($form_state->getValues(), $parents); + if (!$configuration) { + // Next check the raw user input. + $configuration = NestedArray::getValue($form_state->getUserInput(), $parents); + if (!$configuration) { + // If no user input exists, use the default values. + $configuration = $this->getConfiguration()['formatter']; + } + } + + return $this->formatterManager->getInstance([ + 'configuration' => $configuration, + 'field_definition' => $this->getFieldDefinition(), + 'view_mode' => EntityDisplayBase::CUSTOM_MODE, + 'prepare' => TRUE, + ]); + } + +}