diff --git a/core/modules/block/block.module b/core/modules/block/block.module index 88b6ecc..dc60761 100644 --- a/core/modules/block/block.module +++ b/core/modules/block/block.module @@ -50,7 +50,7 @@ function block_help($route_name, Request $request) { $output .= '
' . t('The Custom Block module allows you to create blocks of content, which can be placed in regions throughout the website. Custom blocks can have fields; see the Field module help for more information. Once created, custom blocks can be placed like blocks provided by other modules; see the Block module help page for details. For more information, see the online documentation for the Custom Block module.', array('!custom-blocks' => \Drupal::url('custom_block.list'), '!field-help' => \Drupal::url('help.page', array('name' => 'field')), '!blocks' => \Drupal::url('help.page', array('name' => 'block')), '!online-help' => 'https://drupal.org/documentation/modules/custom_block')) . '
'; - $output .= '' . t('This page lists user-created blocks. These blocks are derived from block types. A block type can consist of different fields and display settings. From the block types tab you can manage these fields as well as create new block types.') . '
'; - return $output; - - case 'custom_block.type_list': - $output = '' . t('This page lists block types. A block type can consist of different fields and display settings. From here you can manage these fields as well as create new block types.') . '
'; - return $output; - - } -} - -/** - * Implements hook_theme(). - */ -function custom_block_theme($existing, $type, $theme, $path) { - return array( - 'custom_block_add_list' => array( - 'variables' => array('content' => NULL), - 'file' => 'custom_block.pages.inc', - 'template' => 'custom-block-add-list', - ), - ); -} - -/** - * Loads a custom block type. - * - * @param int $id - * The ID of the custom block type to load. - * - * @return \Drupal\custom_block\Entity\CustomBlockType|null - * A CustomBlockType object or NULL if the requested $id does not exist. - */ -function custom_block_type_load($id) { - return entity_load('custom_block_type', $id); -} - -/** - * Loads a custom block. - * - * @param int $id - * The id of the custom block. - * - * @return \Drupal\custom_block\Entity\CustomBlock|null - * A CustomBlock object or NULL if the requested $id does not exist. - */ -function custom_block_load($id) { - return entity_load('custom_block', $id); -} - -/** - * Implements hook_entity_type_alter(). - */ -function custom_block_entity_type_alter(array &$entity_types) { - /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */ - // Add a translation handler for fields if the language module is enabled. - if (\Drupal::moduleHandler()->moduleExists('language')) { - $translation = $entity_types['custom_block']->get('translation'); - $translation['custom_block'] = TRUE; - $entity_types['custom_block']->set('translation', $translation); - } -} - -/** - * Implements hook_entity_bundle_info(). - */ -function custom_block_entity_bundle_info() { - $bundles = array(); - foreach (\Drupal::configFactory()->listAll('custom_block.type.') as $config_name) { - $config = \Drupal::config($config_name); - $bundles['custom_block'][$config->get('id')]['label'] = $config->get('label'); - } - return $bundles; -} - -/** - * Adds the default body field to a custom block type. - * - * @param string $block_type_id - * Id of the block type. - * @param string $label - * (optional) The label for the body instance. Defaults to 'Body' - * - * @return array() - * Body field instance. - */ -function custom_block_add_body_field($block_type_id, $label = 'Body') { - // Add or remove the body field, as needed. - $field = field_info_field('custom_block', 'body'); - $instance = field_info_instance('custom_block', 'body', $block_type_id); - if (empty($field)) { - $field = entity_create('field_config', array( - 'name' => 'body', - 'entity_type' => 'custom_block', - 'type' => 'text_with_summary', - )); - $field->save(); - } - if (empty($instance)) { - $instance = entity_create('field_instance_config', array( - 'field_name' => 'body', - 'entity_type' => 'custom_block', - 'bundle' => $block_type_id, - 'label' => $label, - 'settings' => array('display_summary' => FALSE), - )); - $instance->save(); - - // Assign widget settings for the 'default' form mode. - entity_get_form_display('custom_block', $block_type_id, 'default') - ->setComponent('body', array( - 'type' => 'text_textarea_with_summary', - )) - ->save(); - - // Assign display settings for 'default' view mode. - entity_get_display('custom_block', $block_type_id, 'default') - ->setComponent('body', array( - 'label' => 'hidden', - 'type' => 'text_default', - )) - ->save(); - } - - return $instance; -} diff --git a/core/modules/block/custom_block/custom_block.pages.inc b/core/modules/block/custom_block/custom_block.pages.inc deleted file mode 100644 index f24e16b..0000000 --- a/core/modules/block/custom_block/custom_block.pages.inc +++ /dev/null @@ -1,37 +0,0 @@ -query->all(); - foreach ($variables['content'] as $type) { - $variables['types'][$type->id()] = array( - 'link' => \Drupal::l($type->label(), 'custom_block.add_form', array('custom_block_type' => $type->id()), array('query' => $query)), - 'description' => Xss::filterAdmin($type->description), - 'title' => $type->label(), - 'localized_options' => array( - 'query' => $query, - ), - ); - } -} diff --git a/core/modules/block/custom_block/custom_block.routing.yml b/core/modules/block/custom_block/custom_block.routing.yml deleted file mode 100644 index cad1f09..0000000 --- a/core/modules/block/custom_block/custom_block.routing.yml +++ /dev/null @@ -1,80 +0,0 @@ -custom_block.type_list: - path: '/admin/structure/block/custom-blocks/types' - defaults: - _entity_list: 'custom_block_type' - _title: 'Edit' - requirements: - _permission: 'administer blocks' - -custom_block.add_page: - path: '/block/add' - defaults: - _content: '\Drupal\custom_block\Controller\CustomBlockController::add' - _title: 'Add custom block' - options: - _admin_route: TRUE - requirements: - _permission: 'administer blocks' - -custom_block.add_form: - path: '/block/add/{custom_block_type}' - defaults: - _content: '\Drupal\custom_block\Controller\CustomBlockController::addForm' - _title_callback: 'Drupal\custom_block\Controller\CustomBlockController::getAddFormTitle' - options: - _admin_route: TRUE - requirements: - _permission: 'administer blocks' - -custom_block.type_delete: - path: '/admin/structure/block/custom-blocks/manage/{custom_block_type}/delete' - defaults: - _entity_form: 'custom_block_type.delete' - _title: 'Delete' - requirements: - _entity_access: 'custom_block_type.delete' - options: - _admin_route: TRUE - -custom_block.edit: - path: '/block/{custom_block}' - defaults: - _entity_form: 'custom_block.edit' - options: - _admin_route: TRUE - requirements: - _entity_access: 'custom_block.update' - -custom_block.delete: - path: '/block/{custom_block}/delete' - defaults: - _entity_form: 'custom_block.delete' - _title: 'Delete' - options: - _admin_route: TRUE - requirements: - _entity_access: 'custom_block.delete' - -custom_block.type_add: - path: '/admin/structure/block/custom-blocks/types/add' - defaults: - _entity_form: 'custom_block_type.add' - _title: 'Add' - requirements: - _permission: 'administer blocks' - -custom_block.type_edit: - path: '/admin/structure/block/custom-blocks/manage/{custom_block_type}' - defaults: - _entity_form: 'custom_block_type.edit' - _title: 'Edit' - requirements: - _entity_access: 'custom_block_type.update' - -custom_block.list: - path: '/admin/structure/block/custom-blocks' - defaults: - _title: 'Custom block library' - _entity_list: 'custom_block' - requirements: - _permission: 'administer blocks' diff --git a/core/modules/block/custom_block/js/custom_block.js b/core/modules/block/custom_block/js/custom_block.js deleted file mode 100644 index be0ea7d..0000000 --- a/core/modules/block/custom_block/js/custom_block.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @file - * Defines Javascript behaviors for the custom_block module. - */ - -(function ($) { - - "use strict"; - - Drupal.behaviors.customBlockDetailsSummaries = { - attach: function (context) { - var $context = $(context); - $context.find('.custom-block-form-revision-information').drupalSetSummary(function (context) { - var $context = $(context); - var revisionCheckbox = $context.find('.form-item-revision input'); - - // Return 'New revision' if the 'Create new revision' checkbox is checked, - // or if the checkbox doesn't exist, but the revision log does. For users - // without the "Administer content" permission the checkbox won't appear, - // but the revision log will if the content type is set to auto-revision. - if (revisionCheckbox.is(':checked') || (!revisionCheckbox.length && $context.find('.form-item-log textarea').length)) { - return Drupal.t('New revision'); - } - - return Drupal.t('No revision'); - }); - - $context.find('fieldset.custom-block-translation-options').drupalSetSummary(function (context) { - var $context = $(context); - var translate; - var $checkbox = $context.find('.form-item-translation-translate input'); - - if ($checkbox.size()) { - translate = $checkbox.is(':checked') ? Drupal.t('Needs to be updated') : Drupal.t('Does not need to be updated'); - } - else { - $checkbox = $context.find('.form-item-translation-retranslate input'); - translate = $checkbox.is(':checked') ? Drupal.t('Flag other translations as outdated') : Drupal.t('Do not flag other translations as outdated'); - } - - return translate; - }); - } - }; - -})(jQuery); diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Controller/CustomBlockController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Controller/CustomBlockController.php deleted file mode 100644 index e30c42d..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Controller/CustomBlockController.php +++ /dev/null @@ -1,115 +0,0 @@ -get('entity.manager'); - return new static( - $entity_manager->getStorage('custom_block'), - $entity_manager->getStorage('custom_block_type') - ); - } - - /** - * Constructs a CustomBlock object. - * - * @param \Drupal\Core\Entity\EntityStorageInterface $custom_block_storage - * The custom block storage. - * @param \Drupal\Core\Entity\EntityStorageInterface $custom_block_type_storage - * The custom block type storage. - */ - public function __construct(EntityStorageInterface $custom_block_storage, EntityStorageInterface $custom_block_type_storage) { - $this->customBlockStorage = $custom_block_storage; - $this->customBlockTypeStorage = $custom_block_type_storage; - } - - /** - * Displays add custom block links for available types. - * - * @param \Symfony\Component\HttpFoundation\Request $request - * The current request object. - * - * @return array - * A render array for a list of the custom block types that can be added or - * if there is only one custom block type defined for the site, the function - * returns the custom block add page for that custom block type. - */ - public function add(Request $request) { - $types = $this->customBlockTypeStorage->loadMultiple(); - if ($types && count($types) == 1) { - $type = reset($types); - return $this->addForm($type, $request); - } - - return array('#theme' => 'custom_block_add_list', '#content' => $types); - } - - /** - * Presents the custom block creation form. - * - * @param \Drupal\custom_block\CustomBlockTypeInterface $custom_block_type - * The custom block type to add. - * @param \Symfony\Component\HttpFoundation\Request $request - * The current request object. - * - * @return array - * A form array as expected by drupal_render(). - */ - public function addForm(CustomBlockTypeInterface $custom_block_type, Request $request) { - $block = $this->customBlockStorage->create(array( - 'type' => $custom_block_type->id() - )); - if (($theme = $request->query->get('theme')) && in_array($theme, array_keys(list_themes()))) { - // We have navigated to this page from the block library and will keep track - // of the theme for redirecting the user to the configuration page for the - // newly created block in the given theme. - $block->setTheme($theme); - } - return $this->entityFormBuilder()->getForm($block); - } - - /** - * Provides the page title for this controller. - * - * @param \Drupal\custom_block\CustomBlockTypeInterface $custom_block_type - * The custom block type being added. - * - * @return string - * The page title. - */ - public function getAddFormTitle(CustomBlockTypeInterface $custom_block_type) { - return $this->t('Add %type custom block', array('%type' => $custom_block_type->label())); - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockAccessController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockAccessController.php deleted file mode 100644 index c1d65be..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockAccessController.php +++ /dev/null @@ -1,29 +0,0 @@ -customBlockStorage = $custom_block_storage; - $this->languageManager = $language_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - $entity_manager = $container->get('entity.manager'); - return new static( - $entity_manager, - $entity_manager->getStorage('custom_block'), - $container->get('language_manager') - ); - } - - /** - * Overrides \Drupal\Core\Entity\EntityForm::prepareEntity(). - * - * Prepares the custom block object. - * - * Fills in a few default values, and then invokes hook_custom_block_prepare() - * on all modules. - */ - protected function prepareEntity() { - $block = $this->entity; - // Set up default values, if required. - $block_type = entity_load('custom_block_type', $block->bundle()); - if (!$block->isNew()) { - $block->setRevisionLog(NULL); - } - // Always use the default revision setting. - $block->setNewRevision($block_type->revision); - } - - /** - * {@inheritdoc} - */ - public function form(array $form, array &$form_state) { - $block = $this->entity; - $account = $this->currentUser(); - - if ($this->operation == 'edit') { - $form['#title'] = $this->t('Edit custom block %label', array('%label' => $block->label())); - } - // Override the default CSS class name, since the user-defined custom block - // type name in 'TYPE-block-form' potentially clashes with third-party class - // names. - $form['#attributes']['class'][0] = drupal_html_class('block-' . $block->bundle() . '-form'); - - if ($this->moduleHandler->moduleExists('language')) { - $language_configuration = language_get_default_configuration('custom_block', $block->bundle()); - - // Set the correct default language. - if ($block->isNew()) { - $language_default = $this->languageManager->getCurrentLanguage($language_configuration['langcode']); - $block->langcode->value = $language_default->id; - } - } - - $form['langcode'] = array( - '#title' => $this->t('Language'), - '#type' => 'language_select', - '#default_value' => $block->getUntranslated()->language()->id, - '#languages' => Language::STATE_ALL, - '#access' => isset($language_configuration['language_show']) && $language_configuration['language_show'], - ); - - $form['advanced'] = array( - '#type' => 'vertical_tabs', - '#weight' => 99, - ); - - // Add a log field if the "Create new revision" option is checked, or if the - // current user has the ability to check that option. - $form['revision_information'] = array( - '#type' => 'details', - '#title' => $this->t('Revision information'), - // Open by default when "Create new revision" is checked. - '#open' => $block->isNewRevision(), - '#group' => 'advanced', - '#attributes' => array( - 'class' => array('custom-block-form-revision-information'), - ), - '#attached' => array( - 'library' => array('custom_block/drupal.custom_block'), - ), - '#weight' => 20, - '#access' => $block->isNewRevision() || $account->hasPermission('administer blocks'), - ); - - $form['revision_information']['revision'] = array( - '#type' => 'checkbox', - '#title' => $this->t('Create new revision'), - '#default_value' => $block->isNewRevision(), - '#access' => $account->hasPermission('administer blocks'), - ); - - // Check the revision log checkbox when the log textarea is filled in. - // This must not happen if "Create new revision" is enabled by default, - // since the state would auto-disable the checkbox otherwise. - if (!$block->isNewRevision()) { - $form['revision_information']['revision']['#states'] = array( - 'checked' => array( - 'textarea[name="log"]' => array('empty' => FALSE), - ), - ); - } - - $form['revision_information']['log'] = array( - '#type' => 'textarea', - '#title' => $this->t('Revision log message'), - '#rows' => 4, - '#default_value' => $block->getRevisionLog(), - '#description' => $this->t('Briefly desribe the changes you have made.'), - ); - - return parent::form($form, $form_state, $block); - } - - /** - * Overrides \Drupal\Core\Entity\EntityForm::submit(). - * - * Updates the custom block object by processing the submitted values. - * - * This function can be called by a "Next" button of a wizard to update the - * form state's entity with the current step's values before proceeding to the - * next step. - */ - public function submit(array $form, array &$form_state) { - // Build the block object from the submitted values. - $block = parent::submit($form, $form_state); - - // Save as a new revision if requested to do so. - if (!empty($form_state['values']['revision'])) { - $block->setNewRevision(); - } - - return $block; - } - - /** - * {@inheritdoc} - */ - public function save(array $form, array &$form_state) { - $block = $this->entity; - $insert = $block->isNew(); - $block->save(); - $watchdog_args = array('@type' => $block->bundle(), '%info' => $block->label()); - $block_type = entity_load('custom_block_type', $block->bundle()); - $t_args = array('@type' => $block_type->label(), '%info' => $block->label()); - - if ($insert) { - watchdog('content', '@type: added %info.', $watchdog_args, WATCHDOG_NOTICE); - drupal_set_message($this->t('@type %info has been created.', $t_args)); - } - else { - watchdog('content', '@type: updated %info.', $watchdog_args, WATCHDOG_NOTICE); - drupal_set_message($this->t('@type %info has been updated.', $t_args)); - } - - if ($block->id()) { - $form_state['values']['id'] = $block->id(); - $form_state['id'] = $block->id(); - if ($insert) { - if (!$theme = $block->getTheme()) { - $theme = $this->config('system.theme')->get('default'); - } - $form_state['redirect_route'] = array( - 'route_name' => 'block.admin_add', - 'route_parameters' => array( - 'plugin_id' => 'custom_block:' . $block->uuid(), - 'theme' => $theme, - ), - ); - } - else { - $form_state['redirect_route']['route_name'] = 'custom_block.list'; - } - } - else { - // In the unlikely case something went wrong on save, the block will be - // rebuilt and block form redisplayed. - drupal_set_message($this->t('The block could not be saved.'), 'error'); - $form_state['rebuild'] = TRUE; - } - - // Clear the page and block caches. - Cache::invalidateTags(array('content' => TRUE)); - } - - /** - * {@inheritdoc} - */ - public function validateForm(array &$form, array &$form_state) { - if ($this->entity->isNew()) { - $exists = $this->customBlockStorage->loadByProperties(array('info' => $form_state['values']['info'])); - if (!empty($exists)) { - $this->setFormError('info', $form_state, $this->t('A block with description %name already exists.', array( - '%name' => $form_state['values']['info'][0]['value'], - ))); - } - } - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockInterface.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockInterface.php deleted file mode 100644 index 00cac2c..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockInterface.php +++ /dev/null @@ -1,83 +0,0 @@ -getLabel($entity); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getDefaultOperations(EntityInterface $entity) { - $operations = parent::getDefaultOperations($entity); - if (isset($operations['edit'])) { - $operations['edit']['query']['destination'] = 'admin/structure/block/custom-blocks'; - } - return $operations; - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTranslationHandler.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTranslationHandler.php deleted file mode 100644 index 2bdd7f0..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTranslationHandler.php +++ /dev/null @@ -1,43 +0,0 @@ - 'additional_settings', - '#weight' => 100, - '#attributes' => array( - 'class' => array('custom-block-translation-options'), - ), - ); - } - } - - /** - * {@inheritdoc} - */ - protected function entityFormTitle(EntityInterface $entity) { - $block_type = entity_load('custom_block_type', $entity->bundle()); - return t('Edit @type @title', array('@type' => $block_type->label(), '@title' => $entity->label())); - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeForm.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeForm.php deleted file mode 100644 index c790efa..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeForm.php +++ /dev/null @@ -1,107 +0,0 @@ -entity; - - $form['label'] = array( - '#type' => 'textfield', - '#title' => t('Label'), - '#maxlength' => 255, - '#default_value' => $block_type->label(), - '#description' => t("Provide a label for this block type to help identify it in the administration pages."), - '#required' => TRUE, - ); - $form['id'] = array( - '#type' => 'machine_name', - '#default_value' => $block_type->id(), - '#machine_name' => array( - 'exists' => 'custom_block_type_load', - ), - '#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH, - '#disabled' => !$block_type->isNew(), - ); - - $form['description'] = array( - '#type' => 'textarea', - '#default_value' => $block_type->description, - '#description' => t('Enter a description for this block type.'), - '#title' => t('Description'), - ); - - $form['revision'] = array( - '#type' => 'checkbox', - '#title' => t('Create new revision'), - '#default_value' => $block_type->revision, - '#description' => t('Create a new revision by default for this block type.') - ); - - if ($this->moduleHandler->moduleExists('content_translation')) { - $form['language'] = array( - '#type' => 'details', - '#title' => t('Language settings'), - '#group' => 'additional_settings', - ); - - $language_configuration = language_get_default_configuration('custom_block', $block_type->id()); - $form['language']['language_configuration'] = array( - '#type' => 'language_configuration', - '#entity_information' => array( - 'entity_type' => 'custom_block', - 'bundle' => $block_type->id(), - ), - '#default_value' => $language_configuration, - ); - - $form['#submit'][] = 'language_configuration_element_submit'; - } - - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save'), - ); - - return $form; - } - - /** - * Overrides \Drupal\Core\Entity\EntityForm::save(). - */ - public function save(array $form, array &$form_state) { - $block_type = $this->entity; - $status = $block_type->save(); - - $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo()); - if ($status == SAVED_UPDATED) { - drupal_set_message(t('Custom block type %label has been updated.', array('%label' => $block_type->label()))); - watchdog('custom_block', 'Custom block type %label has been updated.', array('%label' => $block_type->label()), WATCHDOG_NOTICE, $edit_link); - } - else { - drupal_set_message(t('Custom block type %label has been added.', array('%label' => $block_type->label()))); - watchdog('custom_block', 'Custom block type %label has been added.', array('%label' => $block_type->label()), WATCHDOG_NOTICE, $edit_link); - } - - $form_state['redirect_route']['route_name'] = 'custom_block.type_list'; - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeInterface.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeInterface.php deleted file mode 100644 index 53bfe1b..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeInterface.php +++ /dev/null @@ -1,17 +0,0 @@ -generateFromUrl($entity->label(), $entity->urlInfo()); - $row['description'] = Xss::filterAdmin($entity->description); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - protected function getTitle() { - return $this->t('Custom block types'); - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockViewBuilder.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockViewBuilder.php deleted file mode 100644 index 16e11ee..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockViewBuilder.php +++ /dev/null @@ -1,33 +0,0 @@ -isNew() && $view_mode == 'full') { - $build['#contextual_links']['custom_block'] = array( - 'route_parameters' => array('custom_block' => $entity->id()), - 'metadata' => array('changed' => $entity->getChangedTime()), - ); - } - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php deleted file mode 100644 index 71913b7..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php +++ /dev/null @@ -1,232 +0,0 @@ -revision_id->value = NULL; - $duplicate->id->value = NULL; - return $duplicate; - } - - /** - * {@inheritdoc} - */ - public function setTheme($theme) { - $this->theme = $theme; - return $this; - } - - /** - * {@inheritdoc} - */ - public function getTheme() { - return $this->theme; - } - - /** - * {@inheritdoc} - */ - public function postSave(EntityStorageInterface $storage, $update = TRUE) { - parent::postSave($storage, $update); - - // Invalidate the block cache to update custom block-based derivatives. - \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); - } - - /** - * {@inheritdoc} - */ - public function getInstances() { - return entity_load_multiple_by_properties('block', array('plugin' => 'custom_block:' . $this->uuid())); - } - - /** - * {@inheritdoc} - */ - public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) { - parent::preSaveRevision($storage, $record); - - if ($this->isNewRevision()) { - // When inserting either a new custom block or a new custom_block - // revision, $entity->log must be set because {block_custom_revision}.log - // is a text column and therefore cannot have a default value. However, - // it might not be set at this point (for example, if the user submitting - // the form does not have permission to create revisions), so we ensure - // that it is at least an empty string in that case. - // @todo: Make the {block_custom_revision}.log column nullable so that we - // can remove this check. - if (!isset($record->log)) { - $record->log = ''; - } - } - elseif (isset($this->original) && (!isset($record->log) || $record->log === '')) { - // If we are updating an existing custom_block without adding a new - // revision and the user did not supply a log, keep the existing one. - $record->log = $this->original->getRevisionLog(); - } - } - - /** - * {@inheritdoc} - */ - public function delete() { - foreach ($this->getInstances() as $instance) { - $instance->delete(); - } - parent::delete(); - } - - /** - * {@inheritdoc} - */ - public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { - $fields['id'] = FieldDefinition::create('integer') - ->setLabel(t('Custom block ID')) - ->setDescription(t('The custom block ID.')) - ->setReadOnly(TRUE) - ->setSetting('unsigned', TRUE); - - $fields['uuid'] = FieldDefinition::create('uuid') - ->setLabel(t('UUID')) - ->setDescription(t('The custom block UUID.')) - ->setReadOnly(TRUE); - - $fields['revision_id'] = FieldDefinition::create('integer') - ->setLabel(t('Revision ID')) - ->setDescription(t('The revision ID.')) - ->setReadOnly(TRUE) - ->setSetting('unsigned', TRUE); - - $fields['langcode'] = FieldDefinition::create('language') - ->setLabel(t('Language code')) - ->setDescription(t('The custom block language code.')); - - $fields['info'] = FieldDefinition::create('string') - ->setLabel(t('Block description')) - ->setDescription(t('A brief description of your block.')) - ->setRevisionable(TRUE) - ->setRequired(TRUE) - ->setDisplayOptions('form', array( - 'type' => 'string', - 'weight' => -5, - )) - ->setDisplayConfigurable('form', TRUE); - - $fields['type'] = FieldDefinition::create('entity_reference') - ->setLabel(t('Block type')) - ->setDescription(t('The block type.')) - ->setSetting('target_type', 'custom_block_type') - ->setSetting('max_length', EntityTypeInterface::BUNDLE_MAX_LENGTH); - - $fields['log'] = FieldDefinition::create('string') - ->setLabel(t('Revision log message')) - ->setDescription(t('The revision log message.')) - ->setRevisionable(TRUE); - - $fields['changed'] = FieldDefinition::create('changed') - ->setLabel(t('Changed')) - ->setDescription(t('The time that the custom block was last edited.')) - ->setRevisionable(TRUE); - - return $fields; - } - - /** - * {@inheritdoc} - */ - public function getChangedTime() { - return $this->get('changed')->value; - } - - /** - * {@inheritdoc} - */ - public function getRevisionLog() { - return $this->get('log')->value; - } - - /** - * {@inheritdoc} - */ - public function setInfo($info) { - $this->set('info', $info); - return $this; - } - - /** - * {@inheritdoc} - */ - public function setRevisionLog($log) { - $this->set('log', $log); - return $this; - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlockType.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlockType.php deleted file mode 100644 index a7674d0..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlockType.php +++ /dev/null @@ -1,100 +0,0 @@ -isSyncing()) { - entity_invoke_bundle_hook('create', 'custom_block', $this->id()); - if (!$this->isSyncing()) { - custom_block_add_body_field($this->id); - } - } - elseif ($this->getOriginalId() != $this->id) { - entity_invoke_bundle_hook('rename', 'custom_block', $this->getOriginalId(), $this->id); - } - } - - /** - * {@inheritdoc} - */ - public static function postDelete(EntityStorageInterface $storage, array $entities) { - parent::postDelete($storage, $entities); - - foreach ($entities as $entity) { - entity_invoke_bundle_hook('delete', 'custom_block', $entity->id()); - } - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Form/CustomBlockDeleteForm.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Form/CustomBlockDeleteForm.php deleted file mode 100644 index 36df166..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Form/CustomBlockDeleteForm.php +++ /dev/null @@ -1,64 +0,0 @@ -t('Are you sure you want to delete %name?', array('%name' => $this->entity->label())); - } - - /** - * {@inheritdoc} - */ - public function getCancelRoute() { - return array( - 'route_name' => 'block.admin_display', - ); - } - - /** - * {@inheritdoc} - */ - public function getConfirmText() { - return $this->t('Delete'); - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, array &$form_state) { - $instances = $this->entity->getInstances(); - - $form['message'] = array( - '#markup' => format_plural(count($instances), 'This will also remove 1 placed block instance.', 'This will also remove @count placed block instances.'), - '#access' => !empty($instances), - ); - - return parent::buildForm($form, $form_state); - } - - /** - * {@inheritdoc} - */ - public function submit(array $form, array &$form_state) { - $this->entity->delete(); - drupal_set_message($this->t('Custom block %label has been deleted.', array('%label' => $this->entity->label()))); - watchdog('custom_block', 'Custom block %label has been deleted.', array('%label' => $this->entity->label()), WATCHDOG_NOTICE); - $form_state['redirect_route']['route_name'] = 'custom_block.list'; - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Form/CustomBlockTypeDeleteForm.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Form/CustomBlockTypeDeleteForm.php deleted file mode 100644 index 8b7a681..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Form/CustomBlockTypeDeleteForm.php +++ /dev/null @@ -1,93 +0,0 @@ -queryFactory = $query_factory; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('entity.query') - ); - } - - /** - * {@inheritdoc} - */ - public function getQuestion() { - return $this->t('Are you sure you want to delete %label?', array('%label' => $this->entity->label())); - } - - /** - * {@inheritdoc} - */ - public function getCancelRoute() { - return array( - 'route_name' => 'custom_block.type_list', - ); - } - - /** - * {@inheritdoc} - */ - public function getConfirmText() { - return $this->t('Delete'); - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, array &$form_state) { - $blocks = $this->queryFactory->get('custom_block')->condition('type', $this->entity->id())->execute(); - if (!empty($blocks)) { - $caption = '' . format_plural(count($blocks), '%label is used by 1 custom block on your site. You can not remove this block type until you have removed all of the %label blocks.', '%label is used by @count custom blocks on your site. You may not remove %label until you have removed all of the %label custom blocks.', array('%label' => $this->entity->label())) . '
'; - $form['description'] = array('#markup' => $caption); - return $form; - } - else { - return parent::buildForm($form, $form_state); - } - } - - /** - * {@inheritdoc} - */ - public function submit(array $form, array &$form_state) { - $this->entity->delete(); - $form_state['redirect_route']['route_name'] = 'custom_block.type_list'; - drupal_set_message(t('Custom block type %label has been deleted.', array('%label' => $this->entity->label()))); - watchdog('custom_block', 'Custom block type %label has been deleted.', array('%label' => $this->entity->label()), WATCHDOG_NOTICE); - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php deleted file mode 100644 index 5ef3ec2..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php +++ /dev/null @@ -1,164 +0,0 @@ -blockManager = $block_manager; - $this->entityManager = $entity_manager; - $this->moduleHandler = $module_handler; - $this->account = $account; - } - - /** - * {@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.block'), - $container->get('entity.manager'), - $container->get('module_handler'), - $container->get('current_user') - ); - } - - /** - * {@inheritdoc} - */ - public function defaultConfiguration() { - return array( - 'status' => TRUE, - 'info' => '', - 'view_mode' => 'full', - // Modify the default max age for custom block blocks: modifications made - // to them will automatically invalidate corresponding cache tags, thus - // allowing us to cache custom block blocks forever. - 'cache' => array( - 'max_age' => \Drupal\Core\Cache\Cache::PERMANENT, - ), - ); - } - - /** - * Overrides \Drupal\block\BlockBase::blockForm(). - * - * Adds body and description fields to the block configuration form. - */ - public function blockForm($form, &$form_state) { - $form['custom_block']['view_mode'] = array( - '#type' => 'select', - '#options' => $this->entityManager->getViewModeOptions('custom_block'), - '#title' => t('View mode'), - '#description' => t('Output the block in this view mode.'), - '#default_value' => $this->configuration['view_mode'] - ); - $form['title']['#description'] = t('The title of the block as shown to the user.'); - return $form; - } - - /** - * Overrides \Drupal\block\BlockBase::blockSubmit(). - */ - public function blockSubmit($form, &$form_state) { - // Invalidate the block cache to update custom block-based derivatives. - if ($this->moduleHandler->moduleExists('block')) { - $this->configuration['view_mode'] = $form_state['values']['custom_block']['view_mode']; - $this->blockManager->clearCachedDefinitions(); - } - } - - /** - * {@inheritdoc} - */ - public function build() { - $uuid = $this->getDerivativeId(); - if ($block = entity_load_by_uuid('custom_block', $uuid)) { - return entity_view($block, $this->configuration['view_mode']); - } - else { - return array( - '#markup' => t('Block with uuid %uuid does not exist. Add custom block.', array( - '%uuid' => $uuid, - '!url' => url('block/add') - )), - '#access' => $this->account->hasPermission('administer blocks') - ); - } - } -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php deleted file mode 100644 index f93b413..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php +++ /dev/null @@ -1,28 +0,0 @@ -derivatives[$custom_block->uuid()] = $base_plugin_definition; - $this->derivatives[$custom_block->uuid()]['admin_label'] = $custom_block->label(); - } - return parent::getDerivativeDefinitions($base_plugin_definition); - } -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php deleted file mode 100644 index af9b359..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php +++ /dev/null @@ -1,39 +0,0 @@ -attributes->has('theme')) { - $options['query']['theme'] = $request->attributes->get('theme'); - } - // Adds a destination on custom block listing. - if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'custom_block.list') { - $options['query']['destination'] = 'admin/structure/block/custom-blocks'; - } - // Adds a destination on custom block listing. - if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'custom_block.list') { - $options['query']['destination'] = 'admin/structure/block/custom-blocks'; - } - return $options; - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockCacheTagsTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockCacheTagsTest.php deleted file mode 100644 index cfd87a9..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockCacheTagsTest.php +++ /dev/null @@ -1,57 +0,0 @@ - 'Llama', - 'type' => 'basic', - 'body' => array( - 'value' => 'The name "llama" was adopted by European settlers from native Peruvians.', - 'format' => 'plain_text', - ), - )); - $custom_block->save(); - - return $custom_block; - } - - /** - * {@inheritdoc} - * - * Each comment must have a comment body, which always has a text format. - */ - protected function getAdditionalCacheTagsForEntity(EntityInterface $entity) { - return array('filter_format:plain_text'); - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockCreationTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockCreationTest.php deleted file mode 100644 index 167014e..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockCreationTest.php +++ /dev/null @@ -1,221 +0,0 @@ - 'Custom Block creation', - 'description' => 'Create a block and test saving it.', - 'group' => 'Custom Block', - ); - } - - /** - * Sets the test up. - */ - protected function setUp() { - parent::setUp(); - $this->drupalLogin($this->adminUser); - } - - /** - * Creates a "Basic page" block and verifies its consistency in the database. - */ - public function testCustomBlockCreation() { - // Add a new view mode and verify if it is selected as expected. - $this->drupalLogin($this->drupalCreateUser(array('administer display modes'))); - $this->drupalGet('admin/structure/display-modes/view/add/custom_block'); - $edit = array( - 'id' => 'test_view_mode', - 'label' => 'Test View Mode', - ); - $this->drupalPostForm(NULL, $edit, t('Save')); - $this->assertRaw(t('Saved the %label view mode.', array('%label' => $edit['label']))); - - $this->drupalLogin($this->adminUser); - - // Create a block. - $edit = array(); - $edit['info[0][value]'] = 'Test Block'; - $edit['body[0][value]'] = $this->randomName(16); - $this->drupalPostForm('block/add/basic', $edit, t('Save')); - - // Check that the Basic block has been created. - $this->assertRaw(format_string('!block %name has been created.', array( - '!block' => 'Basic block', - '%name' => $edit['info[0][value]'] - )), 'Basic block created.'); - - // Change the view mode. - $view_mode['settings[custom_block][view_mode]'] = 'test_view_mode'; - $this->drupalPostForm(NULL, $view_mode, t('Save block')); - - // Go to the configure page and verify that the new view mode is correct. - $this->drupalGet('admin/structure/block/manage/testblock'); - $this->assertFieldByXPath('//select[@name="settings[custom_block][view_mode]"]/option[@selected="selected"]/@value', 'test_view_mode', 'View mode changed to Test View Mode'); - - // Test the available view mode options. - $this->assertOption('edit-settings-custom-block-view-mode', 'default', 'The default view mode is available.'); - - // Check that the block exists in the database. - $blocks = entity_load_multiple_by_properties('custom_block', array('info' => $edit['info[0][value]'])); - $block = reset($blocks); - $this->assertTrue($block, 'Custom Block found in database.'); - - // Check that attempting to create another block with the same value for - // 'info' returns an error. - $this->drupalPostForm('block/add/basic', $edit, t('Save')); - - // Check that the Basic block has been created. - $this->assertRaw(format_string('A block with description %name already exists.', array( - '%name' => $edit['info[0][value]'] - ))); - $this->assertResponse(200); - } - - /** - * Create a default custom block. - * - * Creates a custom block from defaults and ensures that the 'basic block' - * type is being used. - */ - public function testDefaultCustomBlockCreation() { - $edit = array(); - $edit['info[0][value]'] = $this->randomName(8); - $edit['body[0][value]'] = $this->randomName(16); - // Don't pass the custom block type in the url so the default is forced. - $this->drupalPostForm('block/add', $edit, t('Save')); - - // Check that the block has been created and that it is a basic block. - $this->assertRaw(format_string('!block %name has been created.', array( - '!block' => 'Basic block', - '%name' => $edit['info[0][value]'], - )), 'Basic block created.'); - - // Check that the block exists in the database. - $blocks = entity_load_multiple_by_properties('custom_block', array('info' => $edit['info[0][value]'])); - $block = reset($blocks); - $this->assertTrue($block, 'Default Custom Block found in database.'); - } - - /** - * Verifies that a transaction rolls back the failed creation. - */ - public function testFailedBlockCreation() { - // Create a block. - try { - $this->createCustomBlock('fail_creation'); - $this->fail('Expected exception has not been thrown.'); - } - catch (\Exception $e) { - $this->pass('Expected exception has been thrown.'); - } - - if (Database::getConnection()->supportsTransactions()) { - // Check that the block does not exist in the database. - $id = db_select('custom_block', 'b') - ->fields('b', array('id')) - ->condition('info', 'fail_creation') - ->execute() - ->fetchField(); - $this->assertFalse($id, 'Transactions supported, and block not found in database.'); - } - else { - // Check that the block exists in the database. - $id = db_select('custom_block', 'b') - ->fields('b', array('id')) - ->condition('info', 'fail_creation') - ->execute() - ->fetchField(); - $this->assertTrue($id, 'Transactions not supported, and block found in database.'); - - // Check that the failed rollback was logged. - $records = db_query("SELECT wid FROM {watchdog} WHERE message LIKE 'Explicit rollback failed%'")->fetchAll(); - $this->assertTrue(count($records) > 0, 'Transactions not supported, and rollback error logged to watchdog.'); - } - } - - /** - * Test deleting a block. - */ - public function testBlockDelete() { - // Create a block. - $edit = array(); - $edit['info[0][value]'] = $this->randomName(8); - $body = $this->randomName(16); - $edit['body[0][value]'] = $body; - $this->drupalPostForm('block/add/basic', $edit, t('Save')); - - // Place the block. - $instance = array( - 'id' => drupal_strtolower($edit['info[0][value]']), - 'settings[label]' => $edit['info[0][value]'], - 'region' => 'sidebar_first', - ); - $block = entity_load('custom_block', 1); - $url = 'admin/structure/block/add/custom_block:' . $block->uuid() . '/' . \Drupal::config('system.theme')->get('default'); - $this->drupalPostForm($url, $instance, t('Save block')); - - $block = custom_block_load(1); - - // Test getInstances method. - $this->assertEqual(1, count($block->getInstances())); - - // Navigate to home page. - $this->drupalGet(''); - $this->assertText($body); - - // Delete the block. - $this->drupalGet('block/1/delete'); - $this->assertText(format_plural(1, 'This will also remove 1 placed block instance.', 'This will also remove @count placed block instance.')); - - $this->drupalPostForm(NULL, array(), 'Delete'); - $this->assertRaw(t('Custom block %name has been deleted.', array('%name' => $edit['info[0][value]']))); - - // Create another block and force the plugin cache to flush. - $edit2 = array(); - $edit2['info[0][value]'] = $this->randomName(8); - $body2 = $this->randomName(16); - $edit2['body[0][value]'] = $body2; - $this->drupalPostForm('block/add/basic', $edit2, t('Save')); - - $this->assertNoRaw('Error message'); - - // Create another block with no instances, and test we don't get a - // confirmation message about deleting instances. - $edit3 = array(); - $edit3['info[0][value]'] = $this->randomName(8); - $body = $this->randomName(16); - $edit3['body[0][value]'] = $body; - $this->drupalPostForm('block/add/basic', $edit3, t('Save')); - - // Show the delete confirm form. - $this->drupalGet('block/3/delete'); - $this->assertNoText('This will also remove'); - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php deleted file mode 100644 index 5c7d46b..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php +++ /dev/null @@ -1,118 +0,0 @@ - 'Custom Block field test', - 'description' => 'Test block fieldability.', - 'group' => 'Custom Block', - ); - } - - /** - * Checks block edit functionality. - */ - public function testBlockFields() { - $this->drupalLogin($this->adminUser); - - $this->blockType = $this->createCustomBlockType('link'); - - // Create a field with settings to validate. - $this->field = entity_create('field_config', array( - 'name' => drupal_strtolower($this->randomName()), - 'entity_type' => 'custom_block', - 'type' => 'link', - 'cardinality' => 2, - )); - $this->field->save(); - $this->instance = entity_create('field_instance_config', array( - 'field_name' => $this->field->getName(), - 'entity_type' => 'custom_block', - 'bundle' => 'link', - 'settings' => array( - 'title' => DRUPAL_OPTIONAL, - ), - )); - $this->instance->save(); - entity_get_form_display('custom_block', 'link', 'default') - ->setComponent($this->field->getName(), array( - 'type' => 'link_default', - )) - ->save(); - entity_get_display('custom_block', 'link', 'default') - ->setComponent($this->field->getName(), array( - 'type' => 'link', - 'label' => 'hidden', - )) - ->save(); - - // Create a block. - $this->drupalGet('block/add/link'); - $edit = array( - 'info[0][value]' => $this->randomName(8), - $this->field->getName() . '[0][url]' => 'http://example.com', - $this->field->getName() . '[0][title]' => 'Example.com' - ); - $this->drupalPostForm(NULL, $edit, t('Save')); - $block = entity_load('custom_block', 1); - $url = 'admin/structure/block/add/custom_block:' . $block->uuid() . '/' . \Drupal::config('system.theme')->get('default'); - // Place the block. - $instance = array( - 'id' => drupal_strtolower($edit['info[0][value]']), - 'settings[label]' => $edit['info[0][value]'], - 'region' => 'sidebar_first', - ); - $this->drupalPostForm($url, $instance, t('Save block')); - // Navigate to home page. - $this->drupalGet('' . t('The Custom Block module allows you to create blocks of content, which can be placed in regions throughout the website. Custom blocks can have fields; see the Field module help for more information. Once created, custom blocks can be placed like blocks provided by other modules; see the Block module help page for details. For more information, see the online documentation for the Custom Block module.', array('!block-content' => \Drupal::url('block_content.list'), '!field-help' => \Drupal::url('help.page', array('name' => 'field')), '!blocks' => \Drupal::url('help.page', array('name' => 'block')), '!online-help' => 'https://drupal.org/documentation/modules/block_content')) . '
'; + $output .= '' . t('This page lists user-created blocks. These blocks are derived from block types. A block type can consist of different fields and display settings. From the block types tab you can manage these fields as well as create new block types.') . '
'; + return $output; + + case 'block_content.type_list': + $output = '' . t('This page lists block types. A block type can consist of different fields and display settings. From here you can manage these fields as well as create new block types.') . '
'; + return $output; + + } +} + +/** + * Implements hook_theme(). + */ +function block_content_theme($existing, $type, $theme, $path) { + return array( + 'block_content_add_list' => array( + 'variables' => array('content' => NULL), + 'file' => 'block_content.pages.inc', + 'template' => 'block-content-add-list', + ), + ); +} + +/** + * Loads a custom block type. + * + * @param int $id + * The ID of the custom block type to load. + * + * @return \Drupal\block_content\Entity\BlockContentType|null + * A BlockContentType object or NULL if the requested $id does not exist. + */ +function block_content_type_load($id) { + return entity_load('block_content_type', $id); +} + +/** + * Loads a custom block. + * + * @param int $id + * The id of the custom block. + * + * @return \Drupal\block_content\Entity\BlockContent|null + * A BlockContent object or NULL if the requested $id does not exist. + */ +function block_content_load($id) { + return entity_load('block_content', $id); +} + +/** + * Implements hook_entity_type_alter(). + */ +function block_content_entity_type_alter(array &$entity_types) { + /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */ + // Add a translation handler for fields if the language module is enabled. + if (\Drupal::moduleHandler()->moduleExists('language')) { + $translation = $entity_types['block_content']->get('translation'); + $translation['block_content'] = TRUE; + $entity_types['block_content']->set('translation', $translation); + } +} + +/** + * Implements hook_entity_bundle_info(). + */ +function block_content_entity_bundle_info() { + $bundles = array(); + foreach (\Drupal::configFactory()->listAll('block_content.type.') as $config_name) { + $config = \Drupal::config($config_name); + $bundles['block_content'][$config->get('id')]['label'] = $config->get('label'); + } + return $bundles; +} + +/** + * Adds the default body field to a custom block type. + * + * @param string $block_type_id + * Id of the block type. + * @param string $label + * (optional) The label for the body instance. Defaults to 'Body' + * + * @return array() + * Body field instance. + */ +function block_content_add_body_field($block_type_id, $label = 'Body') { + // Add or remove the body field, as needed. + $field = field_info_field('block_content', 'body'); + $instance = field_info_instance('block_content', 'body', $block_type_id); + if (empty($field)) { + $field = entity_create('field_config', array( + 'name' => 'body', + 'entity_type' => 'block_content', + 'type' => 'text_with_summary', + )); + $field->save(); + } + if (empty($instance)) { + $instance = entity_create('field_instance_config', array( + 'field_name' => 'body', + 'entity_type' => 'block_content', + 'bundle' => $block_type_id, + 'label' => $label, + 'settings' => array('display_summary' => FALSE), + )); + $instance->save(); + + // Assign widget settings for the 'default' form mode. + entity_get_form_display('block_content', $block_type_id, 'default') + ->setComponent('body', array( + 'type' => 'text_textarea_with_summary', + )) + ->save(); + + // Assign display settings for 'default' view mode. + entity_get_display('block_content', $block_type_id, 'default') + ->setComponent('body', array( + 'label' => 'hidden', + 'type' => 'text_default', + )) + ->save(); + } + + return $instance; +} diff --git a/core/modules/block_content/block_content.pages.inc b/core/modules/block_content/block_content.pages.inc new file mode 100644 index 0000000..d2dc0c4 --- /dev/null +++ b/core/modules/block_content/block_content.pages.inc @@ -0,0 +1,37 @@ +query->all(); + foreach ($variables['content'] as $type) { + $variables['types'][$type->id()] = array( + 'link' => \Drupal::l($type->label(), 'block_content.add_form', array('block_content_type' => $type->id()), array('query' => $query)), + 'description' => Xss::filterAdmin($type->description), + 'title' => $type->label(), + 'localized_options' => array( + 'query' => $query, + ), + ); + } +} diff --git a/core/modules/block_content/block_content.routing.yml b/core/modules/block_content/block_content.routing.yml new file mode 100644 index 0000000..b6a1aaf --- /dev/null +++ b/core/modules/block_content/block_content.routing.yml @@ -0,0 +1,80 @@ +block_content.type_list: + path: '/admin/structure/block/block-content/types' + defaults: + _entity_list: 'block_content_type' + _title: 'Edit' + requirements: + _permission: 'administer blocks' + +block_content.add_page: + path: '/block/add' + defaults: + _content: '\Drupal\block_content\Controller\BlockContentController::add' + _title: 'Add custom block' + options: + _admin_route: TRUE + requirements: + _permission: 'administer blocks' + +block_content.add_form: + path: '/block/add/{block_content_type}' + defaults: + _content: '\Drupal\block_content\Controller\BlockContentController::addForm' + _title_callback: 'Drupal\block_content\Controller\BlockContentController::getAddFormTitle' + options: + _admin_route: TRUE + requirements: + _permission: 'administer blocks' + +block_content.type_delete: + path: '/admin/structure/block/block-content/manage/{block_content_type}/delete' + defaults: + _entity_form: 'block_content_type.delete' + _title: 'Delete' + requirements: + _entity_access: 'block_content_type.delete' + options: + _admin_route: TRUE + +block_content.edit: + path: '/block/{block_content}' + defaults: + _entity_form: 'block_content.edit' + options: + _admin_route: TRUE + requirements: + _entity_access: 'block_content.update' + +block_content.delete: + path: '/block/{block_content}/delete' + defaults: + _entity_form: 'block_content.delete' + _title: 'Delete' + options: + _admin_route: TRUE + requirements: + _entity_access: 'block_content.delete' + +block_content.type_add: + path: '/admin/structure/block/block-content/types/add' + defaults: + _entity_form: 'block_content_type.add' + _title: 'Add' + requirements: + _permission: 'administer blocks' + +block_content.type_edit: + path: '/admin/structure/block/block-content/manage/{block_content_type}' + defaults: + _entity_form: 'block_content_type.edit' + _title: 'Edit' + requirements: + _entity_access: 'block_content_type.update' + +block_content.list: + path: '/admin/structure/block/block-content' + defaults: + _title: 'Custom block library' + _entity_list: 'block_content' + requirements: + _permission: 'administer blocks' diff --git a/core/modules/block_content/config/install/block_content.type.basic.yml b/core/modules/block_content/config/install/block_content.type.basic.yml new file mode 100644 index 0000000..02982e4 --- /dev/null +++ b/core/modules/block_content/config/install/block_content.type.basic.yml @@ -0,0 +1,5 @@ +id: basic +label: 'Basic block' +revision: 0 +description: 'A basic block contains a title and a body.' +langcode: en diff --git a/core/modules/block_content/config/install/entity.view_mode.block_content.full.yml b/core/modules/block_content/config/install/entity.view_mode.block_content.full.yml new file mode 100644 index 0000000..c558d54 --- /dev/null +++ b/core/modules/block_content/config/install/entity.view_mode.block_content.full.yml @@ -0,0 +1,8 @@ +id: block_content.full +label: Full +status: false +cache: true +targetEntityType: block_content +dependencies: + module: + - block_content diff --git a/core/modules/block_content/config/schema/block_content.schema.yml b/core/modules/block_content/config/schema/block_content.schema.yml new file mode 100644 index 0000000..d87edfc --- /dev/null +++ b/core/modules/block_content/config/schema/block_content.schema.yml @@ -0,0 +1,27 @@ +# Schema for the configuration files of the Custom Block module. + +block_content.type.*: + type: mapping + label: 'Custom block type settings' + mapping: + id: + type: string + label: 'Machine-readable name' + uuid: + type: string + label: 'UUID' + label: + type: label + label: 'Label' + revision: + type: integer + label: 'Create new revision' + description: + type: text + label: 'Description' + status: + type: boolean + label: 'Status' + langcode: + type: string + label: 'Default language' diff --git a/core/modules/block_content/js/block_content.js b/core/modules/block_content/js/block_content.js new file mode 100644 index 0000000..e65d7f3 --- /dev/null +++ b/core/modules/block_content/js/block_content.js @@ -0,0 +1,46 @@ +/** + * @file + * Defines Javascript behaviors for the block_content module. + */ + +(function ($) { + + "use strict"; + + Drupal.behaviors.customBlockDetailsSummaries = { + attach: function (context) { + var $context = $(context); + $context.find('.block-content-form-revision-information').drupalSetSummary(function (context) { + var $context = $(context); + var revisionCheckbox = $context.find('.form-item-revision input'); + + // Return 'New revision' if the 'Create new revision' checkbox is checked, + // or if the checkbox doesn't exist, but the revision log does. For users + // without the "Administer content" permission the checkbox won't appear, + // but the revision log will if the content type is set to auto-revision. + if (revisionCheckbox.is(':checked') || (!revisionCheckbox.length && $context.find('.form-item-log textarea').length)) { + return Drupal.t('New revision'); + } + + return Drupal.t('No revision'); + }); + + $context.find('fieldset.block-content-translation-options').drupalSetSummary(function (context) { + var $context = $(context); + var translate; + var $checkbox = $context.find('.form-item-translation-translate input'); + + if ($checkbox.size()) { + translate = $checkbox.is(':checked') ? Drupal.t('Needs to be updated') : Drupal.t('Does not need to be updated'); + } + else { + $checkbox = $context.find('.form-item-translation-retranslate input'); + translate = $checkbox.is(':checked') ? Drupal.t('Flag other translations as outdated') : Drupal.t('Do not flag other translations as outdated'); + } + + return translate; + }); + } + }; + +})(jQuery); diff --git a/core/modules/block_content/lib/Drupal/block_content/BlockContentAccessController.php b/core/modules/block_content/lib/Drupal/block_content/BlockContentAccessController.php new file mode 100644 index 0000000..5709498 --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/BlockContentAccessController.php @@ -0,0 +1,29 @@ +customBlockStorage = $block_content_storage; + $this->languageManager = $language_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + $entity_manager = $container->get('entity.manager'); + return new static( + $entity_manager, + $entity_manager->getStorage('block_content'), + $container->get('language_manager') + ); + } + + /** + * Overrides \Drupal\Core\Entity\EntityForm::prepareEntity(). + * + * Prepares the custom block object. + * + * Fills in a few default values, and then invokes hook_block_content_prepare() + * on all modules. + */ + protected function prepareEntity() { + $block = $this->entity; + // Set up default values, if required. + $block_type = entity_load('block_content_type', $block->bundle()); + if (!$block->isNew()) { + $block->setRevisionLog(NULL); + } + // Always use the default revision setting. + $block->setNewRevision($block_type->revision); + } + + /** + * {@inheritdoc} + */ + public function form(array $form, array &$form_state) { + $block = $this->entity; + $account = $this->currentUser(); + + if ($this->operation == 'edit') { + $form['#title'] = $this->t('Edit custom block %label', array('%label' => $block->label())); + } + // Override the default CSS class name, since the user-defined custom block + // type name in 'TYPE-block-form' potentially clashes with third-party class + // names. + $form['#attributes']['class'][0] = drupal_html_class('block-' . $block->bundle() . '-form'); + + if ($this->moduleHandler->moduleExists('language')) { + $language_configuration = language_get_default_configuration('block_content', $block->bundle()); + + // Set the correct default language. + if ($block->isNew()) { + $language_default = $this->languageManager->getCurrentLanguage($language_configuration['langcode']); + $block->langcode->value = $language_default->id; + } + } + + $form['langcode'] = array( + '#title' => $this->t('Language'), + '#type' => 'language_select', + '#default_value' => $block->getUntranslated()->language()->id, + '#languages' => Language::STATE_ALL, + '#access' => isset($language_configuration['language_show']) && $language_configuration['language_show'], + ); + + $form['advanced'] = array( + '#type' => 'vertical_tabs', + '#weight' => 99, + ); + + // Add a log field if the "Create new revision" option is checked, or if the + // current user has the ability to check that option. + $form['revision_information'] = array( + '#type' => 'details', + '#title' => $this->t('Revision information'), + // Open by default when "Create new revision" is checked. + '#open' => $block->isNewRevision(), + '#group' => 'advanced', + '#attributes' => array( + 'class' => array('block-content-form-revision-information'), + ), + '#attached' => array( + 'library' => array('block_content/drupal.block_content'), + ), + '#weight' => 20, + '#access' => $block->isNewRevision() || $account->hasPermission('administer blocks'), + ); + + $form['revision_information']['revision'] = array( + '#type' => 'checkbox', + '#title' => $this->t('Create new revision'), + '#default_value' => $block->isNewRevision(), + '#access' => $account->hasPermission('administer blocks'), + ); + + // Check the revision log checkbox when the log textarea is filled in. + // This must not happen if "Create new revision" is enabled by default, + // since the state would auto-disable the checkbox otherwise. + if (!$block->isNewRevision()) { + $form['revision_information']['revision']['#states'] = array( + 'checked' => array( + 'textarea[name="log"]' => array('empty' => FALSE), + ), + ); + } + + $form['revision_information']['log'] = array( + '#type' => 'textarea', + '#title' => $this->t('Revision log message'), + '#rows' => 4, + '#default_value' => $block->getRevisionLog(), + '#description' => $this->t('Briefly desribe the changes you have made.'), + ); + + return parent::form($form, $form_state, $block); + } + + /** + * Overrides \Drupal\Core\Entity\EntityForm::submit(). + * + * Updates the custom block object by processing the submitted values. + * + * This function can be called by a "Next" button of a wizard to update the + * form state's entity with the current step's values before proceeding to the + * next step. + */ + public function submit(array $form, array &$form_state) { + // Build the block object from the submitted values. + $block = parent::submit($form, $form_state); + + // Save as a new revision if requested to do so. + if (!empty($form_state['values']['revision'])) { + $block->setNewRevision(); + } + + return $block; + } + + /** + * {@inheritdoc} + */ + public function save(array $form, array &$form_state) { + $block = $this->entity; + $insert = $block->isNew(); + $block->save(); + $watchdog_args = array('@type' => $block->bundle(), '%info' => $block->label()); + $block_type = entity_load('block_content_type', $block->bundle()); + $t_args = array('@type' => $block_type->label(), '%info' => $block->label()); + + if ($insert) { + watchdog('content', '@type: added %info.', $watchdog_args, WATCHDOG_NOTICE); + drupal_set_message($this->t('@type %info has been created.', $t_args)); + } + else { + watchdog('content', '@type: updated %info.', $watchdog_args, WATCHDOG_NOTICE); + drupal_set_message($this->t('@type %info has been updated.', $t_args)); + } + + if ($block->id()) { + $form_state['values']['id'] = $block->id(); + $form_state['id'] = $block->id(); + if ($insert) { + if (!$theme = $block->getTheme()) { + $theme = $this->config('system.theme')->get('default'); + } + $form_state['redirect_route'] = array( + 'route_name' => 'block.admin_add', + 'route_parameters' => array( + 'plugin_id' => 'block_content:' . $block->uuid(), + 'theme' => $theme, + ), + ); + } + else { + $form_state['redirect_route']['route_name'] = 'block_content.list'; + } + } + else { + // In the unlikely case something went wrong on save, the block will be + // rebuilt and block form redisplayed. + drupal_set_message($this->t('The block could not be saved.'), 'error'); + $form_state['rebuild'] = TRUE; + } + + // Clear the page and block caches. + Cache::invalidateTags(array('content' => TRUE)); + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + if ($this->entity->isNew()) { + $exists = $this->customBlockStorage->loadByProperties(array('info' => $form_state['values']['info'])); + if (!empty($exists)) { + $this->setFormError('info', $form_state, $this->t('A block with description %name already exists.', array( + '%name' => $form_state['values']['info'][0]['value'], + ))); + } + } + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/BlockContentInterface.php b/core/modules/block_content/lib/Drupal/block_content/BlockContentInterface.php new file mode 100644 index 0000000..29ef69f --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/BlockContentInterface.php @@ -0,0 +1,83 @@ +getLabel($entity); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getDefaultOperations(EntityInterface $entity) { + $operations = parent::getDefaultOperations($entity); + if (isset($operations['edit'])) { + $operations['edit']['query']['destination'] = 'admin/structure/block/block-content'; + } + return $operations; + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/BlockContentTranslationHandler.php b/core/modules/block_content/lib/Drupal/block_content/BlockContentTranslationHandler.php new file mode 100644 index 0000000..148e249 --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/BlockContentTranslationHandler.php @@ -0,0 +1,43 @@ + 'additional_settings', + '#weight' => 100, + '#attributes' => array( + 'class' => array('block-content-translation-options'), + ), + ); + } + } + + /** + * {@inheritdoc} + */ + protected function entityFormTitle(EntityInterface $entity) { + $block_type = entity_load('block_content_type', $entity->bundle()); + return t('Edit @type @title', array('@type' => $block_type->label(), '@title' => $entity->label())); + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/BlockContentTypeForm.php b/core/modules/block_content/lib/Drupal/block_content/BlockContentTypeForm.php new file mode 100644 index 0000000..b35ccc5 --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/BlockContentTypeForm.php @@ -0,0 +1,107 @@ +entity; + + $form['label'] = array( + '#type' => 'textfield', + '#title' => t('Label'), + '#maxlength' => 255, + '#default_value' => $block_type->label(), + '#description' => t("Provide a label for this block type to help identify it in the administration pages."), + '#required' => TRUE, + ); + $form['id'] = array( + '#type' => 'machine_name', + '#default_value' => $block_type->id(), + '#machine_name' => array( + 'exists' => 'block_content_type_load', + ), + '#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH, + '#disabled' => !$block_type->isNew(), + ); + + $form['description'] = array( + '#type' => 'textarea', + '#default_value' => $block_type->description, + '#description' => t('Enter a description for this block type.'), + '#title' => t('Description'), + ); + + $form['revision'] = array( + '#type' => 'checkbox', + '#title' => t('Create new revision'), + '#default_value' => $block_type->revision, + '#description' => t('Create a new revision by default for this block type.') + ); + + if ($this->moduleHandler->moduleExists('content_translation')) { + $form['language'] = array( + '#type' => 'details', + '#title' => t('Language settings'), + '#group' => 'additional_settings', + ); + + $language_configuration = language_get_default_configuration('block_content', $block_type->id()); + $form['language']['language_configuration'] = array( + '#type' => 'language_configuration', + '#entity_information' => array( + 'entity_type' => 'block_content', + 'bundle' => $block_type->id(), + ), + '#default_value' => $language_configuration, + ); + + $form['#submit'][] = 'language_configuration_element_submit'; + } + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + + return $form; + } + + /** + * Overrides \Drupal\Core\Entity\EntityForm::save(). + */ + public function save(array $form, array &$form_state) { + $block_type = $this->entity; + $status = $block_type->save(); + + $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo()); + if ($status == SAVED_UPDATED) { + drupal_set_message(t('Custom block type %label has been updated.', array('%label' => $block_type->label()))); + watchdog('block_content', 'Custom block type %label has been updated.', array('%label' => $block_type->label()), WATCHDOG_NOTICE, $edit_link); + } + else { + drupal_set_message(t('Custom block type %label has been added.', array('%label' => $block_type->label()))); + watchdog('block_content', 'Custom block type %label has been added.', array('%label' => $block_type->label()), WATCHDOG_NOTICE, $edit_link); + } + + $form_state['redirect_route']['route_name'] = 'block_content.type_list'; + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/BlockContentTypeInterface.php b/core/modules/block_content/lib/Drupal/block_content/BlockContentTypeInterface.php new file mode 100644 index 0000000..cb21631 --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/BlockContentTypeInterface.php @@ -0,0 +1,17 @@ +generateFromUrl($entity->label(), $entity->urlInfo()); + $row['description'] = Xss::filterAdmin($entity->description); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + protected function getTitle() { + return $this->t('Custom block types'); + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/BlockContentViewBuilder.php b/core/modules/block_content/lib/Drupal/block_content/BlockContentViewBuilder.php new file mode 100644 index 0000000..0977e9f --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/BlockContentViewBuilder.php @@ -0,0 +1,33 @@ +isNew() && $view_mode == 'full') { + $build['#contextual_links']['block_content'] = array( + 'route_parameters' => array('block_content' => $entity->id()), + 'metadata' => array('changed' => $entity->getChangedTime()), + ); + } + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Controller/BlockContentController.php b/core/modules/block_content/lib/Drupal/block_content/Controller/BlockContentController.php new file mode 100644 index 0000000..04279e6 --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Controller/BlockContentController.php @@ -0,0 +1,115 @@ +get('entity.manager'); + return new static( + $entity_manager->getStorage('block_content'), + $entity_manager->getStorage('block_content_type') + ); + } + + /** + * Constructs a BlockContent object. + * + * @param \Drupal\Core\Entity\EntityStorageInterface $block_content_storage + * The custom block storage. + * @param \Drupal\Core\Entity\EntityStorageInterface $block_content_type_storage + * The custom block type storage. + */ + public function __construct(EntityStorageInterface $block_content_storage, EntityStorageInterface $block_content_type_storage) { + $this->customBlockStorage = $block_content_storage; + $this->customBlockTypeStorage = $block_content_type_storage; + } + + /** + * Displays add custom block links for available types. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request object. + * + * @return array + * A render array for a list of the custom block types that can be added or + * if there is only one custom block type defined for the site, the function + * returns the custom block add page for that custom block type. + */ + public function add(Request $request) { + $types = $this->customBlockTypeStorage->loadMultiple(); + if ($types && count($types) == 1) { + $type = reset($types); + return $this->addForm($type, $request); + } + + return array('#theme' => 'block_content_add_list', '#content' => $types); + } + + /** + * Presents the custom block creation form. + * + * @param \Drupal\block_content\BlockContentTypeInterface $block_content_type + * The custom block type to add. + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request object. + * + * @return array + * A form array as expected by drupal_render(). + */ + public function addForm(BlockContentTypeInterface $block_content_type, Request $request) { + $block = $this->customBlockStorage->create(array( + 'type' => $block_content_type->id() + )); + if (($theme = $request->query->get('theme')) && in_array($theme, array_keys(list_themes()))) { + // We have navigated to this page from the block library and will keep track + // of the theme for redirecting the user to the configuration page for the + // newly created block in the given theme. + $block->setTheme($theme); + } + return $this->entityFormBuilder()->getForm($block); + } + + /** + * Provides the page title for this controller. + * + * @param \Drupal\block_content\BlockContentTypeInterface $block_content_type + * The custom block type being added. + * + * @return string + * The page title. + */ + public function getAddFormTitle(BlockContentTypeInterface $block_content_type) { + return $this->t('Add %type custom block', array('%type' => $block_content_type->label())); + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Entity/BlockContent.php b/core/modules/block_content/lib/Drupal/block_content/Entity/BlockContent.php new file mode 100644 index 0000000..d85baef --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Entity/BlockContent.php @@ -0,0 +1,232 @@ +revision_id->value = NULL; + $duplicate->id->value = NULL; + return $duplicate; + } + + /** + * {@inheritdoc} + */ + public function setTheme($theme) { + $this->theme = $theme; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getTheme() { + return $this->theme; + } + + /** + * {@inheritdoc} + */ + public function postSave(EntityStorageInterface $storage, $update = TRUE) { + parent::postSave($storage, $update); + + // Invalidate the block cache to update custom block-based derivatives. + \Drupal::service('plugin.manager.block')->clearCachedDefinitions(); + } + + /** + * {@inheritdoc} + */ + public function getInstances() { + return entity_load_multiple_by_properties('block', array('plugin' => 'block_content:' . $this->uuid())); + } + + /** + * {@inheritdoc} + */ + public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) { + parent::preSaveRevision($storage, $record); + + if ($this->isNewRevision()) { + // When inserting either a new custom block or a new block_content + // revision, $entity->log must be set because {block_custom_revision}.log + // is a text column and therefore cannot have a default value. However, + // it might not be set at this point (for example, if the user submitting + // the form does not have permission to create revisions), so we ensure + // that it is at least an empty string in that case. + // @todo: Make the {block_custom_revision}.log column nullable so that we + // can remove this check. + if (!isset($record->log)) { + $record->log = ''; + } + } + elseif (isset($this->original) && (!isset($record->log) || $record->log === '')) { + // If we are updating an existing block_content without adding a new + // revision and the user did not supply a log, keep the existing one. + $record->log = $this->original->getRevisionLog(); + } + } + + /** + * {@inheritdoc} + */ + public function delete() { + foreach ($this->getInstances() as $instance) { + $instance->delete(); + } + parent::delete(); + } + + /** + * {@inheritdoc} + */ + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { + $fields['id'] = FieldDefinition::create('integer') + ->setLabel(t('Custom block ID')) + ->setDescription(t('The custom block ID.')) + ->setReadOnly(TRUE) + ->setSetting('unsigned', TRUE); + + $fields['uuid'] = FieldDefinition::create('uuid') + ->setLabel(t('UUID')) + ->setDescription(t('The custom block UUID.')) + ->setReadOnly(TRUE); + + $fields['revision_id'] = FieldDefinition::create('integer') + ->setLabel(t('Revision ID')) + ->setDescription(t('The revision ID.')) + ->setReadOnly(TRUE) + ->setSetting('unsigned', TRUE); + + $fields['langcode'] = FieldDefinition::create('language') + ->setLabel(t('Language code')) + ->setDescription(t('The custom block language code.')); + + $fields['info'] = FieldDefinition::create('string') + ->setLabel(t('Block description')) + ->setDescription(t('A brief description of your block.')) + ->setRevisionable(TRUE) + ->setRequired(TRUE) + ->setDisplayOptions('form', array( + 'type' => 'string', + 'weight' => -5, + )) + ->setDisplayConfigurable('form', TRUE); + + $fields['type'] = FieldDefinition::create('entity_reference') + ->setLabel(t('Block type')) + ->setDescription(t('The block type.')) + ->setSetting('target_type', 'block_content_type') + ->setSetting('max_length', EntityTypeInterface::BUNDLE_MAX_LENGTH); + + $fields['log'] = FieldDefinition::create('string') + ->setLabel(t('Revision log message')) + ->setDescription(t('The revision log message.')) + ->setRevisionable(TRUE); + + $fields['changed'] = FieldDefinition::create('changed') + ->setLabel(t('Changed')) + ->setDescription(t('The time that the custom block was last edited.')) + ->setRevisionable(TRUE); + + return $fields; + } + + /** + * {@inheritdoc} + */ + public function getChangedTime() { + return $this->get('changed')->value; + } + + /** + * {@inheritdoc} + */ + public function getRevisionLog() { + return $this->get('log')->value; + } + + /** + * {@inheritdoc} + */ + public function setInfo($info) { + $this->set('info', $info); + return $this; + } + + /** + * {@inheritdoc} + */ + public function setRevisionLog($log) { + $this->set('log', $log); + return $this; + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Entity/BlockContentType.php b/core/modules/block_content/lib/Drupal/block_content/Entity/BlockContentType.php new file mode 100644 index 0000000..b75c58d --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Entity/BlockContentType.php @@ -0,0 +1,100 @@ +isSyncing()) { + entity_invoke_bundle_hook('create', 'block_content', $this->id()); + if (!$this->isSyncing()) { + block_content_add_body_field($this->id); + } + } + elseif ($this->getOriginalId() != $this->id) { + entity_invoke_bundle_hook('rename', 'block_content', $this->getOriginalId(), $this->id); + } + } + + /** + * {@inheritdoc} + */ + public static function postDelete(EntityStorageInterface $storage, array $entities) { + parent::postDelete($storage, $entities); + + foreach ($entities as $entity) { + entity_invoke_bundle_hook('delete', 'block_content', $entity->id()); + } + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Form/BlockContentDeleteForm.php b/core/modules/block_content/lib/Drupal/block_content/Form/BlockContentDeleteForm.php new file mode 100644 index 0000000..fc3e7ab --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Form/BlockContentDeleteForm.php @@ -0,0 +1,64 @@ +t('Are you sure you want to delete %name?', array('%name' => $this->entity->label())); + } + + /** + * {@inheritdoc} + */ + public function getCancelRoute() { + return array( + 'route_name' => 'block.admin_display', + ); + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return $this->t('Delete'); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $instances = $this->entity->getInstances(); + + $form['message'] = array( + '#markup' => format_plural(count($instances), 'This will also remove 1 placed block instance.', 'This will also remove @count placed block instances.'), + '#access' => !empty($instances), + ); + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submit(array $form, array &$form_state) { + $this->entity->delete(); + drupal_set_message($this->t('Custom block %label has been deleted.', array('%label' => $this->entity->label()))); + watchdog('block_content', 'Custom block %label has been deleted.', array('%label' => $this->entity->label()), WATCHDOG_NOTICE); + $form_state['redirect_route']['route_name'] = 'block_content.list'; + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Form/BlockContentTypeDeleteForm.php b/core/modules/block_content/lib/Drupal/block_content/Form/BlockContentTypeDeleteForm.php new file mode 100644 index 0000000..0b53217 --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Form/BlockContentTypeDeleteForm.php @@ -0,0 +1,93 @@ +queryFactory = $query_factory; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity.query') + ); + } + + /** + * {@inheritdoc} + */ + public function getQuestion() { + return $this->t('Are you sure you want to delete %label?', array('%label' => $this->entity->label())); + } + + /** + * {@inheritdoc} + */ + public function getCancelRoute() { + return array( + 'route_name' => 'block_content.type_list', + ); + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return $this->t('Delete'); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $blocks = $this->queryFactory->get('block_content')->condition('type', $this->entity->id())->execute(); + if (!empty($blocks)) { + $caption = '' . format_plural(count($blocks), '%label is used by 1 custom block on your site. You can not remove this block type until you have removed all of the %label blocks.', '%label is used by @count custom blocks on your site. You may not remove %label until you have removed all of the %label custom blocks.', array('%label' => $this->entity->label())) . '
'; + $form['description'] = array('#markup' => $caption); + return $form; + } + else { + return parent::buildForm($form, $form_state); + } + } + + /** + * {@inheritdoc} + */ + public function submit(array $form, array &$form_state) { + $this->entity->delete(); + $form_state['redirect_route']['route_name'] = 'block_content.type_list'; + drupal_set_message(t('Custom block type %label has been deleted.', array('%label' => $this->entity->label()))); + watchdog('block_content', 'Custom block type %label has been deleted.', array('%label' => $this->entity->label()), WATCHDOG_NOTICE); + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Plugin/Block/BlockContentBlock.php b/core/modules/block_content/lib/Drupal/block_content/Plugin/Block/BlockContentBlock.php new file mode 100644 index 0000000..9f3d92d --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Plugin/Block/BlockContentBlock.php @@ -0,0 +1,164 @@ +blockManager = $block_manager; + $this->entityManager = $entity_manager; + $this->moduleHandler = $module_handler; + $this->account = $account; + } + + /** + * {@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.block'), + $container->get('entity.manager'), + $container->get('module_handler'), + $container->get('current_user') + ); + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return array( + 'status' => TRUE, + 'info' => '', + 'view_mode' => 'full', + // Modify the default max age for custom block blocks: modifications made + // to them will automatically invalidate corresponding cache tags, thus + // allowing us to cache custom block blocks forever. + 'cache' => array( + 'max_age' => \Drupal\Core\Cache\Cache::PERMANENT, + ), + ); + } + + /** + * Overrides \Drupal\block\BlockBase::blockForm(). + * + * Adds body and description fields to the block configuration form. + */ + public function blockForm($form, &$form_state) { + $form['block_content']['view_mode'] = array( + '#type' => 'select', + '#options' => $this->entityManager->getViewModeOptions('block_content'), + '#title' => t('View mode'), + '#description' => t('Output the block in this view mode.'), + '#default_value' => $this->configuration['view_mode'] + ); + $form['title']['#description'] = t('The title of the block as shown to the user.'); + return $form; + } + + /** + * Overrides \Drupal\block\BlockBase::blockSubmit(). + */ + public function blockSubmit($form, &$form_state) { + // Invalidate the block cache to update custom block-based derivatives. + if ($this->moduleHandler->moduleExists('block')) { + $this->configuration['view_mode'] = $form_state['values']['block_content']['view_mode']; + $this->blockManager->clearCachedDefinitions(); + } + } + + /** + * {@inheritdoc} + */ + public function build() { + $uuid = $this->getDerivativeId(); + if ($block = entity_load_by_uuid('block_content', $uuid)) { + return entity_view($block, $this->configuration['view_mode']); + } + else { + return array( + '#markup' => t('Block with uuid %uuid does not exist. Add custom block.', array( + '%uuid' => $uuid, + '!url' => url('block/add') + )), + '#access' => $this->account->hasPermission('administer blocks') + ); + } + } +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Plugin/Derivative/BlockContent.php b/core/modules/block_content/lib/Drupal/block_content/Plugin/Derivative/BlockContent.php new file mode 100644 index 0000000..a7c1784 --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Plugin/Derivative/BlockContent.php @@ -0,0 +1,28 @@ +derivatives[$block_content->uuid()] = $base_plugin_definition; + $this->derivatives[$block_content->uuid()]['admin_label'] = $block_content->label(); + } + return parent::getDerivativeDefinitions($base_plugin_definition); + } +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Plugin/Menu/LocalAction/BlockContentAddLocalAction.php b/core/modules/block_content/lib/Drupal/block_content/Plugin/Menu/LocalAction/BlockContentAddLocalAction.php new file mode 100644 index 0000000..e22425e --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Plugin/Menu/LocalAction/BlockContentAddLocalAction.php @@ -0,0 +1,39 @@ +attributes->has('theme')) { + $options['query']['theme'] = $request->attributes->get('theme'); + } + // Adds a destination on custom block listing. + if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'block_content.list') { + $options['query']['destination'] = 'admin/structure/block/block-content'; + } + // Adds a destination on custom block listing. + if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'block_content.list') { + $options['query']['destination'] = 'admin/structure/block/block-content'; + } + return $options; + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Tests/BlockContentCacheTagsTest.php b/core/modules/block_content/lib/Drupal/block_content/Tests/BlockContentCacheTagsTest.php new file mode 100644 index 0000000..52c3286 --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Tests/BlockContentCacheTagsTest.php @@ -0,0 +1,57 @@ + 'Llama', + 'type' => 'basic', + 'body' => array( + 'value' => 'The name "llama" was adopted by European settlers from native Peruvians.', + 'format' => 'plain_text', + ), + )); + $block_content->save(); + + return $block_content; + } + + /** + * {@inheritdoc} + * + * Each comment must have a comment body, which always has a text format. + */ + protected function getAdditionalCacheTagsForEntity(EntityInterface $entity) { + return array('filter_format:plain_text'); + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Tests/BlockContentCreationTest.php b/core/modules/block_content/lib/Drupal/block_content/Tests/BlockContentCreationTest.php new file mode 100644 index 0000000..9f35693 --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Tests/BlockContentCreationTest.php @@ -0,0 +1,221 @@ + 'Custom Block creation', + 'description' => 'Create a block and test saving it.', + 'group' => 'Custom Block', + ); + } + + /** + * Sets the test up. + */ + protected function setUp() { + parent::setUp(); + $this->drupalLogin($this->adminUser); + } + + /** + * Creates a "Basic page" block and verifies its consistency in the database. + */ + public function testBlockContentCreation() { + // Add a new view mode and verify if it is selected as expected. + $this->drupalLogin($this->drupalCreateUser(array('administer display modes'))); + $this->drupalGet('admin/structure/display-modes/view/add/block_content'); + $edit = array( + 'id' => 'test_view_mode', + 'label' => 'Test View Mode', + ); + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->assertRaw(t('Saved the %label view mode.', array('%label' => $edit['label']))); + + $this->drupalLogin($this->adminUser); + + // Create a block. + $edit = array(); + $edit['info[0][value]'] = 'Test Block'; + $edit['body[0][value]'] = $this->randomName(16); + $this->drupalPostForm('block/add/basic', $edit, t('Save')); + + // Check that the Basic block has been created. + $this->assertRaw(format_string('!block %name has been created.', array( + '!block' => 'Basic block', + '%name' => $edit['info[0][value]'] + )), 'Basic block created.'); + + // Change the view mode. + $view_mode['settings[block_content][view_mode]'] = 'test_view_mode'; + $this->drupalPostForm(NULL, $view_mode, t('Save block')); + + // Go to the configure page and verify that the new view mode is correct. + $this->drupalGet('admin/structure/block/manage/testblock'); + $this->assertFieldByXPath('//select[@name="settings[block_content][view_mode]"]/option[@selected="selected"]/@value', 'test_view_mode', 'View mode changed to Test View Mode'); + + // Test the available view mode options. + $this->assertOption('edit-settings-block-content-view-mode', 'default', 'The default view mode is available.'); + + // Check that the block exists in the database. + $blocks = entity_load_multiple_by_properties('block_content', array('info' => $edit['info[0][value]'])); + $block = reset($blocks); + $this->assertTrue($block, 'Custom Block found in database.'); + + // Check that attempting to create another block with the same value for + // 'info' returns an error. + $this->drupalPostForm('block/add/basic', $edit, t('Save')); + + // Check that the Basic block has been created. + $this->assertRaw(format_string('A block with description %name already exists.', array( + '%name' => $edit['info[0][value]'] + ))); + $this->assertResponse(200); + } + + /** + * Create a default custom block. + * + * Creates a custom block from defaults and ensures that the 'basic block' + * type is being used. + */ + public function testDefaultBlockContentCreation() { + $edit = array(); + $edit['info[0][value]'] = $this->randomName(8); + $edit['body[0][value]'] = $this->randomName(16); + // Don't pass the custom block type in the url so the default is forced. + $this->drupalPostForm('block/add', $edit, t('Save')); + + // Check that the block has been created and that it is a basic block. + $this->assertRaw(format_string('!block %name has been created.', array( + '!block' => 'Basic block', + '%name' => $edit['info[0][value]'], + )), 'Basic block created.'); + + // Check that the block exists in the database. + $blocks = entity_load_multiple_by_properties('block_content', array('info' => $edit['info[0][value]'])); + $block = reset($blocks); + $this->assertTrue($block, 'Default Custom Block found in database.'); + } + + /** + * Verifies that a transaction rolls back the failed creation. + */ + public function testFailedBlockCreation() { + // Create a block. + try { + $this->createBlockContent('fail_creation'); + $this->fail('Expected exception has not been thrown.'); + } + catch (\Exception $e) { + $this->pass('Expected exception has been thrown.'); + } + + if (Database::getConnection()->supportsTransactions()) { + // Check that the block does not exist in the database. + $id = db_select('block_content', 'b') + ->fields('b', array('id')) + ->condition('info', 'fail_creation') + ->execute() + ->fetchField(); + $this->assertFalse($id, 'Transactions supported, and block not found in database.'); + } + else { + // Check that the block exists in the database. + $id = db_select('block_content', 'b') + ->fields('b', array('id')) + ->condition('info', 'fail_creation') + ->execute() + ->fetchField(); + $this->assertTrue($id, 'Transactions not supported, and block found in database.'); + + // Check that the failed rollback was logged. + $records = db_query("SELECT wid FROM {watchdog} WHERE message LIKE 'Explicit rollback failed%'")->fetchAll(); + $this->assertTrue(count($records) > 0, 'Transactions not supported, and rollback error logged to watchdog.'); + } + } + + /** + * Test deleting a block. + */ + public function testBlockDelete() { + // Create a block. + $edit = array(); + $edit['info[0][value]'] = $this->randomName(8); + $body = $this->randomName(16); + $edit['body[0][value]'] = $body; + $this->drupalPostForm('block/add/basic', $edit, t('Save')); + + // Place the block. + $instance = array( + 'id' => drupal_strtolower($edit['info[0][value]']), + 'settings[label]' => $edit['info[0][value]'], + 'region' => 'sidebar_first', + ); + $block = entity_load('block_content', 1); + $url = 'admin/structure/block/add/block_content:' . $block->uuid() . '/' . \Drupal::config('system.theme')->get('default'); + $this->drupalPostForm($url, $instance, t('Save block')); + + $block = block_content_load(1); + + // Test getInstances method. + $this->assertEqual(1, count($block->getInstances())); + + // Navigate to home page. + $this->drupalGet(''); + $this->assertText($body); + + // Delete the block. + $this->drupalGet('block/1/delete'); + $this->assertText(format_plural(1, 'This will also remove 1 placed block instance.', 'This will also remove @count placed block instance.')); + + $this->drupalPostForm(NULL, array(), 'Delete'); + $this->assertRaw(t('Custom block %name has been deleted.', array('%name' => $edit['info[0][value]']))); + + // Create another block and force the plugin cache to flush. + $edit2 = array(); + $edit2['info[0][value]'] = $this->randomName(8); + $body2 = $this->randomName(16); + $edit2['body[0][value]'] = $body2; + $this->drupalPostForm('block/add/basic', $edit2, t('Save')); + + $this->assertNoRaw('Error message'); + + // Create another block with no instances, and test we don't get a + // confirmation message about deleting instances. + $edit3 = array(); + $edit3['info[0][value]'] = $this->randomName(8); + $body = $this->randomName(16); + $edit3['body[0][value]'] = $body; + $this->drupalPostForm('block/add/basic', $edit3, t('Save')); + + // Show the delete confirm form. + $this->drupalGet('block/3/delete'); + $this->assertNoText('This will also remove'); + } + +} diff --git a/core/modules/block_content/lib/Drupal/block_content/Tests/BlockContentFieldTest.php b/core/modules/block_content/lib/Drupal/block_content/Tests/BlockContentFieldTest.php new file mode 100644 index 0000000..f32a1ea --- /dev/null +++ b/core/modules/block_content/lib/Drupal/block_content/Tests/BlockContentFieldTest.php @@ -0,0 +1,118 @@ + 'Custom Block field test', + 'description' => 'Test block fieldability.', + 'group' => 'Custom Block', + ); + } + + /** + * Checks block edit functionality. + */ + public function testBlockFields() { + $this->drupalLogin($this->adminUser); + + $this->blockType = $this->createBlockContentType('link'); + + // Create a field with settings to validate. + $this->field = entity_create('field_config', array( + 'name' => drupal_strtolower($this->randomName()), + 'entity_type' => 'block_content', + 'type' => 'link', + 'cardinality' => 2, + )); + $this->field->save(); + $this->instance = entity_create('field_instance_config', array( + 'field_name' => $this->field->getName(), + 'entity_type' => 'block_content', + 'bundle' => 'link', + 'settings' => array( + 'title' => DRUPAL_OPTIONAL, + ), + )); + $this->instance->save(); + entity_get_form_display('block_content', 'link', 'default') + ->setComponent($this->field->getName(), array( + 'type' => 'link_default', + )) + ->save(); + entity_get_display('block_content', 'link', 'default') + ->setComponent($this->field->getName(), array( + 'type' => 'link', + 'label' => 'hidden', + )) + ->save(); + + // Create a block. + $this->drupalGet('block/add/link'); + $edit = array( + 'info[0][value]' => $this->randomName(8), + $this->field->getName() . '[0][url]' => 'http://example.com', + $this->field->getName() . '[0][title]' => 'Example.com' + ); + $this->drupalPostForm(NULL, $edit, t('Save')); + $block = entity_load('block_content', 1); + $url = 'admin/structure/block/add/block_content:' . $block->uuid() . '/' . \Drupal::config('system.theme')->get('default'); + // Place the block. + $instance = array( + 'id' => drupal_strtolower($edit['info[0][value]']), + 'settings[label]' => $edit['info[0][value]'], + 'region' => 'sidebar_first', + ); + $this->drupalPostForm($url, $instance, t('Save block')); + // Navigate to home page. + $this->drupalGet('