2007-08-30 16:27:12 +00:00
< ? php
/**
* @ file
2008-12-30 16:43:20 +00:00
* Administrative page callbacks for menu module .
2007-08-30 16:27:12 +00:00
*/
2013-02-08 23:55:25 +00:00
use Drupal\menu_link\Plugin\Core\Entity\MenuLink ;
2013-01-10 18:33:53 +00:00
use Drupal\system\Plugin\Core\Entity\Menu ;
2013-02-01 16:21:13 +00:00
use Drupal\Component\Utility\NestedArray ;
2013-02-28 02:14:38 +00:00
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException ;
2012-06-04 12:06:09 +00:00
2007-08-30 16:27:12 +00:00
/**
* Menu callback which shows an overview page of all the custom menus and their descriptions .
*/
function menu_overview_page () {
2013-05-02 06:42:27 +00:00
return Drupal :: entityManager ()
2013-01-19 04:58:23 +00:00
-> getListController ( 'menu' )
-> render ();
2009-03-28 03:58:55 +00:00
}
/**
2013-01-10 18:33:53 +00:00
* Page callback : Presents the menu creation form .
2010-04-13 15:23:03 +00:00
*
2013-01-10 18:33:53 +00:00
* @ return array
* A form array as expected by drupal_render () .
2010-04-13 15:23:03 +00:00
*
2013-01-10 18:33:53 +00:00
* @ see menu_menu ()
2009-03-28 03:58:55 +00:00
*/
2013-01-10 18:33:53 +00:00
function menu_menu_add () {
$menu = entity_create ( 'menu' , array ());
return entity_get_form ( $menu );
}
2009-05-24 17:39:35 +00:00
2013-01-10 18:33:53 +00:00
/**
* Page callback : Presents the menu edit form .
*
* @ param \Drupal\system\Plugin\Core\Entity\Menu $menu
* The menu to edit .
*
* @ return array
* A form array as expected by drupal_render () .
*
* @ see menu_menu ()
*/
function menu_menu_edit ( Menu $menu ) {
drupal_set_title ( t ( 'Edit menu %label' , array ( '%label' => $menu -> label ())), PASS_THROUGH );
return entity_get_form ( $menu );
2007-08-30 16:27:12 +00:00
}
/**
2013-02-01 16:21:13 +00:00
* Form constructor to edit an entire menu tree at once .
2007-11-09 22:14:41 +00:00
*
2009-03-31 01:45:31 +00:00
* Shows for one menu the menu links accessible to the current user and
2007-11-09 22:14:41 +00:00
* relevant operations .
2013-02-01 16:21:13 +00:00
*
* This form constructor can be integrated as a section into another form . It
* relies on the following keys in $form_state :
* - menu : A loaded menu definition , as returned by menu_load () .
* - menu_overview_form_parents : An array containing the parent keys to this
* form .
* Forms integrating this section should call menu_overview_form_submit () from
* their form submit handler .
2007-08-30 16:27:12 +00:00
*/
2013-02-01 16:21:13 +00:00
function menu_overview_form ( $form , & $form_state ) {
2007-11-17 14:25:23 +00:00
global $menu_admin ;
2013-02-01 16:21:13 +00:00
// Ensure that menu_overview_form_submit() knows the parents of this form
// section.
$form [ '#tree' ] = TRUE ;
$form [ '#theme' ] = 'menu_overview_form' ;
$form_state += array ( 'menu_overview_form_parents' => array ());
2013-06-07 10:48:55 +00:00
$form [ '#attached' ][ 'css' ] = array ( drupal_get_path ( 'module' , 'menu' ) . '/css/menu.admin.css' );
2013-02-08 23:55:25 +00:00
2009-08-24 01:49:41 +00:00
$links = array ();
2013-04-11 12:55:05 +00:00
$query = Drupal :: entityQuery ( 'menu_link' )
2013-02-08 23:55:25 +00:00
-> condition ( 'menu_name' , $form_state [ 'menu' ] -> id ());
for ( $i = 1 ; $i <= MENU_MAX_DEPTH ; $i ++ ) {
$query -> sort ( 'p' . $i , 'ASC' );
}
$result = $query -> execute ();
if ( ! empty ( $result )) {
$links = menu_link_load_multiple ( $result );
2009-08-24 01:49:41 +00:00
}
2013-02-08 23:55:25 +00:00
2012-07-28 16:23:35 +00:00
$delta = max ( count ( $links ), 50 );
2009-08-24 01:49:41 +00:00
$tree = menu_tree_data ( $links );
2007-08-30 16:27:12 +00:00
$node_links = array ();
menu_tree_collect_node_links ( $tree , $node_links );
2008-01-21 12:12:44 +00:00
// We indicate that a menu administrator is running the menu access check.
2007-11-17 14:25:23 +00:00
$menu_admin = TRUE ;
2007-08-30 16:27:12 +00:00
menu_tree_check_access ( $tree , $node_links );
2007-11-17 14:25:23 +00:00
$menu_admin = FALSE ;
2007-11-09 22:14:41 +00:00
2013-02-01 16:21:13 +00:00
// Inline the "Add link" action so it displays right above the table of
// links. No access check needed, since this form has the same access
// restriction as adding menu items to the menu.
$form [ 'inline_actions' ] = array (
'#prefix' => '<ul class="action-links">' ,
'#suffix' => '</ul>' ,
);
$form [ 'inline_actions' ][ 'add' ] = array (
'#theme' => 'menu_local_action' ,
'#link' => array (
'href' => 'admin/structure/menu/manage/' . $form_state [ 'menu' ] -> id () . '/add' ,
'title' => t ( 'Add link' ),
),
);
2012-07-28 16:23:35 +00:00
$form = array_merge ( $form , _menu_overview_tree_form ( $tree , $delta ));
2013-02-01 16:21:13 +00:00
$form [ '#empty_text' ] = t ( 'There are no menu links yet. <a href="@link">Add link</a>.' , array ( '@link' => url ( 'admin/structure/menu/manage/' . $form_state [ 'menu' ] -> id () . '/add' )));
2010-01-30 07:59:26 +00:00
2007-11-09 22:14:41 +00:00
return $form ;
2007-08-30 16:27:12 +00:00
}
/**
2007-11-09 22:14:41 +00:00
* Recursive helper function for menu_overview_form () .
2010-06-26 17:43:22 +00:00
*
* @ param $tree
* The menu_tree retrieved by menu_tree_data .
2012-07-28 16:23:35 +00:00
* @ param $delta
* The default number of menu items used in the menu weight selector is 50.
2007-08-30 16:27:12 +00:00
*/
2012-07-28 16:23:35 +00:00
function _menu_overview_tree_form ( $tree , $delta = 50 ) {
2009-06-07 02:30:13 +00:00
$form = & drupal_static ( __FUNCTION__ , array ( '#tree' => TRUE ));
2007-08-30 16:27:12 +00:00
foreach ( $tree as $data ) {
2013-06-12 16:45:28 +00:00
$title = '' ;
2007-08-30 16:27:12 +00:00
$item = $data [ 'link' ];
// Don't show callbacks; these have $item['hidden'] < 0.
2007-11-24 20:59:32 +00:00
if ( $item && $item [ 'hidden' ] >= 0 ) {
2008-04-14 17:48:46 +00:00
$mlid = 'mlid:' . $item [ 'mlid' ];
2007-11-09 22:14:41 +00:00
$form [ $mlid ][ '#item' ] = $item ;
2009-08-22 14:34:23 +00:00
$form [ $mlid ][ '#attributes' ] = $item [ 'hidden' ] ? array ( 'class' => array ( 'menu-disabled' )) : array ( 'class' => array ( 'menu-enabled' ));
2012-08-18 11:11:59 +00:00
$form [ $mlid ][ 'title' ][ '#markup' ] = l ( $item [ 'title' ], $item [ 'href' ], $item [ 'localized_options' ]);
if ( $item [ 'hidden' ]) {
$form [ $mlid ][ 'title' ][ '#markup' ] .= ' (' . t ( 'disabled' ) . ')' ;
}
elseif ( $item [ 'link_path' ] == 'user' && $item [ 'module' ] == 'system' ) {
$form [ $mlid ][ 'title' ][ '#markup' ] .= ' (' . t ( 'logged in users only' ) . ')' ;
}
2007-11-09 22:14:41 +00:00
$form [ $mlid ][ 'hidden' ] = array (
'#type' => 'checkbox' ,
2010-10-20 01:31:07 +00:00
'#title' => t ( 'Enable @title menu link' , array ( '@title' => $item [ 'title' ])),
'#title_display' => 'invisible' ,
2007-11-09 22:14:41 +00:00
'#default_value' => ! $item [ 'hidden' ],
);
2007-11-20 10:18:43 +00:00
$form [ $mlid ][ 'weight' ] = array (
'#type' => 'weight' ,
2012-07-28 16:23:35 +00:00
'#delta' => $delta ,
2010-06-26 17:43:22 +00:00
'#default_value' => $item [ 'weight' ],
2010-06-20 17:34:51 +00:00
'#title_display' => 'invisible' ,
2010-10-20 01:31:07 +00:00
'#title' => t ( 'Weight for @title' , array ( '@title' => $item [ 'title' ])),
2007-11-20 10:18:43 +00:00
);
$form [ $mlid ][ 'mlid' ] = array (
'#type' => 'hidden' ,
'#value' => $item [ 'mlid' ],
);
$form [ $mlid ][ 'plid' ] = array (
2010-06-20 17:34:51 +00:00
'#type' => 'hidden' ,
2010-06-26 17:43:22 +00:00
'#default_value' => $item [ 'plid' ],
2007-11-20 10:18:43 +00:00
);
2007-11-09 22:14:41 +00:00
// Build a list of operations.
2007-08-30 16:27:12 +00:00
$operations = array ();
2012-10-09 19:49:07 +00:00
$links = array ();
$links [ 'edit' ] = array (
2013-02-16 22:47:28 +00:00
'title' => t ( 'Edit' ),
2012-10-09 19:49:07 +00:00
'href' => 'admin/structure/menu/item/' . $item [ 'mlid' ] . '/edit' ,
);
2013-02-16 22:47:28 +00:00
$operations [ 'edit' ] = array ( '#type' => 'link' , '#title' => t ( 'Edit' ), '#href' => 'admin/structure/menu/item/' . $item [ 'mlid' ] . '/edit' );
2007-08-30 16:27:12 +00:00
// Only items created by the menu module can be deleted.
2007-12-06 21:35:14 +00:00
if ( $item [ 'module' ] == 'menu' || $item [ 'updated' ] == 1 ) {
2012-10-09 19:49:07 +00:00
$links [ 'delete' ] = array (
2013-02-16 22:47:28 +00:00
'title' => t ( 'Delete' ),
2012-10-09 19:49:07 +00:00
'href' => 'admin/structure/menu/item/' . $item [ 'mlid' ] . '/delete' ,
);
2013-02-16 22:47:28 +00:00
$operations [ 'delete' ] = array ( '#type' => 'link' , '#title' => t ( 'Delete' ), '#href' => 'admin/structure/menu/item/' . $item [ 'mlid' ] . '/delete' );
2007-08-30 16:27:12 +00:00
}
// Set the reset column.
elseif ( $item [ 'module' ] == 'system' && $item [ 'customized' ]) {
2012-10-09 19:49:07 +00:00
$links [ 'reset' ] = array (
2013-02-16 22:47:28 +00:00
'title' => t ( 'Reset' ),
2012-10-09 19:49:07 +00:00
'href' => 'admin/structure/menu/item/' . $item [ 'mlid' ] . '/reset' ,
);
2013-02-16 22:47:28 +00:00
$operations [ 'reset' ] = array ( '#type' => 'link' , '#title' => t ( 'Reset' ), '#href' => 'admin/structure/menu/item/' . $item [ 'mlid' ] . '/reset' );
2007-08-30 16:27:12 +00:00
}
2012-10-09 19:49:07 +00:00
$form [ $mlid ][ 'operations' ] = array (
'#type' => 'operations' ,
'#links' => $links ,
);
2007-08-30 16:27:12 +00:00
}
2007-11-09 22:14:41 +00:00
2007-08-30 16:27:12 +00:00
if ( $data [ 'below' ]) {
2012-07-28 16:23:35 +00:00
_menu_overview_tree_form ( $data [ 'below' ], $delta );
2007-11-09 22:14:41 +00:00
}
}
return $form ;
}
2007-11-20 10:18:43 +00:00
/**
* Submit handler for the menu overview form .
2007-11-20 13:24:54 +00:00
*
2007-11-20 10:18:43 +00:00
* This function takes great care in saving parent items first , then items
* underneath them . Saving items in the incorrect order can break the menu tree .
2007-11-20 13:24:54 +00:00
*
2007-11-20 10:18:43 +00:00
* @ see menu_overview_form ()
*/
2013-02-01 16:21:13 +00:00
function menu_overview_form_submit ( $complete_form , & $form_state ) {
// Form API supports constructing and validating self-contained sections
// within forms, but does not allow to handle the form section's submission
// equally separated yet. Therefore, we use a $form_state key to point to
// the parents of the form section.
$parents = $form_state [ 'menu_overview_form_parents' ];
$input = NestedArray :: getValue ( $form_state [ 'input' ], $parents );
$form = & NestedArray :: getValue ( $complete_form , $parents );
2007-11-20 10:18:43 +00:00
// When dealing with saving menu items, the order in which these items are
// saved is critical. If a changed child item is saved before its parent,
// the child item could be saved with an invalid path past its immediate
// parent. To prevent this, save items in the form in the same order they
2013-02-01 16:21:13 +00:00
// are sent, ensuring parents are saved first, then their children.
2007-11-20 10:18:43 +00:00
// See http://drupal.org/node/181126#comment-632270
2013-03-09 05:46:58 +00:00
$order = is_array ( $input ) ? array_flip ( array_keys ( $input )) : array ();
2013-02-01 16:21:13 +00:00
// Update our original form with the new order.
$form = array_intersect_key ( array_merge ( $order , $form ), $form );
2007-11-20 10:18:43 +00:00
$updated_items = array ();
2009-10-09 17:16:46 +00:00
$fields = array ( 'weight' , 'plid' );
2007-11-09 22:14:41 +00:00
foreach ( element_children ( $form ) as $mlid ) {
2007-11-20 10:18:43 +00:00
if ( isset ( $form [ $mlid ][ '#item' ])) {
2007-11-09 22:14:41 +00:00
$element = $form [ $mlid ];
2007-11-20 10:18:43 +00:00
// Update any fields that have changed in this menu item.
foreach ( $fields as $field ) {
if ( $element [ $field ][ '#value' ] != $element [ $field ][ '#default_value' ]) {
$element [ '#item' ][ $field ] = $element [ $field ][ '#value' ];
$updated_items [ $mlid ] = $element [ '#item' ];
}
}
// Hidden is a special case, the value needs to be reversed.
2007-11-09 22:14:41 +00:00
if ( $element [ 'hidden' ][ '#value' ] != $element [ 'hidden' ][ '#default_value' ]) {
2009-03-16 20:31:11 +00:00
// Convert to integer rather than boolean due to PDO cast to string.
$element [ '#item' ][ 'hidden' ] = $element [ 'hidden' ][ '#value' ] ? 0 : 1 ;
2007-11-20 10:18:43 +00:00
$updated_items [ $mlid ] = $element [ '#item' ];
2007-11-09 22:14:41 +00:00
}
2007-08-30 16:27:12 +00:00
}
}
2007-11-20 10:18:43 +00:00
// Save all our changed items to the database.
foreach ( $updated_items as $item ) {
2007-11-21 19:12:00 +00:00
$item [ 'customized' ] = 1 ;
2007-11-20 10:18:43 +00:00
menu_link_save ( $item );
}
2007-08-30 16:27:12 +00:00
}
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for the menu overview form into a table .
*
* @ param $variables
* An associative array containing :
* - form : A render element representing the form .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2007-08-30 16:27:12 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_menu_overview_form ( $variables ) {
$form = $variables [ 'form' ];
2007-11-26 16:19:37 +00:00
drupal_add_tabledrag ( 'menu-overview' , 'match' , 'parent' , 'menu-plid' , 'menu-plid' , 'menu-mlid' , TRUE , MENU_MAX_DEPTH - 1 );
2007-11-20 10:18:43 +00:00
drupal_add_tabledrag ( 'menu-overview' , 'order' , 'sibling' , 'menu-weight' );
$header = array (
2009-03-20 19:18:11 +00:00
t ( 'Menu link' ),
2009-08-22 14:34:23 +00:00
array ( 'data' => t ( 'Enabled' ), 'class' => array ( 'checkbox' )),
2007-11-20 10:18:43 +00:00
t ( 'Weight' ),
2012-10-09 19:49:07 +00:00
t ( 'Operations' ),
2007-11-20 10:18:43 +00:00
);
2007-11-09 22:14:41 +00:00
$rows = array ();
foreach ( element_children ( $form ) as $mlid ) {
if ( isset ( $form [ $mlid ][ 'hidden' ])) {
$element = & $form [ $mlid ];
2007-11-20 10:18:43 +00:00
// Add special classes to be used for tabledrag.js.
2009-08-22 14:34:23 +00:00
$element [ 'plid' ][ '#attributes' ][ 'class' ] = array ( 'menu-plid' );
$element [ 'mlid' ][ '#attributes' ][ 'class' ] = array ( 'menu-mlid' );
$element [ 'weight' ][ '#attributes' ][ 'class' ] = array ( 'menu-weight' );
2007-11-20 10:18:43 +00:00
// Change the parent field to a hidden. This allows any value but hides the field.
$element [ 'plid' ][ '#type' ] = 'hidden' ;
2007-11-09 22:14:41 +00:00
$row = array ();
2009-10-09 01:00:08 +00:00
$row [] = theme ( 'indentation' , array ( 'size' => $element [ '#item' ][ 'depth' ] - 1 )) . drupal_render ( $element [ 'title' ]);
2009-10-09 17:16:46 +00:00
$row [] = array ( 'data' => drupal_render ( $element [ 'hidden' ]), 'class' => array ( 'checkbox' , 'menu-enabled' ));
2007-11-20 10:18:43 +00:00
$row [] = drupal_render ( $element [ 'weight' ]) . drupal_render ( $element [ 'plid' ]) . drupal_render ( $element [ 'mlid' ]);
2012-10-09 19:49:07 +00:00
$row [] = drupal_render ( $element [ 'operations' ]);
2007-08-30 16:27:12 +00:00
2007-11-09 22:14:41 +00:00
$row = array_merge ( array ( 'data' => $row ), $element [ '#attributes' ]);
2009-08-22 14:34:23 +00:00
$row [ 'class' ][] = 'draggable' ;
2007-11-09 22:14:41 +00:00
$rows [] = $row ;
}
}
$output = '' ;
2009-06-27 23:49:19 +00:00
if ( empty ( $rows )) {
$rows [] = array ( array ( 'data' => $form [ '#empty_text' ], 'colspan' => '7' ));
2007-11-09 22:14:41 +00:00
}
2013-02-01 16:21:13 +00:00
$output .= drupal_render ( $form [ 'inline_actions' ]);
2009-10-09 01:00:08 +00:00
$output .= theme ( 'table' , array ( 'header' => $header , 'rows' => $rows , 'attributes' => array ( 'id' => 'menu-overview' )));
2009-02-03 18:55:32 +00:00
$output .= drupal_render_children ( $form );
2007-11-09 22:14:41 +00:00
return $output ;
2007-08-30 16:27:12 +00:00
}
/**
2010-10-13 13:43:21 +00:00
* Returns whether a menu name already exists .
*
* @ see menu_edit_menu ()
* @ see form_validate_machine_name ()
2007-08-30 16:27:12 +00:00
*/
2010-10-13 13:43:21 +00:00
function menu_edit_menu_name_exists ( $value ) {
2013-01-10 18:33:53 +00:00
$custom_exists = entity_load ( 'menu' , $value );
2010-10-13 13:43:21 +00:00
// 'menu-' is added to the menu name to avoid name-space conflicts.
$value = 'menu-' . $value ;
2013-04-11 12:55:05 +00:00
$link_exists = Drupal :: entityQuery ( 'menu_link' ) -> condition ( 'menu_name' , $value ) -> range ( 0 , 1 ) -> count () -> execute ();
2009-05-15 04:07:20 +00:00
2010-10-13 13:43:21 +00:00
return $custom_exists || $link_exists ;
2007-08-30 16:27:12 +00:00
}
/**
* Submit function for adding or editing a custom menu .
*/
function menu_edit_menu_submit ( $form , & $form_state ) {
$menu = $form_state [ 'values' ];
2009-09-28 22:14:31 +00:00
$path = 'admin/structure/menu/manage/' ;
2007-08-30 16:27:12 +00:00
if ( $form [ '#insert' ]) {
// Add 'menu-' to the menu name to help avoid name-space conflicts.
2013-01-10 18:33:53 +00:00
$menu [ 'id' ] = 'menu-' . $menu [ 'id' ];
2013-02-08 23:55:25 +00:00
$system_link = entity_load_multiple_by_properties ( 'menu_link' , array ( 'link_path' => 'admin/structure/menu' , 'module' => 'system' ));
$system_link = reset ( $system_link );
$menu_link = entity_create ( 'menu_link' , array (
'link_title' => $menu [ 'label' ],
'link_path' => $path . $menu [ 'id' ],
'router_path' => $path . '%' ,
'plid' => $system_link -> id (),
));
$menu_link -> save ();
2009-10-09 08:02:25 +00:00
menu_save ( $menu );
2007-08-30 16:27:12 +00:00
}
else {
2009-10-09 08:02:25 +00:00
menu_save ( $menu );
2013-02-08 23:55:25 +00:00
$menu_links = entity_load_multiple_by_properties ( 'menu_link' , array ( 'link_path' => $path . $menu [ 'id' ]));
foreach ( $menu_links as $menu_link ) {
$menu_link -> link_title = $menu [ 'label' ];
$menu_link -> save ();
2007-08-30 16:27:12 +00:00
}
}
2010-05-04 20:31:53 +00:00
drupal_set_message ( t ( 'Your configuration has been saved.' ));
2013-01-10 18:33:53 +00:00
$form_state [ 'redirect' ] = $path . $menu [ 'id' ];
2007-08-30 16:27:12 +00:00
}
/**
2013-02-08 23:55:25 +00:00
* Menu callback : Provides the menu link submission form .
*
* @ param \Drupal\system\Plugin\Core\Entity\Menu $menu
* An entity representing a custom menu .
*
* @ return
* Returns the menu link submission form .
*/
function menu_link_add ( Menu $menu ) {
$menu_link = entity_create ( 'menu_link' , array (
'mlid' => 0 ,
'plid' => 0 ,
'menu_name' => $menu -> id (),
));
drupal_set_title ( t ( 'Add menu link' ));
return entity_get_form ( $menu_link );
}