Summary

This is a simple but powerful module for Drupal 7 that allows administrators to effectively manage child entities when their parent entities are deleted. Upon parent entity deletion, it gives the option to either delete all dependent entities or drill down the tree of child entities and unselect any that you wish to maintain. The term "parent" and "child" depends on the set up. Some may prefer to set up their children to refer to their parents, and others may prefer to set up their parents to refer to their children. Only users who have the correct permissions will be able to access this option; otherwise, no dependent entities will be deleted.

Currently, this module only supports entities that are in Core and the Rules:config entity. There is no explicit way to delete file entities in Core and, therefore, there is no delete confirm page and not supported in this module.

Project Page

http://drupal.org/sandbox/atozstudio/1892808

Git Repository

git clone http://git.drupal.org/sandbox/atozstudio/1892808.git entity_reference_cascade_delete

Requirements

Entity Reference

Installation

Install as usual. See Installing contributed modules (Drupal 7) for further information.

Configuration

1. Go to Entity Reference Cascade Delete settings (admin/config/content/ercd) to choose the correct entity reference model. Then choose which entities can trigger a cascade deletion when they are deleted and which entity types will be subject to the cascade deletion. Keep in mind that users will have the option of unselecting all specific entities on the "confirm delete" pages.
2. Set appropriate permissions for each role. Permissions are broken down to each parent-child entity reference.

Troubleshooting

If you don't see any referencing/referenced entities showing up--or not as many as you expected to see--when deleting an entity, check the following things:

  1. Make sure you have actually enabled a cascade deletion for that entity.
  2. Make sure your user role has permission to perform the cascade deletion.
  3. Check if the entites you were expecting to see are referenced/referencing an entity that is outside the scope of the cascade.

Reviews of Other Projects

CommentFileSizeAuthor
#6 List of nodes/child35.12 KBBizible
#6 Delete page38.24 KBBizible

Comments

sprocketman’s picture

Issue summary: View changes

Changing repository location to location

sprocketman’s picture

Issue summary: View changes

Adding quote to repository location so that it doesn't appear to be a link.

sprocketman’s picture

Issue summary: View changes

Another attempt with the quotes.

vineet.osscube’s picture

Hi,
Firstly there is lots of issue regarding line spaces, indentation & comments.

Look at this !
http://ventral.org/pareview/httpgitdrupalorgsandboxatozstudio1892808git

Here you can check source code whether it meets drupal coding standards or not, and advise you what to change in your code. You can repeat review after your commits, and can fix those errors.

Also your code repository is in master branch, move your code to new branch 7.x-1.x & delete master branch.

sprocketman’s picture

Wow, that was quick. Thanks for the review. I have switched to branch 7.x-1.x, removed the master branch, and updated code formatting to satisfy the code standards. Beyond that, hopefully the module is soundly coded.

miloyz’s picture

Status: Needs review » Needs work

Hi atozstudio,

Thanks very much for submitting this very interesting module.
Thank you for fixing all the coding standards validation issues brought up by osscube.

I didn't have much time to go into the module in depth, but what I can already tell is that ercd.install seems to be well coded and you avoided making the common mistake of forgetting to remove variables upon module uninstall. So this looks good already.

So I pushed a little bit further my investigations and looked at ercd.js, which looks like it could be greatly improved and I would have the following comment:
Could you please consider using the Drupal Javascript behavior handling, for example, as it was suggested by DYdave on #1846194-7: Custom Add Block?

So your code would look more like:

(function ($) {

/**
 * TODO: This is an example:
 * TODO: Change this: Provide the toggle features for the fieldsets on settings
 * page [Watchout not to be longer than 80 characters]
 */
Drupal.behaviors.ercd = {

  attach: function(context, settings) {
    $('.ercd-trigger').change(function() {
      if ($(this).attr('checked')) {

        [...The rest of your JS code and logic should be here...]

      }
    }
  }
}

})(jQuery);

 

One more validation related advice would be for you to run the coding standards validation (PAReview) again, after you have committed your changes, to make sure you didn't introduce any new coding standards errors when you made the changes. After that, feel free to change the status back to needs review, that will save you one not so useful review from another user who would have simply told you about the coding errors mistakes (more back and forth = more time). This is something very common that happens to all of us (and just for one whitespace at the end of the line... the status is changed back to needs work again).

I didn't push my investigations any further than the JS file yet, but I think we should be giving this project more reviews after these issues have been fixed.

Feel free to let me know if you would have questions, comments or concerns on any of the reported items, I would surely be glad to provide more information.

Hope that helps improving module's code.
Cheers!

sprocketman’s picture

Status: Needs work » Needs review

Thank you for the review, miloyz. It was really helpful. I have updated the js to include Drupal.behaviors and moved most of the js code there. I have also simplified a great amount of the code due to some changes I made in the 2 forms that the js interacts with. Finally, I have run PAReview again with the new commit and no errors are showing, so I'm setting the status back to "needs review".

Thanks again.

sprocketman’s picture

Issue summary: View changes

Just leaving the repository location as it was.

sprocketman’s picture

Issue tags: +PAreview: review bonus

Adding tag: PAReview: review bonus

Bizible’s picture

StatusFileSize
new38.24 KB
new35.12 KB

Documentation:
This is how I'm using the terms parent/child: Parent is the node being deleted, and child is the node being referenced by parent's entity reference field.

I'm confused by the module's description, and wording compared to how it works. I was expecting this module to delete the child node(s) that would be orphaned when the parent is deleted. Whereas it deletes the parents of the node being deleted.

...manage dependent entities when their parent entities are deleted.

Instead of parent, should it be child here?
When I think of dependent, I think that the child depends on the parent, so when the parent is deleted, it deletes the child. I'll help with this wording when it's clearer.

The summary/description could be more explicit that it adds extra functionality to the delete confirmation page.

Upon parent entity deletion, it gives the option to either delete all dependent entities.

This blurb doesn't do this module justice as to when it works. Something like "Before confirming the deletion of a node, the administrator is able to choose other ('parent'/'child') nodes that can be deleted."

Testing
I tried this out on a fresh install and used Devel Generate to generate some nodes for a new node type named 'random' that had an Entity Reference field that referenced the new node type('random'). Devel Generate filled in the entity reference to nodes of the same content type so afterwards I had a pretty complicated list of parent/child relationships several levels deep.

Not sure if this an error or not now...
I think I'm getting an error. The module seems to be working in reverse and allowing me to delete the parents, but not the children. See pics. The first image shows a view with nodes on the left, and children on right. The first image has 'Cogo Macto Usitas' highlighted which is what I'm deleting, but instead of getting to delete child node 'Abico'(second image), I'm getting parent nodes of 'Cogo.'
List of nodes
Delete Page

Javascript review
The Drupal.behaviors.ercd.attach is effectively the Drupal equivalent of $(document).ready(), so you should move the code at line 73 into the 'attach' function, or if you want to keep it separate, change the $(document).ready into a named function like ercd_init and call it from the 'attach' function.

In ercd_set_state, you could save some clock cycles by using variables, instead of repeating code.

Instead of repeating this: $(this).parent().next('.ercd-child'). (lines 139,140,142,147)

Add a variable near the top of the function.
var $next = $this.parent().next('.ercd-child');
and shorten the lines to use the variable:$next.fadeIn(); (line 140)

Note that because '$' is a valid character for JavaScript variables, $next is a variable and has nothing to do with jQuery's $ other than that it is storing jQuery's return.

Line 119 you send $(container) into ercd_set_state(), but every time you use 'container' in ercd_set_state you pass it through $() again(lines 135,153,155). This is the equivalent of doing $($(container)). Also line 77 is the same unnecessary wrapping. You should remove the $() wrapping the variables on 77 & 119.

Line 144, slipped through the pareview for comments. Add a space after //, capitalize the t, and put period at the end. //this is borrowed from misc/collapse.js

sprocketman’s picture

Status: Needs review » Needs work

Bizible, thanks for your very thorough review. I see that I was approaching the parent/child relationship from the opposite direction, which brings up the fact that this does need to work in both direction. I think I need to set up another setting that allows users to choose in which direction we want the cascade to take place.

Regarding...

Devel Generate filled in the entity reference to nodes of the same content type so afterwards I had a pretty complicated list of parent/child relationships several levels deep.

...Yes, it can become complicated, but ultimately that is up to the admin and how they set things up. Realistically, I don't see this being used for all entity reference situations (although it could), but more likely it would be used in specific cases that would be less likely to create such deep reference trees. The more references you set up to trigger a cascade, the more complicated your tree selection is likely to be.

Finally, thanks for the clarification on both Drupal.behaviors and $(document).ready();. I thought that Drupal.behaviors was just for events that could be triggered several times and $(document).ready() was for things that happened just once on page load. On the use of jQuery in those particular situations, I apparently have never fully understood the how $() works! Not sure why I got into the habit of this, but I always wrapped jQuery objects in $() if I needed to apply other jQuery calls to them. Good to know!

Updating status to "needs work".

sprocketman’s picture

Issue summary: View changes

Adding another reviewed project.

sprocketman’s picture

Issue summary: View changes

Updated the summary to better reflect changes to the module.

sprocketman’s picture

Status: Needs work » Needs review

Made corrections re: #6 and made significant changes to how the settings work, allowing for parent->child and child->parent type references. Changing status back to "needs review".

ain’s picture

Status: Needs review » Needs work
Issue tags: -PAreview: review bonus

Automated review

All fine, no errors.

Manual review

  1. ercd_admin_settings() instructions have no support for translations (t()).
  2. functions in ercd.admin.inc not properly documented, e.g. ercd_build_settings_reference_tree() parameters.

Recommendations

  1. In ercd_uninstall() you could as well directly delete all variables instead of iterating through the result.
  2. Having large chunks of markup in translated strings is not a good idea.
sprocketman’s picture

Status: Needs work » Needs review

Thanks for the review, ain, and thanks for catching the missing documentation. I had a feeling I was getting sloppy!

1. I added documentation for ercd_build_settings_reference_tree() and added at least a @return directive for ercd_update_settings_reference_tree().

2. I've also tried to remove as much markup from the t() functions as possible. There are still a few cases, but I think quite a bit less than before. The user instructions were actually getting to t(), but I made it more explicit in the code.

3. The only thing I didn't address was the uninstall routine. I could directly delete the variables based on the current content types, but that wouldn't take into account other content types that were added/altered/deleted over time and used entity reference fields. Because of that, this seemed to be most effective way of ensuring I get all of the variables ever set by the module. If you can think of a better way, please let me know. Thanks.

sprocketman’s picture

Issue tags: +PAreview: review bonus

Adding tag: PAReview: review bonus

klausi’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -PAreview: review bonus

manual review:

  1. "$field_name}['und']": do not use 'und', use the constant LANGUAGE_NONE instead.
  2. ercd_get_referencing_child_ids(): why do you use check_plain() here? This seems like an API function and sanitization should be done as close as possible/useful to the actual output. If the ids are never printed they don't have to be sanitized, and the data should be unaltered when it is passed around internally.
  3. "$_SESSION['ercd_selections'] = $selections;": why do you need that? I think hook_entity_delete() does not make sense in your use case, just use a regular form submit handler where you delete stuff. Then you don't have to mess around with session variables.
  4. " '@referenceType' => check_plain($reference_type),": the "@" placeholder will already sanitize the variable for you and double escaping is bad.
  5. "t($entity_info['label'] . ': ' . $entity_info['bundles'][$reference_entity['bundle']]['label']),": do not concatenate strings in t(), use placeholders instead.
  6. Javascript: "ercd_set_message($container, 'Entities Selected');": use Drupal.t() to translate the messages, see http://drupal.org/node/323109
  7. VERSION.txt: why is that needed?

But that are not major application blockers, so I guess this is RTBC. Removing review bonus tag, you can add it again if you have done another 3 reviews of other projects.

klausi’s picture

Issue summary: View changes

Formatting adjustment.

sprocketman’s picture

Status: Reviewed & tested by the community » Needs review

Ok, I have updated the following things:
1. Replaced [und] with [LANGUAGE_NONE].
2. Cleaned up some of the "over-sanitizing" that was taking place.
3. Moved entity delete logic from hook_entity_delete to a submit handler so that it isn't necessary to use the session variable. I knew that had the aroma of being hack-ish, so thanks for the suggestion klausi.
4. Cleaned up the uses of t() by removing any concatenation in favor of placeholders. I'm actually not sure why I did that in those cases since I did it the correct way elsewhere.
5. Add Drupal.t() to javascript output. Again, thanks for that suggestion klausi. I had a feeling there must be some way to do that, but was unaware of the javascript compliment to the php version.
6. Removed VERSION.txt. This is a file that is just part of a git flow model that I've been using.

However, a few major changes have been made to this module, including:
1. Ensuring that certain user roles never get deleted, specifically user id 1 and administrators.
2. Ensuring that entities that belong to an entity reference relationship outside the scope of the current cascade is preserved so that other relationships are not broken.

As such, I would like to move this back to needs review.

sprocketman’s picture

klausi’s picture

Status: Needs review » Reviewed & tested by the community

manual review:

  • ercd_install()): do not assume that the administrative role has role ID 3! I think there is a variable that you can retrieve to get the administrative user role ID. And you should use the anonymous role constant instead of 1.

Back to RTBC.

sprocketman’s picture

Thanks, klausi. I should have checked on those things, so thanks for the tips. I am now using DRUPAL_ANONYMOUS_RID and the user_admin_role variable to populate $immune_roles in ercd_install().

sprocketman’s picture

Issue summary: View changes

Updating troubleshooting information.

klausi’s picture

Status: Reviewed & tested by the community » Fixed

no other objections for more than a week, so ...

Thanks for your contribution, atozstudio!

I updated your account to let you promote this to a full project and also create new projects as either a sandbox or a "full" project.

Here are some recommended readings to help with excellent maintainership:

You can find lots more contributors chatting on IRC in #drupal-contribute. So, come hang out and get involved!

Thanks, also, for your patience with the review process. Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.

Thanks to the dedicated reviewer(s) as well.

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

Anonymous’s picture

Issue summary: View changes

Removed note about comment entities.