commit eb528228cda1c1f8c1a45db7eae13c1b4c0e843b Merge: ffbcf20 c27d77e Author: Lee Rowlands Date: Sat Jan 19 10:36:36 2013 +1000 Merge branch '8.x' into custom-blocks-content-entities-1871772 Conflicts: core/modules/block/custom_block/custom_block.module core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/block/block/CustomBlock.php core/modules/block/lib/Drupal/block/Tests/BlockTest.php diff --cc core/lib/Drupal/Core/Entity/EntityNG.php index b798bcf,99a29ca..0305fc2 --- a/core/lib/Drupal/Core/Entity/EntityNG.php +++ b/core/lib/Drupal/Core/Entity/EntityNG.php @@@ -10,6 -10,6 +10,7 @@@ namespace Drupal\Core\Entity use Drupal\Core\TypedData\ContextAwareInterface; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Component\Uuid\Uuid; ++use Drupal\Core\Language\Language; use ArrayIterator; use InvalidArgumentException; diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php index a1aa4ae,0000000..7a079a5 mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php @@@ -1,226 -1,0 +1,226 @@@ +type->value); + // If this is a new custom block, fill in the default values. + if (isset($block->bid->value)) { + $block->set('log', NULL); + } + // Always use the default revision setting. + $block->setNewRevision($block_type->revision); + + module_invoke_all('custom_block_prepare', $block); + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::form(). + */ + public function form(array $form, array &$form_state, EntityInterface $block) { + + // 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->type->value . '-form'); + + // Basic block information. + // These elements are just values so they are not even sent to the client. + foreach (array('bid', 'vid') as $key) { + $form[$key] = array( + '#type' => 'value', + '#value' => $block->$key->value, + ); + } + + $form['info'] = array( + '#type' => 'textfield', + '#title' => t('Block description'), + '#required' => TRUE, + '#default_value' => $block->info->value, + '#weight' => -5, + '#description' => t('A brief description of your block. Used on the Blocks administration page.', array('@overview' => url('admin/structure/block'))), + ); + + $form['machine_name'] = array( + '#type' => 'machine_name', + '#default_value' => $block->machine_name->value, + '#machine_name' => array( + 'exists' => 'custom_block_load', + 'source' => array('info') + ), + '#weight' => -4, + '#disabled' => !$block->isNew(), + ); + + $language_configuration = module_invoke('language', 'get_default_configuration', 'custom_block', $block->type->value); + $form['langcode'] = array( + '#title' => t('Language'), + '#type' => 'language_select', + '#default_value' => $block->langcode->value, + '#languages' => LANGUAGE_ALL, + '#access' => isset($language_configuration['language_hidden']) && !$language_configuration['language_hidden'], + ); + + $form['additional_settings'] = 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' => t('Revision information'), + '#collapsible' => TRUE, + // Collapsed by default when "Create new revision" is unchecked. + '#collapsed' => !$block->isNewRevision(), + '#group' => 'additional_settings', + '#attributes' => array( + 'class' => array('custom-block-form-revision-information'), + ), + '#attached' => array( + 'js' => array(drupal_get_path('module', 'custom_block') . '/custom_block.js'), + ), + '#weight' => 20, + '#access' => $block->isNewRevision() || user_access('administer blocks'), + ); + + $form['revision_information']['revision'] = array( + '#type' => 'checkbox', + '#title' => t('Create new revision'), + '#default_value' => $block->isNewRevision(), + '#access' => user_access('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' => t('Revision log message'), + '#rows' => 4, + '#default_value' => !empty($block->log->value) ? $block->log->value : '', + '#description' => t('Briefly describe the changes you have made.'), + ); + + return parent::form($form, $form_state, $block); + } + + /** + * 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. + * + * Overrides Drupal\Core\Entity\EntityFormController::submit(). + */ + 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(); + } + + foreach (module_implements('custom_block_submit') as $module) { + $function = $module . '_custom_block_submit'; + $function($block, $form, $form_state); + } + + return $block; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + */ + public function save(array $form, array &$form_state) { + $block = $this->getEntity($form_state); + $insert = empty($block->bid->value); + $block->save(); + $watchdog_args = array('@type' => $block->bundle(), '%info' => $block->label()); + $block_type = entity_load('custom_block_type', $block->type->value); + $t_args = array('@type' => $block_type->label(), '%info' => $block->label()); + + if ($insert) { + watchdog('content', '@type: added %info.', $watchdog_args, WATCHDOG_NOTICE); + drupal_set_message(t('@type %info has been created.', $t_args)); + } + else { + watchdog('content', '@type: updated %info.', $watchdog_args, WATCHDOG_NOTICE); + drupal_set_message(t('@type %info has been updated.', $t_args)); + } + + if ($block->bid->value) { + $form_state['values']['bid'] = $block->bid->value; + $form_state['bid'] = $block->bid->value; + if ($insert) { + if ($theme = $block->getTheme()) { - $form_state['redirect'] = 'admin/structure/block/manage/custom_block:' . $block->machine_name->value . '/' . $theme; ++ $form_state['redirect'] = 'admin/structure/block/add/custom_block:' . $block->machine_name->value . '/' . $theme; + } + else { - $form_state['redirect'] = 'admin/structure/block/manage/custom_block:' . $block->machine_name->value . '/' . variable_get('theme_default', 'stark'); ++ $form_state['redirect'] = 'admin/structure/block/add/custom_block:' . $block->machine_name->value . '/' . variable_get('theme_default', 'stark'); + } + } + else { + $form_state['redirect'] = 'admin/structure/block'; + } + } + else { + // In the unlikely case something went wrong on save, the block will be + // rebuilt and block form redisplayed. + drupal_set_message(t('The block could not be saved.'), 'error'); + $form_state['rebuild'] = TRUE; + } + + // Clear the page and block caches. + cache_invalidate_tags(array('content' => TRUE)); + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::delete(). + */ + public function delete(array $form, array &$form_state) { + $destination = array(); + if (isset($_GET['destination'])) { + $destination = drupal_get_destination(); + unset($_GET['destination']); + } + $block = $this->buildEntity($form, $form_state); + $form_state['redirect'] = array('block/' . $block->machine_name->value . '/delete', array('query' => $destination)); + } + +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php index 8befb87,0000000..ad7a772 mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php @@@ -1,224 -1,0 +1,226 @@@ +bid->value; + } + + /** + * Implements Drupal\Core\Entity\EntityInterface::bundle(). + */ + public function bundle() { + return $this->type->value; + } + + /** + * Implements Drupal\Core\Entity\EntityInterface::label(). + */ + public function label($langcode = NULL) { + return $this->info->value; + } + + /** + * Overrides Drupal\Core\Entity\Entity::createDuplicate(). + */ + public function createDuplicate() { + $duplicate = parent::createDuplicate(); + $duplicate->set('vid', NULL); + $duplicate->set('bid', NULL); + $duplicate->set('machine_name', NULL); + return $duplicate; + } + + /** + * Overrides Drupal\Core\Entity\Entity::getRevisionId(). + */ + public function getRevisionId() { + return $this->vid->value; + } + + /** + * Sets the theme value. + * + * When creating a new custom block from the block library, the user is + * redirected to the configure form for that block in the given theme. The + * theme is stored against the block when the custom block add form is shown. + * + * @param string $theme + * The theme name. + */ + public function setTheme($theme) { + $this->theme = $theme; + } + + /** + * Gets the theme value. + * + * When creating a new custom block from the block library, the user is + * redirected to the configure form for that block in the given theme. The + * theme is stored against the block when the custom block add form is shown. + * + * @return string + * The theme name. + */ + public function getTheme() { + return $this->theme; + } + + /** + * The plain data values of the contained properties. + * + * Define default values. + * + * @var array + */ - protected $values = array(); ++ protected $values = array( ++ 'langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))), ++ ); + + /** + * Initialize the object. Invoked upon construction and wake up. + */ + protected function init() { + parent::init(); + // We unset all defined properties, so magic getters apply. + unset($this->bid); + unset($this->info); + unset($this->vid); + unset($this->log); + unset($this->machine_name); + unset($this->uuid); + unset($this->langcode); + unset($this->type); + unset($this->new); + } +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/block/block/CustomBlock.php index f472ff7,ffb6544..0ed4776 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/block/block/CustomBlock.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/block/block/CustomBlock.php @@@ -57,19 -47,27 +45,19 @@@ class CustomBlock extends BlockBase * Adds body and description fields to the block configuration form. */ public function blockForm($form, &$form_state) { - // @todo Disable this field when editing an existing block and provide a - // separate interface for administering custom blocks. - $form['info'] = array( - '#type' => 'textfield', - '#title' => t('Block description'), - '#required' => TRUE, - '#default_value' => $this->configuration['info'], - '#description' => t('A brief description of your block. Used on the Blocks administration page. Changing this field will change the description for all copies of this block.', array('@overview' => url('admin/structure/block'))), - ); - // @todo Disable this field when editing an existing block and provide a - // separate interface for administering custom blocks. - $form['body'] = array( - '#type' => 'text_format', - '#title' => t('Block body'), - '#default_value' => $this->configuration['body'], - '#format' => isset($this->configuration['format']) ? $this->configuration['format'] : filter_default_format(), - '#description' => t('The content of the block as shown to the user. Changing this field will change the block body everywhere it is used.'), - '#rows' => 15, - '#required' => TRUE, + $view_modes = array(); + $info = entity_get_info('custom_block'); + foreach ($info['view_modes'] as $view_mode => $detail) { + $view_modes[$view_mode] = $detail['label']; + } + $form['custom_block']['view_mode'] = array( + '#type' => 'select', + '#options' => $view_modes, + '#title' => t('View mode'), + '#description' => t('Output the block in this view mode.'), + '#default_value' => $this->configuration['view_mode'] ); - $form['custom_block']['title']['#description'] = t('The title of the block as shown to the user.'); + $form['title']['#description'] = t('The title of the block as shown to the user.'); return $form; } @@@ -84,22 -105,15 +72,21 @@@ } /** - * Implements \Drupal\block\BlockBase::blockBuild(). + * Implements \Drupal\block\BlockBase::build(). */ - public function blockBuild() { + public function build() { - // Populate the block with the user-defined block body. - return array( - '#theme' => 'custom_block_block', - '#body' => $this->configuration['body'], - '#format' => $this->configuration['format'], - ); + list(, $machine_name) = explode(':', $this->getPluginId()); + if ($block = custom_block_machine_name_load($machine_name)) { + return entity_view($block, $this->configuration['view_mode']); + } + else { + return array( + '#markup' => t('Block with name %name does not exist. Add custom block.', array( + '%name' => $block_id, + '!url' => url('block/add') + )), + '#access' => user_access('administer blocks') + ); + } } -- } diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockBuildContentTest.php index 5ec715c,0000000..3c56d56 mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockBuildContentTest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockBuildContentTest.php @@@ -1,38 -1,0 +1,41 @@@ + 'Rebuild content', + 'description' => 'Test the rebuilding of content for full view modes.', + 'group' => 'Custom Block', + ); + } + - /** - * Ensures that content is rebuilt in calls to custom_block_build_content(). - */ - function testCustomBlockRebuildContent() { ++ /** ++ * Ensures that content is rebuilt in calls to custom_block_build_content(). ++ */ ++ public function testCustomBlockRebuildContent() { + $block = $this->createCustomBlock(); + + // Set a property in the content array so we can test for its existence later on. + $block->content['test_content_property'] = array( + '#value' => $this->randomString(), + ); + $content = entity_view_multiple(array($block), 'full'); + + // If the property doesn't exist it means the block->content was rebuilt. + $this->assertFalse(isset($content['test_content_property']), 'Custom block content was emptied prior to being built.'); + } +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockCreationTest.php index 49e0b22,0000000..e7581a8 mode 100644,000000..100644 --- 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 @@@ -1,100 -1,0 +1,106 @@@ + 'Custom Block creation', + 'description' => 'Create a block and test saving it.', + 'group' => 'Custom Block', + ); + } + - function setUp() { ++ /** ++ * Sets the test up. ++ */ ++ public function setUp() { + parent::setUp(); - $this->drupalLogin($this->admin_user); ++ $this->drupalLogin($this->adminUser); + } + + /** + * Creates a "Basic page" block and verifies its consistency in the database. + */ - function testCustomBlockCreation() { ++ public function testCustomBlockCreation() { + // Create a block. + $edit = array(); + $langcode = LANGUAGE_NOT_SPECIFIED; + $edit['info'] = $this->randomName(8); + $edit['machine_name'] = drupal_strtolower($edit['info']); + $edit["block_body[$langcode][0][value]"] = $this->randomName(16); + $this->drupalPost('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"] + )), 'Basic block created.'); + + // Check that the block exists in the database. + $blocks = entity_load_multiple_by_properties('custom_block', array('info' => $edit['info'])); + $block = reset($blocks); + $this->assertTrue($block, 'Custom Block found in database.'); + } + + /** + * Verifies that a transaction rolls back the failed creation. + */ - function testFailedBlockCreation() { ++ 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. + $bid = db_select('block_custom', 'b') + ->fields('b', array('bid')) + ->condition('info', 'fail_creation') + ->execute() + ->fetchField(); + $this->assertFalse($bid, 'Transactions supported, and block not found in database.'); + } + else { + // Check that the block exists in the database. + $bid = db_select('block_custom', 'b') + ->fields('b', array('bid')) + ->condition('info', 'fail_creation') + ->execute() + ->fetchField(); + $this->assertTrue($bid, '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.'); + } + } +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockLoadHooksTest.php index 30b2203,0000000..9f57074 mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockLoadHooksTest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockLoadHooksTest.php @@@ -1,67 -1,0 +1,70 @@@ + 'Custom Block load hooks', + 'description' => 'Test the hooks invoked when a custom block is being loaded.', + 'group' => 'Custom Block', + ); + } + + /** + * Tests that hook_custom_block_load() is invoked correctly. + */ - function testHookCustomBlockLoad() { ++ public function testHookCustomBlockLoad() { + $other_bundle = $this->createCustomBlockType('other'); + // Create some sample articles and pages. + $custom_block1 = $this->createCustomBlock(); + $custom_block2 = $this->createCustomBlock(); + $custom_block3 = $this->createCustomBlock(); + $custom_block4 = $this->createCustomBlock(FALSE, $other_bundle->id()); + + // Check that when a set of custom blocks that only contains basic blocks is + // loaded, the properties added to the custom block by + // custom_block_test_load_custom_block() correctly reflect the expected + // values. + $custom_blocks = entity_load_multiple_by_properties('custom_block', array('type' => 'basic')); + $loaded_custom_block = end($custom_blocks); + $this->assertEqual($loaded_custom_block->custom_block_test_loaded_bids, array( + $custom_block1->bid->value, + $custom_block2->bid->value, + $custom_block3->bid->value + ), 'hook_custom_block_load() received the correct list of custom_block IDs the first time it was called.'); + $this->assertEqual($loaded_custom_block->custom_block_test_loaded_types, array('basic'), 'hook_custom_block_load() received the correct list of custom block types the first time it was called.'); + + // Now, as part of the same page request, load a set of custom_blocks that contain + // both basic and other bundle, and make sure the parameters passed to + // custom_block_test_custom_block_load() are correctly updated. + $custom_blocks = entity_load_multiple('custom_block', entity_query('custom_block')->execute(), TRUE); + $loaded_custom_block = end($custom_blocks); + $this->assertEqual($loaded_custom_block->custom_block_test_loaded_bids, array( + $custom_block1->bid->value, + $custom_block2->bid->value, + $custom_block3->bid->value, + $custom_block4->bid->value + ), 'hook_custom_block_load() received the correct list of custom_block IDs the second time it was called.'); + $this->assertEqual($loaded_custom_block->custom_block_test_loaded_types, array('basic', 'other'), 'hook_custom_block_load() received the correct list of custom_block types the second time it was called.'); + } +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockRevisionsTest.php index 2497ff5,0000000..e13fd71 mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockRevisionsTest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockRevisionsTest.php @@@ -1,86 -1,0 +1,92 @@@ + 'Custom Block revisions', + 'description' => 'Create a block with revisions.', + 'group' => 'Custom Block', + ); + } + - function setUp() { ++ /** ++ * Sets the test up. ++ */ ++ public function setUp() { + parent::setUp(); + + // Create initial block. + $block = $this->createCustomBlock('initial'); + + $blocks = array(); + $logs = array(); + + // Get original block. + $blocks[] = $block->vid->value; + $logs[] = ''; + + // Create three revisions. + $revision_count = 3; + for ($i = 0; $i < $revision_count; $i++) { + $block->setNewRevision(TRUE); + $logs[] = $block->log->value = $this->randomName(32); + $block->save(); + $blocks[] = $block->vid->value; + } + + $this->blocks = $blocks; + $this->logs = $logs; + } + + /** + * Checks block revision related operations. + */ - function testRevisions() { ++ public function testRevisions() { + $blocks = $this->blocks; + $logs = $this->logs; + + foreach ($blocks as $delta => $vid) { + // Confirm the correct revision text appears. + $loaded = entity_revision_load('custom_block', $vid); + // Verify log is the same. + $this->assertEqual($loaded->log->value, $logs[$delta], format_string('Correct log message found for revision !revision', array( + '!revision' => $loaded->vid->value + ))); + } + + // Confirm that this is the default revision. + $this->assertTrue($loaded->isDefaultRevision(), 'Third block revision is the default one.'); + + // Make a new revision and set it to not be default. + // This will create a new revision that is not "front facing". + // Save this as a non-default revision. + $loaded->setNewRevision(); + $loaded->isDefaultRevision = FALSE; + $loaded->block_body = $this->randomName(8); + $loaded->save(); + + $this->drupalGet('block/' . $loaded->bid->value); + $this->assertNoText($loaded->block_body->value, 'Revision body text is not present on default version of block.'); + + // Verify that the non-default revision vid is greater than the default + // revision vid. + $default_revision = entity_load('custom_block', $loaded->bid->value); + $this->assertTrue($loaded->vid->value > $default_revision->vid->value, 'Revision vid is greater than default revision vid.'); + } +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockSaveTest.php index 077294b,0000000..30fc1ba mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockSaveTest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockSaveTest.php @@@ -1,103 -1,0 +1,110 @@@ + 'Custom Block save', + 'description' => 'Test $custom_block->save() for saving content.', + 'group' => 'Custom Block', + ); + } + - function setUp() { ++ /** ++ * Sets the test up. ++ */ ++ public function setUp() { + parent::setUp(); - $this->drupalLogin($this->admin_user); ++ $this->drupalLogin($this->adminUser); + } + + /** + * Checks whether custom block IDs are saved properly during an import. + */ - function testImport() { ++ public function testImport() { + // Custom block ID must be a number that is not in the database. + $max_bid = db_query('SELECT MAX(bid) FROM {block_custom}')->fetchField(); + $test_bid = $max_bid + mt_rand(1000, 1000000); + $info = $this->randomName(8); + $block = array( + 'info' => $info, + 'machine_name' => $info, + 'block_body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $this->randomName(32)))), + 'type' => 'basic', + 'bid' => $test_bid + ); + $block = entity_create('custom_block', $block); + $block->enforceIsNew(TRUE); + $block->save(); + + // Verify that block_submit did not wipe the provided bid. + $this->assertEqual($block->bid->value, $test_bid, 'Block imported using provide bid'); + + // Test the import saved. + $block_by_bid = custom_block_load($test_bid); + $this->assertTrue($block_by_bid, 'Custom block load by block ID.'); + } + + /** - * Tests determing changes in hook_block_presave() and verifies the static - * block load cache is cleared upon save. ++ * Tests determing changes in hook_block_presave(). ++ * ++ * Verifies the static block load cache is cleared upon save. + */ - function testDeterminingChanges() { ++ public function testDeterminingChanges() { + // Initial creation. + $block = $this->createCustomBlock('test_changes'); + + // Update the block without applying changes. + $block->save(); + $this->assertEqual($block->label(), 'test_changes', 'No changes have been determined.'); + + // Apply changes. + $block->info->value = 'updated'; + $block->save(); + + // The hook implementations custom_block_test_custom_block_presave() and + // custom_block_test_custom_block_update() determine changes and change the + // title. + $this->assertEqual($block->label(), 'updated_presave_update', 'Changes have been determined.'); + + // Test the static block load cache to be cleared. + $block = custom_block_load($block->bid->value); + $this->assertEqual($block->label(), 'updated_presave', 'Static cache has been cleared.'); + } + + /** + * Tests saving a block on block insert. + * + * This test ensures that a block has been fully saved when + * hook_custom_block_insert() is invoked, so that the block can be saved again + * in a hook implementation without errors. + * + * @see block_test_block_insert() + */ - function testCustomBlockSaveOnInsert() { ++ public function testCustomBlockSaveOnInsert() { + // custom_block_test_custom_block_insert() tiggers a save on insert if the + // title equals 'new'. + $block = $this->createCustomBlock('new'); + $this->assertEqual($block->label(), 'CustomBlock ' . $block->bid->value, 'Custom block saved on block insert.'); + } +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTestBase.php index aa11305,0000000..f919a46 mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTestBase.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTestBase.php @@@ -1,92 -1,0 +1,98 @@@ +admin_user = $this->drupalCreateUser($this->permissions); ++ $this->adminUser = $this->drupalCreateUser($this->permissions); + } + + /** + * Creates a custom block. + * + * @param string $title + * (optional) Title of block. When no value is given uses a random name. + * Defaults to FALSE. + * @param string $bundle + * (optional) Bundle name. Defaults to 'basic'. + * + * @return Drupal\custom_block\Plugin\Core\Entity\CustomBlock + * Created custom block. + */ - function createCustomBlock($title = FALSE, $bundle = 'basic') { ++ protected function createCustomBlock($title = FALSE, $bundle = 'basic') { + $title = ($title ? : $this->randomName()); + if ($custom_block = entity_create('custom_block', array( + 'machine_name' => $title, + 'info' => $title, + 'type' => $bundle, + 'langcode' => 'en' + ))) { + $custom_block->save(); + } + return $custom_block; + } + + /** + * Creates a custom block type (bundle). + * + * @param string $label + * The block type label. + * + * @return Drupal\custom_block\Plugin\Core\Entity\CustomBlockType + * Created custom block type. + */ - function createCustomBlockType($label) { ++ protected function createCustomBlockType($label) { + $bundle = entity_create('custom_block_type', array( + 'id' => $label, + 'label' => $label, + 'revision' => FALSE + )); + $bundle->save(); + return $bundle; + } + +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTranslationUITest.php index 7c6513b,0000000..ae12319 mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTranslationUITest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTranslationUITest.php @@@ -1,144 -1,0 +1,165 @@@ + 'Custom Block translation UI', + 'description' => 'Tests the node translation UI.', + 'group' => 'Custom Block', + ); + } + + /** + * Overrides \Drupal\simpletest\WebTestBase::setUp(). + */ - function setUp() { ++ public function setUp() { + $this->entityType = 'custom_block'; + $this->bundle = 'basic'; + $this->name = drupal_strtolower($this->randomName()); ++ $this->testLanguageSelector = FALSE; + parent::setUp(); + } + + /** + * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission(). + */ - function getTranslatorPermissions() { - return array('translate any entity', 'edit original values', 'access administration pages', 'administer blocks'); ++ public function getTranslatorPermissions() { ++ return array( ++ 'translate any entity', ++ 'edit original values', ++ 'access administration pages', ++ 'administer blocks', ++ 'administer custom_block fields' ++ ); + } + + /** + * Creates a custom block. + * + * @param string $title + * (optional) Title of block. When no value is given uses a random name. + * Defaults to FALSE. + * @param string $bundle + * (optional) Bundle name. When no value is given, defaults to + * $this->bundle. Defaults to FALSE. + * + * @return Drupal\custom_block\Plugin\Core\Entity\CustomBlock + * Created custom block. + */ - function createCustomBlock($title = FALSE, $bundle = FALSE) { ++ protected function createCustomBlock($title = FALSE, $bundle = FALSE) { + $title = ($title ? : $this->randomName()); + $bundle = ($bundle ? : $this->bundle); + $custom_block = entity_create('custom_block', array( + 'machine_name' => $title, + 'info' => $title, + 'type' => $bundle, + 'langcode' => 'en' + )); + $custom_block->save(); + return $custom_block; + } + + /** + * Tests field translation form. + */ - function testFieldTranslationForm() { - $admin_user = $this->drupalCreateUser(array('translate any entity', 'access administration pages', 'administer blocks')); ++ public function testFieldTranslationForm() { ++ $admin_user = $this->drupalCreateUser(array( ++ 'translate any entity', ++ 'access administration pages', ++ 'administer blocks', ++ 'administer custom_block fields' ++ )); + $this->drupalLogin($admin_user); + + $block = $this->createCustomBlock($this->name); + + // Visit translation page. + $this->drupalGet('block/' . $block->machine_name->value . '/translations'); + $this->assertRaw('Not translated'); + + // Delete the only translatable field. + field_delete_field('field_test_et_ui_test'); + + // Visit translation page. + $this->drupalGet('block/' . $block->machine_name->value . '/translations'); + $this->assertRaw('no translatable fields'); + } + + /** + * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getNewEntityValues(). + */ + protected function getNewEntityValues($langcode) { + return array('machine_name' => $this->name, 'info' => $this->name) + parent::getNewEntityValues($langcode); + } + + /** + * Test that no metadata is stored for a disabled bundle. + */ + public function testDisabledBundle() { + // Create a bundle that does not have translation enabled. - $disabledBundle = $this->randomName(); ++ $disabled_bundle = $this->randomName(); + $bundle = entity_create('custom_block_type', array( - 'id' => $disabledBundle, - 'label' => $disabledBundle, ++ 'id' => $disabled_bundle, ++ 'label' => $disabled_bundle, + 'revision' => FALSE + )); + $bundle->save(); + + // Create a node for each bundle. - $enabledCustomBlock = $this->createCustomBlock(); - $disabledCustomBlock = $this->createCustomBlock(FALSE, $bundle->id()); ++ $enabled_custom_block = $this->createCustomBlock(); ++ $disabled_custom_block = $this->createCustomBlock(FALSE, $bundle->id()); + + // Make sure that only a single row was inserted into the + // {translation_entity} table. + $rows = db_query('SELECT * FROM {translation_entity}')->fetchAll(); + $this->assertEqual(1, count($rows)); - $this->assertEqual($enabledCustomBlock->id(), reset($rows)->entity_id); ++ $this->assertEqual($enabled_custom_block->id(), reset($rows)->entity_id); + } + + /** + * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getEditValues(). + */ + protected function getEditValues($values, $langcode, $new = FALSE) { + $edit = parent::getEditValues($values, $langcode, $new); + // Can't submit machine name if not new. + if (!$new) { + unset($edit['machine_name']); + } + return $edit; + } +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php index 805824d,0000000..5138393 mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php @@@ -1,123 -1,0 +1,126 @@@ + 'CustomBlock types', + 'description' => 'Ensures that custom block type functions work correctly.', + 'group' => 'Custom Block', + ); + } + + /** + * Tests creating a block type programmatically and via a form. + */ - function testCustomBlockTypeCreation() { ++ public function testCustomBlockTypeCreation() { + // Create a block type programmaticaly. + $type = $this->createCustomBlockType('other'); + + $block_type = entity_load('custom_block_type', 'other'); + $this->assertTrue($block_type, 'The new block type has been created.'); + + // Login a test user. - $this->drupalLogin($this->admin_user); ++ $this->drupalLogin($this->adminUser); + + $this->drupalGet('block/add/' . $type->id()); + $this->assertResponse(200, 'The new block type can be accessed at bloack/add.'); + + // Create a block type via the user interface. + $edit = array( + 'id' => 'foo', + 'label' => 'title for foo', + ); + $this->drupalPost('admin/structure/custom-blocks/add', $edit, t('Save')); + $block_type = entity_load('custom_block_type', 'foo'); + $this->assertTrue($block_type, 'The new block type has been created.'); + } + + /** + * Tests editing a block type using the UI. + */ - function testCustomBlockTypeEditing() { - $this->drupalLogin($this->admin_user); ++ public function testCustomBlockTypeEditing() { ++ $this->drupalLogin($this->adminUser); + // We need two block types to prevent /block/add redirecting. + $this->createCustomBlockType('other'); + + $instance = field_info_instance('custom_block', 'block_body', 'basic'); + $this->assertEqual($instance['label'], 'Block body', 'Body field was found.'); + + // Verify that title and body fields are displayed. + $this->drupalGet('block/add/basic'); + $this->assertRaw('Block description', 'Block info field was found.'); + $this->assertRaw('Block body', 'Body field was found.'); + + // Change the block type name. + $edit = array( + 'label' => 'Bar', + ); + $this->drupalPost('admin/structure/custom-blocks/manage/basic', $edit, t('Save')); + field_info_cache_clear(); + + $this->drupalGet('block/add'); + $this->assertRaw('Bar', 'New name was displayed.'); + $this->clickLink('Bar'); + $this->assertEqual(url('block/add/basic', array('absolute' => TRUE)), $this->getUrl(), 'Original machine name was used in URL.'); + + // Remove the body field. + $this->drupalPost('admin/structure/custom-blocks/manage/basic/fields/block_body/delete', array(), t('Delete')); + // Resave the settings for this type. + $this->drupalPost('admin/structure/custom-blocks/manage/basic', array(), t('Save')); + // Check that the body field doesn't exist. + $this->drupalGet('block/add/basic'); + $this->assertNoRaw('Block body', 'Body field was not found.'); + } + + /** + * Tests deleting a block type that still has content. + */ - function testCustomBlockTypeDeletion() { ++ public function testCustomBlockTypeDeletion() { + // Create a block type programmatically. + $type = $this->createCustomBlockType('foo'); + - $this->drupalLogin($this->admin_user); ++ $this->drupalLogin($this->adminUser); + + // Add a new block of this type. + $block = $this->createCustomBlock(FALSE, 'foo'); + // Attempt to delete the block type, which should not be allowed. + $this->drupalGet('admin/structure/custom-blocks/manage/' . $type->id() . '/delete'); + $this->assertRaw( + t('%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.', array('%label' => $type->label())), + 'The block type will not be deleted until all blocks of that type are removed.' + ); + $this->assertNoText(t('This action cannot be undone.'), 'The node type deletion confirmation form is not available.'); + + // Delete the block. + $block->delete(); + // Attempt to delete the block type, which should now be allowed. + $this->drupalGet('admin/structure/custom-blocks/manage/' . $type->id() . '/delete'); + $this->assertRaw( + t('Are you sure you want to delete %type?', array('%type' => $type->id())), + 'The block type is available for deletion.' + ); + $this->assertText(t('This action cannot be undone.'), 'The custom block type deletion confirmation form is available.'); + } + +} diff --cc core/modules/block/custom_block/lib/Drupal/custom_block/Tests/PageEditTest.php index bd00e45,0000000..71231f2 mode 100644,000000..100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/PageEditTest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/PageEditTest.php @@@ -1,86 -1,0 +1,92 @@@ + 'Custom Block edit', + 'description' => 'Create a block and test block edit functionality.', + 'group' => 'Custom Block', + ); + } + - function setUp() { ++ /** ++ * Sets the test up. ++ */ ++ public function setUp() { + $this->permissions[] = 'view custom blocks'; + parent::setUp(); + } + + /** + * Checks block edit functionality. + */ - function testPageEdit() { - $this->drupalLogin($this->admin_user); ++ public function testPageEdit() { ++ $this->drupalLogin($this->adminUser); + + $langcode = LANGUAGE_NOT_SPECIFIED; + $title_key = 'info'; + $body_key = "block_body[$langcode][0][value]"; + // Create block to edit. + $edit = array(); + $edit['info'] = $edit['machine_name'] = drupal_strtolower($this->randomName(8)); + $edit[$body_key] = $this->randomName(16); + $this->drupalPost('block/add/basic', $edit, t('Save')); + + // Check that the block exists in the database. + $blocks = entity_query('custom_block')->condition('info', $edit['info'])->execute(); + $block = entity_load('custom_block', reset($blocks)); + $this->assertTrue($block, 'Custom block found in database.'); + + // Check that "edit" link points to correct page. - $this->drupalGet('block/'. $block->machine_name->value); ++ $this->drupalGet('block/' . $block->machine_name->value); + $this->clickLink(t('Edit')); + $edit_url = url("block/" . $block->machine_name->value . "/edit", array('absolute' => TRUE)); + $actual_url = $this->getURL(); + $this->assertEqual($edit_url, $actual_url, 'On edit page.'); + + // Check that the title and body fields are displayed with the correct values. + $active = '' . t('(active tab)') . ''; + $link_text = t('!local-task-title!active', array('!local-task-title' => t('Edit'), '!active' => $active)); + $this->assertText(strip_tags($link_text), 0, 'Edit tab found and marked active.'); + $this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.'); + $this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.'); + + // Edit the content of the block. + $edit = array(); + $edit[$title_key] = $this->randomName(8); + $edit[$body_key] = $this->randomName(16); + // Stay on the current page, without reloading. + $this->drupalPost(NULL, $edit, t('Save')); + + // Check that the title and body fields are displayed with the updated values. - $this->drupalGet('block/'. $block->machine_name->value); ++ $this->drupalGet('block/' . $block->machine_name->value); + $this->assertText($edit[$title_key], 'Title displayed.'); + $this->assertText($edit[$body_key], 'Body displayed.'); + + // Edit the same block, creating a new revision. + $this->drupalGet("block/" . $block->machine_name->value . "/edit"); + $edit = array(); + $edit['info'] = $this->randomName(8); + $edit[$body_key] = $this->randomName(16); + $edit['revision'] = TRUE; + $this->drupalPost(NULL, $edit, t('Save')); + + // Ensure that the block revision has been created. + $revised_block = entity_load('custom_block', $block->bid->value, TRUE); + $this->assertNotIdentical($block->vid->value, $revised_block->vid->value, 'A new revision has been created.'); + } +} diff --cc core/modules/block/lib/Drupal/block/Tests/BlockTest.php index 0b6cc0e,67796b1..1f56b93 --- a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php @@@ -106,34 -102,27 +102,32 @@@ class BlockTest extends WebTestBase } } - // Add a new custom block by filling out the input form on the admin/structure/block/add page. + // Add a new custom block by filling out the input form on block/add/basic. $info = strtolower($this->randomName(8)); + $langcode = LANGUAGE_NOT_SPECIFIED; + $values = array( + 'info' => $info, + 'machine_name' => $info, + "block_body[$langcode][0][value]" => $this->randomName(8) + ); + $this->drupalPost('block/add/basic', $values, t('Save')); $custom_block['machine_name'] = $info; - $custom_block['title'] = $this->randomName(8); - $custom_block['info'] = $info; + $custom_block['label'] = $this->randomName(8); - $custom_block['body[value]'] = $this->randomName(32); $custom_block['region'] = $this->regions[0]; - $this->drupalPost("admin/structure/block/list/block_plugin_ui:$default_theme/add/custom_blocks", $custom_block, t('Save block')); + $this->drupalPost(NULL, $custom_block, t('Save block')); - $plugin_id = "plugin.core.block.$default_theme.$info"; - $block = $manager->getInstance(array('config' => $plugin_id)); - $config = $block->getConfig(); + $block = entity_load('block', $default_theme . '.' . $info); // Confirm that the custom block has been created, and then query the created bid. - $this->assertText(t('The block configuration has been saved.'), 'Custom block successfully created.'); + $this->assertText(t('The block configuration has been saved.'), 'Custom block instance successfully created.'); - // Check that entity_view() returns the correct title and content. - // @todo This assumes that a block's content can be rendered without its - // wrappers. If this is a reasonable expectation, it should be documented - // elsewhere. + // Check that block_block_view() returns the correct content. - $data = $block->build(); + $data = entity_view($block, 'content'); - $definition = $block->getPlugin()->getDefinition(); - $config = $definition['settings']; - $this->assertEqual(check_markup($custom_block['body[value]'], $config['format']), render($data), 'BlockInterface::build() provides correct block content.'); + $output = render($data); + + $this->drupalSetcontent($output); + $elements = $this->xpath('//div[@class=:class]', array(':class' => 'field-item even')); + + $this->assertEqual($values["block_body[$langcode][0][value]"], $elements[0], 'BlockInterface::build() provides correct block content.'); // Check whether the block can be moved to all available regions. $custom_block['module'] = 'block'; @@@ -167,41 -156,35 +161,40 @@@ $default_theme = variable_get('theme_default', 'stark'); $this->removeDefaultBlocks(); - // Add a new custom block by filling out the input form on the admin/structure/block/add page. - $info = $this->randomName(8); + // Add a new custom block by filling out the input form on block/add/basic. + $info = strtolower($this->randomName(8)); + $langcode = LANGUAGE_NOT_SPECIFIED; + $values = array( + 'info' => $info, + 'machine_name' => $info, + "block_body[$langcode][0][value]" => '

Full HTML

', + "block_body[$langcode][0][format]" => 'full_html' + ); + $this->drupalPost('block/add/basic', $values, t('Save')); $custom_block['machine_name'] = $info; - $custom_block['title'] = $this->randomName(8); - $custom_block['info'] = $info; + $custom_block['label'] = $this->randomName(8); - $custom_block['body[value]'] = '

Full HTML

'; - $full_html_format = filter_format_load('full_html'); - $custom_block['body[format]'] = $full_html_format->format; $custom_block['region'] = $this->regions[0]; - $this->drupalPost("admin/structure/block/list/block_plugin_ui:$default_theme/add/custom_blocks", $custom_block, t('Save block')); + $this->drupalPost(NULL, $custom_block, t('Save block')); // Set the created custom block to a specific region. - $edit['blocks[0][region]'] = $this->regions[1]; + $edit['blocks[' . $default_theme . '.' . $custom_block['machine_name'] . '][region]'] = $this->regions[1]; $this->drupalPost('admin/structure/block', $edit, t('Save blocks')); - // Confirm that the custom block is being displayed using configured text format. + // Confirm that the custom block is being displayed using configured text + // format. $this->drupalGet(''); $this->assertRaw('

Full HTML

', 'Custom block successfully being displayed using Full HTML.'); - // Confirm that a user without access to Full HTML can not see the body field, - // but can still submit the form without errors. + // Confirm that a user without access to Full HTML can not see the body + // field, but can still submit the form without errors. $block_admin = $this->drupalCreateUser(array('administer blocks')); - $config_block_id = "admin/structure/block/manage/plugin.core.block.$default_theme.$info/$default_theme"; $this->drupalLogin($block_admin); - $this->drupalGet("admin/structure/block/manage/$default_theme.$info/configure"); - $this->assertFieldByXPath("//textarea[@name='body[value]' and @disabled='disabled']", t('This field has been disabled because you do not have sufficient permissions to edit it.'), 'Body field contains denied message'); - $this->drupalPost("admin/structure/block/manage/$default_theme.$info/configure", array(), t('Save block')); + $this->drupalGet("block/$info/edit"); + $this->assertFieldByXPath("//textarea[@name='block_body[und][0][value]' and @disabled='disabled']", t('This field has been disabled because you do not have sufficient permissions to edit it.'), 'Body field contains denied message'); $this->assertNoText(t('Ensure that each block description is unique.')); - // Confirm that the custom block is still being displayed using configured text format. + // Confirm that the custom block is still being displayed using configured + // text format. $this->drupalGet(''); $this->assertRaw('

Full HTML

', 'Custom block successfully being displayed using Full HTML.'); }