View source
<?php
namespace Drupal\fieldblock\Plugin\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Plugin\DataType\EntityAdapter;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FormatterInterface;
use Drupal\Core\Field\FormatterPluginManager;
use Drupal\Core\Form\FormHelper;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Form\SubformStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class FieldBlock extends BlockBase implements ContainerFactoryPluginInterface {
protected $entityTypeManager;
protected $entityFieldManager;
protected $formatterPluginManager;
protected $routeMatch;
private $languageManager;
protected $fieldBlockEntity;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entityTypeManager, EntityFieldManagerInterface $entityFieldManager, FormatterPluginManager $formatter_plugin_manager, RouteMatchInterface $route_match, LanguageManagerInterface $languageManager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entityTypeManager;
$this->entityFieldManager = $entityFieldManager;
$this->formatterPluginManager = $formatter_plugin_manager;
$this->routeMatch = $route_match;
$this->languageManager = $languageManager;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('entity_type.manager'), $container
->get('entity_field.manager'), $container
->get('plugin.manager.field.formatter'), $container
->get('current_route_match'), $container
->get('language_manager'));
}
public function defaultConfiguration() {
return [
'label_from_field' => TRUE,
'field_name' => '',
'formatter_id' => '',
'formatter_settings' => [],
];
}
protected function getFieldOptions() {
$field_definitions = $this->entityFieldManager
->getFieldStorageDefinitions($this
->getDerivativeId());
$options = [];
foreach ($field_definitions as $definition) {
$options[$definition
->getName()] = $definition
->getLabel();
}
return $options;
}
protected function getFormatterOptions(FieldDefinitionInterface $field_definition) {
$options = $this->formatterPluginManager
->getOptions($field_definition
->getType());
foreach ($options as $id => $label) {
$definition = $this->formatterPluginManager
->getDefinition($id, FALSE);
$formatter_plugin_class = isset($definition['class']) ? $definition['class'] : NULL;
$applicable = $formatter_plugin_class instanceof FormatterInterface && $formatter_plugin_class::isApplicable($field_definition);
if ($applicable) {
unset($options[$id]);
}
}
return $options;
}
protected function getFieldDefinition($field_name) {
$field_storage_config = $this
->getFieldStorageDefinition($field_name);
return BaseFieldDefinition::createFromFieldStorageDefinition($field_storage_config);
}
protected function getFieldStorageDefinition($field_name) {
$field_storage_definitions = $this->entityFieldManager
->getFieldStorageDefinitions($this
->getDerivativeId());
return $field_storage_definitions[$field_name];
}
public function blockForm($form, FormStateInterface $form_state) {
if ($form_state instanceof SubformStateInterface) {
$form_state = $form_state
->getCompleteFormState();
}
$form['label_from_field'] = [
'#title' => $this
->t('Use field label as block title'),
'#type' => 'checkbox',
'#default_value' => $this->configuration['label_from_field'],
];
$form['field_name'] = [
'#title' => $this
->t('Field'),
'#type' => 'select',
'#options' => $this
->getFieldOptions(),
'#default_value' => $this->configuration['field_name'],
'#required' => TRUE,
'#ajax' => [
'callback' => [
$this,
'blockFormChangeFieldOrFormatterAjax',
],
'wrapper' => 'edit-block-formatter-wrapper',
],
];
$form['formatter'] = [
'#type' => 'container',
'#id' => 'edit-block-formatter-wrapper',
];
$field_name = $form_state
->getValue([
'settings',
'field_name',
], $this->configuration['field_name']);
$field_definition = NULL;
$formatter_id = $form_state
->getValue([
'settings',
'formatter',
'id',
], $this->configuration['formatter_id']);
if ($field_name) {
$field_definition = $this
->getFieldDefinition($field_name);
$formatter_options = $this
->getFormatterOptions($field_definition);
if (empty($formatter_options)) {
$formatter_id = '';
}
else {
if (empty($formatter_id)) {
$formatter_id = key($formatter_options);
}
$form['formatter']['id'] = [
'#title' => $this
->t('Formatter'),
'#type' => 'select',
'#options' => $formatter_options,
'#default_value' => $this->configuration['formatter_id'],
'#required' => TRUE,
'#ajax' => [
'callback' => [
$this,
'blockFormChangeFieldOrFormatterAjax',
],
'wrapper' => 'edit-block-formatter-wrapper',
],
];
}
}
$form['formatter']['change'] = [
'#type' => 'submit',
'#name' => 'fieldblock_change_field',
'#value' => $this
->t('Change field'),
'#attributes' => [
'class' => [
'js-hide',
],
],
'#limit_validation_errors' => [
[
'settings',
],
],
'#submit' => [
[
get_class($this),
'blockFormChangeFieldOrFormatter',
],
],
];
if ($formatter_id) {
$formatter_settings = $this->configuration['formatter_settings'] + $this->formatterPluginManager
->getDefaultSettings($formatter_id);
$formatter_options = [
'field_definition' => $field_definition,
'view_mode' => '_custom',
'configuration' => [
'type' => $formatter_id,
'settings' => $formatter_settings,
'label' => '',
'weight' => 0,
],
];
if ($formatter_plugin = $this->formatterPluginManager
->getInstance($formatter_options)) {
$formatter_settings_form = $formatter_plugin
->settingsForm($form, $form_state);
FormHelper::rewriteStatesSelector($formatter_settings_form, "fields[{$field_name}][settings_edit_form]", 'settings[formatter][settings]');
}
if (!empty($formatter_settings_form)) {
$form['formatter']['settings'] = $formatter_settings_form;
$form['formatter']['settings']['#type'] = 'fieldset';
$form['formatter']['settings']['#title'] = $this
->t('Formatter settings');
}
}
return $form;
}
public static function blockFormChangeFieldOrFormatter(array $form, FormStateInterface $form_state) {
$form_state
->setRebuild();
}
public function blockFormChangeFieldOrFormatterAjax(array $form) {
return $form['settings']['formatter'];
}
public function blockSubmit($form, FormStateInterface $form_state) {
$this->configuration['label_from_field'] = $form_state
->getValue('label_from_field');
$this->configuration['field_name'] = $form_state
->getValue('field_name');
$this->configuration['formatter_id'] = $form_state
->getValue([
'formatter',
'id',
], '');
$this->configuration['formatter_settings'] = $form_state
->getValue([
'formatter',
'settings',
], []);
}
public function calculateDependencies() {
$dependencies = parent::calculateDependencies();
if (($field_storage_definition = $this
->getFieldStorageDefinition($this->configuration['field_name'])) && $field_storage_definition instanceof EntityInterface) {
$dependencies['config'][] = $field_storage_definition
->getConfigDependencyName();
}
if (!empty($this->configuration['formatter_id'])) {
$dependencies['module'][] = $this->formatterPluginManager
->getDefinition($this->configuration['formatter_id'])['provider'];
}
return $dependencies;
}
protected function blockAccess(AccountInterface $account) {
$entity = $this
->getEntity();
if ($entity) {
$field = $entity
->get($this->configuration['field_name']);
return AccessResult::allowedIf(!$field
->isEmpty() && $field
->access('view', $account));
}
return AccessResult::forbidden();
}
public function build() {
$build = [];
$entity = $this
->getEntity();
if ($entity) {
$build['field'] = $this
->getTranslatedFieldFromEntity($entity)
->view([
'label' => 'hidden',
'type' => $this->configuration['formatter_id'],
'settings' => $this->configuration['formatter_settings'],
]);
if ($this->configuration['label_from_field'] && !empty($build['field']['#title'])) {
$build['#title'] = $build['field']['#title'];
}
}
return $build;
}
private function getTranslatedFieldFromEntity(ContentEntityInterface $entity) {
$language = $this->languageManager
->getCurrentLanguage()
->getId();
$field = $entity
->get($this->configuration['field_name']);
if ($entity
->hasTranslation($language)) {
$translatedEntity = $entity
->getTranslation($language);
$adapter = EntityAdapter::createFromEntity($translatedEntity);
$field
->setContext($this->configuration['field_name'], $adapter);
}
return $field;
}
public function getCacheTags() {
$entity = $this
->getEntity();
if ($entity) {
return $entity
->getCacheTags();
}
return parent::getCacheTags();
}
public function getCacheContexts() {
return [
'route',
];
}
protected function getEntity() {
if (!isset($this->fieldBlockEntity)) {
$entity_type = $this
->getDerivativeId();
$entity = NULL;
$field_name = $this->configuration['field_name'];
$route_name = $this->routeMatch
->getRouteName();
$is_canonical_route = $route_name === 'entity.' . $entity_type . '.canonical';
$is_latest_route = $route_name == 'entity.' . $entity_type . '.latest_version';
if ($is_canonical_route || $is_latest_route) {
$entity = $this->routeMatch
->getParameter($entity_type);
}
elseif ($entity_type === 'node') {
if ($route_name == 'entity.node.revision') {
$entity_revision = $this->routeMatch
->getParameter('node_revision');
$entity = $this->entityTypeManager
->getStorage('node')
->loadRevision($entity_revision);
}
elseif ($route_name == 'entity.node.preview' && $this->routeMatch
->getParameter('view_mode_id') === 'full') {
$entity = $this->routeMatch
->getParameter('node_preview');
}
}
if ($entity instanceof ContentEntityInterface && $entity
->getEntityTypeId() === $entity_type && $entity
->hasField($field_name)) {
$this->fieldBlockEntity = $entity;
}
}
return $this->fieldBlockEntity;
}
}