class ComponentBlock in Component blocks 1.0.x
Same name and namespace in other branches
- 1.x src/Plugin/Block/ComponentBlock.php \Drupal\component_blocks\Plugin\Block\ComponentBlock
- 1.1.x src/Plugin/Block/ComponentBlock.php \Drupal\component_blocks\Plugin\Block\ComponentBlock
Defines a class for a specially shaped block.
Plugin annotation
@Block(
id = "component_blocks",
admin_label = @Translation("Component blocks"),
category = @Translation("Component blocks"),
deriver = "Drupal\component_blocks\Plugin\Deriver\ComponentBlockBlockDeriver",
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\Core\Block\BlockBase implements BlockPluginInterface, ContextAwarePluginInterface, PluginWithFormsInterface, PreviewFallbackInterface uses BlockPluginTrait, ContextAwarePluginAssignmentTrait, ContextAwarePluginTrait
- class \Drupal\component_blocks\Plugin\Block\ComponentBlock implements ContainerFactoryPluginInterface uses LayoutBuilderContextTrait
- class \Drupal\Core\Block\BlockBase implements BlockPluginInterface, ContextAwarePluginInterface, PluginWithFormsInterface, PreviewFallbackInterface uses BlockPluginTrait, ContextAwarePluginAssignmentTrait, ContextAwarePluginTrait
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of ComponentBlock
File
- src/
Plugin/ Block/ ComponentBlock.php, line 36
Namespace
Drupal\component_blocks\Plugin\BlockView source
class ComponentBlock extends BlockBase implements ContainerFactoryPluginInterface {
use LayoutBuilderContextTrait;
const FIXED = '__fixed';
/**
* Plugin manager.
*
* @var \Drupal\ui_patterns\UiPatternsManager
*/
private $uiPatternsManager;
/**
* Entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Context handler.
*
* @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
*/
private $contextHandler;
/**
* Formatter manager.
*
* @var \Drupal\Core\Field\FormatterPluginManager
*/
private $formatterPluginManager;
/**
* Token service.
*
* @var \Drupal\Core\Utility\Token
*/
private $token;
/**
* Constructs a new ComponentBlock.
*
* @param array $configuration
* Configuration.
* @param string $plugin_id
* Plugin Id.
* @param array $plugin_definition
* Plugin definition.
* @param \Drupal\ui_patterns\UiPatternsManager $uiPatternsManager
* Plugin manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* Entity type manager.
* @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $contextHandler
* Context handler.
* @param \Drupal\Core\Field\FormatterPluginManager $formatterPluginManager
* Formatter manager.
* @param \Drupal\Core\Utility\Token $token
* Token service.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, UiPatternsManager $uiPatternsManager, EntityTypeManagerInterface $entityTypeManager, ContextHandlerInterface $contextHandler, FormatterPluginManager $formatterPluginManager, Token $token) {
$this->uiPatternsManager = $uiPatternsManager;
$this->entityTypeManager = $entityTypeManager;
$this->contextHandler = $contextHandler;
$this->formatterPluginManager = $formatterPluginManager;
$this->token = $token;
// This has to be last because the parent constructor calls
// ::setConfiguration.
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('plugin.manager.ui_patterns'), $container
->get('entity_type.manager'), $container
->get('context.handler'), $container
->get('plugin.manager.field.formatter'), $container
->get('token'));
}
/**
* {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
$defaultConfiguration = $this
->defaultConfiguration();
$plugin = $this
->uiPatternsManager()
->getDefinition($this->pluginDefinition['ui_pattern_id']);
foreach ($plugin['fields'] as $item) {
if (!($item['ui'] ?? TRUE)) {
// We don't want duplicates for no-ui items - default is enough.
unset($configuration['variables'][$item
->getName()]['value']);
}
}
$this->configuration = NestedArray::mergeDeep($this
->baseConfigurationDefaults(), $defaultConfiguration, $configuration);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
$plugin = $this
->uiPatternsManager()
->getDefinition($this->pluginDefinition['ui_pattern_id']);
$defaults = array_map(function (PatternDefinitionField $item) {
return [
'source' => self::FIXED,
'value' => $item['default'] ?? '',
];
}, $plugin['fields']);
return [
'variables' => $defaults,
];
}
/**
* {@inheritdoc}
*/
public function build() {
$definition = $this
->uiPatternsManager()
->getDefinition($this->pluginDefinition['ui_pattern_id']);
$context = [];
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $this
->getContextValue('entity');
$view_builder = $this->entityTypeManager
->getViewBuilder($entity
->getEntityTypeId());
$metadata = new BubbleableMetadata();
$metadata
->addCacheableDependency($entity);
foreach ($this
->getConfiguration()['variables'] as $context_id => $details) {
if ($details['source'] === self::FIXED) {
if (!is_scalar($details['value'])) {
// Allow for array default values.
$context[$context_id] = $details['value'];
continue;
}
try {
$value = $this->token
->replace($details['value'], [
$entity
->getEntityTypeId() => $entity,
], [], $metadata);
if ($value !== $details['value']) {
// Token replacement sanitizes, so we need to flag as such.
$value = Markup::create($value);
}
} catch (EntityMalformedException $e) {
// Attempt to get e.g an entity URL without a saved entity in layout
// builder.
$value = '';
}
$context[$context_id] = $value;
continue;
}
try {
$formatter_output = $view_builder
->viewField($entity
->get($details['source']), array_intersect_key($details, [
'type' => TRUE,
'settings' => TRUE,
]) + [
'label' => 'hidden',
]);
if (Element::isEmpty($formatter_output)) {
// No output other than cache metadata.
$metadata
->merge(CacheableMetadata::createFromRenderArray($formatter_output));
continue;
}
$context[$context_id] = [
'#theme' => 'field__component_block',
] + $formatter_output;
} catch (EntityMalformedException $e) {
// Attempt to get e.g an entity URL without a saved entity in layout
// builder.
$context[$context_id] = '';
}
}
$build = [
'#type' => 'pattern',
'#id' => $this->pluginDefinition['ui_pattern_id'],
'#fields' => $context,
'#context' => [
'type' => 'entity',
'entity' => $entity,
],
];
// Attach libraries to the block;.
if (!empty($definition['libraries'])) {
$metadata
->addAttachments([
'library' => $definition['libraries'],
]);
}
$metadata
->applyTo($build);
return $build;
}
/**
* {@inheritdoc}
*/
public function blockForm($form, FormStateInterface $form_state) {
$plugin = $this
->uiPatternsManager()
->getDefinition($this->pluginDefinition['ui_pattern_id']);
$form = parent::blockForm($form, $form_state);
$form['variables'] = [
'#type' => 'details',
'#title' => $this
->t('Context variables'),
'#open' => TRUE,
'#tree' => TRUE,
];
$contexts = $this
->contextHandler()
->getMatchingContexts($form_state
->getTemporaryValue('gathered_contexts') ?: [], $this
->getContextDefinition('entity'));
$context = reset($contexts);
/** @var \Drupal\Core\Entity\ContentEntityInterface $sample_entity */
$sample_entity = $context
->getContextData()
->getValue();
$fields = array_map(function (FieldDefinitionInterface $field) {
return $field
->getLabel();
}, $sample_entity
->getFieldDefinitions());
$fields[self::FIXED] = $this
->t('Fixed input');
foreach ($plugin['fields'] as $id => $details) {
if (!($details['ui'] ?? TRUE)) {
$form['variables'][$id] = [
'source' => [
'#type' => 'value',
'#value' => self::FIXED,
],
'value' => [
'#type' => 'value',
'#value' => $details['default'],
],
];
continue;
}
$form['variables'][$id] = [
'#type' => 'container',
'#process' => [
[
$this,
'formatterSettingsProcessCallback',
],
],
'#prefix' => '<div id="component-settings-' . $id . '">',
'#suffix' => '</div>',
'label' => [
'#type' => 'item',
'#markup' => $details['label'],
],
'source' => [
'#type' => 'select',
'#options' => $fields,
'#default_value' => self::FIXED,
'#title' => $this
->t('Source'),
'#ajax' => [
'callback' => [
get_class($this),
'updateElementValue',
],
'wrapper' => 'component-settings-' . $id,
],
],
];
}
return $form;
}
/**
* Render API callback: builds the formatter settings elements.
*/
public function formatterSettingsProcessCallback(array &$element, FormStateInterface $form_state, array &$complete_form) {
if ($configuration = $this
->getCurrentConfiguration($element['#parents'], $form_state)) {
if ($configuration['source'] === self::FIXED) {
$element['value'] = [
'#type' => 'textfield',
'#default_value' => $configuration['value'] ?? '',
'#title' => $this
->t('Fixed value'),
];
return $element;
}
$contexts = $this
->contextHandler()
->getMatchingContexts($form_state
->getTemporaryValue('gathered_contexts') ?: [], $this
->getContextDefinition('entity'));
// Contexts can become empty on subsequent ajax requests with layout
// builder.
if (!$contexts) {
$contexts = $this
->contextHandler()
->getMatchingContexts($this
->getAvailableContexts($form_state
->getBuildInfo()['args'][0]), $this
->getContextDefinition('entity'));
}
$context = reset($contexts);
/** @var \Drupal\Core\Entity\ContentEntityInterface $sample_entity */
$sample_entity = $context
->getContextData()
->getValue();
$field_definition = $sample_entity
->getFieldDefinition($configuration['source']);
$formatter_configuration = array_intersect_key($configuration, [
'type' => TRUE,
'settings' => TRUE,
]) + [
'label' => 'hidden',
];
$options = $this
->getApplicablePluginOptions($field_definition);
$keys = array_keys($options);
$formatter_configuration += [
'type' => reset($keys),
'settings' => $this
->formatterPluginManager()
->getDefaultSettings(reset($keys)),
];
$formatter = $this
->formatterPluginManager()
->getInstance([
'configuration' => $formatter_configuration,
'field_definition' => $field_definition,
'view_mode' => EntityDisplayBase::CUSTOM_MODE,
'prepare' => TRUE,
]);
$element['source']['#default_value'] = $configuration['source'];
$element['type'] = [
'#type' => 'select',
'#options' => $options,
'#default_value' => $formatter_configuration['type'],
'#required' => TRUE,
'#title' => $this
->t('Formatter'),
'#ajax' => [
'callback' => [
static::class,
'updateElementValue',
],
'wrapper' => 'component-settings-' . end($element['#parents']),
],
];
$element['settings'] = $formatter
->settingsForm($complete_form, $form_state);
$element['settings']['#parents'] = array_merge($element['#parents'], [
'settings',
]);
}
return $element;
}
/**
* Gets the current configuration for given parents.
*
* @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 array|null
* The current configuration.
*/
protected function getCurrentConfiguration(array $parents, FormStateInterface $form_state) : ?array {
// Use the processed values, if available.
$configuration = NestedArray::getValue($form_state
->getValues(), $parents);
$variable = end($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.
$settings = $this
->getConfiguration()['variables'][$variable];
return $settings;
}
}
return $configuration;
}
/**
* Ajax callback that updates options.
*/
public static function updateElementValue(array $form, FormStateInterface $form_state) {
$array_parents = $form_state
->getTriggeringElement()['#array_parents'];
array_pop($array_parents);
return NestedArray::getValue($form, $array_parents);
}
/**
* {@inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $form_state) {
$this->configuration['variables'] = $form_state
->getValue('variables');
}
/**
* 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
->formatterPluginManager()
->getOptions($field_definition
->getType());
$applicable_options = [];
foreach ($options as $option => $label) {
$plugin_class = DefaultFactory::getPluginClass($option, $this
->formatterPluginManager()
->getDefinition($option));
if ($plugin_class::isApplicable($field_definition)) {
$applicable_options[$option] = $label;
}
}
return $applicable_options;
}
/**
* {@inheritdoc}
*/
protected function contextHandler() {
// phpcs:disable DrupalPractice.Objects.GlobalDrupal.GlobalDrupal
return $this->contextHandler ?: \Drupal::service('context.handler');
}
/**
* Gets the formatter plugin manager.
*
* In some AJAX contexts, the constructor is not called.
*
* @return \Drupal\Core\Field\FormatterPluginManager
* Manager.
*/
protected function formatterPluginManager() : FormatterPluginManager {
if (!$this->formatterPluginManager) {
$this->formatterPluginManager = \Drupal::service('plugin.manager.field.formatter');
}
return $this->formatterPluginManager;
}
/**
* Gets the UI patterns manager.
*
* In some AJAX contexts, the constructor is not called.
*
* @return \Drupal\ui_patterns\UiPatternsManager
* Manager.
*/
protected function uiPatternsManager() : UiPatternsManager {
if (!$this->uiPatternsManager) {
$this->uiPatternsManager = \Drupal::service('plugin.manager.ui_patterns');
}
return $this->uiPatternsManager;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
BlockBase:: |
public | function |
Form constructor. Overrides PluginFormInterface:: |
2 |
BlockPluginInterface:: |
constant | Indicates the block label (title) should be displayed to end users. | ||
BlockPluginTrait:: |
protected | property | The transliteration service. | |
BlockPluginTrait:: |
public | function | ||
BlockPluginTrait:: |
protected | function | Returns generic default configuration for block plugins. | |
BlockPluginTrait:: |
protected | function | Indicates whether the block should be shown. | 16 |
BlockPluginTrait:: |
public | function | 3 | |
BlockPluginTrait:: |
public | function | Creates a generic configuration form for all block types. Individual block plugins can add elements to this form by overriding BlockBase::blockForm(). Most block plugins should not override this method unless they need to alter the generic form elements. Aliased as: traitBuildConfigurationForm | |
BlockPluginTrait:: |
public | function | ||
BlockPluginTrait:: |
public | function | 1 | |
BlockPluginTrait:: |
public | function | 1 | |
BlockPluginTrait:: |
public | function | 3 | |
BlockPluginTrait:: |
public | function | ||
BlockPluginTrait:: |
public | function | ||
BlockPluginTrait:: |
public | function | Sets the transliteration service. | |
BlockPluginTrait:: |
public | function | Most block plugins should not override this method. To add submission handling for a specific block type, override BlockBase::blockSubmit(). | |
BlockPluginTrait:: |
protected | function | Wraps the transliteration service. | |
BlockPluginTrait:: |
public | function | Most block plugins should not override this method. To add validation for a specific block type, override BlockBase::blockValidate(). | 1 |
ComponentBlock:: |
private | property | Context handler. | |
ComponentBlock:: |
protected | property | Entity type manager. | |
ComponentBlock:: |
private | property | Formatter manager. | |
ComponentBlock:: |
private | property | Token service. | |
ComponentBlock:: |
private | property | Plugin manager. | |
ComponentBlock:: |
public | function |
Overrides BlockPluginTrait:: |
|
ComponentBlock:: |
public | function |
Overrides BlockPluginTrait:: |
|
ComponentBlock:: |
public | function |
Builds and returns the renderable array for this block plugin. Overrides BlockPluginInterface:: |
|
ComponentBlock:: |
protected | function |
Wraps the context handler. Overrides ContextAwarePluginAssignmentTrait:: |
|
ComponentBlock:: |
public static | function |
Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface:: |
|
ComponentBlock:: |
public | function |
Overrides BlockPluginTrait:: |
|
ComponentBlock:: |
constant | |||
ComponentBlock:: |
protected | function | Gets the formatter plugin manager. | |
ComponentBlock:: |
public | function | Render API callback: builds the formatter settings elements. | |
ComponentBlock:: |
protected | function | Returns an array of applicable formatter options for a field. | |
ComponentBlock:: |
protected | function | Gets the current configuration for given parents. | |
ComponentBlock:: |
public | function |
Overrides BlockPluginTrait:: |
|
ComponentBlock:: |
protected | function | Gets the UI patterns manager. | |
ComponentBlock:: |
public static | function | Ajax callback that updates options. | |
ComponentBlock:: |
public | function |
Constructs a new ComponentBlock. Overrides BlockPluginTrait:: |
|
ContextAwarePluginAssignmentTrait:: |
protected | function | Builds a form element for assigning a context to a given slot. | |
ContextAwarePluginTrait:: |
protected | property | The data objects representing the context of this plugin. | |
ContextAwarePluginTrait:: |
protected | property | Tracks whether the context has been initialized from configuration. | |
ContextAwarePluginTrait:: |
public | function | 9 | |
ContextAwarePluginTrait:: |
public | function | 7 | |
ContextAwarePluginTrait:: |
public | function | 4 | |
ContextAwarePluginTrait:: |
public | function | ||
ContextAwarePluginTrait:: |
public | function | ||
ContextAwarePluginTrait:: |
public | function | ||
ContextAwarePluginTrait:: |
public | function | ||
ContextAwarePluginTrait:: |
public | function | ||
ContextAwarePluginTrait:: |
public | function | ||
ContextAwarePluginTrait:: |
public | function | ||
ContextAwarePluginTrait:: |
abstract protected | function | 1 | |
ContextAwarePluginTrait:: |
public | function | 1 | |
ContextAwarePluginTrait:: |
public | function | ||
ContextAwarePluginTrait:: |
public | function | ||
ContextAwarePluginTrait:: |
public | function | ||
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
public | function | 2 | |
DependencySerializationTrait:: |
public | function | 2 | |
LayoutBuilderContextTrait:: |
protected | property | The context repository. | |
LayoutBuilderContextTrait:: |
protected | function | Gets the context repository service. | |
LayoutBuilderContextTrait:: |
protected | function | Provides all available contexts, both global and section_storage-specific. | |
LayoutBuilderContextTrait:: |
protected | function | Returns all populated contexts, both global and section-storage-specific. | |
MessengerTrait:: |
protected | property | The messenger. | 27 |
MessengerTrait:: |
public | function | Gets the messenger. | 27 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
PluginWithFormsTrait:: |
public | function | Implements \Drupal\Core\Plugin\PluginWithFormsInterface::getFormClass(). | |
PluginWithFormsTrait:: |
public | function | Implements \Drupal\Core\Plugin\PluginWithFormsInterface::hasFormClass(). | |
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |