Issue #2767857 by Berdir, tstoeckler: Add destination to edit, delete, enable, disable links in entity list builders

8.5.x
Lee Rowlands 2017-08-25 16:18:29 +10:00
parent 30a133b0f4
commit 401bd662cb
No known key found for this signature in database
GPG Key ID: 2B829A3DF9204DC4
11 changed files with 68 additions and 67 deletions

View File

@ -37,14 +37,14 @@ class ConfigEntityListBuilder extends EntityListBuilder {
$operations['enable'] = [
'title' => t('Enable'),
'weight' => -10,
'url' => $entity->urlInfo('enable'),
'url' => $this->ensureDestination($entity->toUrl('enable')),
];
}
elseif ($entity->hasLinkTemplate('disable')) {
$operations['disable'] = [
'title' => t('Disable'),
'weight' => 40,
'url' => $entity->urlInfo('disable'),
'url' => $this->ensureDestination($entity->toUrl('disable')),
];
}
}

View File

@ -2,6 +2,8 @@
namespace Drupal\Core\Entity;
use Drupal\Core\Routing\RedirectDestinationTrait;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@ -11,6 +13,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class EntityListBuilder extends EntityHandlerBase implements EntityListBuilderInterface, EntityHandlerInterface {
use RedirectDestinationTrait;
/**
* The entity storage class.
*
@ -143,14 +147,14 @@ class EntityListBuilder extends EntityHandlerBase implements EntityListBuilderIn
$operations['edit'] = [
'title' => $this->t('Edit'),
'weight' => 10,
'url' => $entity->urlInfo('edit-form'),
'url' => $this->ensureDestination($entity->toUrl('edit-form')),
];
}
if ($entity->access('delete') && $entity->hasLinkTemplate('delete-form')) {
$operations['delete'] = [
'title' => $this->t('Delete'),
'weight' => 100,
'url' => $entity->urlInfo('delete-form'),
'url' => $this->ensureDestination($entity->toUrl('delete-form')),
];
}
@ -250,4 +254,17 @@ class EntityListBuilder extends EntityHandlerBase implements EntityListBuilderIn
return;
}
/**
* Ensures that a destination is present on the given URL.
*
* @param \Drupal\Core\Url $url
* The URL object to which the destination should be added.
*
* @return \Drupal\Core\Url
* The updated URL object.
*/
protected function ensureDestination(Url $url) {
return $url->mergeOptions(['query' => $this->getRedirectDestination()->getAsArray()]);
}
}

View File

@ -44,14 +44,15 @@ class ConfigurationTest extends BrowserTestBase {
$this->drupalPostForm('admin/config/system/actions/add/' . Crypt::hashBase64('action_goto_action'), $edit, t('Save'));
$this->assertResponse(200);
$action_id = $edit['id'];
// Make sure that the new complex action was saved properly.
$this->assertText(t('The action has been successfully saved.'), "Make sure we get a confirmation that we've successfully saved the complex action.");
$this->assertText($action_label, "Make sure the action label appears on the configuration page after we've saved the complex action.");
// Make another POST request to the action edit page.
$this->clickLink(t('Configure'));
preg_match('|admin/config/system/actions/configure/(.+)|', $this->getUrl(), $matches);
$aid = $matches[1];
$edit = [];
$new_action_label = $this->randomMachineName();
$edit['label'] = $new_action_label;
@ -73,7 +74,7 @@ class ConfigurationTest extends BrowserTestBase {
$this->clickLink(t('Delete'));
$this->assertResponse(200);
$edit = [];
$this->drupalPostForm("admin/config/system/actions/configure/$aid/delete", $edit, t('Delete'));
$this->drupalPostForm(NULL, $edit, t('Delete'));
$this->assertResponse(200);
// Make sure that the action was actually deleted.
@ -82,7 +83,7 @@ class ConfigurationTest extends BrowserTestBase {
$this->assertResponse(200);
$this->assertNoText($new_action_label, "Make sure the action label does not appear on the overview page after we've deleted the action.");
$action = Action::load($aid);
$action = Action::load($action_id);
$this->assertFalse($action, 'Make sure the action is gone after being deleted.');
}

View File

@ -4,7 +4,6 @@ namespace Drupal\block_content;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityListBuilder;
use Drupal\Core\Routing\RedirectDestinationTrait;
/**
* Defines a class to build a listing of custom block entities.
@ -13,8 +12,6 @@ use Drupal\Core\Routing\RedirectDestinationTrait;
*/
class BlockContentListBuilder extends EntityListBuilder {
use RedirectDestinationTrait;
/**
* {@inheritdoc}
*/
@ -31,15 +28,4 @@ class BlockContentListBuilder extends EntityListBuilder {
return $row + parent::buildRow($entity);
}
/**
* {@inheritdoc}
*/
public function getDefaultOperations(EntityInterface $entity) {
$operations = parent::getDefaultOperations($entity);
if (isset($operations['edit'])) {
$operations['edit']['query']['destination'] = $this->getRedirectDestination()->get();
}
return $operations;
}
}

View File

@ -2,6 +2,7 @@
namespace Drupal\config\Tests;
use Drupal\Core\Routing\RedirectDestinationTrait;
use Drupal\simpletest\WebTestBase;
use Drupal\config_test\Entity\ConfigTest;
use Drupal\Core\Entity\EntityStorageInterface;
@ -13,6 +14,8 @@ use Drupal\Core\Entity\EntityStorageInterface;
*/
class ConfigEntityListTest extends WebTestBase {
use RedirectDestinationTrait;
/**
* Modules to enable.
*
@ -54,17 +57,17 @@ class ConfigEntityListTest extends WebTestBase {
'edit' => [
'title' => t('Edit'),
'weight' => 10,
'url' => $entity->urlInfo(),
'url' => $entity->toUrl()->setOption('query', $this->getRedirectDestination()->getAsArray()),
],
'disable' => [
'title' => t('Disable'),
'weight' => 40,
'url' => $entity->urlInfo('disable'),
'url' => $entity->toUrl('disable')->setOption('query', $this->getRedirectDestination()->getAsArray()),
],
'delete' => [
'title' => t('Delete'),
'weight' => 100,
'url' => $entity->urlInfo('delete-form'),
'url' => $entity->toUrl('delete-form')->setOption('query', $this->getRedirectDestination()->getAsArray()),
],
];
@ -129,12 +132,12 @@ class ConfigEntityListTest extends WebTestBase {
'edit' => [
'title' => t('Edit'),
'weight' => 10,
'url' => $entity->urlInfo(),
'url' => $entity->toUrl()->setOption('query', $this->getRedirectDestination()->getAsArray()),
],
'delete' => [
'title' => t('Delete'),
'weight' => 100,
'url' => $entity->urlInfo('delete-form'),
'url' => $entity->toUrl('delete-form')->setOption('query', $this->getRedirectDestination()->getAsArray()),
],
];

View File

@ -4,6 +4,7 @@ namespace Drupal\Tests\filter\Functional;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Url;
use Drupal\filter\Entity\FilterFormat;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
@ -135,16 +136,9 @@ class FilterAdminTest extends BrowserTestBase {
// Edit text format.
$this->drupalGet('admin/config/content/formats');
// Cannot use the assertNoLinkByHref method as it does partial url matching
// and 'admin/config/content/formats/manage/' . $format_id . '/disable'
// exists.
// @todo: See https://www.drupal.org/node/2031223 for the above.
$edit_link = $this->xpath('//a[@href=:href]', [
':href' => \Drupal::url('entity.filter_format.edit_form', ['filter_format' => $format_id])
]);
$this->assertNotEmpty($edit_link, format_string('Link href %href found.',
['%href' => 'admin/config/content/formats/manage/' . $format_id]
));
$destination = Url::fromRoute('filter.admin_overview')->toString();
$edit_href = Url::fromRoute('entity.filter_format.edit_form', ['filter_format' => $format_id], ['query' => ['destination' => $destination]])->toString();
$this->assertSession()->linkByHrefExists($edit_href);
$this->drupalGet('admin/config/content/formats/manage/' . $format_id);
$this->drupalPostForm(NULL, [], t('Save configuration'));

View File

@ -25,13 +25,6 @@ class NodeListBuilder extends EntityListBuilder {
*/
protected $dateFormatter;
/**
* The redirect destination service.
*
* @var \Drupal\Core\Routing\RedirectDestinationInterface
*/
protected $redirectDestination;
/**
* Constructs a new NodeListBuilder object.
*
@ -128,17 +121,4 @@ class NodeListBuilder extends EntityListBuilder {
return $row + parent::buildRow($entity);
}
/**
* {@inheritdoc}
*/
protected function getDefaultOperations(EntityInterface $entity) {
$operations = parent::getDefaultOperations($entity);
$destination = $this->redirectDestination->getAsArray();
foreach ($operations as $key => $operation) {
$operations[$key]['query'] = $destination;
}
return $operations;
}
}

View File

@ -43,14 +43,14 @@ class NodeActionsConfigurationTest extends BrowserTestBase {
$this->drupalPostForm('admin/config/system/actions/add/' . Crypt::hashBase64('node_assign_owner_action'), $edit, t('Save'));
$this->assertResponse(200);
$action_id = $edit['id'];
// Make sure that the new action was saved properly.
$this->assertText(t('The action has been successfully saved.'), 'The node_assign_owner_action action has been successfully saved.');
$this->assertText($action_label, 'The label of the node_assign_owner_action action appears on the actions administration page after saving.');
// Make another POST request to the action edit page.
$this->clickLink(t('Configure'));
preg_match('|admin/config/system/actions/configure/(.+)|', $this->getUrl(), $matches);
$aid = $matches[1];
$edit = [];
$new_action_label = $this->randomMachineName();
$edit['label'] = $new_action_label;
@ -68,7 +68,7 @@ class NodeActionsConfigurationTest extends BrowserTestBase {
$this->clickLink(t('Delete'));
$this->assertResponse(200);
$edit = [];
$this->drupalPostForm("admin/config/system/actions/configure/$aid/delete", $edit, t('Delete'));
$this->drupalPostForm(NULL, $edit, t('Delete'));
$this->assertResponse(200);
// Make sure that the action was actually deleted.
@ -77,7 +77,7 @@ class NodeActionsConfigurationTest extends BrowserTestBase {
$this->assertResponse(200);
$this->assertNoText($new_action_label, 'The label for the node_assign_owner_action action does not appear on the actions administration page after deleting.');
$action = Action::load($aid);
$action = Action::load($action_id);
$this->assertFalse($action, 'The node_assign_owner_action action is not available after being deleted.');
}

View File

@ -84,7 +84,7 @@ class EntityOperations extends FieldPluginBase {
$options = parent::defineOptions();
$options['destination'] = [
'default' => TRUE,
'default' => FALSE,
];
return $options;
@ -99,7 +99,7 @@ class EntityOperations extends FieldPluginBase {
$form['destination'] = [
'#type' => 'checkbox',
'#title' => $this->t('Include destination'),
'#description' => $this->t('Include a <code>destination</code> parameter in the link to return the user to the original view upon completing the link action.'),
'#description' => $this->t('Enforce a <code>destination</code> parameter in the link to return the user to the original view upon completing the link action. Most operations include a destination by default and this setting is no longer needed.'),
'#default_value' => $this->options['destination'],
];
}

View File

@ -73,7 +73,10 @@ class FieldEntityOperationsTest extends ViewTestBase {
$this->assertTrue(count($operations) > 0, 'There are operations.');
foreach ($operations as $operation) {
$expected_destination = Url::fromUri('internal:/test-entity-operations')->toString();
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[@href=:path and text()=:title]', [':path' => $operation['url']->toString() . '?destination=' . $expected_destination, ':title' => (string) $operation['title']]);
// Update destination property of the URL as generating it in the
// test would by default point to the frontpage.
$operation['url']->setOption('query', ['destination' => $expected_destination]);
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[@href=:path and text()=:title]', [':path' => $operation['url']->toString(), ':title' => (string) $operation['title']]);
$this->assertEqual(count($result), 1, t('Found entity @operation link with destination parameter.', ['@operation' => $operation['title']]));
// Entities which were created in Hungarian should link to the Hungarian
// edit form, others to the English one (which has no path prefix here).

View File

@ -11,6 +11,7 @@ use Drupal\Core\Access\AccessResult;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityListBuilder;
use Drupal\Core\Routing\RedirectDestinationInterface;
use Drupal\entity_test\EntityTestListBuilder;
use Drupal\Tests\UnitTestCase;
@ -62,6 +63,13 @@ class EntityListBuilderTest extends UnitTestCase {
*/
protected $role;
/**
* The redirect destination service.
*
* @var \Drupal\Core\Routing\RedirectDestinationInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $redirectDestination;
/**
* The EntityListBuilder object to test.
*
@ -80,7 +88,8 @@ class EntityListBuilderTest extends UnitTestCase {
$this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface');
$this->entityType = $this->getMock('\Drupal\Core\Entity\EntityTypeInterface');
$this->translationManager = $this->getMock('\Drupal\Core\StringTranslation\TranslationInterface');
$this->entityListBuilder = new TestEntityListBuilder($this->entityType, $this->roleStorage, $this->moduleHandler);
$this->entityListBuilder = new TestEntityListBuilder($this->entityType, $this->roleStorage);
$this->redirectDestination = $this->getMock(RedirectDestinationInterface::class);
$this->container = new ContainerBuilder();
\Drupal::setContainer($this->container);
}
@ -117,12 +126,20 @@ class EntityListBuilderTest extends UnitTestCase {
$url->expects($this->any())
->method('toArray')
->will($this->returnValue([]));
$url->expects($this->atLeastOnce())
->method('mergeOptions')
->with(['query' => ['destination' => '/foo/bar']]);
$this->role->expects($this->any())
->method('urlInfo')
->method('toUrl')
->will($this->returnValue($url));
$list = new EntityListBuilder($this->entityType, $this->roleStorage, $this->moduleHandler);
$this->redirectDestination->expects($this->atLeastOnce())
->method('getAsArray')
->willReturn(['destination' => '/foo/bar']);
$list = new EntityListBuilder($this->entityType, $this->roleStorage);
$list->setStringTranslation($this->translationManager);
$list->setRedirectDestination($this->redirectDestination);
$operations = $list->getOperations($this->role);
$this->assertInternalType('array', $operations);