3 namespace Drupal\Core\Block;
5 use Drupal\Core\Access\AccessResult;
6 use Drupal\Core\Form\FormStateInterface;
7 use Drupal\Core\Messenger\MessengerTrait;
8 use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
9 use Drupal\Core\Plugin\ContextAwarePluginBase;
10 use Drupal\Component\Utility\NestedArray;
11 use Drupal\Core\Language\LanguageInterface;
12 use Drupal\Core\Plugin\PluginWithFormsInterface;
13 use Drupal\Core\Plugin\PluginWithFormsTrait;
14 use Drupal\Core\Render\PreviewFallbackInterface;
15 use Drupal\Core\Session\AccountInterface;
16 use Drupal\Component\Transliteration\TransliterationInterface;
19 * Defines a base block implementation that most blocks plugins will extend.
21 * This abstract class provides the generic block configuration form, default
22 * block settings, and handling for general user-defined block visibility
27 abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface, PluginWithFormsInterface, PreviewFallbackInterface {
29 use ContextAwarePluginAssignmentTrait;
31 use PluginWithFormsTrait;
34 * The transliteration service.
36 * @var \Drupal\Component\Transliteration\TransliterationInterface
38 protected $transliteration;
43 public function label() {
44 if (!empty($this->configuration['label'])) {
45 return $this->configuration['label'];
48 $definition = $this->getPluginDefinition();
49 // Cast the admin label to a string since it is an object.
50 // @see \Drupal\Core\StringTranslation\TranslatableMarkup
51 return (string) $definition['admin_label'];
57 public function __construct(array $configuration, $plugin_id, $plugin_definition) {
58 parent::__construct($configuration, $plugin_id, $plugin_definition);
59 $this->setConfiguration($configuration);
65 public function getConfiguration() {
66 return $this->configuration;
72 public function setConfiguration(array $configuration) {
73 $this->configuration = NestedArray::mergeDeep(
74 $this->baseConfigurationDefaults(),
75 $this->defaultConfiguration(),
81 * Returns generic default configuration for block plugins.
84 * An associative array with the default configuration.
86 protected function baseConfigurationDefaults() {
88 'id' => $this->getPluginId(),
90 'provider' => $this->pluginDefinition['provider'],
91 'label_display' => static::BLOCK_LABEL_VISIBLE,
98 public function defaultConfiguration() {
105 public function setConfigurationValue($key, $value) {
106 $this->configuration[$key] = $value;
112 public function calculateDependencies() {
119 public function access(AccountInterface $account, $return_as_object = FALSE) {
120 $access = $this->blockAccess($account);
121 return $return_as_object ? $access : $access->isAllowed();
125 * Indicates whether the block should be shown.
127 * Blocks with specific access checking should override this method rather
128 * than access(), in order to avoid repeating the handling of the
129 * $return_as_object argument.
131 * @param \Drupal\Core\Session\AccountInterface $account
132 * The user session for which to check access.
134 * @return \Drupal\Core\Access\AccessResult
137 * @see self::access()
139 protected function blockAccess(AccountInterface $account) {
140 // By default, the block is visible.
141 return AccessResult::allowed();
147 * Creates a generic configuration form for all block types. Individual
148 * block plugins can add elements to this form by overriding
149 * BlockBase::blockForm(). Most block plugins should not override this
150 * method unless they need to alter the generic form elements.
152 * @see \Drupal\Core\Block\BlockBase::blockForm()
154 public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
155 $definition = $this->getPluginDefinition();
156 $form['provider'] = [
158 '#value' => $definition['provider'],
161 $form['admin_label'] = [
163 '#title' => $this->t('Block description'),
164 '#plain_text' => $definition['admin_label'],
167 '#type' => 'textfield',
168 '#title' => $this->t('Title'),
170 '#default_value' => $this->label(),
173 $form['label_display'] = [
174 '#type' => 'checkbox',
175 '#title' => $this->t('Display title'),
176 '#default_value' => ($this->configuration['label_display'] === static::BLOCK_LABEL_VISIBLE),
177 '#return_value' => static::BLOCK_LABEL_VISIBLE,
180 // Add context mapping UI form elements.
181 $contexts = $form_state->getTemporaryValue('gathered_contexts') ?: [];
182 $form['context_mapping'] = $this->addContextAssignmentElement($this, $contexts);
183 // Add plugin-specific settings for this block type.
184 $form += $this->blockForm($form, $form_state);
191 public function blockForm($form, FormStateInterface $form_state) {
198 * Most block plugins should not override this method. To add validation
199 * for a specific block type, override BlockBase::blockValidate().
201 * @see \Drupal\Core\Block\BlockBase::blockValidate()
203 public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
204 // Remove the admin_label form item element value so it will not persist.
205 $form_state->unsetValue('admin_label');
207 $this->blockValidate($form, $form_state);
213 public function blockValidate($form, FormStateInterface $form_state) {}
218 * Most block plugins should not override this method. To add submission
219 * handling for a specific block type, override BlockBase::blockSubmit().
221 * @see \Drupal\Core\Block\BlockBase::blockSubmit()
223 public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
224 // Process the block's submission handling if no errors occurred only.
225 if (!$form_state->getErrors()) {
226 $this->configuration['label'] = $form_state->getValue('label');
227 $this->configuration['label_display'] = $form_state->getValue('label_display');
228 $this->configuration['provider'] = $form_state->getValue('provider');
229 $this->blockSubmit($form, $form_state);
236 public function blockSubmit($form, FormStateInterface $form_state) {}
241 public function getMachineNameSuggestion() {
242 $definition = $this->getPluginDefinition();
243 $admin_label = $definition['admin_label'];
245 // @todo This is basically the same as what is done in
246 // \Drupal\system\MachineNameController::transliterate(), so it might make
247 // sense to provide a common service for the two.
248 $transliterated = $this->transliteration()->transliterate($admin_label, LanguageInterface::LANGCODE_DEFAULT, '_');
249 $transliterated = mb_strtolower($transliterated);
251 $transliterated = preg_replace('@[^a-z0-9_.]+@', '', $transliterated);
253 return $transliterated;
259 public function getPreviewFallbackString() {
260 return $this->t('Placeholder for the "@block" block', ['@block' => $this->label()]);
264 * Wraps the transliteration service.
266 * @return \Drupal\Component\Transliteration\TransliterationInterface
268 protected function transliteration() {
269 if (!$this->transliteration) {
270 $this->transliteration = \Drupal::transliteration();
272 return $this->transliteration;
276 * Sets the transliteration service.
278 * @param \Drupal\Component\Transliteration\TransliterationInterface $transliteration
279 * The transliteration service.
281 public function setTransliteration(TransliterationInterface $transliteration) {
282 $this->transliteration = $transliteration;