Add custom menu API

Amitaibu - May 26, 2009 - 11:19
Project:Drupal
Version:7.x-dev
Component:menu system
Category:feature request
Priority:normal
Assigned:Unassigned
Status:closed
Issue tags:API addition, API change, API clean-up, DX (Developer Experience), Needs Documentation, Needs tests
Description

While working on an hook_update_N() I needed to pragmatically add a new custom menu. This patch allows doing it using an API.

AttachmentSizeStatusTest resultOperations
menu-custom-save-1.patch2.71 KBIdleFailed: Failed to install HEAD.View details

#1

Amitaibu - May 26, 2009 - 11:39

Test added to patch.

AttachmentSizeStatusTest resultOperations
menu-custom-save-2.patch3.98 KBIdleFailed: Failed to install HEAD.View details

#2

Berdir - May 26, 2009 - 11:52
Status:needs review» needs work

+function menu_custom_save($menu = array()) {
+  $menu += array('description' => '');
+  $menus = menu_get_menus();
+  if (empty($menus[$menu['menu_name']])) {
+    db_insert('menu_custom')
+      ->fields(array(
+        'menu_name' => $menu['menu_name'],
+        'title' => $menu['title'],
+        'description' => $menu['description'],
+      ))
+      ->execute();
+  }
+  else {
+    db_update('menu_custom')
+      ->fields(array(
+        'title' => $menu['title'],
+        'description' => $menu['description'],
+      ))
+      ->condition('menu_name', $menu['menu_name'])
+      ->execute();   
+  }

If we explicitly only use title, description and menu_name, why not use menu_custom_save($menu_name, $title, $description = '') ?

#3

Amitaibu - May 26, 2009 - 12:15
Status:needs work» needs review

10x Berdir, here's the patch according to your comments.

AttachmentSizeStatusTest resultOperations
menu-custom-save-3.patch3.55 KBIdleFailed: Failed to install HEAD.View details

#4

Berdir - May 26, 2009 - 12:54

looks better now :)

Optioanl

:)

#5

Amitaibu - May 26, 2009 - 13:21

Fix typo.

AttachmentSizeStatusTest resultOperations
menu-custom-save-4.patch3.55 KBIdleFailed: Failed to install HEAD.View details

#6

chx - May 26, 2009 - 23:28

The tests should use random string/name.

#7

moshe weitzman - May 27, 2009 - 02:15

What's the advantage of a random string? Seems equivalent to me.

#8

Amitaibu - May 27, 2009 - 13:54

Test is now with random strings.

AttachmentSizeStatusTest resultOperations
menu-custom-save-8.patch3.7 KBIdleFailed: Failed to install HEAD.View details

#9

catch - June 1, 2009 - 23:22
Status:needs review» reviewed & tested by the community

Looks great.

#10

Amitaibu - June 10, 2009 - 17:45

chx in IRC asked if we really need to have this function - maybe just a drupal_write_record() is ok. I think that maybe it's better to have this API function for DX. Any thoughts?

#11

tic2000 - June 10, 2009 - 19:18

For me the function name doesn't sound right. menu_save_item, menu_set_item maybe?

#12

catch - June 10, 2009 - 19:50

We have menu_link_save() for custom menu links, this is for top level menus.

I'm pretty sure I've seen people ask how to make top level menus before, it'd be nice for them to find (or be directed) to an API function even if it's as light as this one.

#13

bjaspan - June 11, 2009 - 04:03

chx asked for my opinion on this but my battery is dying, will check in later

(translation: "subscribe")

#14

System Message - June 24, 2009 - 01:30
Status:reviewed & tested by the community» needs work

The last submitted patch failed testing.

#15

Amitaibu - August 17, 2009 - 13:26
Status:needs work» needs review

re-roll.

AttachmentSizeStatusTest resultOperations
menu-custom-save-15.patch3.44 KBIdleFailed: Failed to apply patch.View details

#16

System Message - August 17, 2009 - 13:40
Status:needs review» needs work

The last submitted patch failed testing.

#17

Amitaibu - August 19, 2009 - 06:37
Status:needs work» needs review

hmm, I still need to learn how to patch with git... I hope Testbot will like this one.

AttachmentSizeStatusTest resultOperations
menu-custom-save-17.patch3.43 KBIdleFailed: Failed to install HEAD.View details

#18

dropcube - August 27, 2009 - 05:08
Title:Add menu_custom_save API» Add custom menu API
Category:feature request» task
Priority:normal» critical
Status:needs review» needs work

For API consistency, we should also have a menu_custom_delete() function. Also, this API function should be in menu.module, the module that allows custom menus, not in menu.inc.

This API would be a great addition, to be used in install profiles, ... etc., and for a better developer experience. Tagging accordingly.

#19

dropcube - August 27, 2009 - 05:16
Assigned to:Anonymous» dropcube

I will take care of it.

#20

dropcube - August 27, 2009 - 06:12
Status:needs work» needs review

Added the following changes to the patch at #17.

- menu_custom_save() moved from menu.inc to menu.module, the module that allows custom menus.
- added menu_custom_delete() to delete custom menu and menu links associated.
- menu_custom_save() should receive a $custom_menu object, for consistency with others API in core.
- Used menu_custom_save() in menu.install, and toolbar.install instead of manually executing queries.
- Used menu_custom_delete() in the menu delete form submit handlers in menu.admin.inc.

AttachmentSizeStatusTest resultOperations
custom-menu-API.patch7.6 KBIdleFailed: 13452 passes, 2 fails, 0 exceptionsView details

#21

Davy Van Den Bremt - August 27, 2009 - 15:24

Looks great. Have been creating some menu and items. Didn't find any other referentes to menu_custom either.

#22

Pasqualle - August 27, 2009 - 16:42

+ * @param $custom_menu
+ *   The custom menu object or array to be saved.
+ * @return
+ *   Status constant indicating if role was created or updated.
+ *   Failure to write the user role record will return FALSE. Otherwise.
+ *   SAVED_NEW or SAVED_UPDATED is returned depending on the operation
+ *   performed.
+ */
+ function menu_custom_save($custom_menu) {

1. I do not like when a function parameter type is not specified exactly. Would it be a problem to allow only array type $custom_menu? As I see it is used as array everywhere.
2. I do not see any return statement in this function.

#23

dropcube - August 27, 2009 - 19:22

@Pasqualle, thanks for the review.

1. I do not like when a function parameter type is not specified exactly. Would it be a problem to allow only array type $custom_menu? As I see it is used as array everywhere.

An object is being used for consistency with other module_*_save() API functions in core. IMO, it's PHP, we do not need strict type checking.

2. I do not see any return statement in this function.

No, no return statement , removed the comment.

AttachmentSizeStatusTest resultOperations
custom-menu-API-23.patch7.35 KBIdleFailed: Failed to run tests.View details

#24

Pasqualle - August 27, 2009 - 20:03

That's right, we do not need strict type checking, as it is PHP, but it would be nice to have. So when I see a variable named $custom_menu then I would know what type should I expect.
As I see (http://api.drupal.org/api/search/7/_save) there is only 1 *_save() function (file_save) where different variable types are allowed, and I would rather fix that also than creating a new one..

#25

Pasqualle - August 27, 2009 - 20:28

the file_save() issue #561520: $file is an object

#26

dropcube - August 27, 2009 - 21:00

Well, I suggest to leave it as an object, and do the typecasting so that we don't have to change everywhere an array is used. Then, we can convert the other structures to stdClass if you prefer.
4 days to code freeze!!!

#27

Pasqualle - August 27, 2009 - 21:34

I do not know which issue are you referencing to. The $custom_menu is an array everywhere, so the function parameter should be an array. The $file is an object everywhere so the function parameter should be an object. I do not understand what else do you want to change..
I am happy with array and object variables as function parameters, I just want the type to be specified, as it is specified (mostly?) everywhere in Drupal.

#28

Amitaibu - August 27, 2009 - 21:37
Status:needs review» needs work

In #2 Berdir asked
> why not use menu_custom_save($menu_name, $title, $description = '') ?

Which in terms of DX I think is better in this situation.

The name of the custom menu to be deleted..

Nit pick - Two dots(..)

Also, how about adding a test for the menu delete? (I don't have a dev enviorement on this computer so can;t re-roll myself...)

#29

Pasqualle - August 27, 2009 - 22:03

@Amitaibu: only one variable should be used for the item to be inserted into db. that is the common format of *_save functions..

#30

dropcube - August 27, 2009 - 22:35
Status:needs work» needs review

For consistency with other *_save() API functions in core, we should use an object as the parameter to that function.
It's easy to read, can be modified inside the function and the changes persists without requiring to be passed by reference, etc...

- Removed the trailing dot in the docs.

AttachmentSizeStatusTest resultOperations
custom-menu-API-30.patch7.35 KBIdleFailed: 13491 passes, 2 fails, 0 exceptionsView details

#31

Pasqualle - August 27, 2009 - 23:22

changed the menu_custom_save() function to accept array type parameter only. $menu and $custom_menu is used as array, so the function parameter should be an array. There are many *_save() functions with array parameters, so the function is consistent with the rest of core..

moved menu_custom_save() and menu_custom_delete() into menu.inc as these functions should be accessible even the menu module is disabled.

AttachmentSizeStatusTest resultOperations
473082-31-custom-menu-API.patch7.17 KBIdleFailed: 13453 passes, 2 fails, 0 exceptionsView details

#32

dropcube - August 28, 2009 - 05:39

Custom menus are handled by menu.module, which in fact, creates the table {menu_custom}. So, those API functions should live in menu.module, not in menu.inc. If the menu.module is not installed, you probably don't need to use those functions.

Note, for example, that toolbar.module has menu.module as a dependency.

About the parameter as array or as object, I do not think that is something worth further discussion, whatever the decision, for me is fine. The most important is to get this API in before the freeze.

#33

Pasqualle - August 29, 2009 - 15:01

you are right, the table is created with menu.module therefore the functions should be in menu module.

but we should decide which form should be used:

<?php
function mymodule_install() {
 
menu_custom_save(..)
}
function
mymodule_uninstall() {
 
menu_custom_delete(..)
}
?>

vs
<?php
function mymodule_install() {
  if
module_exists('menu') {
   
menu_custom_save(..)
  }
}
function
mymodule_uninstall() {
  if
module_exists('menu') {
   
menu_custom_delete(..)
  }
}
function
mymodule_modules_installed($modules) {
  if (
in_array('menu', $modules)) {
   
menu_custom_save(..)
  }
}
?>

I think 99% of Drupal sites have the menu module enabled, so moving the creation of menu_custom table to system.install is still an option, to make the code cleaner.. If it is too much here, then a new issue should be created, and menu_save() and menu_delete() should be moved back to menu.module for this patch..

#34

dropcube - August 29, 2009 - 16:41

I think 99% of Drupal sites have the menu module enabled, so moving the creation of menu_custom table to system.install is still an option, to make the code cleaner..

No. On the contrary, each module should be responsible of installing it's own tables and stuff, handling it's updates, etc... I don't want that table created if I don't 'want' menu.module enabled in my application/site/install profile, etc... Well, that's not the point of that issue.

@Pasqualle, can we mark one the patchs in this issue as RTBC ? Code freeze is here ;). It's a valuable addition, and it's is a really simple patch. So, let's go on.

#35

Pasqualle - August 29, 2009 - 17:14

as I see #31 is the closest to RTBC, I will just move the functions back to menu.module..

#36

Pasqualle - August 29, 2009 - 17:28
AttachmentSizeStatusTest resultOperations
473082-36-custom-menu-API.patch7.42 KBIdleFailed: Invalid PHP syntax in modules/menu/menu.admin.inc.View details

#37

dropcube - August 30, 2009 - 07:03

I think it's ready to go.

- Updated the tests to check that all menu links associated to a menu were removed from database when then menu is deleted.

AttachmentSizeStatusTest resultOperations
custom-menu-API-37.patch7.98 KBIdleFailed: 12642 passes, 0 fails, 36 exceptionsView details

#38

Amitaibu - August 30, 2009 - 07:41

I've added a test to the custom_menu_delete()

AttachmentSizeStatusTest resultOperations
473082-custom-menu--api-38.patch7.92 KBIdleFailed: 12590 passes, 0 fails, 27 exceptionsView details

#39

dropcube - August 30, 2009 - 07:43
Status:needs review» reviewed & tested by the community

Ok, all test passed. I think it is RTBC.

#40

Amitaibu - August 30, 2009 - 07:49
Status:reviewed & tested by the community» needs review

hmm, it didn't upload my patch.

AttachmentSizeStatusTest resultOperations
473082-custom-menu--api-38.patch7.92 KBIdleFailed: 12620 passes, 0 fails, 36 exceptionsView details

#41

Amitaibu - August 30, 2009 - 08:02

* Test from #40 was already covered.
* Fixed a query placeholder (menu_name >> :menu_name)
* Fixed a typo in the toolbar.install (Admininstration >> Administration).

AttachmentSizeStatusTest resultOperations
custom-menu-API-41.patch7.95 KBIdleFailed: 13448 passes, 2 fails, 0 exceptionsView details

#42

dropcube - August 30, 2009 - 08:20
Status:needs review» reviewed & tested by the community

#43

pwolanin - August 30, 2009 - 13:05
Category:task» feature request

This looks sensible - it should indeed be in menu module, and an API for this is one of those things that we just didn't have time for in D6.

#44

System Message - August 31, 2009 - 08:33
Status:reviewed & tested by the community» needs work

The last submitted patch failed testing.

#45

lilou - August 31, 2009 - 12:47
Status:needs work» reviewed & tested by the community

HEAD is broken.

#46

webchick - September 11, 2009 - 02:38
Status:reviewed & tested by the community» needs work

+++ modules/menu/menu.module 30 Aug 2009 07:00:56 -0000
@@ -496,3 +496,38 @@
+/**
+ * Save a custom menu.
+ *
+ * @param $custom_menu
+ *   The custom menu array. Keys are:
+ *   - menu_name    Unique key for menu.
+ *   - title        Menu title; displayed at top of block.
+ *   - description  Menu description.
+ */
+function menu_custom_save(array $custom_menu) {

If those are the only keys, I think I'd prefer to enumerate the parameters ($name, $title, $description). That'd be more user-friendly for people using IDEs.

Also, I'd prefer names like menu_save_custom_menu() and menu_delete_custom_menu() since they're more descriptive.

+++ modules/menu/menu.test 30 Aug 2009 07:01:00 -0000
@@ -87,6 +87,34 @@
+  /**
+   * Add custom menu using API.
+   */
+  function addCustomMenuApi() {

That function name is confusing; it makes it sound like you're adding your own custom menu API. :P Maybe add a Via or With or something in there to make it more clear?

+++ modules/menu/menu.test 30 Aug 2009 07:01:00 -0000
@@ -87,6 +87,34 @@
+    $menu_name = substr(md5($this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI);

Why 16 and not a constant like you have with MENU_MAX_MENU_NAME_LENGTH_UI?

I'm on crack. Are you, too?

#47

Amitaibu - September 13, 2009 - 13:41
Status:needs work» needs review

Patch addresses #46 comments.

> Why 16 and not a constant like you have with MENU_MAX_MENU_NAME_LENGTH_UI?

I kept it as is, to follow addCustomMenu() which uses '16'. I went over quickly on other tests and saw the use of explicit numbers (testPagePreviewWithRevisions() in node.test for example).

AttachmentSizeStatusTest resultOperations
473082-custom-menu-API-47.patch7.14 KBIdleFailed: 13496 passes, 2 fails, 0 exceptionsView details

#48

pwolanin - September 20, 2009 - 14:53

Should we not call the functions menu_custom_menu_save()? Generally we put the verb last like, node_save(), menu_link_save(), etc.

#49

pwolanin - September 23, 2009 - 13:43
Status:needs review» needs work
Issue tags:+API clean-up

see above - let's be more consistent in terms of funciton naming. Otherwise this is essentially done

#50

sun - September 23, 2009 - 17:45

@webchick: That's inconsistent.

I agree with pwolanin in #48. We always use the pattern [object]_[action]() for CRUD functions in core.

We also use single arguments for CRUD functions throughout core. Only the loader function usually takes an ID instead of an object.

And we already have http://api.drupal.org/api/search/7/menu_load --

Hence, I don't see why these couldn't be simply named menu_save() and menu_delete() ? Only the last one needs a special validation to not delete system menus.

Anything else would be a DrupalWTF.

#51

pwolanin - September 24, 2009 - 00:11

@sun - the table is {menu_custom} and there MUST be a significant distinction made between what these functions are operating on and hook_menu, hook_menu_alter, which are operating on the router.

so, I'd suggest going back to menu_custom_save() or menu_custom_menu_save(), or something like that.

#52

sun - September 24, 2009 - 00:48
Assigned to:dropcube» sun

#53

sun - September 24, 2009 - 01:56
Status:needs work» needs review

Alright, so our [object] is 'menu_custom'. ++consistency

Here we go.

AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.patch15.31 KBIdleFailed: Failed to apply patch.View details

#54

dropcube - September 24, 2009 - 02:48

+++ modules/menu/menu.module 24 Sep 2009 01:43:37 -0000
@@ -198,12 +198,68 @@ function menu_overview_title($menu) {
+  // Delete all links from the menu.
+  db_delete('menu_links')
+    ->condition('menu_name', $menu['menu_name'])
+    ->execute();

I think we should use API function menu_link_delete here, mainly because it invokes hook_menu_link_delete(), but this function also clear caches, update parental status for menu links, etc... so that may be an expensive operation. Thoughts ?

#55

sun - September 24, 2009 - 03:06

aha! I think that's the same mess that's happening in http://api.drupal.org/api/function/menu_delete_menu_confirm_submit/7 before the menu is deleted? ;)

#56

sun - September 24, 2009 - 03:13
Assigned to:sun» Anonymous

Doesn't seem so. However, we could load all items before deleting them and invoke hook_menu_link_delete() manually.

We should additionally clear the caches in the API function to make it consistent with other CRUD functions.

Interesting: http://api.drupal.org/api/function/menu_delete_menu_confirm_submit/7 and http://api.drupal.org/api/function/_menu_delete_item/7 invoke different functions to clear the caches.

#57

pwolanin - September 24, 2009 - 11:22

Did Rickard's hook get in to act each time we delete a menu link?

If the cache is already clear, additional calls to clear it shoudl be relatively fast right? Deleting should be a very rare operation.

#58

sun - September 24, 2009 - 17:53

Since we need to fetch the list of items anyway, we could simply set $item['plid'] = 0 and $item['has_children'] = FALSE before invoking _menu_delete_item(), so we skip the expensive and senseless operations here:

- Re-parenting of children

- _menu_update_parental_status() [which somehow looks very similar to _menu_delete_item()'s re-parenting, just acting on a different column... but anyway]

I also see that both cache clearing functions invoked by _menu_delete_item() take special care for multiple invocations:

http://api.drupal.org/api/function/menu_cache_clear/7
http://api.drupal.org/api/function/_menu_clear_page_cache/7

Which means that we actually do not have to clear the cache on our own, since _menu_delete_item() will clear all caches in case the menu contained some links.

AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.58.patch18.25 KBIdleFailed: Invalid PHP syntax in modules/menu/menu.api.php.View details

#59

System Message - September 24, 2009 - 18:05
Status:needs review» needs work

The last submitted patch failed testing.

#60

sun - September 24, 2009 - 18:09
Status:needs work» needs review

Disabled slave #44, since it returned strange results for a couple of patches.

#61

sun - September 24, 2009 - 18:19
AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.61.patch18.25 KBIdleFailed: Failed to apply patch.View details

#62

sun - September 28, 2009 - 16:03

Anyone up for approving this patch?

#63

pwolanin - September 28, 2009 - 20:42

Does it make sense to use the API function during the install hook?

#64

sun - September 28, 2009 - 21:20

Of course! It's the main reason why we want to do this after all: Stop writing raw stuff into the database and use proper API functions instead.

Instead of questioning this, we should move forward, and provide and use more API functions in installers/uninstallers and installation profiles. Text formats, filters, user roles, user permissions, and with this patch also custom menus can finally all be handled with proper functions instead of raw database queries.

#65

pwolanin - September 28, 2009 - 22:03

+ * Delete a custom menu.

The _delete function doxygen is incomplete - it should make very clear that it both deletes the custom menu AND all menu links associated with that custom menu.

#66

sun - September 28, 2009 - 23:23

Clarified PHPDoc - although we aren't so verbose in other API functions that delete user data...

Needed re-roll due to #508570: Restore URL consistency for node types and menus anyway... :)

AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.66.patch18.73 KBIdleFailed: 13487 passes, 2 fails, 0 exceptionsView details

#67

System Message - September 28, 2009 - 23:40
Status:needs review» needs work

The last submitted patch failed testing.

#68

pwolanin - September 28, 2009 - 23:45

Well, we don't necessarily delete lots of other data do we? e.g. if I delete a user, I think their content is may be retained.

#69

sun - September 29, 2009 - 01:42
Status:needs work» needs review

Fixing the tests as well. :)

AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.69.patch18.73 KBIdleFailed: Failed to apply patch.View details

#70

Dave Reid - October 4, 2009 - 02:49

Subscribing. This is so very handy for some contrib modules (devel, admin_menu, etc).

#71

Dave Reid - October 4, 2009 - 19:07

+++ modules/menu/menu.api.php 29 Sep 2009 01:04:06 -0000
@@ -220,5 +220,57 @@ function hook_menu_link_delete($link) {
+ * @return
+ *   None.

Pretty sure we don't document @return if there is no return value.

This review is powered by Dreditor.

#72

Dave Reid - October 4, 2009 - 19:08
Status:needs review» needs work

#73

sun - October 4, 2009 - 19:30
Status:needs work» needs review

Removed.

For whom is concerned: #516254: Remove @return PHPDocs where nothing is return

AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.73.patch19.34 KBIdleFailed: Failed to apply patch.View details

#74

Dave Reid - October 4, 2009 - 19:49
Status:needs review» reviewed & tested by the community

Looks good, bot likes and lots of concern has gone into this.

#75

webchick - October 5, 2009 - 01:56
Status:reviewed & tested by the community» needs work

node_save()
user_save()
comment_save()
menu_custom_save()

"One of these things is not like the other...."

I don't like "custom" being in the function name:

1) These are not for just "custom" menus, but also system-defined menus such as Navigation, Management, etc.
2) As a developer, the function I'm going to search api.drupal.org for is "menu_save", for compatibility with our other CRUD API function names. When I don't find it, I'm going to resort to db_insert() and db_delete() like our .profile file currently does.
3) Our functions map to the data concept, not to the table name. It's not users_save() even though the table is called users. It's not node_revisions_save(). Etc.

If anything, I'd rename the menu_custom table to menu if we really care about the discrepancy. But the number of people with innate knowledge of Drupal's DB internals vs. those searching through api.drupal.org is probably a 1:10000000 ratio, so I'm not that fussed about it.

#76

sun - October 5, 2009 - 08:56

First of all, straight re-roll due to conflicts.

AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.76.patch18.66 KBIdleFailed: Failed to apply patch.View details

#77

sun - October 5, 2009 - 09:07
Status:needs work» needs review

I agree with webchick, and I already wondered when I saw the naming request above (which didn't contain any reasoning).

I double-checked that these function names do not clash with other functions.

AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.77.patch16.31 KBIdleFailed: 13526 passes, 13 fails, 3 exceptionsView details

#78

sun - October 5, 2009 - 09:36

chx additionally asked in IRC, why we don't follow the usual hook_*_insert() and hook_*_update() pattern here. I replied that we couldn't, because we don't know.

But sleeping over that question helped.

Given this patch, we might even remove that man-made limitation in a follow-up issue.

AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.78.patch19.66 KBIdleFailed: Failed to apply patch.View details

#79

Rob Loach - October 6, 2009 - 19:30

Applied the patch, played around in the menu administration, added some menu items, deleted others. Looked at the code and really liked how clean it made the code. The thing I like most about it is how it moves the Block Menu handling code from the Menu module into the Block module. I'm inclined to set this to RTBC, but chx said he wanted to discuss some stuff. So, in the mean time, I'll just subscribe.

#80

sun - October 6, 2009 - 20:54

chx requested to squeeze a @todo into menu_save() to remind us to replace that 'old_name' condition with the proper db_merge() result, which should tell us whether the query inserted or updated something, which is currently not the case.

So this patch should be ready to fly.

AttachmentSizeStatusTest resultOperations
drupal.menu-custom-api.80.patch19.77 KBIdleFailed: Failed to apply patch.View details

#81

Dave Reid - October 7, 2009 - 02:28

+++ modules/menu/menu.module 6 Oct 2009 20:52:27 -0000
@@ -198,12 +198,98 @@ function menu_overview_title($menu) {
+  db_merge('menu_custom')
+    ->key(array('menu_name' => $menu['menu_name']))

If we're renaming an existing menu, won't this create a new record instead of updating the old one? Shouldn't the merge be on $menu['old_name']? Do we test when this happens?

I'm on crack. Are you, too?

#82

sun - October 7, 2009 - 09:35

@DaveReid:

+++ modules/menu/menu.api.php 6 Oct 2009 20:49:04 -0000
@@ -358,5 +358,77 @@ function hook_menu_link_delete($link) {
+ * @param $menu
...
+ *   - old_name: The current 'menu_name'. Note that internal menu names cannot
+ *     be changed after initial creation.
...
+function hook_menu_update($menu) {
+++ modules/menu/menu.module 6 Oct 2009 20:52:27 -0000
@@ -198,12 +198,98 @@ function menu_overview_title($menu) {
+function menu_save($menu) {
...
+  // Since custom menus are keyed by name and their machine-name cannot be
+  // changed, there is no real differentiation between inserting and updating a
+  // menu. To overcome this, we define the existing menu_name as 'old_name' in
+  // menu_edit_menu().

What's unclear here?

#83

Dave Reid - October 7, 2009 - 16:06
Status:needs review» reviewed & tested by the community

@tha_sun: Listen up kids, don't drink and review!

My only concern is taken care of, code is good, love the APIs, test bot likes...RTBC'd!

#84

webchick - October 9, 2009 - 08:02
Status:reviewed & tested by the community» needs work
Issue tags:+Needs Documentation

Good stuff. Committed to HEAD!

This needs to be documented in the upgrade guide.

#85

Amitaibu - October 11, 2009 - 09:13
Priority:critical» normal
Status:needs work» needs review

It seems I can't edit the convert 6 to 7 page, so here's it is. Someone with better English should go over it :)

---

In Drupal 6 in order to create a custom menu (i.e. a menu you would create via admin/build/menu/add) you had to query the {menu_custom} table yourself.

In D7 several API functions to create, update and delete custom menus and related hooks were added.

<?php
function foo() {
 
$menu = array(
   
'title' => 'My menu',
   
'menu_name' => 'my_menu',
   
'description' => 'My custom menu',
  );
 
// Add a new custom menu.
 
menu_save($menu);

 
// Delete the custom menu.
  // Although only the 'menu_name' key is required, we pass the full
  // $menu, so other modules may act on it.
 
menu_delete($menu);
}

function
foo_menu_delete($menu) {
  if (
$menu['menu_name'] == 'my_menu') {
   
drupal_set_mesasge(t('You have deleted the foo custom menu.'));
  }
}
?>

#86

System Message - October 11, 2009 - 08:35
Status:needs review» needs work

The last submitted patch failed testing.

#87

salvis - October 17, 2009 - 17:33
Category:feature request» bug report
Priority:normal» critical
Status:needs work» needs review

[EDIT: This has become obsolete — skip to #473082-105: Add custom menu API]

Has anyone actually run this?

<?php
function menu_delete($menu) {
 
// Delete all links from the menu.
 
$links = db_query("SELECT * FROM {menu_links} WHERE menu_name = :menu_name", array(':menu_name' => $menu['menu_name']));
  foreach (
$links as $link) {
   
// To speed up the deletion process, we reset some link properties that
    // would trigger re-parenting logic in _menu_delete_item() and
    // _menu_update_parental_status().
   
$link['has_children'] = FALSE;
   
$link['plid'] = 0;
   
_menu_delete_item($link);
  }

 
// Delete the custom menu.
 
db_delete('menu_custom')
    ->
condition('menu_name', $menu['menu_name'])
    ->
execute();

 
module_invoke_all('menu_delete', $menu);
}
?>

This crashes because $link is an object. The attached patch fixes it.

AttachmentSizeStatusTest resultOperations
menu_delete.patch687 bytesIdlePassed: 13656 passes, 0 fails, 0 exceptionsView details

#88

Dave Reid - October 14, 2009 - 00:24
Status:needs review» needs work

@salvis: That's not going to work because _menu_delete_item() expects an array.

#89

salvis - October 14, 2009 - 00:50
Status:needs work» needs review

@Dave Reid: Look at the code of _menu_delete_item(). I did run it...

#90

Dave Reid - October 14, 2009 - 01:00

Well we could avoid the additional array -> object processing if we just fetch objects. For large menus maybe it would make a difference.

#91

salvis - October 14, 2009 - 01:14

Yes, for those sites that keep deleting menus day in and day out over and over again. ;-)

I actually tried PDO::FETCH_ASSOC, but I prefer nice and clean code.

#92

sun - October 14, 2009 - 01:14

There you go.

Now we need tests.

AttachmentSizeStatusTest resultOperations
drupal.menu-delete-fix.patch902 bytesIdleFailed: 13970 passes, 0 fails, 1 exceptionView details

#93

System Message - October 14, 2009 - 01:45
Status:needs review» needs work

The last submitted patch failed testing.

#94

salvis - October 14, 2009 - 06:41

@sun:

What you meant was

<?php
  $links
= db_query("SELECT * FROM {menu_links} WHERE menu_name = :menu_name", array(':menu_name' => $menu['menu_name']), array('fetch' => PDO::FETCH_ASSOC));
?>

but as I said, I prefer #87. It's easier to get right, easier to read, it builds on the chosen default behavior of db_query() and thus helps to reinforce the fact that we get back objects by default.

Adding obscure flags in obscure places keeps us from developing a natural code flow, as you've demonstrated very nicely.

Setting back to needs review for #87.

AttachmentSizeStatusTest resultOperations
menu_delete.patch687 bytesIdlePassed: 13680 passes, 0 fails, 0 exceptionsView details

#95

salvis - October 14, 2009 - 06:44
Status:needs work» needs review

#96

Berdir - October 14, 2009 - 09:01

@salvis

While your code might look cleaner, there was a decision to use arrays inside menu.inc/menu.module. Not very concistent with the rest of core, I know, but now is probably not the right time to change that.

#97

sun - October 14, 2009 - 13:55

By all means, PDO fetch modes are not obscure at all. You are just not used to them - but you definitely will in D7. We use them in many more places throughout core.

Whether ->fetch() or using third argument to db_query() doesn't matter for me. Maybe Berdir can clarify about which of both "should rather" be used. :)

#98

salvis - October 14, 2009 - 16:31

@sun: You didn't get it to work in two attempts. That tells me it's too difficult to get right. Can't you see that?

#99

pwolanin - October 16, 2009 - 03:30
Status:needs review» needs work

menu links and router items should always be arrays - this was a D6 core design decision. you can argue if it's wrong, but then you need to change all of the rest of core to match.

#100

salvis - October 16, 2009 - 06:48
Status:needs work» needs review

Ok, if that's how we want to have it...

AttachmentSizeStatusTest resultOperations
theme_username.565792.44.patch1.97 KBIdleFailed: Failed to apply patch.View details

#101

salvis - October 16, 2009 - 06:50

Oops, sorry, wrong file...

AttachmentSizeStatusTest resultOperations
menu_delete.473082.100.patch882 bytesIdleFailed: Failed to apply patch.View details

#102

pwolanin - October 16, 2009 - 11:46

looks fine

#103

webchick - October 16, 2009 - 15:26

Let's get a test for this.

#104

System Message - October 17, 2009 - 07:10
Status:needs review» needs work

The last submitted patch failed testing.

#105

salvis - October 17, 2009 - 17:30
Category:bug report» feature request
Priority:critical» normal
Status:needs work» active

Committing #511286: D7UX: Implement customizable shortcuts fixed the bug I reported in #87 above — thanks.

I'm resetting the flags to what they were in #87 (#473082-85: Add custom menu API) above, except NR would fall back to NW right away. That's where we stand now.

@Amitaibu: Can you pick it up again, please?

#106

Amitaibu - October 17, 2009 - 18:09

I either need to get rights to add the docs + code example from #85, or someone with those rights should do it.

#107

sun - November 2, 2009 - 17:41
Status:active» needs work
Issue tags:+Needs tests

#108

Amitaibu - December 4, 2009 - 16:10

Can anyone grant me access to add the docs from #85?

#109

webchick - December 4, 2009 - 18:40

I just fixed the permissions again on http://drupal.org/update/modules/6/7, you should be good to go. Thanks, Amitaibu!

#110

Amitaibu - December 8, 2009 - 14:30

#111

catch - December 8, 2009 - 15:18
Status:needs work» fixed

#112

System Message - December 22, 2009 - 15:20
Status:fixed» closed

Automatically closed -- issue fixed for 2 weeks with no activity.

 
 

Drupal is a registered trademark of Dries Buytaert.