BlockBase.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. <?php
  2. namespace Drupal\Core\Block;
  3. use Drupal\Core\Access\AccessResult;
  4. use Drupal\Core\Form\FormStateInterface;
  5. use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
  6. use Drupal\Core\Plugin\ContextAwarePluginBase;
  7. use Drupal\Component\Utility\Unicode;
  8. use Drupal\Component\Utility\NestedArray;
  9. use Drupal\Core\Language\LanguageInterface;
  10. use Drupal\Core\Plugin\PluginWithFormsInterface;
  11. use Drupal\Core\Plugin\PluginWithFormsTrait;
  12. use Drupal\Core\Session\AccountInterface;
  13. use Drupal\Component\Transliteration\TransliterationInterface;
  14. /**
  15. * Defines a base block implementation that most blocks plugins will extend.
  16. *
  17. * This abstract class provides the generic block configuration form, default
  18. * block settings, and handling for general user-defined block visibility
  19. * settings.
  20. *
  21. * @ingroup block_api
  22. */
  23. abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface, PluginWithFormsInterface {
  24. use ContextAwarePluginAssignmentTrait;
  25. use PluginWithFormsTrait;
  26. /**
  27. * The transliteration service.
  28. *
  29. * @var \Drupal\Component\Transliteration\TransliterationInterface
  30. */
  31. protected $transliteration;
  32. /**
  33. * {@inheritdoc}
  34. */
  35. public function label() {
  36. if (!empty($this->configuration['label'])) {
  37. return $this->configuration['label'];
  38. }
  39. $definition = $this->getPluginDefinition();
  40. // Cast the admin label to a string since it is an object.
  41. // @see \Drupal\Core\StringTranslation\TranslatableMarkup
  42. return (string) $definition['admin_label'];
  43. }
  44. /**
  45. * {@inheritdoc}
  46. */
  47. public function __construct(array $configuration, $plugin_id, $plugin_definition) {
  48. parent::__construct($configuration, $plugin_id, $plugin_definition);
  49. $this->setConfiguration($configuration);
  50. }
  51. /**
  52. * {@inheritdoc}
  53. */
  54. public function getConfiguration() {
  55. return $this->configuration;
  56. }
  57. /**
  58. * {@inheritdoc}
  59. */
  60. public function setConfiguration(array $configuration) {
  61. $this->configuration = NestedArray::mergeDeep(
  62. $this->baseConfigurationDefaults(),
  63. $this->defaultConfiguration(),
  64. $configuration
  65. );
  66. }
  67. /**
  68. * Returns generic default configuration for block plugins.
  69. *
  70. * @return array
  71. * An associative array with the default configuration.
  72. */
  73. protected function baseConfigurationDefaults() {
  74. return [
  75. 'id' => $this->getPluginId(),
  76. 'label' => '',
  77. 'provider' => $this->pluginDefinition['provider'],
  78. 'label_display' => static::BLOCK_LABEL_VISIBLE,
  79. ];
  80. }
  81. /**
  82. * {@inheritdoc}
  83. */
  84. public function defaultConfiguration() {
  85. return [];
  86. }
  87. /**
  88. * {@inheritdoc}
  89. */
  90. public function setConfigurationValue($key, $value) {
  91. $this->configuration[$key] = $value;
  92. }
  93. /**
  94. * {@inheritdoc}
  95. */
  96. public function calculateDependencies() {
  97. return [];
  98. }
  99. /**
  100. * {@inheritdoc}
  101. */
  102. public function access(AccountInterface $account, $return_as_object = FALSE) {
  103. $access = $this->blockAccess($account);
  104. return $return_as_object ? $access : $access->isAllowed();
  105. }
  106. /**
  107. * Indicates whether the block should be shown.
  108. *
  109. * Blocks with specific access checking should override this method rather
  110. * than access(), in order to avoid repeating the handling of the
  111. * $return_as_object argument.
  112. *
  113. * @param \Drupal\Core\Session\AccountInterface $account
  114. * The user session for which to check access.
  115. *
  116. * @return \Drupal\Core\Access\AccessResult
  117. * The access result.
  118. *
  119. * @see self::access()
  120. */
  121. protected function blockAccess(AccountInterface $account) {
  122. // By default, the block is visible.
  123. return AccessResult::allowed();
  124. }
  125. /**
  126. * {@inheritdoc}
  127. *
  128. * Creates a generic configuration form for all block types. Individual
  129. * block plugins can add elements to this form by overriding
  130. * BlockBase::blockForm(). Most block plugins should not override this
  131. * method unless they need to alter the generic form elements.
  132. *
  133. * @see \Drupal\Core\Block\BlockBase::blockForm()
  134. */
  135. public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
  136. $definition = $this->getPluginDefinition();
  137. $form['provider'] = [
  138. '#type' => 'value',
  139. '#value' => $definition['provider'],
  140. ];
  141. $form['admin_label'] = [
  142. '#type' => 'item',
  143. '#title' => $this->t('Block description'),
  144. '#plain_text' => $definition['admin_label'],
  145. ];
  146. $form['label'] = [
  147. '#type' => 'textfield',
  148. '#title' => $this->t('Title'),
  149. '#maxlength' => 255,
  150. '#default_value' => $this->label(),
  151. '#required' => TRUE,
  152. ];
  153. $form['label_display'] = [
  154. '#type' => 'checkbox',
  155. '#title' => $this->t('Display title'),
  156. '#default_value' => ($this->configuration['label_display'] === static::BLOCK_LABEL_VISIBLE),
  157. '#return_value' => static::BLOCK_LABEL_VISIBLE,
  158. ];
  159. // Add context mapping UI form elements.
  160. $contexts = $form_state->getTemporaryValue('gathered_contexts') ?: [];
  161. $form['context_mapping'] = $this->addContextAssignmentElement($this, $contexts);
  162. // Add plugin-specific settings for this block type.
  163. $form += $this->blockForm($form, $form_state);
  164. return $form;
  165. }
  166. /**
  167. * {@inheritdoc}
  168. */
  169. public function blockForm($form, FormStateInterface $form_state) {
  170. return [];
  171. }
  172. /**
  173. * {@inheritdoc}
  174. *
  175. * Most block plugins should not override this method. To add validation
  176. * for a specific block type, override BlockBase::blockValidate().
  177. *
  178. * @see \Drupal\Core\Block\BlockBase::blockValidate()
  179. */
  180. public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
  181. // Remove the admin_label form item element value so it will not persist.
  182. $form_state->unsetValue('admin_label');
  183. $this->blockValidate($form, $form_state);
  184. }
  185. /**
  186. * {@inheritdoc}
  187. */
  188. public function blockValidate($form, FormStateInterface $form_state) {}
  189. /**
  190. * {@inheritdoc}
  191. *
  192. * Most block plugins should not override this method. To add submission
  193. * handling for a specific block type, override BlockBase::blockSubmit().
  194. *
  195. * @see \Drupal\Core\Block\BlockBase::blockSubmit()
  196. */
  197. public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
  198. // Process the block's submission handling if no errors occurred only.
  199. if (!$form_state->getErrors()) {
  200. $this->configuration['label'] = $form_state->getValue('label');
  201. $this->configuration['label_display'] = $form_state->getValue('label_display');
  202. $this->configuration['provider'] = $form_state->getValue('provider');
  203. $this->blockSubmit($form, $form_state);
  204. }
  205. }
  206. /**
  207. * {@inheritdoc}
  208. */
  209. public function blockSubmit($form, FormStateInterface $form_state) {}
  210. /**
  211. * {@inheritdoc}
  212. */
  213. public function getMachineNameSuggestion() {
  214. $definition = $this->getPluginDefinition();
  215. $admin_label = $definition['admin_label'];
  216. // @todo This is basically the same as what is done in
  217. // \Drupal\system\MachineNameController::transliterate(), so it might make
  218. // sense to provide a common service for the two.
  219. $transliterated = $this->transliteration()->transliterate($admin_label, LanguageInterface::LANGCODE_DEFAULT, '_');
  220. $transliterated = Unicode::strtolower($transliterated);
  221. $transliterated = preg_replace('@[^a-z0-9_.]+@', '', $transliterated);
  222. return $transliterated;
  223. }
  224. /**
  225. * Wraps the transliteration service.
  226. *
  227. * @return \Drupal\Component\Transliteration\TransliterationInterface
  228. */
  229. protected function transliteration() {
  230. if (!$this->transliteration) {
  231. $this->transliteration = \Drupal::transliteration();
  232. }
  233. return $this->transliteration;
  234. }
  235. /**
  236. * Sets the transliteration service.
  237. *
  238. * @param \Drupal\Component\Transliteration\TransliterationInterface $transliteration
  239. * The transliteration service.
  240. */
  241. public function setTransliteration(TransliterationInterface $transliteration) {
  242. $this->transliteration = $transliteration;
  243. }
  244. }