Commit 1dab0e1c authored by webchick's avatar webchick

Issue #1497380 by Berdir, andypost, jibran, tim.plunkett: Convert shortcut sets to ConfigEntity.

parent 2ae15972
<?php
/**
* @file
* Contains \Drupal\shortcut\Plugin\Core\Entity\Shortcut.
*/
namespace Drupal\shortcut\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
/**
* Defines the Shortcut configuration entity.
*
* @Plugin(
* id = "shortcut",
* label = @Translation("Shortcut set"),
* module = "shortcut",
* controller_class = "Drupal\shortcut\ShortcutStorageController",
* list_controller_class = "Drupal\shortcut\ShortcutListController",
* form_controller_class = {
* "default" = "Drupal\shortcut\ShortcutFormController"
* },
* config_prefix = "shortcut.set",
* entity_keys = {
* "id" = "id",
* "label" = "label",
* "uuid" = "uuid"
* }
* )
*/
class Shortcut extends ConfigEntityBase {
/**
* The machine name for the configuration entity.
*
* @var string
*/
public $id;
/**
* The UUID for the configuration entity.
*
* @var string
*/
public $uuid;
/**
* The human-readable name of the configuration entity.
*
* @var string
*/
public $label;
/**
* Overrides \Drupal\Core\Entity\Entity::uri().
*/
public function uri() {
return array(
'path' => 'admin/config/user-interface/shortcut/manage/' . $this->id(),
'options' => array(
'entity_type' => $this->entityType,
'entity' => $this,
),
);
}
}
<?php
/**
* @file
* Contains \Drupal\shortcut\ShortcutFormController.
*/
namespace Drupal\shortcut;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityFormController;
/**
* Form controller for the shortcut set entity edit forms.
*/
class ShortcutFormController extends EntityFormController {
/**
* Overrides \Drupal\Core\Entity\EntityFormController::form().
*/
public function form(array $form, array &$form_state, EntityInterface $entity) {
$form = parent::form($form, $form_state, $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' => 'shortcut_set_load',
'source' => array('label'),
'replace_pattern' => '[^a-z0-9-]+',
'replace' => '-',
),
'#default_value' => $entity->id(),
'#disabled' => !$entity->isNew(),
// This id could be used for menu name.
'#maxlength' => 23,
);
$form['actions']['submit']['#value'] = t('Create new set');
return $form;
}
/**
* Overrides \Drupal\Core\Entity\EntityFormController::actions().
*/
protected function actions(array $form, array &$form_state) {
// Disable delete of default shortcut set.
$actions = parent::actions($form, $form_state);
$actions['delete']['#access'] = shortcut_set_delete_access($this->getEntity($form_state));
return $actions;
}
/**
* Overrides \Drupal\Core\Entity\EntityFormController::validate().
*/
public function validate(array $form, array &$form_state) {
parent::validate($form, $form_state);
$entity = $this->getEntity($form_state);
// Check to prevent a duplicate title.
if ($form_state['values']['label'] != $entity->label() && shortcut_set_title_exists($form_state['values']['label'])) {
form_set_error('label', t('The shortcut set %name already exists. Choose another name.', array('%name' => $form_state['values']['label'])));
}
}
/**
* Overrides \Drupal\Core\Entity\EntityFormController::save().
*/
public function save(array $form, array &$form_state) {
$entity = $this->getEntity($form_state);
$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['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $entity->id();
}
/**
* Overrides \Drupal\Core\Entity\EntityFormController::delete().
*/
public function delete(array $form, array &$form_state) {
$entity = $this->getEntity($form_state);
$form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $entity->id() . '/delete';
}
}
<?php
/**
* Contains \Drupal\shortcut\ShortcutListController.
*/
namespace Drupal\shortcut;
use Drupal\Core\Config\Entity\ConfigEntityListController;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a listing of contact categories.
*/
class ShortcutListController extends ConfigEntityListController {
/**
* Overrides \Drupal\Core\Entity\EntityListController::buildHeader().
*/
public function buildHeader() {
$row['label'] = t('Name');
$row['operations'] = t('Operations');
return $row;
}
/**
* Overrides \Drupal\Core\Entity\EntityListController::getOperations().
*/
public function getOperations(EntityInterface $entity) {
$uri = $entity->uri();
$operations['list'] = array(
'title' => t('list links'),
'href' => $uri['path'],
);
$operations['edit'] = array(
'title' => t('edit set'),
'href' => $uri['path'] . '/edit',
'options' => $uri['options'],
'weight' => 10,
);
if (shortcut_set_delete_access($entity)) {
$operations['delete'] = array(
'title' => t('delete set'),
'href' => $uri['path'] . '/delete',
'options' => $uri['options'],
'weight' => 100,
);
}
return $operations;
}
/**
* Overrides \Drupal\Core\Entity\EntityListController::buildRow().
*/
public function buildRow(EntityInterface $entity) {
$row['name'] = check_plain($entity->label());
$row['operations']['data'] = $this->buildOperations($entity);
return $row;
}
}
<?php
/**
* @file
* Contains \Drupal\shortcut\ShortcutStorageController.
*/
namespace Drupal\shortcut;
use Drupal\Core\Config\Entity\ConfigStorageController;
use Drupal\Core\Entity\EntityInterface;
/**
* Defines a storage controller for shortcut entities.
*/
class ShortcutStorageController extends ConfigStorageController {
/**
* Overrides \Drupal\config\ConfigStorageController::save().
*/
public function save(EntityInterface $entity) {
// Generate menu-compatible set name.
if (!$entity->getOriginalID()) {
// Save a new shortcut set with links copied from the user's default set.
$default_set = shortcut_default_set();
// Generate a name to have no collisions with menu.
// Size of menu_name is 32 so id could be 23 = 32 - strlen('shortcut-').
$id = substr($entity->id(), 0, 23);
$entity->set('id', $id);
$entity->set('links', menu_links_clone($default_set->links, $id));
}
return parent::save($entity);
}
/**
* Overrides \Drupal\config\ConfigStorageController::postSave().
*/
function postSave(EntityInterface $entity, $update) {
// Process links in shortcut set.
// If links were provided for the set, save them.
if (isset($entity->links)) {
foreach ($entity->links as &$link) {
// Do not specifically associate these links with the shortcut module,
// since other modules may make them editable via the menu system.
// However, we do need to specify the correct menu name.
$link['menu_name'] = 'shortcut-' . $entity->id();
$link['plid'] = 0;
menu_link_save($link);
}
}
parent::postSave($entity, $update);
}
/**
* Overrides \Drupal\Core\Entity\ConfigStorageController::preDelete().
*/
protected function preDelete($entities) {
foreach ($entities as $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();
// Next, delete the menu links for this set.
menu_delete_links('shortcut-' . $entity->id());
}
parent::preDelete($entities);
}
}
......@@ -44,14 +44,14 @@ function testShortcutLinkAdd() {
// Check that each new shortcut links where it should.
foreach ($test_cases as $test) {
$title = $this->randomName(10);
$title = $this->randomName();
$form_data = array(
'shortcut_link[link_title]' => $title,
'shortcut_link[link_path]' => $test['path'],
);
$this->drupalPost('admin/config/user-interface/shortcut/' . $set->set_name . '/add-link', $form_data, t('Save'));
$this->drupalPost('admin/config/user-interface/shortcut/manage/' . $set->id() . '/add-link', $form_data, t('Save'));
$this->assertResponse(200);
$saved_set = shortcut_set_load($set->set_name);
$saved_set = shortcut_set_load($set->id());
$paths = $this->getShortcutInformation($saved_set, 'link_path');
$test_path = empty($test['path']) ? '<front>' : $test['path'];
$this->assertTrue(in_array(drupal_container()->get('path.alias_manager')->getSystemPath($test_path), $paths), 'Shortcut created: '. $test['path']);
......@@ -67,7 +67,7 @@ function testShortcutQuickLink() {
config('system.theme')->set('admin', 'seven')->save();
variable_set('node_admin_theme', TRUE);
$this->drupalGet($this->set->links[0]['link_path']);
$this->assertRaw(t('Remove from %title shortcuts', array('%title' => $this->set->title)), '"Add to shortcuts" link properly switched to "Remove from shortcuts".');
$this->assertRaw(t('Remove from %title shortcuts', array('%title' => $this->set->label())), '"Add to shortcuts" link properly switched to "Remove from shortcuts".');
}
/**
......@@ -77,10 +77,10 @@ function testShortcutLinkRename() {
$set = $this->set;
// Attempt to rename shortcut link.
$new_link_name = $this->randomName(10);
$new_link_name = $this->randomName();
$this->drupalPost('admin/config/user-interface/shortcut/link/' . $set->links[0]['mlid'], array('shortcut_link[link_title]' => $new_link_name, 'shortcut_link[link_path]' => $set->links[0]['link_path']), t('Save'));
$saved_set = shortcut_set_load($set->set_name);
$saved_set = shortcut_set_load($set->id());
$titles = $this->getShortcutInformation($saved_set, 'link_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.');
......@@ -96,7 +96,7 @@ function testShortcutLinkChangePath() {
$new_link_path = 'admin/config';
$this->drupalPost('admin/config/user-interface/shortcut/link/' . $set->links[0]['mlid'], array('shortcut_link[link_title]' => $set->links[0]['link_title'], 'shortcut_link[link_path]' => $new_link_path), t('Save'));
$saved_set = shortcut_set_load($set->set_name);
$saved_set = shortcut_set_load($set->id());
$paths = $this->getShortcutInformation($saved_set, 'link_path');
$this->assertTrue(in_array($new_link_path, $paths), 'Shortcut path changed: ' . $new_link_path);
$this->assertLinkByHref($new_link_path, 0, 'Shortcut with new path appears on the page.');
......@@ -109,7 +109,7 @@ function testShortcutLinkDelete() {
$set = $this->set;
$this->drupalPost('admin/config/user-interface/shortcut/link/' . $set->links[0]['mlid'] . '/delete', array(), 'Delete');
$saved_set = shortcut_set_load($set->set_name);
$saved_set = shortcut_set_load($set->id());
$mlids = $this->getShortcutInformation($saved_set, 'mlid');
$this->assertFalse(in_array($set->links[0]['mlid'], $mlids), 'Successfully deleted a shortcut.');
}
......
......@@ -26,36 +26,36 @@ public static function getInfo() {
* Tests creating a shortcut set.
*/
function testShortcutSetAdd() {
$new_set = $this->generateShortcutSet($this->randomName(10));
$sets = shortcut_sets();
$this->assertTrue(isset($sets[$new_set->set_name]), 'Successfully created a shortcut set.');
$new_set = $this->generateShortcutSet($this->randomName());
$sets = entity_load_multiple('shortcut');
$this->assertTrue(isset($sets[$new_set->id()]), 'Successfully created a shortcut set.');
$this->drupalGet('user/' . $this->admin_user->uid . '/shortcuts');
$this->assertText($new_set->title, 'Generated shortcut set was listed as a choice on the user account page.');
$this->assertText($new_set->label(), 'Generated shortcut set was listed as a choice on the user account page.');
}
/**
* Tests switching a user's own shortcut set.
*/
function testShortcutSetSwitchOwn() {
$new_set = $this->generateShortcutSet($this->randomName(10));
$new_set = $this->generateShortcutSet($this->randomName());
// Attempt to switch the default shortcut set to the newly created shortcut
// set.
$this->drupalPost('user/' . $this->admin_user->uid . '/shortcuts', array('set' => $new_set->set_name), t('Change set'));
$this->drupalPost('user/' . $this->admin_user->uid . '/shortcuts', array('set' => $new_set->id()), t('Change set'));
$this->assertResponse(200);
$current_set = shortcut_current_displayed_set($this->admin_user);
$this->assertTrue($new_set->set_name == $current_set->set_name, 'Successfully switched own shortcut set.');
$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->randomName(10));
$new_set = $this->generateShortcutSet($this->randomName());
shortcut_set_assign_user($new_set, $this->shortcut_user);
$current_set = shortcut_current_displayed_set($this->shortcut_user);
$this->assertTrue($new_set->set_name == $current_set->set_name, "Successfully switched another user's shortcut set.");
$this->assertTrue($new_set->id() == $current_set->id(), "Successfully switched another user's shortcut set.");
}
/**
......@@ -64,12 +64,13 @@ function testShortcutSetAssign() {
function testShortcutSetSwitchCreate() {
$edit = array(
'set' => 'new',
'new' => $this->randomName(10),
'id' => strtolower($this->randomName()),
'label' => $this->randomString(),
);
$this->drupalPost('user/' . $this->admin_user->uid . '/shortcuts', $edit, t('Change set'));
$current_set = shortcut_current_displayed_set($this->admin_user);
$this->assertNotEqual($current_set->set_name, $this->set->set_name, 'A shortcut set can be switched to at the same time as it is created.');
$this->assertEqual($current_set->title, $edit['new'], 'The new set is correctly assigned to the user.');
$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.');
}
/**
......@@ -78,24 +79,24 @@ function testShortcutSetSwitchCreate() {
function testShortcutSetSwitchNoSetName() {
$edit = array('set' => 'new');
$this->drupalPost('user/' . $this->admin_user->uid . '/shortcuts', $edit, t('Change set'));
$this->assertText(t('The new set name is required.'));
$this->assertText(t('The new set label is required.'));
$current_set = shortcut_current_displayed_set($this->admin_user);
$this->assertEqual($current_set->set_name, $this->set->set_name, 'Attempting to switch to a new shortcut set without providing a set name does not succeed.');
$this->assertEqual($current_set->id(), $this->set->id(), 'Attempting to switch to a new shortcut set without providing a set name does not succeed.');
}
/**
* Tests that shortcut_set_save() correctly updates existing links.
* Tests that save() correctly updates existing links.
*/
function testShortcutSetSave() {
$set = $this->set;
$old_mlids = $this->getShortcutInformation($set, 'mlid');
$set->links[] = $this->generateShortcutLink('admin', $this->randomName(10));
shortcut_set_save($set);
$saved_set = shortcut_set_load($set->set_name);
$set->links[] = $this->generateShortcutLink('admin', $this->randomName());
$set->save();
$saved_set = shortcut_set_load($set->id());
$new_mlids = $this->getShortcutInformation($saved_set, 'mlid');
$this->assertTrue(count(array_intersect($old_mlids, $new_mlids)) == count($old_mlids), 'shortcut_set_save() did not inadvertently change existing mlids.');
$this->assertTrue(count(array_intersect($old_mlids, $new_mlids)) == count($old_mlids), 'Shortcut::save() did not inadvertently change existing mlids.');
}
/**
......@@ -104,53 +105,53 @@ function testShortcutSetSave() {
function testShortcutSetRename() {
$set = $this->set;
$new_title = $this->randomName(10);
$this->drupalPost('admin/config/user-interface/shortcut/' . $set->set_name . '/edit', array('title' => $new_title), t('Save'));
$set = shortcut_set_load($set->set_name);
$this->assertTrue($set->title == $new_title, 'Shortcut set has been successfully renamed.');
$new_label = $this->randomName();
$this->drupalPost('admin/config/user-interface/shortcut/manage/' . $set->id() . '/edit', array('label' => $new_label), t('Save'));
$set = shortcut_set_load($set->id());
$this->assertTrue($set->label() == $new_label, 'Shortcut set has been successfully renamed.');
}
/**
* Tests renaming a shortcut set to the same name as another set.
*/
function testShortcutSetRenameAlreadyExists() {
$set = $this->generateShortcutSet($this->randomName(10));
$existing_title = $this->set->title;
$this->drupalPost('admin/config/user-interface/shortcut/' . $set->set_name . '/edit', array('title' => $existing_title), t('Save'));
$this->assertRaw(t('The shortcut set %name already exists. Choose another name.', array('%name' => $existing_title)));
$set = shortcut_set_load($set->set_name);
$this->assertNotEqual($set->title, $existing_title, format_string('The shortcut set %title cannot be renamed to %new-title because a shortcut set with that title already exists.', array('%title' => $set->title, '%new-title' => $existing_title)));
$set = $this->generateShortcutSet($this->randomName());
$existing_label = $this->set->label();
$this->drupalPost('admin/config/user-interface/shortcut/manage/' . $set->id() . '/edit', array('label' => $existing_label), t('Save'));
$this->assertRaw(t('The shortcut set %name already exists. Choose another name.', array('%name' => $existing_label)));
$set = shortcut_set_load($set->id());
$this->assertNotEqual($set->label(), $existing_label, format_string('The shortcut set %title cannot be renamed to %new-title because a shortcut set with that title already exists.', array('%title' => $set->label(), '%new-title' => $existing_label)));
}
/**
* Tests unassigning a shortcut set.
*/
function testShortcutSetUnassign() {
$new_set = $this->generateShortcutSet($this->randomName(10));
$new_set = $this->generateShortcutSet($this->randomName());
shortcut_set_assign_user($new_set, $this->shortcut_user);
shortcut_set_unassign_user($this->shortcut_user);
$current_set = shortcut_current_displayed_set($this->shortcut_user);
$default_set = shortcut_default_set($this->shortcut_user);
$this->assertTrue($current_set->set_name == $default_set->set_name, "Successfully unassigned another user's shortcut set.");
$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->randomName(10));
$new_set = $this->generateShortcutSet($this->randomName());
$this->drupalPost('admin/config/user-interface/shortcut/' . $new_set->set_name . '/delete', array(), t('Delete'));
$sets = shortcut_sets();
$this->assertFalse(isset($sets[$new_set->set_name]), 'Successfully deleted a shortcut set.');
$this->drupalPost('admin/config/user-interface/shortcut/manage/' . $new_set->id() . '/delete', array(), t('Delete'));
$sets = entity_load_multiple('shortcut');
$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/' . SHORTCUT_DEFAULT_SET_NAME . '/delete');
$this->drupalGet('admin/config/user-interface/shortcut/manage/default/delete');
$this->assertResponse(403);
}
......@@ -158,11 +159,11 @@ function testShortcutSetDeleteDefault() {
* Tests creating a new shortcut set with a defined set name.
*/
function testShortcutSetCreateWithSetName() {
$random_name = $this->randomName(10);
$new_set = $this->generateShortcutSet($random_name, TRUE, $random_name);
$sets = shortcut_sets();
$random_name = $this->randomName();
$new_set = $this->generateShortcutSet($random_name, $random_name, TRUE);
$sets = entity_load_multiple('shortcut');
$this->assertTrue(isset($sets[$random_name]), 'Successfully created a shortcut set with a defined set name.');
$this->drupalGet('user/' . $this->admin_user->uid . '/shortcuts');
$this->assertText($new_set->title, 'Generated shortcut set was listed as a choice on the user account page.');
$this->assertText($new_set->label(), 'Generated shortcut set was listed as a choice on the user account page.');
}
}
......@@ -8,7 +8,6 @@
namespace Drupal\shortcut\Tests;
use Drupal\simpletest\WebTestBase;
use stdClass;
/**
* Defines base class for shortcut test cases.
......@@ -51,7 +50,7 @@ function setUp() {
$this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
// Populate the default shortcut set.
$shortcut_set = shortcut_set_load(SHORTCUT_DEFAULT_SET_NAME);
$shortcut_set = shortcut_set_load('default');
$shortcut_set->links[] = array(
'link_path' => 'node/add',
'link_title' => st('Add content'),
......@@ -62,7 +61,7 @@ function setUp() {
'link_title' => st('Find content'),
'weight' => -19,
);
shortcut_set_save($shortcut_set);
$shortcut_set->save();
}
// Create users.
......@@ -74,29 +73,23 @@ function setUp() {
// Log in as admin and grab the default shortcut set.
$this->drupalLogin($this->admin_user);
$this->set = shortcut_set_load(SHORTCUT_DEFAULT_SET_NAME);
$this->set = shortcut_set_load('default');
shortcut_set_assign_user($this->set, $this->admin_user);
}
/**
* Creates a generic shortcut set.
*/
function generateShortcutSet($title = '', $default_links = TRUE, $set_name = '') {
$set = new stdClass();
$set->title = empty($title) ? $this->randomName(10) : $title;
// Set name is generated automatically if not set.
if (!empty($set_name)) {
$set->set_name = $set_name;
}
if ($default_links) {
$set->links = array();
$set->links[] = $this->generateShortcutLink('node/add');
$set->links[] = $this->generateShortcutLink('admin/content');
}
shortcut_set_save($set);
function generateShortcutSet($label = '', $id = NULL, $default_links = TRUE) {
$set = entity_create('shortcut', array(
'id' => isset($id) ? $id : strtolower($this->randomName()),
'label' => empty($label) ? $this->randomString() : $label,
'links' => (!$default_links) ? array() : array(
$this->generateShortcutLink('node/add'),
$this->generateShortcutLink('admin/content'),
),
));
$set->save();
return $set;
}
......@@ -106,7 +99,7 @@ function generateShortcutSet($title = '', $default_links = TRUE, $set_name = '')
function generateShortcutLink($path, $title = '') {
$link = array(
'link_path' => $path,
'link_title' => !empty($title) ? $title : $this->randomName(10),
'link_title' => !empty($title) ? $title : $this->randomName(),
);
return $link;
......
This diff is collapsed.
......@@ -5,60 +5,21 @@
* Install, update and uninstall functions for the shortcut module.
*/
/**
* Implements hook_install().
*/
function shortcut_install() {
$t = get_t();
// Create an initial default shortcut set.
$shortcut_set = new stdClass();
$shortcut_set->title = $t('Default');
$shortcut_set->links = array();
shortcut_set_save($shortcut_set);
}
/**
* Implements hook_uninstall().
*/
function shortcut_uninstall() {
drupal_load('module', 'shortcut');
// Delete the menu links associated with each shortcut set.
foreach (shortcut_sets() as $shortcut_set) {
menu_delete_links($shortcut_set->set_name);
}
// @todo find a way to clean-up associated menu links.
/*foreach (entity_load_multiple('shortcut') as $shortcut_set) {
menu_delete_links('shortcut-' . $shortcut_set->id());
}*/
}
/**
* Implements hook_schema().
*/
function shortcut_schema() {
$schema['shortcut_set'] = array(
'description' => 'Stores information about sets of shortcuts links.',
'fields' => array(
'set_name' => array(
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => '',
'description' => "Primary Key: The {menu_links}.menu_name under which the set's links are stored.",
),
'title' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'The title of the set.',
),
),
'primary key' => array('set_name'),
'foreign keys' => array(
'menu_name' => array(
'table' => 'menu_links',