Move into nested docroot

This commit is contained in:
Rob Davies 2017-02-13 15:31:17 +00:00
parent 83a0d3a149
commit c8b70abde9
13405 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,52 @@
<?php
namespace Drupal\shortcut\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\shortcut\ShortcutSetInterface;
use Drupal\shortcut\ShortcutInterface;
/**
* Provides route responses for taxonomy.module.
*/
class ShortcutController extends ControllerBase {
/**
* Returns a form to add a new shortcut to a given set.
*
* @param \Drupal\shortcut\ShortcutSetInterface $shortcut_set
* The shortcut set this shortcut will be added to.
*
* @return array
* The shortcut add form.
*/
public function addForm(ShortcutSetInterface $shortcut_set) {
$shortcut = $this->entityManager()->getStorage('shortcut')->create(array('shortcut_set' => $shortcut_set->id()));
return $this->entityFormBuilder()->getForm($shortcut, 'add');
}
/**
* Deletes the selected shortcut.
*
* @param \Drupal\shortcut\ShortcutInterface $shortcut
* The shortcut to delete.
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* A redirect to the previous location or the front page when destination
* is not set.
*/
public function deleteShortcutLinkInline(ShortcutInterface $shortcut) {
$label = $shortcut->label();
try {
$shortcut->delete();
drupal_set_message($this->t('The shortcut %title has been deleted.', array('%title' => $label)));
}
catch (\Exception $e) {
drupal_set_message($this->t('Unable to delete the shortcut for %title.', array('%title' => $label)), 'error');
}
return $this->redirect('<front>');
}
}

View file

@ -0,0 +1,80 @@
<?php
namespace Drupal\shortcut\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Path\PathValidatorInterface;
use Drupal\shortcut\ShortcutSetInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
/**
* Builds the page for administering shortcut sets.
*/
class ShortcutSetController extends ControllerBase {
/**
* The path validator.
*
* @var \Drupal\Core\Path\PathValidatorInterface
*/
protected $pathValidator;
/**
* Creates a new ShortcutSetController instance.
*
* @param \Drupal\Core\Path\PathValidatorInterface $path_validator
* The path validator.
*/
public function __construct(PathValidatorInterface $path_validator) {
$this->pathValidator = $path_validator;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('path.validator'));
}
/**
* Creates a new link in the provided shortcut set.
*
* @param \Drupal\shortcut\ShortcutSetInterface $shortcut_set
* The shortcut set to add a link to.
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* A redirect response to the front page, or the previous location.
*
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
*/
public function addShortcutLinkInline(ShortcutSetInterface $shortcut_set, Request $request) {
$link = $request->query->get('link');
$name = $request->query->get('name');
if (parse_url($link, PHP_URL_SCHEME) === NULL && $this->pathValidator->isValid($link)) {
$shortcut = $this->entityManager()->getStorage('shortcut')->create(array(
'title' => $name,
'shortcut_set' => $shortcut_set->id(),
'link' => array(
'uri' => 'internal:/' . $link,
),
));
try {
$shortcut->save();
drupal_set_message($this->t('Added a shortcut for %title.', array('%title' => $shortcut->label())));
}
catch (\Exception $e) {
drupal_set_message($this->t('Unable to add a shortcut for %title.', array('%title' => $shortcut->label())), 'error');
}
return $this->redirect('<front>');
}
throw new AccessDeniedHttpException();
}
}

View file

@ -0,0 +1,184 @@
<?php
namespace Drupal\shortcut\Entity;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\link\LinkItemInterface;
use Drupal\shortcut\ShortcutInterface;
/**
* Defines the shortcut entity class.
*
* @property \Drupal\link\LinkItemInterface link
*
* @ContentEntityType(
* id = "shortcut",
* label = @Translation("Shortcut link"),
* handlers = {
* "access" = "Drupal\shortcut\ShortcutAccessControlHandler",
* "form" = {
* "default" = "Drupal\shortcut\ShortcutForm",
* "add" = "Drupal\shortcut\ShortcutForm",
* "edit" = "Drupal\shortcut\ShortcutForm",
* "delete" = "Drupal\shortcut\Form\ShortcutDeleteForm"
* },
* "translation" = "Drupal\content_translation\ContentTranslationHandler"
* },
* base_table = "shortcut",
* data_table = "shortcut_field_data",
* translatable = TRUE,
* entity_keys = {
* "id" = "id",
* "uuid" = "uuid",
* "bundle" = "shortcut_set",
* "label" = "title",
* "langcode" = "langcode",
* },
* links = {
* "canonical" = "/admin/config/user-interface/shortcut/link/{shortcut}",
* "delete-form" = "/admin/config/user-interface/shortcut/link/{shortcut}/delete",
* "edit-form" = "/admin/config/user-interface/shortcut/link/{shortcut}",
* },
* list_cache_tags = { "config:shortcut_set_list" },
* bundle_entity_type = "shortcut_set"
* )
*/
class Shortcut extends ContentEntityBase implements ShortcutInterface {
/**
* {@inheritdoc}
*/
public function getTitle() {
return $this->get('title')->value;
}
/**
* {@inheritdoc}
*/
public function setTitle($link_title) {
$this->set('title', $link_title);
return $this;
}
/**
* {@inheritdoc}
*/
public function getWeight() {
return $this->get('weight')->value;
}
/**
* {@inheritdoc}
*/
public function setWeight($weight) {
$this->set('weight', $weight);
return $this;
}
/**
* {@inheritdoc}
*/
public function getUrl() {
return $this->link->first()->getUrl();
}
/**
* {@inheritdoc}
*/
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update);
// Entity::postSave() calls Entity::invalidateTagsOnSave(), which only
// handles the regular cases. The Shortcut entity has one special case: a
// newly created shortcut is *also* added to a shortcut set, so we must
// invalidate the associated shortcut set's cache tag.
if (!$update) {
Cache::invalidateTags($this->getCacheTagsToInvalidate());
}
}
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
/** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
$fields = parent::baseFieldDefinitions($entity_type);
$fields['id']->setDescription(t('The ID of the shortcut.'));
$fields['uuid']->setDescription(t('The UUID of the shortcut.'));
$fields['shortcut_set']->setLabel(t('Shortcut set'))
->setDescription(t('The bundle of the shortcut.'));
$fields['langcode']->setDescription(t('The language code of the shortcut.'));
$fields['title'] = BaseFieldDefinition::create('string')
->setLabel(t('Name'))
->setDescription(t('The name of the shortcut.'))
->setRequired(TRUE)
->setTranslatable(TRUE)
->setSetting('max_length', 255)
->setDisplayOptions('form', array(
'type' => 'string_textfield',
'weight' => -10,
'settings' => array(
'size' => 40,
),
));
$fields['weight'] = BaseFieldDefinition::create('integer')
->setLabel(t('Weight'))
->setDescription(t('Weight among shortcuts in the same shortcut set.'));
$fields['link'] = BaseFieldDefinition::create('link')
->setLabel(t('Path'))
->setDescription(t('The location this shortcut points to.'))
->setRequired(TRUE)
->setSettings(array(
'link_type' => LinkItemInterface::LINK_INTERNAL,
'title' => DRUPAL_DISABLED,
))
->setDisplayOptions('form', array(
'type' => 'link_default',
'weight' => 0,
))
->setDisplayConfigurable('form', TRUE);
return $fields;
}
/**
* {@inheritdoc}
*/
public function getCacheTagsToInvalidate() {
return $this->shortcut_set->entity->getCacheTags();
}
/**
* Sort shortcut objects.
*
* Callback for uasort().
*
* @param \Drupal\shortcut\ShortcutInterface $a
* First item for comparison.
* @param \Drupal\shortcut\ShortcutInterface $b
* Second item for comparison.
*
* @return int
* The comparison result for uasort().
*/
public static function sort(ShortcutInterface $a, ShortcutInterface $b) {
$a_weight = $a->getWeight();
$b_weight = $b->getWeight();
if ($a_weight == $b_weight) {
return strnatcasecmp($a->getTitle(), $b->getTitle());
}
return ($a_weight < $b_weight) ? -1 : 1;
}
}

View file

@ -0,0 +1,124 @@
<?php
namespace Drupal\shortcut\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\shortcut\ShortcutSetInterface;
/**
* Defines the Shortcut set configuration entity.
*
* @ConfigEntityType(
* id = "shortcut_set",
* label = @Translation("Shortcut set"),
* handlers = {
* "storage" = "Drupal\shortcut\ShortcutSetStorage",
* "access" = "Drupal\shortcut\ShortcutSetAccessControlHandler",
* "list_builder" = "Drupal\shortcut\ShortcutSetListBuilder",
* "form" = {
* "default" = "Drupal\shortcut\ShortcutSetForm",
* "add" = "Drupal\shortcut\ShortcutSetForm",
* "edit" = "Drupal\shortcut\ShortcutSetForm",
* "customize" = "Drupal\shortcut\Form\SetCustomize",
* "delete" = "Drupal\shortcut\Form\ShortcutSetDeleteForm"
* }
* },
* config_prefix = "set",
* bundle_of = "shortcut",
* entity_keys = {
* "id" = "id",
* "label" = "label"
* },
* links = {
* "customize-form" = "/admin/config/user-interface/shortcut/manage/{shortcut_set}/customize",
* "delete-form" = "/admin/config/user-interface/shortcut/manage/{shortcut_set}/delete",
* "edit-form" = "/admin/config/user-interface/shortcut/manage/{shortcut_set}",
* "collection" = "/admin/config/user-interface/shortcut",
* },
* config_export = {
* "id",
* "label",
* }
* )
*/
class ShortcutSet extends ConfigEntityBundleBase implements ShortcutSetInterface {
/**
* The machine name for the configuration entity.
*
* @var string
*/
protected $id;
/**
* The human-readable name of the configuration entity.
*
* @var string
*/
protected $label;
/**
* {@inheritdoc}
*/
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update);
if (!$update && !$this->isSyncing()) {
// Save a new shortcut set with links copied from the user's default set.
$default_set = shortcut_default_set();
// This is the default set, do not copy shortcuts.
if ($default_set->id() != $this->id()) {
foreach ($default_set->getShortcuts() as $shortcut) {
$shortcut = $shortcut->createDuplicate();
$shortcut->enforceIsNew();
$shortcut->shortcut_set->target_id = $this->id();
$shortcut->save();
}
}
}
}
/**
* {@inheritdoc}
*/
public static function preDelete(EntityStorageInterface $storage, array $entities) {
parent::preDelete($storage, $entities);
foreach ($entities as $entity) {
$storage->deleteAssignedShortcutSets($entity);
// Next, delete the shortcuts for this set.
$shortcut_ids = \Drupal::entityQuery('shortcut')
->condition('shortcut_set', $entity->id(), '=')
->execute();
$controller = \Drupal::entityManager()->getStorage('shortcut');
$entities = $controller->loadMultiple($shortcut_ids);
$controller->delete($entities);
}
}
/**
* {@inheritdoc}
*/
public function resetLinkWeights() {
$weight = -50;
foreach ($this->getShortcuts() as $shortcut) {
$shortcut->setWeight(++$weight);
$shortcut->save();
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getShortcuts() {
$shortcuts = \Drupal::entityManager()->getStorage('shortcut')->loadByProperties(array('shortcut_set' => $this->id()));
uasort($shortcuts, array('\Drupal\shortcut\Entity\Shortcut', 'sort'));
return $shortcuts;
}
}

View file

@ -0,0 +1,110 @@
<?php
namespace Drupal\shortcut\Form;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
/**
* Builds the shortcut set customize form.
*/
class SetCustomize extends EntityForm {
/**
* The entity being used by this form.
*
* @var \Drupal\shortcut\ShortcutSetInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$form['shortcuts'] = array(
'#tree' => TRUE,
'#weight' => -20,
);
$form['shortcuts']['links'] = array(
'#type' => 'table',
'#header' => array(t('Name'), t('Weight'), t('Operations')),
'#empty' => $this->t('No shortcuts available. <a href=":link">Add a shortcut</a>', array(':link' => $this->url('shortcut.link_add', array('shortcut_set' => $this->entity->id())))),
'#attributes' => array('id' => 'shortcuts'),
'#tabledrag' => array(
array(
'action' => 'order',
'relationship' => 'sibling',
'group' => 'shortcut-weight',
),
),
);
foreach ($this->entity->getShortcuts() as $shortcut) {
$id = $shortcut->id();
$url = $shortcut->getUrl();
if (!$url->access()) {
continue;
}
$form['shortcuts']['links'][$id]['#attributes']['class'][] = 'draggable';
$form['shortcuts']['links'][$id]['name'] = array(
'#type' => 'link',
'#title' => $shortcut->getTitle(),
) + $url->toRenderArray();
unset($form['shortcuts']['links'][$id]['name']['#access_callback']);
$form['shortcuts']['links'][$id]['#weight'] = $shortcut->getWeight();
$form['shortcuts']['links'][$id]['weight'] = array(
'#type' => 'weight',
'#title' => t('Weight for @title', array('@title' => $shortcut->getTitle())),
'#title_display' => 'invisible',
'#default_value' => $shortcut->getWeight(),
'#attributes' => array('class' => array('shortcut-weight')),
);
$links['edit'] = array(
'title' => t('Edit'),
'url' => $shortcut->urlInfo(),
);
$links['delete'] = array(
'title' => t('Delete'),
'url' => $shortcut->urlInfo('delete-form'),
);
$form['shortcuts']['links'][$id]['operations'] = array(
'#type' => 'operations',
'#links' => $links,
'#access' => $url->access(),
);
}
return $form;
}
/**
* {@inheritdoc}
*/
protected function actions(array $form, FormStateInterface $form_state) {
// Only includes a Save action for the entity, no direct Delete button.
return array(
'submit' => array(
'#type' => 'submit',
'#value' => t('Save'),
'#access' => (bool) Element::getVisibleChildren($form['shortcuts']['links']),
'#submit' => array('::submitForm', '::save'),
),
);
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
foreach ($this->entity->getShortcuts() as $shortcut) {
$weight = $form_state->getValue(array('shortcuts', 'links', $shortcut->id(), 'weight'));
$shortcut->setWeight($weight);
$shortcut->save();
}
drupal_set_message(t('The shortcut set has been updated.'));
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\shortcut\Form;
use Drupal\Core\Entity\ContentEntityDeleteForm;
use Drupal\Core\Url;
/**
* Builds the shortcut link deletion form.
*/
class ShortcutDeleteForm extends ContentEntityDeleteForm {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'shortcut_confirm_delete';
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('entity.shortcut_set.customize_form', array(
'shortcut_set' => $this->entity->bundle(),
));
}
/**
* {@inheritdoc}
*/
protected function getRedirectUrl() {
return $this->getCancelUrl();
}
}

View file

@ -0,0 +1,75 @@
<?php
namespace Drupal\shortcut\Form;
use Drupal\Core\Entity\EntityDeleteForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\shortcut\ShortcutSetStorageInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Database\Connection;
/**
* Builds the shortcut set deletion form.
*/
class ShortcutSetDeleteForm extends EntityDeleteForm {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* The shortcut storage.
*
* @var \Drupal\shortcut\ShortcutSetStorageInterface
*/
protected $storage;
/**
* Constructs a ShortcutSetDeleteForm object.
*/
public function __construct(Connection $database, ShortcutSetStorageInterface $storage) {
$this->database = $database;
$this->storage = $storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database'),
$container->get('entity.manager')->getStorage('shortcut_set')
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// Find out how many users are directly assigned to this shortcut set, and
// make a message.
$number = $this->storage->countAssignedUsers($this->entity);
$info = '';
if ($number) {
$info .= '<p>' . $this->formatPlural($number,
'1 user has chosen or been assigned to this shortcut set.',
'@count users have chosen or been assigned to this shortcut set.') . '</p>';
}
// Also, if a module implements hook_shortcut_default_set(), it's possible
// that this set is being used as a default set. Add a message about that too.
if ($this->moduleHandler->getImplementations('shortcut_default_set')) {
$info .= '<p>' . t('If you have chosen this shortcut set as the default for some or all users, they may also be affected by deleting it.') . '</p>';
}
$form['info'] = array(
'#markup' => $info,
);
return parent::buildForm($form, $form_state);
}
}

View file

@ -0,0 +1,227 @@
<?php
namespace Drupal\shortcut\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\shortcut\Entity\ShortcutSet;
use Drupal\shortcut\ShortcutSetStorageInterface;
use Drupal\user\UserInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Builds the shortcut set switch form.
*/
class SwitchShortcutSet extends FormBase {
/**
* The account the shortcut set is for.
*
* @var \Drupal\user\UserInterface
*/
protected $user;
/**
* The shortcut set storage.
*
* @var \Drupal\shortcut\ShortcutSetStorageInterface
*/
protected $shortcutSetStorage;
/**
* Constructs a SwitchShortcutSet object.
*
* @param \Drupal\shortcut\ShortcutSetStorageInterface $shortcut_set_storage
* The shortcut set storage.
*/
public function __construct(ShortcutSetStorageInterface $shortcut_set_storage) {
$this->shortcutSetStorage = $shortcut_set_storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager')->getStorage('shortcut_set')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'shortcut_set_switch';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, UserInterface $user = NULL) {
$account = $this->currentUser();
$this->user = $user;
// Prepare the list of shortcut sets.
$options = array_map(function (ShortcutSet $set) {
return $set->label();
}, $this->shortcutSetStorage->loadMultiple());
$current_set = shortcut_current_displayed_set($this->user);
// Only administrators can add shortcut sets.
$add_access = $account->hasPermission('administer shortcuts');
if ($add_access) {
$options['new'] = $this->t('New set');
}
$account_is_user = $this->user->id() == $account->id();
if (count($options) > 1) {
$form['set'] = array(
'#type' => 'radios',
'#title' => $account_is_user ? $this->t('Choose a set of shortcuts to use') : $this->t('Choose a set of shortcuts for this user'),
'#options' => $options,
'#default_value' => $current_set->id(),
);
$form['label'] = array(
'#type' => 'textfield',
'#title' => $this->t('Label'),
'#description' => $this->t('The new set is created by copying items from your default shortcut set.'),
'#access' => $add_access,
'#states' => array(
'visible' => array(
':input[name="set"]' => array('value' => 'new'),
),
'required' => array(
':input[name="set"]' => array('value' => 'new'),
),
),
);
$form['id'] = array(
'#type' => 'machine_name',
'#machine_name' => array(
'exists' => array($this, 'exists'),
'replace_pattern' => '[^a-z0-9-]+',
'replace' => '-',
),
// This ID could be used for menu name.
'#maxlength' => 23,
'#states' => array(
'required' => array(
':input[name="set"]' => array('value' => 'new'),
),
),
'#required' => FALSE,
);
if (!$account_is_user) {
$default_set = $this->shortcutSetStorage->getDefaultSet($this->user);
$form['new']['#description'] = $this->t('The new set is created by copying items from the %default set.', array('%default' => $default_set->label()));
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Change set'),
);
}
else {
// There is only 1 option, so output a message in the $form array.
$form['info'] = array(
'#markup' => '<p>' . $this->t('You are currently using the %set-name shortcut set.', array('%set-name' => $current_set->label())) . '</p>',
);
}
return $form;
}
/**
* Determines if a shortcut set exists already.
*
* @param string $id
* The set ID to check.
*
* @return bool
* TRUE if the shortcut set exists, FALSE otherwise.
*/
public function exists($id) {
return (bool) $this->shortcutSetStorage->getQuery()
->condition('id', $id)
->execute();
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
if ($form_state->getValue('set') == 'new') {
// Check to prevent creating a shortcut set with an empty title.
if (trim($form_state->getValue('label')) == '') {
$form_state->setErrorByName('label', $this->t('The new set label is required.'));
}
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$account = $this->currentUser();
$account_is_user = $this->user->id() == $account->id();
if ($form_state->getValue('set') == 'new') {
// Save a new shortcut set with links copied from the user's default set.
/* @var \Drupal\shortcut\Entity\ShortcutSet $set */
$set = $this->shortcutSetStorage->create(array(
'id' => $form_state->getValue('id'),
'label' => $form_state->getValue('label'),
));
$set->save();
$replacements = array(
'%user' => $this->user->label(),
'%set_name' => $set->label(),
':switch-url' => $this->url('<current>'),
);
if ($account_is_user) {
// Only administrators can create new shortcut sets, so we know they have
// access to switch back.
drupal_set_message($this->t('You are now using the new %set_name shortcut set. You can edit it from this page or <a href=":switch-url">switch back to a different one.</a>', $replacements));
}
else {
drupal_set_message($this->t('%user is now using a new shortcut set called %set_name. You can edit it from this page.', $replacements));
}
$form_state->setRedirect(
'entity.shortcut_set.customize_form',
array('shortcut_set' => $set->id())
);
}
else {
// Switch to a different shortcut set.
/* @var \Drupal\shortcut\Entity\ShortcutSet $set */
$set = $this->shortcutSetStorage->load($form_state->getValue('set'));
$replacements = array(
'%user' => $this->user->getDisplayName(),
'%set_name' => $set->label(),
);
drupal_set_message($account_is_user ? $this->t('You are now using the %set_name shortcut set.', $replacements) : $this->t('%user is now using the %set_name shortcut set.', $replacements));
}
// Assign the shortcut set to the provided user account.
$this->shortcutSetStorage->assignUser($set, $this->user);
}
/**
* Checks access for the shortcut set switch form.
*
* @param \Drupal\user\UserInterface $user
* (optional) The owner of the shortcut set.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function checkAccess(UserInterface $user = NULL) {
return shortcut_set_switch_access($user);
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\shortcut\Plugin\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Session\AccountInterface;
/**
* Provides a 'Shortcut' block.
*
* @Block(
* id = "shortcuts",
* admin_label = @Translation("Shortcuts"),
* category = @Translation("Menus")
* )
*/
class ShortcutsBlock extends BlockBase {
/**
* {@inheritdoc}
*/
public function build() {
return array(
shortcut_renderable_links(shortcut_current_displayed_set()),
);
}
/**
* {@inheritdoc}
*/
protected function blockAccess(AccountInterface $account) {
return AccessResult::allowedIfHasPermission($account, 'access shortcuts');
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Drupal\shortcut\Plugin\migrate\destination;
use Drupal\migrate\Row;
use Drupal\migrate\Plugin\migrate\destination\EntityConfigBase;
/**
* @MigrateDestination(
* id = "entity:shortcut_set"
* )
*/
class EntityShortcutSet extends EntityConfigBase {
/**
* {@inheritdoc}
*/
protected function getEntity(Row $row, array $old_destination_id_values) {
$entity = parent::getEntity($row, $old_destination_id_values);
// Set the "syncing" flag to TRUE, to avoid duplication of default
// shortcut links
$entity->setSyncing(TRUE);
return $entity;
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace Drupal\shortcut\Plugin\migrate\destination;
use Drupal\shortcut\ShortcutSetStorageInterface;
use Drupal\user\Entity\User;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\migrate\Plugin\migrate\destination\DestinationBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
/**
* @MigrateDestination(
* id = "shortcut_set_users"
* )
*/
class ShortcutSetUsers extends DestinationBase implements ContainerFactoryPluginInterface {
/**
* The shortcut set storage handler.
*
* @var \Drupal\shortcut\ShortcutSetStorageInterface
*/
protected $shortcutSetStorage;
/**
* Constructs an entity destination plugin.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration.
* @param \Drupal\shortcut\ShortcutSetStorageInterface $shortcut_set_storage
* The shortcut_set entity storage handler.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, ShortcutSetStorageInterface $shortcut_set_storage) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
$this->shortcutSetStorage = $shortcut_set_storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$migration,
$container->get('entity.manager')->getStorage('shortcut_set')
);
}
/**
* {@inheritdoc}
*/
public function getIds() {
return array(
'set_name' => array(
'type' => 'string',
),
'uid' => array(
'type' => 'integer',
),
);
}
/**
* {@inheritdoc}
*/
public function fields(MigrationInterface $migration = NULL) {
return [
'uid' => 'The users.uid for this set.',
'source' => 'The shortcut_set.set_name that will be displayed for this user.',
];
}
/**
* {@inheritdoc}
*/
public function import(Row $row, array $old_destination_id_values = array()) {
/** @var \Drupal\shortcut\ShortcutSetInterface $set */
$set = $this->shortcutSetStorage->load($row->getDestinationProperty('set_name'));
/** @var \Drupal\user\UserInterface $account */
$account = User::load($row->getDestinationProperty('uid'));
$this->shortcutSetStorage->assignUser($set, $account);
return array($set->id(), $account->id());
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace Drupal\shortcut\Plugin\migrate\source\d7;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal 7 shortcut links source from database.
*
* @MigrateSource(
* id = "d7_shortcut",
* source_provider = "shortcut"
* )
*/
class Shortcut extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
return $this->select('menu_links', 'ml')
->fields('ml', array('mlid', 'menu_name', 'link_path', 'link_title', 'weight'))
->condition('hidden', '0')
->condition('menu_name', 'shortcut-set-%', 'LIKE')
->orderBy('ml.mlid');
}
/**
* {@inheritdoc}
*/
public function fields() {
return array(
'mlid' => $this->t("The menu.mlid primary key for this menu item (= shortcut link)."),
'menu_name' => $this->t("The menu_name (= set name) for this shortcut link."),
'link_path' => $this->t("The link for this shortcut."),
'link_title' => $this->t("The title for this shortcut."),
'weight' => $this->t("The weight for this shortcut"),
);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['mlid']['type'] = 'integer';
return $ids;
}
}

View file

@ -0,0 +1,42 @@
<?php
namespace Drupal\shortcut\Plugin\migrate\source\d7;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal 7 shortcut_set source from database.
*
* @MigrateSource(
* id = "d7_shortcut_set",
* source_provider = "shortcut"
* )
*/
class ShortcutSet extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
return $this->select('shortcut_set', 'ss')->fields('ss');
}
/**
* {@inheritdoc}
*/
public function fields() {
return array(
'set_name' => $this->t("The name under which the set's links are stored."),
'title' => $this->t("The title of the set."),
);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['set_name']['type'] = 'string';
return $ids;
}
}

View file

@ -0,0 +1,48 @@
<?php
namespace Drupal\shortcut\Plugin\migrate\source\d7;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal 7 shortcut_set_users source from database.
*
* @MigrateSource(
* id = "d7_shortcut_set_users",
* source_provider = "shortcut"
* )
*/
class ShortcutSetUsers extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
return $this->select('shortcut_set_users', 'ssu')->fields('ssu');
}
/**
* {@inheritdoc}
*/
public function fields() {
return array(
'uid' => $this->t('The users.uid for this set.'),
'set_name' => $this->t('The shortcut_set.set_name that will be displayed for this user.'),
);
}
/**
* {@inheritdoc}
*/
public function getIds() {
return array(
'set_name' => array(
'type' => 'string',
),
'uid' => array(
'type' => 'integer',
),
);
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace Drupal\shortcut;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityHandlerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines the access control handler for the shortcut entity type.
*
* @see \Drupal\shortcut\Entity\Shortcut
*/
class ShortcutAccessControlHandler extends EntityAccessControlHandler implements EntityHandlerInterface {
/**
* The shortcut_set storage.
*
* @var \Drupal\shortcut\ShortcutSetStorageInterface
*/
protected $shortcutSetStorage;
/**
* Constructs a ShortcutAccessControlHandler object.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type definition.
* @param \Drupal\shortcut\ShortcutSetStorageInterface $shortcut_set_storage
* The shortcut_set storage.
*/
public function __construct(EntityTypeInterface $entity_type, ShortcutSetStorageInterface $shortcut_set_storage) {
parent::__construct($entity_type);
$this->shortcutSetStorage = $shortcut_set_storage;
}
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static(
$entity_type,
$container->get('entity.manager')->getStorage('shortcut_set')
);
}
/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
if ($shortcut_set = $this->shortcutSetStorage->load($entity->bundle())) {
return shortcut_set_edit_access($shortcut_set, $account);
}
// @todo Fix this bizarre code: how can a shortcut exist without a shortcut
// set? The above if-test is unnecessary. See https://www.drupal.org/node/2339903.
return AccessResult::neutral()->addCacheableDependency($entity);
}
/**
* {@inheritdoc}
*/
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
if ($shortcut_set = $this->shortcutSetStorage->load($entity_bundle)) {
return shortcut_set_edit_access($shortcut_set, $account);
}
// @todo Fix this bizarre code: how can a shortcut exist without a shortcut
// set? The above if-test is unnecessary. See https://www.drupal.org/node/2339903.
return AccessResult::neutral();
}
}

View file

@ -0,0 +1,51 @@
<?php
namespace Drupal\shortcut;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Form\FormStateInterface;
/**
* Form handler for the shortcut entity forms.
*/
class ShortcutForm extends ContentEntityForm {
/**
* The entity being used by this form.
*
* @var \Drupal\shortcut\ShortcutInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$entity = $this->entity;
$status = $entity->save();
$url = $entity->getUrl();
// There's an edge case where a user can have permission to
// 'link to any content', but has no right to access the linked page. So we
// check the access before showing the link.
if ($url->access()) {
$view_link = \Drupal::l($entity->getTitle(), $url);
}
else {
$view_link = $entity->getTitle();
}
if ($status == SAVED_UPDATED) {
$message = $this->t('The shortcut %link has been updated.', array('%link' => $view_link));
}
else {
$message = $this->t('Added a shortcut for %title.', array('%title' => $view_link));
}
drupal_set_message($message);
$form_state->setRedirect(
'entity.shortcut_set.customize_form',
array('shortcut_set' => $entity->bundle())
);
}
}

View file

@ -0,0 +1,58 @@
<?php
namespace Drupal\shortcut;
use Drupal\Core\Entity\ContentEntityInterface;
/**
* Provides an interface defining a shortcut entity.
*/
interface ShortcutInterface extends ContentEntityInterface {
/**
* Returns the title of this shortcut.
*
* @return string
* The title of this shortcut.
*/
public function getTitle();
/**
* Sets the title of this shortcut.
*
* @param string $title
* The title of this shortcut.
*
* @return \Drupal\shortcut\ShortcutInterface
* The called shortcut entity.
*/
public function setTitle($title);
/**
* Returns the weight among shortcuts with the same depth.
*
* @return int
* The shortcut weight.
*/
public function getWeight();
/**
* Sets the weight among shortcuts with the same depth.
*
* @param int $weight
* The shortcut weight.
*
* @return \Drupal\shortcut\ShortcutInterface
* The called shortcut entity.
*/
public function setWeight($weight);
/**
* Returns the URL object pointing to the configured route.
*
* @return \Drupal\Core\Url
* The URL object.
*/
public function getUrl();
}

View file

@ -0,0 +1,47 @@
<?php
namespace Drupal\shortcut;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Session\AccountInterface;
/**
* Defines the access control handler for the shortcut set entity type.
*
* @see \Drupal\shortcut\Entity\ShortcutSet
*/
class ShortcutSetAccessControlHandler extends EntityAccessControlHandler {
/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
switch ($operation) {
case 'update':
if ($account->hasPermission('administer shortcuts')) {
return AccessResult::allowed()->cachePerPermissions();
}
if (!$account->hasPermission('access shortcuts')) {
return AccessResult::neutral()->cachePerPermissions();
}
return AccessResult::allowedIf($account->hasPermission('customize shortcut links') && $entity == shortcut_current_displayed_set($account))->cachePerPermissions()->addCacheableDependency($entity);
case 'delete':
return AccessResult::allowedIf($account->hasPermission('administer shortcuts') && $entity->id() != 'default')->cachePerPermissions();
default:
// No opinion.
return AccessResult::neutral();
}
}
/**
* {@inheritdoc}
*/
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
return AccessResult::allowedIfHasPermission($account, 'administer shortcuts')->orIf(AccessResult::allowedIfHasPermissions($account, ['access shortcuts', 'customize shortcut links'], 'AND'));
}
}

View file

@ -0,0 +1,62 @@
<?php
namespace Drupal\shortcut;
use Drupal\Core\Entity\BundleEntityFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Form handler for the shortcut set entity edit forms.
*/
class ShortcutSetForm extends BundleEntityFormBase {
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$entity = $this->entity;
$form['label'] = array(
'#type' => 'textfield',
'#title' => t('Set name'),
'#description' => t('The new set is created by copying items from your default shortcut set.'),
'#required' => TRUE,
'#default_value' => $entity->label(),
);
$form['id'] = array(
'#type' => 'machine_name',
'#machine_name' => array(
'exists' => '\Drupal\shortcut\Entity\ShortcutSet::load',
'source' => array('label'),
'replace_pattern' => '[^a-z0-9-]+',
'replace' => '-',
),
'#default_value' => $entity->id(),
// This id could be used for menu name.
'#maxlength' => 23,
);
$form['actions']['submit']['#value'] = t('Create new set');
return $this->protectBundleIdElement($form);
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$entity = $this->entity;
$is_new = !$entity->getOriginalId();
$entity->save();
if ($is_new) {
drupal_set_message(t('The %set_name shortcut set has been created. You can edit it from this page.', array('%set_name' => $entity->label())));
}
else {
drupal_set_message(t('Updated set name to %set-name.', array('%set-name' => $entity->label())));
}
$form_state->setRedirectUrl($this->entity->urlInfo('customize-form'));
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Drupal\shortcut;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
/**
* Provides an interface defining a shortcut set entity.
*/
interface ShortcutSetInterface extends ConfigEntityInterface {
/**
* Resets the link weights in a shortcut set to match their current order.
*
* This function can be used, for example, when a new shortcut link is added
* to the set. If the link is added to the end of the array and this function
* is called, it will force that link to display at the end of the list.
*
* @return \Drupal\shortcut\ShortcutSetInterface
* The shortcut set.
*/
public function resetLinkWeights();
/**
* Returns all the shortcuts from a shortcut set sorted correctly.
*
* @return \Drupal\shortcut\ShortcutInterface[]
* An array of shortcut entities.
*/
public function getShortcuts();
}

View file

@ -0,0 +1,48 @@
<?php
namespace Drupal\shortcut;
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
/**
* Defines a class to build a listing of shortcut set entities.
*
* @see \Drupal\shortcut\Entity\ShortcutSet
*/
class ShortcutSetListBuilder extends ConfigEntityListBuilder {
/**
* {@inheritdoc}
*/
public function buildHeader() {
$header['name'] = t('Name');
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*/
public function getDefaultOperations(EntityInterface $entity) {
$operations = parent::getDefaultOperations($entity);
if (isset($operations['edit'])) {
$operations['edit']['title'] = t('Edit shortcut set');
}
$operations['list'] = array(
'title' => t('List links'),
'url' => $entity->urlInfo('customize-form'),
);
return $operations;
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity) {
$row['name'] = $entity->label();
return $row + parent::buildRow($entity);
}
}

View file

@ -0,0 +1,128 @@
<?php
namespace Drupal\shortcut;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a storage for shortcut_set entities.
*/
class ShortcutSetStorage extends ConfigEntityStorage implements ShortcutSetStorageInterface {
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Constructs a ShortcutSetStorageController object.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_info
* The entity info for the entity type.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
* The UUID service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
public function __construct(EntityTypeInterface $entity_info, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager) {
parent::__construct($entity_info, $config_factory, $uuid_service, $language_manager);
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_info) {
return new static(
$entity_info,
$container->get('config.factory'),
$container->get('uuid'),
$container->get('module_handler'),
$container->get('language_manager')
);
}
/**
* {@inheritdoc}
*/
public function deleteAssignedShortcutSets(ShortcutSetInterface $entity) {
// First, delete any user assignments for this set, so that each of these
// users will go back to using whatever default set applies.
db_delete('shortcut_set_users')
->condition('set_name', $entity->id())
->execute();
}
/**
* {@inheritdoc}
*/
public function assignUser(ShortcutSetInterface $shortcut_set, $account) {
db_merge('shortcut_set_users')
->key('uid', $account->id())
->fields(array('set_name' => $shortcut_set->id()))
->execute();
drupal_static_reset('shortcut_current_displayed_set');
}
/**
* {@inheritdoc}
*/
public function unassignUser($account) {
$deleted = db_delete('shortcut_set_users')
->condition('uid', $account->id())
->execute();
return (bool) $deleted;
}
/**
* {@inheritdoc}
*/
public function getAssignedToUser($account) {
$query = db_select('shortcut_set_users', 'ssu');
$query->fields('ssu', array('set_name'));
$query->condition('ssu.uid', $account->id());
return $query->execute()->fetchField();
}
/**
* {@inheritdoc}
*/
public function countAssignedUsers(ShortcutSetInterface $shortcut_set) {
return db_query('SELECT COUNT(*) FROM {shortcut_set_users} WHERE set_name = :name', array(':name' => $shortcut_set->id()))->fetchField();
}
/**
* {@inheritdoc}
*/
public function getDefaultSet(AccountInterface $account) {
// Allow modules to return a default shortcut set name. Since we can only
// have one, we allow the last module which returns a valid result to take
// precedence. If no module returns a valid set, fall back on the site-wide
// default, which is the lowest-numbered shortcut set.
$suggestions = array_reverse($this->moduleHandler->invokeAll('shortcut_default_set', array($account)));
$suggestions[] = 'default';
$shortcut_set = NULL;
foreach ($suggestions as $name) {
if ($shortcut_set = $this->load($name)) {
break;
}
}
return $shortcut_set;
}
}

View file

@ -0,0 +1,79 @@
<?php
namespace Drupal\shortcut;
use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
use Drupal\Core\Session\AccountInterface;
/**
* Defines an interface for shortcut_set entity storage classes.
*/
interface ShortcutSetStorageInterface extends ConfigEntityStorageInterface {
/**
* Assigns a user to a particular shortcut set.
*
* @param \Drupal\shortcut\ShortcutSetInterface $shortcut_set
* An object representing the shortcut set.
* @param $account
* A user account that will be assigned to use the set.
*/
public function assignUser(ShortcutSetInterface $shortcut_set, $account);
/**
* Unassigns a user from any shortcut set they may have been assigned to.
*
* The user will go back to using whatever default set applies.
*
* @param $account
* A user account that will be removed from the shortcut set assignment.
*
* @return bool
* TRUE if the user was previously assigned to a shortcut set and has been
* successfully removed from it. FALSE if the user was already not assigned
* to any set.
*/
public function unassignUser($account);
/**
* Delete shortcut sets assigned to users.
*
* @param \Drupal\shortcut\ShortcutSetInterface $entity
* Delete the user assigned sets belonging to this shortcut.
*/
public function deleteAssignedShortcutSets(ShortcutSetInterface $entity);
/**
* Get the name of the set assigned to this user.
*
* @param \Drupal\user\Entity\User $account
* The user account.
*
* @return string
* The name of the shortcut set assigned to this user.
*/
public function getAssignedToUser($account);
/**
* Get the number of users who have this set assigned to them.
*
* @param \Drupal\shortcut\ShortcutSetInterface $shortcut_set
* The shortcut to count the users assigned to.
*
* @return int
* The number of users who have this set assigned to them.
*/
public function countAssignedUsers(ShortcutSetInterface $shortcut_set);
/**
* Gets the default shortcut set for a given user account.
*
* @param \Drupal\Core\Session\AccountInterface $account
* The user account whose default shortcut set will be returned.
*
* @return \Drupal\shortcut\ShortcutSetInterface
* An object representing the default shortcut set.
*/
public function getDefaultSet(AccountInterface $account);
}

View file

@ -0,0 +1,71 @@
<?php
namespace Drupal\shortcut\Tests;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\shortcut\Entity\Shortcut;
use Drupal\system\Tests\Entity\EntityCacheTagsTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
/**
* Tests the Shortcut entity's cache tags.
*
* @group shortcut
*/
class ShortcutCacheTagsTest extends EntityCacheTagsTestBase {
/**
* {@inheritdoc}
*/
public static $modules = array('shortcut');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Give anonymous users permission to customize shortcut links, so that we
// can verify the cache tags of cached versions of shortcuts.
$user_role = Role::load(RoleInterface::ANONYMOUS_ID);
$user_role->grantPermission('customize shortcut links');
$user_role->grantPermission('access shortcuts');
$user_role->save();
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
// Create a "Llama" shortcut.
$shortcut = Shortcut::create(array(
'shortcut_set' => 'default',
'title' => t('Llama'),
'weight' => 0,
'link' => [['uri' => 'internal:/admin']],
));
$shortcut->save();
return $shortcut;
}
/**
* Tests that when creating a shortcut, the shortcut set tag is invalidated.
*/
public function testEntityCreation() {
// Create a cache entry that is tagged with a shortcut set cache tag.
$cache_tags = ['config:shortcut.set.default'];
\Drupal::cache('render')->set('foo', 'bar', CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
// Verify a cache hit.
$this->verifyRenderCache('foo', $cache_tags);
// Now create a shortcut entity in that shortcut set.
$this->createEntity();
// Verify a cache miss.
$this->assertFalse(\Drupal::cache('render')->get('foo'), 'Creating a new shortcut invalidates the cache tag of the shortcut set.');
}
}

View file

@ -0,0 +1,462 @@
<?php
namespace Drupal\shortcut\Tests;
use Drupal\block_content\Entity\BlockContentType;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Url;
use Drupal\shortcut\Entity\Shortcut;
use Drupal\shortcut\Entity\ShortcutSet;
use Drupal\views\Entity\View;
/**
* Create, view, edit, delete, and change shortcut links.
*
* @group shortcut
*/
class ShortcutLinksTest extends ShortcutTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('router_test', 'views', 'block');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('page_title_block');
}
/**
* Tests that creating a shortcut works properly.
*/
public function testShortcutLinkAdd() {
$set = $this->set;
// Create an alias for the node so we can test aliases.
$path = array(
'source' => '/node/' . $this->node->id(),
'alias' => '/' . $this->randomMachineName(8),
);
$this->container->get('path.alias_storage')->save($path['source'], $path['alias']);
// Create some paths to test.
$test_cases = [
'/',
'/admin',
'/admin/config/system/site-information',
'/node/' . $this->node->id() . '/edit',
$path['alias'],
'/router_test/test2',
'/router_test/test3/value',
];
$test_cases_non_access = [
'/admin',
'/admin/config/system/site-information',
];
// Check that each new shortcut links where it should.
foreach ($test_cases as $test_path) {
$title = $this->randomMachineName();
$form_data = array(
'title[0][value]' => $title,
'link[0][uri]' => $test_path,
);
$this->drupalPostForm('admin/config/user-interface/shortcut/manage/' . $set->id() . '/add-link', $form_data, t('Save'));
$this->assertResponse(200);
$this->assertText(t('Added a shortcut for @title.', array('@title' => $title)));
$saved_set = ShortcutSet::load($set->id());
$paths = $this->getShortcutInformation($saved_set, 'link');
$this->assertTrue(in_array('internal:' . $test_path, $paths), 'Shortcut created: ' . $test_path);
if (in_array($test_path, $test_cases_non_access)) {
$this->assertNoLink($title, SafeMarkup::format('Shortcut link %url not accessible on the page.', ['%url' => $test_path]));
}
else {
$this->assertLink($title, 0, SafeMarkup::format('Shortcut link %url found on the page.', ['%url' => $test_path]));
}
}
$saved_set = ShortcutSet::load($set->id());
// Test that saving and re-loading a shortcut preserves its values.
$shortcuts = $saved_set->getShortcuts();
foreach ($shortcuts as $entity) {
// Test the node routes with parameters.
$entity->save();
$loaded = Shortcut::load($entity->id());
$this->assertEqual($entity->link->uri, $loaded->link->uri);
$this->assertEqual($entity->link->options, $loaded->link->options);
}
// Log in as non admin user, to check that access is checked when creating
// shortcuts.
$this->drupalLogin($this->shortcutUser);
$title = $this->randomMachineName();
$form_data = [
'title[0][value]' => $title,
'link[0][uri]' => '/admin',
];
$this->drupalPostForm('admin/config/user-interface/shortcut/manage/' . $set->id() . '/add-link', $form_data, t('Save'));
$this->assertResponse(200);
$this->assertRaw(t("The path '@link_path' is inaccessible.", ['@link_path' => '/admin']));
$form_data = [
'title[0][value]' => $title,
'link[0][uri]' => '/node',
];
$this->drupalPostForm('admin/config/user-interface/shortcut/manage/' . $set->id() . '/add-link', $form_data, t('Save'));
$this->assertLink($title, 0, 'Shortcut link found on the page.');
// Create a new shortcut set and add a link to it.
$this->drupalLogin($this->adminUser);
$edit = array(
'label' => $this->randomMachineName(),
'id' => strtolower($this->randomMachineName()),
);
$this->drupalPostForm('admin/config/user-interface/shortcut/add-set', $edit, t('Save'));
$title = $this->randomMachineName();
$form_data = [
'title[0][value]' => $title,
'link[0][uri]' => '/admin',
];
$this->drupalPostForm('admin/config/user-interface/shortcut/manage/' . $edit['id'] . '/add-link', $form_data, t('Save'));
$this->assertResponse(200);
}
/**
* Tests that the "add to shortcut" and "remove from shortcut" links work.
*/
public function testShortcutQuickLink() {
\Drupal::service('theme_handler')->install(array('seven'));
$this->config('system.theme')->set('admin', 'seven')->save();
$this->config('node.settings')->set('use_admin_theme', '1')->save();
$this->container->get('router.builder')->rebuild();
$this->drupalLogin($this->rootUser);
$this->drupalGet('admin/config/system/cron');
// Test the "Add to shortcuts" link.
$this->clickLink('Add to Default shortcuts');
$this->assertText('Added a shortcut for Cron.');
$this->assertLink('Cron', 0, 'Shortcut link found on page');
$this->drupalGet('admin/structure');
$this->assertLink('Cron', 0, 'Shortcut link found on different page');
// Test the "Remove from shortcuts" link.
$this->clickLink('Cron');
$this->clickLink('Remove from Default shortcuts');
$this->assertText('The shortcut Cron has been deleted.');
$this->assertNoLink('Cron', 'Shortcut link removed from page');
$this->drupalGet('admin/structure');
$this->assertNoLink('Cron', 'Shortcut link removed from different page');
$this->drupalGet('admin/people');
// Test the "Add to shortcuts" link for a page generated by views.
$this->clickLink('Add to Default shortcuts');
$this->assertText('Added a shortcut for People.');
$this->assertShortcutQuickLink('Remove from Default shortcuts');
// Test the "Remove from shortcuts" link for a page generated by views.
$this->clickLink('Remove from Default shortcuts');
$this->assertText('The shortcut People has been deleted.');
$this->assertShortcutQuickLink('Add to Default shortcuts');
// Test two pages which use same route name but different route parameters.
$this->drupalGet('node/add/page');
// Add Shortcut for Basic Page.
$this->clickLink('Add to Default shortcuts');
$this->assertText('Added a shortcut for Create Basic page.');
// Assure that Article does not have its shortcut indicated as set.
$this->drupalGet('node/add/article');
$link = $this->xpath('//a[normalize-space()=:label]', array(':label' => 'Remove from Default shortcuts'));
$this->assertTrue(empty($link), 'Link Remove to Default shortcuts not found for Create Article page.');
// Add Shortcut for Article.
$this->clickLink('Add to Default shortcuts');
$this->assertText('Added a shortcut for Create Article.');
$this->config('system.theme')->set('default', 'seven')->save();
$this->drupalGet('node/' . $this->node->id());
$title = $this->node->getTitle();
// Test the "Add to shortcuts" link for node view route.
$this->clickLink('Add to Default shortcuts');
$this->assertText(new FormattableMarkup('Added a shortcut for @title.', ['@title' => $title]));
$this->assertShortcutQuickLink('Remove from Default shortcuts');
// Test the "Remove from shortcuts" link for node view route.
$this->clickLink('Remove from Default shortcuts');
$this->assertText(new FormattableMarkup('The shortcut @title has been deleted.', ['@title' => $title]));
$this->assertShortcutQuickLink('Add to Default shortcuts');
\Drupal::service('module_installer')->install(['block_content']);
BlockContentType::create(array(
'id' => 'basic',
'label' => 'Basic block',
'revision' => FALSE,
))->save();
// Test page with HTML tags in title.
$this->drupalGet('admin/structure/block/block-content/manage/basic');
$page_title = new FormattableMarkup('Edit %label custom block type', ['%label' => 'Basic block']);
$this->assertRaw($page_title);
// Add shortcut to this page.
$this->clickLink('Add to Default shortcuts');
$this->assertRaw(new FormattableMarkup('Added a shortcut for %title.', [
'%title' => trim(strip_tags($page_title)),
]));
}
/**
* Tests that shortcut links can be renamed.
*/
public function testShortcutLinkRename() {
$set = $this->set;
// Attempt to rename shortcut link.
$new_link_name = $this->randomMachineName();
$shortcuts = $set->getShortcuts();
$shortcut = reset($shortcuts);
$this->drupalPostForm('admin/config/user-interface/shortcut/link/' . $shortcut->id(), array('title[0][value]' => $new_link_name), t('Save'));
$saved_set = ShortcutSet::load($set->id());
$titles = $this->getShortcutInformation($saved_set, 'title');
$this->assertTrue(in_array($new_link_name, $titles), 'Shortcut renamed: ' . $new_link_name);
$this->assertLink($new_link_name, 0, 'Renamed shortcut link appears on the page.');
$this->assertText(t('The shortcut @link has been updated.', array('@link' => $new_link_name)));
}
/**
* Tests that changing the path of a shortcut link works.
*/
public function testShortcutLinkChangePath() {
$set = $this->set;
// Tests changing a shortcut path.
$new_link_path = '/admin/config';
$shortcuts = $set->getShortcuts();
$shortcut = reset($shortcuts);
$this->drupalPostForm('admin/config/user-interface/shortcut/link/' . $shortcut->id(), array('title[0][value]' => $shortcut->getTitle(), 'link[0][uri]' => $new_link_path), t('Save'));
$saved_set = ShortcutSet::load($set->id());
$paths = $this->getShortcutInformation($saved_set, 'link');
$this->assertTrue(in_array('internal:' . $new_link_path, $paths), 'Shortcut path changed: ' . $new_link_path);
$this->assertLinkByHref($new_link_path, 0, 'Shortcut with new path appears on the page.');
$this->assertText(t('The shortcut @link has been updated.', array('@link' => $shortcut->getTitle())));
}
/**
* Tests that changing the route of a shortcut link works.
*/
public function testShortcutLinkChangeRoute() {
$this->drupalLogin($this->rootUser);
$this->drupalGet('admin/content');
$this->assertResponse(200);
// Disable the view.
View::load('content')->disable()->save();
/** @var \Drupal\Core\Routing\RouteBuilderInterface $router_builder */
$router_builder = \Drupal::service('router.builder');
$router_builder->rebuildIfNeeded();
$this->drupalGet('admin/content');
$this->assertResponse(200);
}
/**
* Tests deleting a shortcut link.
*/
public function testShortcutLinkDelete() {
$set = $this->set;
$shortcuts = $set->getShortcuts();
$shortcut = reset($shortcuts);
$this->drupalPostForm('admin/config/user-interface/shortcut/link/' . $shortcut->id() . '/delete', array(), 'Delete');
$saved_set = ShortcutSet::load($set->id());
$ids = $this->getShortcutInformation($saved_set, 'id');
$this->assertFalse(in_array($shortcut->id(), $ids), 'Successfully deleted a shortcut.');
// Delete all the remaining shortcut links.
entity_delete_multiple('shortcut', array_filter($ids));
// Get the front page to check that no exceptions occur.
$this->drupalGet('');
}
/**
* Tests that the add shortcut link is not displayed for 404/403 errors.
*
* Tests that the "Add to shortcuts" link is not displayed on a page not
* found or a page the user does not have access to.
*/
public function testNoShortcutLink() {
// Change to a theme that displays shortcuts.
\Drupal::service('theme_handler')->install(array('seven'));
$this->config('system.theme')
->set('default', 'seven')
->save();
$this->drupalGet('page-that-does-not-exist');
$result = $this->xpath('//a[contains(@class, "shortcut-action--add")]');
$this->assertTrue(empty($result), 'Add to shortcuts link was not shown on a page not found.');
// The user does not have access to this path.
$this->drupalGet('admin/modules');
$result = $this->xpath('//a[contains(@class, "shortcut-action--add")]');
$this->assertTrue(empty($result), 'Add to shortcuts link was not shown on a page the user does not have access to.');
// Verify that the testing mechanism works by verifying the shortcut link
// appears on admin/content.
$this->drupalGet('admin/content');
$result = $this->xpath('//a[contains(@class, "shortcut-action--remove")]');
$this->assertTrue(!empty($result), 'Remove from shortcuts link was shown on a page the user does have access to.');
// Verify that the shortcut link appears on routing only pages.
$this->drupalGet('router_test/test2');
$result = $this->xpath('//a[contains(@class, "shortcut-action--add")]');
$this->assertTrue(!empty($result), 'Add to shortcuts link was shown on a page the user does have access to.');
}
/**
* Tests that the 'access shortcuts' permissions works properly.
*/
public function testAccessShortcutsPermission() {
// Change to a theme that displays shortcuts.
\Drupal::service('theme_handler')->install(array('seven'));
$this->config('system.theme')
->set('default', 'seven')
->save();
// Add cron to the default shortcut set.
$this->drupalLogin($this->rootUser);
$this->drupalGet('admin/config/system/cron');
$this->clickLink('Add to Default shortcuts');
// Verify that users without the 'access shortcuts' permission can't see the
// shortcuts.
$this->drupalLogin($this->drupalCreateUser(array('access toolbar')));
$this->assertNoLink('Shortcuts', 'Shortcut link not found on page.');
// Verify that users without the 'administer site configuration' permission
// can't see the cron shortcuts.
$this->drupalLogin($this->drupalCreateUser(array('access toolbar', 'access shortcuts')));
$this->assertNoLink('Shortcuts', 'Shortcut link not found on page.');
$this->assertNoLink('Cron', 'Cron shortcut link not found on page.');
// Verify that users with the 'access shortcuts' permission can see the
// shortcuts.
$this->drupalLogin($this->drupalCreateUser(array(
'access toolbar', 'access shortcuts', 'administer site configuration',
)));
$this->clickLink('Shortcuts', 0, 'Shortcut link found on page.');
$this->assertLink('Cron', 0, 'Cron shortcut link found on page.');
$this->verifyAccessShortcutsPermissionForEditPages();
}
/**
* Tests the shortcuts are correctly ordered by weight in the toolbar.
*/
public function testShortcutLinkOrder() {
// Ensure to give permissions to access the shortcuts.
$this->drupalLogin($this->drupalCreateUser(array('access toolbar', 'access shortcuts', 'access content overview', 'administer content types')));
$this->drupalGet(Url::fromRoute('<front>'));
$shortcuts = $this->cssSelect('#toolbar-item-shortcuts-tray .toolbar-menu a');
$this->assertEqual((string) $shortcuts[0], 'Add content');
$this->assertEqual((string) $shortcuts[1], 'All content');
foreach ($this->set->getShortcuts() as $shortcut) {
$shortcut->setWeight($shortcut->getWeight() * -1)->save();
}
$this->drupalGet(Url::fromRoute('<front>'));
$shortcuts = $this->cssSelect('#toolbar-item-shortcuts-tray .toolbar-menu a');
$this->assertEqual((string) $shortcuts[0], 'All content');
$this->assertEqual((string) $shortcuts[1], 'Add content');
}
/**
* Tests that the 'access shortcuts' permission is required for shortcut set
* administration page access.
*/
private function verifyAccessShortcutsPermissionForEditPages() {
// Create a user with customize links and switch sets permissions but
// without the 'access shortcuts' permission.
$test_permissions = array(
'customize shortcut links',
'switch shortcut sets',
);
$noaccess_user = $this->drupalCreateUser($test_permissions);
$this->drupalLogin($noaccess_user);
// Verify that set administration pages are inaccessible without the
// 'access shortcuts' permission.
$edit_paths = array(
'admin/config/user-interface/shortcut/manage/default/customize',
'admin/config/user-interface/shortcut/manage/default',
'user/' . $noaccess_user->id() . '/shortcuts',
);
foreach ($edit_paths as $path) {
$this->drupalGet($path);
$message = format_string('Access is denied on %s', array('%s' => $path));
$this->assertResponse(403, $message);
}
}
/**
* Tests that the 'access shortcuts' permission is required to access the
* shortcut block.
*/
public function testShortcutBlockAccess() {
// Creates a block instance and place in a region through api.
$block = $this->drupalPlaceBlock('shortcuts');
// Verify that users with the 'access shortcuts' permission can see the
// shortcut block.
$this->drupalLogin($this->shortcutUser);
$this->drupalGet('');
$this->assertBlockAppears($block);
$this->drupalLogout();
// Verify that users without the 'access shortcuts' permission can see the
// shortcut block.
$this->drupalLogin($this->drupalCreateUser(array()));
$this->drupalGet('');
$this->assertNoBlockAppears($block);
}
/**
* Passes if a shortcut quick link with the specified label is found.
*
* An optional link index may be passed.
*
* @param string $label
* Text between the anchor tags.
* @param int $index
* Link position counting from zero.
* @param string $message
* (optional) A message to display with the assertion. Do not translate
* messages: use format_string() to embed variables in the message text, not
* t(). If left blank, a default message will be displayed.
* @param string $group
* (optional) The group this message is in, which is displayed in a column
* in test output. Use 'Debug' to indicate this is debugging output. Do not
* translate this string. Defaults to 'Other'; most tests do not override
* this default.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertShortcutQuickLink($label, $index = 0, $message = '', $group = 'Other') {
$links = $this->xpath('//a[normalize-space()=:label]', array(':label' => $label));
$message = ($message ? $message : SafeMarkup::format('Shortcut quick link with label %label found.', array('%label' => $label)));
return $this->assert(isset($links[$index]), $message, $group);
}
}

View file

@ -0,0 +1,211 @@
<?php
namespace Drupal\shortcut\Tests;
use Drupal\shortcut\Entity\ShortcutSet;
/**
* Create, view, edit, delete, and change shortcut sets.
*
* @group shortcut
*/
class ShortcutSetsTest extends ShortcutTestBase {
/**
* Modules to enable.
*
* @var string[]
*/
public static $modules = ['block'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('local_actions_block');
}
/**
* Tests creating a shortcut set.
*/
function testShortcutSetAdd() {
$this->drupalGet('admin/config/user-interface/shortcut');
$this->clickLink(t('Add shortcut set'));
$edit = array(
'label' => $this->randomMachineName(),
'id' => strtolower($this->randomMachineName()),
);
$this->drupalPostForm(NULL, $edit, t('Save'));
$new_set = $this->container->get('entity.manager')->getStorage('shortcut_set')->load($edit['id']);
$this->assertIdentical($new_set->id(), $edit['id'], 'Successfully created a shortcut set.');
$this->drupalGet('user/' . $this->adminUser->id() . '/shortcuts');
$this->assertText($new_set->label(), 'Generated shortcut set was listed as a choice on the user account page.');
}
/**
* Tests editing a shortcut set.
*/
function testShortcutSetEdit() {
$set = $this->set;
$shortcuts = $set->getShortcuts();
// Visit the shortcut set edit admin ui.
$this->drupalGet('admin/config/user-interface/shortcut/manage/' . $set->id() . '/customize');
// Test for the page title.
$this->assertTitle(t('List links') . ' | Drupal');
// Test for the table.
$element = $this->xpath('//div[@class="layout-content"]//table');
$this->assertTrue($element, 'Shortcut entity list table found.');
// Test the table header.
$elements = $this->xpath('//div[@class="layout-content"]//table/thead/tr/th');
$this->assertEqual(count($elements), 3, 'Correct number of table header cells found.');
// Test the contents of each th cell.
$expected_items = array(t('Name'), t('Weight'), t('Operations'));
foreach ($elements as $key => $element) {
$this->assertEqual((string) $element[0], $expected_items[$key]);
}
// Look for test shortcuts in the table.
$weight = count($shortcuts);
$edit = array();
foreach ($shortcuts as $shortcut) {
$title = $shortcut->getTitle();
// Confirm that a link to the shortcut is found within the table.
$this->assertLink($title);
// Look for a test shortcut weight select form element.
$this->assertFieldByName('shortcuts[links][' . $shortcut->id() . '][weight]');
// Change the weight of the shortcut.
$edit['shortcuts[links][' . $shortcut->id() . '][weight]'] = $weight;
$weight--;
}
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('The shortcut set has been updated.'));
\Drupal::entityManager()->getStorage('shortcut')->resetCache();
// Check to ensure that the shortcut weights have changed and that
// ShortcutSet::.getShortcuts() returns shortcuts in the new order.
$this->assertIdentical(array_reverse(array_keys($shortcuts)), array_keys($set->getShortcuts()));
}
/**
* Tests switching a user's own shortcut set.
*/
function testShortcutSetSwitchOwn() {
$new_set = $this->generateShortcutSet($this->randomMachineName());
// Attempt to switch the default shortcut set to the newly created shortcut
// set.
$this->drupalPostForm('user/' . $this->adminUser->id() . '/shortcuts', array('set' => $new_set->id()), t('Change set'));
$this->assertResponse(200);
$current_set = shortcut_current_displayed_set($this->adminUser);
$this->assertTrue($new_set->id() == $current_set->id(), 'Successfully switched own shortcut set.');
}
/**
* Tests switching another user's shortcut set.
*/
function testShortcutSetAssign() {
$new_set = $this->generateShortcutSet($this->randomMachineName());
\Drupal::entityManager()->getStorage('shortcut_set')->assignUser($new_set, $this->shortcutUser);
$current_set = shortcut_current_displayed_set($this->shortcutUser);
$this->assertTrue($new_set->id() == $current_set->id(), "Successfully switched another user's shortcut set.");
}
/**
* Tests switching a user's shortcut set and creating one at the same time.
*/
function testShortcutSetSwitchCreate() {
$edit = array(
'set' => 'new',
'id' => strtolower($this->randomMachineName()),
'label' => $this->randomString(),
);
$this->drupalPostForm('user/' . $this->adminUser->id() . '/shortcuts', $edit, t('Change set'));
$current_set = shortcut_current_displayed_set($this->adminUser);
$this->assertNotEqual($current_set->id(), $this->set->id(), 'A shortcut set can be switched to at the same time as it is created.');
$this->assertEqual($current_set->label(), $edit['label'], 'The new set is correctly assigned to the user.');
}
/**
* Tests switching a user's shortcut set without providing a new set name.
*/
function testShortcutSetSwitchNoSetName() {
$edit = array('set' => 'new');
$this->drupalPostForm('user/' . $this->adminUser->id() . '/shortcuts', $edit, t('Change set'));
$this->assertText(t('The new set label is required.'));
$current_set = shortcut_current_displayed_set($this->adminUser);
$this->assertEqual($current_set->id(), $this->set->id(), 'Attempting to switch to a new shortcut set without providing a set name does not succeed.');
$this->assertFieldByXPath("//input[@name='label' and contains(concat(' ', normalize-space(@class), ' '), ' error ')]", NULL, 'The new set label field has the error class');
}
/**
* Tests renaming a shortcut set.
*/
function testShortcutSetRename() {
$set = $this->set;
$new_label = $this->randomMachineName();
$this->drupalGet('admin/config/user-interface/shortcut');
$this->clickLink(t('Edit shortcut set'));
$this->drupalPostForm(NULL, array('label' => $new_label), t('Save'));
$set = ShortcutSet::load($set->id());
$this->assertTrue($set->label() == $new_label, 'Shortcut set has been successfully renamed.');
}
/**
* Tests unassigning a shortcut set.
*/
function testShortcutSetUnassign() {
$new_set = $this->generateShortcutSet($this->randomMachineName());
$shortcut_set_storage = \Drupal::entityManager()->getStorage('shortcut_set');
$shortcut_set_storage->assignUser($new_set, $this->shortcutUser);
$shortcut_set_storage->unassignUser($this->shortcutUser);
$current_set = shortcut_current_displayed_set($this->shortcutUser);
$default_set = shortcut_default_set($this->shortcutUser);
$this->assertTrue($current_set->id() == $default_set->id(), "Successfully unassigned another user's shortcut set.");
}
/**
* Tests deleting a shortcut set.
*/
function testShortcutSetDelete() {
$new_set = $this->generateShortcutSet($this->randomMachineName());
$this->drupalPostForm('admin/config/user-interface/shortcut/manage/' . $new_set->id() . '/delete', array(), t('Delete'));
$sets = ShortcutSet::loadMultiple();
$this->assertFalse(isset($sets[$new_set->id()]), 'Successfully deleted a shortcut set.');
}
/**
* Tests deleting the default shortcut set.
*/
function testShortcutSetDeleteDefault() {
$this->drupalGet('admin/config/user-interface/shortcut/manage/default/delete');
$this->assertResponse(403);
}
/**
* Tests creating a new shortcut set with a defined set name.
*/
function testShortcutSetCreateWithSetName() {
$random_name = $this->randomMachineName();
$new_set = $this->generateShortcutSet($random_name, $random_name);
$sets = ShortcutSet::loadMultiple();
$this->assertTrue(isset($sets[$random_name]), 'Successfully created a shortcut set with a defined set name.');
$this->drupalGet('user/' . $this->adminUser->id() . '/shortcuts');
$this->assertText($new_set->label(), 'Generated shortcut set was listed as a choice on the user account page.');
}
}

View file

@ -0,0 +1,133 @@
<?php
namespace Drupal\shortcut\Tests;
use Drupal\shortcut\Entity\Shortcut;
use Drupal\shortcut\Entity\ShortcutSet;
use Drupal\shortcut\ShortcutSetInterface;
use Drupal\simpletest\WebTestBase;
/**
* Defines base class for shortcut test cases.
*/
abstract class ShortcutTestBase extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('node', 'toolbar', 'shortcut');
/**
* User with permission to administer shortcuts.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* User with permission to use shortcuts, but not administer them.
*
* @var \Drupal\user\UserInterface
*/
protected $shortcutUser;
/**
* Generic node used for testing.
*
* @var \Drupal\node\NodeInterface
*/
protected $node;
/**
* Site-wide default shortcut set.
*
* @var \Drupal\shortcut\ShortcutSetInterface
*/
protected $set;
protected function setUp() {
parent::setUp();
if ($this->profile != 'standard') {
// Create Basic page and Article node types.
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
$this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
// Populate the default shortcut set.
$shortcut = Shortcut::create(array(
'shortcut_set' => 'default',
'title' => t('Add content'),
'weight' => -20,
'link' => array(
'uri' => 'internal:/node/add',
),
));
$shortcut->save();
$shortcut = Shortcut::create(array(
'shortcut_set' => 'default',
'title' => t('All content'),
'weight' => -19,
'link' => array(
'uri' => 'internal:/admin/content',
),
));
$shortcut->save();
}
// Create users.
$this->adminUser = $this->drupalCreateUser(array('access toolbar', 'administer shortcuts', 'view the administration theme', 'create article content', 'create page content', 'access content overview', 'administer users', 'link to any page', 'edit any article content'));
$this->shortcutUser = $this->drupalCreateUser(array('customize shortcut links', 'switch shortcut sets', 'access shortcuts', 'access content'));
// Create a node.
$this->node = $this->drupalCreateNode(array('type' => 'article'));
// Log in as admin and grab the default shortcut set.
$this->drupalLogin($this->adminUser);
$this->set = ShortcutSet::load('default');
\Drupal::entityManager()->getStorage('shortcut_set')->assignUser($this->set, $this->adminUser);
}
/**
* Creates a generic shortcut set.
*/
function generateShortcutSet($label = '', $id = NULL) {
$set = ShortcutSet::create(array(
'id' => isset($id) ? $id : strtolower($this->randomMachineName()),
'label' => empty($label) ? $this->randomString() : $label,
));
$set->save();
return $set;
}
/**
* Extracts information from shortcut set links.
*
* @param \Drupal\shortcut\ShortcutSetInterface $set
* The shortcut set object to extract information from.
* @param string $key
* The array key indicating what information to extract from each link:
* - 'title': Extract shortcut titles.
* - 'link': Extract shortcut paths.
* - 'id': Extract the shortcut ID.
*
* @return array
* Array of the requested information from each link.
*/
function getShortcutInformation(ShortcutSetInterface $set, $key) {
$info = array();
\Drupal::entityManager()->getStorage('shortcut')->resetCache();
foreach ($set->getShortcuts() as $shortcut) {
if ($key == 'link') {
$info[] = $shortcut->link->uri;
}
else {
$info[] = $shortcut->{$key}->value;
}
}
return $info;
}
}

View file

@ -0,0 +1,127 @@
<?php
namespace Drupal\shortcut\Tests;
use Drupal\content_translation\Tests\ContentTranslationUITestBase;
use Drupal\Core\Entity\EntityChangedInterface;
use Drupal\Core\Language\Language;
/**
* Tests the shortcut translation UI.
*
* @group Shortcut
*/
class ShortcutTranslationUITest extends ContentTranslationUITestBase {
/**
* {inheritdoc}
*/
protected $defaultCacheContexts = ['languages:language_interface', 'session', 'theme', 'user', 'url.path', 'url.query_args', 'url.site'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array(
'language',
'content_translation',
'link',
'shortcut',
'toolbar'
);
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->entityTypeId = 'shortcut';
$this->bundle = 'default';
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function getTranslatorPermissions() {
return array_merge(parent::getTranslatorPermissions(), array('access shortcuts', 'administer shortcuts', 'access toolbar'));
}
/**
* {@inheritdoc}
*/
protected function createEntity($values, $langcode, $bundle_name = NULL) {
$values['link']['uri'] = 'internal:/user';
return parent::createEntity($values, $langcode, $bundle_name);
}
/**
* {@inheritdoc}
*/
protected function getNewEntityValues($langcode) {
return array('title' => array(array('value' => $this->randomMachineName()))) + parent::getNewEntityValues($langcode);
}
protected function doTestBasicTranslation() {
parent::doTestBasicTranslation();
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
foreach ($this->langcodes as $langcode) {
if ($entity->hasTranslation($langcode)) {
$language = new Language(array('id' => $langcode));
// Request the front page in this language and assert that the right
// translation shows up in the shortcut list with the right path.
$this->drupalGet('<front>', array('language' => $language));
$expected_path = \Drupal::urlGenerator()->generateFromRoute('user.page', array(), array('language' => $language));
$label = $entity->getTranslation($langcode)->label();
$elements = $this->xpath('//nav[contains(@class, "toolbar-lining")]/ul[@class="toolbar-menu"]/li/a[contains(@href, :href) and normalize-space(text())=:label]', array(':href' => $expected_path, ':label' => $label));
$this->assertTrue(!empty($elements), format_string('Translated @language shortcut link @label found.', array('@label' => $label, '@language' => $language->getName())));
}
}
}
/**
* {@inheritdoc}
*/
protected function doTestTranslationEdit() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$languages = $this->container->get('language_manager')->getLanguages();
foreach ($this->langcodes as $langcode) {
// We only want to test the title for non-english translations.
if ($langcode != 'en') {
$options = array('language' => $languages[$langcode]);
$url = $entity->urlInfo('edit-form', $options);
$this->drupalGet($url);
$title = t('@title [%language translation]', array(
'@title' => $entity->getTranslation($langcode)->label(),
'%language' => $languages[$langcode]->getName(),
));
$this->assertRaw($title);
}
}
}
/**
* Tests the basic translation workflow.
*/
protected function doTestTranslationChanged() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->assertFalse(
$entity instanceof EntityChangedInterface,
format_string('%entity is not implementing EntityChangedInterface.', array('%entity' => $this->entityTypeId))
);
}
}