Welcome, Guest
Username: Password: Remember me

TOPIC: [ADDED] Cascade delete

Cascade delete 17 Dec 2012 17:09 #6159

  • madaura
  • madaura's Avatar
  • Offline
  • Junior Member
  • Posts: 35
  • Thank you received: 3
  • Karma: 0
Hello guys,

This is the scenario:

When I add a FK to another table, I have 3 FK-integrity options: none, reset, cascade.

I like the last one, but I'd like to let the user JUST delete the record if the parent object has not children attached to it.

For example:

States table
Cities Table

If the State A has already City A1 attached to it, the user won't have the option to delete the State A UNTIL he/she delete the City A1 first.

This is the same idea like joomla works in the back end, for example when you want to delete some category that has sub-categories and so on.

How can I do that?

Thanks
The administrator has disabled public write access.

Re: Cascade delete 17 Dec 2012 18:03 #6160

  • JoomGuy
  • JoomGuy's Avatar
  • Offline
  • Moderator
  • Joomla Enthusiast, Lover of Cooking
  • Posts: 1115
  • Thank you received: 195
  • Karma: 64
To enable this feature there are 2 potential scenarios and solutions;

If you want to do this kind of check globally for all Cascade Delete operations in your application you will need to alter [your component]/admin/classes/jmodel.item.php if in your install package for single item layouts/model instances

OR alternatively, to override this in individual instances, in the model of each that you wish to adapt and override the public function integrityDelete($key, $cid = array()) calling the parent::integrityDelete($key, $cid = array()) method.2 files:[your component]/admin/models/[item_model].php if in your install package for single item layouts/model instances
<?php
/**
* Method to cascad delete items.
*
* @access	public
* @param	string	$key	The foreign key which relate to the cids.
* @param	array	$cid	The deleted ids of foreign table.
*
* @return	boolean	True on success
*/
public function integrityDelete($key, $cid = array())
{
	if (count( $cid ))
	{
		//Do your eval here...
                //check the classes/jmodel.item to see how it is working 
                //and adapt it as necessary
	}
	return true; // 
}
?>
That should get you started!

Gez
Need help with your Cook/Joomla Project? . PM me to find out what I can help with. NO time wasters please!!!
The administrator has disabled public write access.

Re: Cascade delete 17 Dec 2012 21:30 #6162

  • madaura
  • madaura's Avatar
  • Offline
  • Junior Member
  • Posts: 35
  • Thank you received: 3
  • Karma: 0
Thank you for your reply audibleid

I tried the first solution (globally), but I see that this function inside the jmodel.item.php is triggered after the parent record had been deleted, however what I'd like is to have the chance at the moment the user will try to delete the parent record, check if there are children records and if the answer is true display an alert messaje telling the user tnat this operation is not possible.

Thanks for your help!
The administrator has disabled public write access.

Re: Cascade delete 17 Dec 2012 22:38 #6163

  • JoomGuy
  • JoomGuy's Avatar
  • Offline
  • Moderator
  • Joomla Enthusiast, Lover of Cooking
  • Posts: 1115
  • Thank you received: 195
  • Karma: 64
Arghhhhhh! Silly me!!! :oops:

Of course!

I think in that case you'll want to target the classes/jcontroller.item.php to do this globally. Edit the delete() function but be careful. I think you would need to replace the code in the ELSE statement...

So, if I am correct (@admin @BTB300 - just wanna double check this as I've not done it??? :unsure: )

COMMENT OUT:
// Get the model.
$model = $this->getModel();
REPLACE WITH:
// Get the model.
$model = $this->getModel('your-subitem-model');
Adapt the evaluation thereafter to query the cid's against the a count of foreign key fields matching to the sections (cid) passed in the query string.

Alternatively, in the individual controller/[controller-name].php files and override the delete function in a similar fashion to previous post, using the changes above.

I think this is right (untested but should set you off in the right direction).

What a long day!!! :ohmy:

Hope it helps!

Gez
Need help with your Cook/Joomla Project? . PM me to find out what I can help with. NO time wasters please!!!
Last Edit: 18 Dec 2012 14:42 by JoomGuy.
The administrator has disabled public write access.

Re: Cascade delete 18 Dec 2012 14:40 #6169

  • madaura
  • madaura's Avatar
  • Offline
  • Junior Member
  • Posts: 35
  • Thank you received: 3
  • Karma: 0
Hi Gez,

Yes I think this is the route to follow, but I feel a little lost how to create my custom model here, do you have some code that let me understand the logic?

Thanks!
The administrator has disabled public write access.

Re: Cascade delete 18 Dec 2012 15:02 #6170

  • JoomGuy
  • JoomGuy's Avatar
  • Offline
  • Moderator
  • Joomla Enthusiast, Lover of Cooking
  • Posts: 1115
  • Thank you received: 195
  • Karma: 64
Off the top of my head, without checking this with @admin, I'm not 100% sure.

However, here are the basics:
I believe you are going to need to set a custom query in the prepareQuery() that returns the subitems based on the ID of the selected 'parent' item. Then using setState(), set the context to return the result of the the query.

Your raw query would be something like:
SELECT DISTINCT a.id, COUNT(b.subitem) AS subCount
FROM table1 a, table2 b
LEFT JOIN b ON (a.id = b.subitem)
WHERE b.subitem = a.id
GROUP BY a.id
Obviously, this would need to be adapted to fit the way that the model builds the query but if you set $result = $db->loadAssocList() you'll end up with an associative array like;
array(
	0 => array("a.id" => 1, "subCount" => 3),
	1 => array("a.id" => 2, "subCount" => 0),
	2 => array("a.id" => 3, "subCount" => 10),
	3 => array("a.id" => 4, "subCount" => 7),
);
Foreach through these to find all a.id's where subCount == 0 and boom, you should have what you need! Delete the found records and notify the user that all a.id's where subCount > 0 need their child records to be deleted first.

The logic is correct, whether this is the best way is another matter. Please wait for admin's response.

Hope it helps!

Gez
Need help with your Cook/Joomla Project? . PM me to find out what I can help with. NO time wasters please!!!
Last Edit: 18 Dec 2012 15:25 by JoomGuy. Reason: Added info
The administrator has disabled public write access.

Re: Cascade delete 04 Feb 2013 15:37 #6628

  • dyoungers
  • dyoungers's Avatar
  • Offline
  • Premium Member
  • Posts: 123
  • Thank you received: 16
  • Karma: 0
I ran across this thread over the weekend when I was putting in the code to restrict deletes when there is an existing foreign key reference to an item instead of using the reset or cascade options that are provided in the builder (and after reading this thread, I thought others might find what I ended up with useful.)

One key thing is that when I set up the tables, I used the reset option so I had some code to modify in my item models and so I didn't have to remember all the foreign key references, i.e. the delete functions in my item models already had the calls to integrityReset which I could change.

In my case, I thought it would be easier to add an integrityRestrict function to the item class in admin\classes\jmodel.item.php so I could call it (instead of the reset function) wherever I needed to restrict the delete process.

The code that I added for the integrityRestrict looked like this:
/**
	* Method to restrict deleting fk referenced items.
	*
	* @access	public
	* @param	string	$key	The foreign key which relate to the cids.
	* @param	array	&$cid	The ids to be deleted in foreign table. (referenced ids are removed)
	*
	* @return	boolean	True on success
	*/
	public function integrityRestrict($key, &$cid = array())
	{
		if (count( $cid ))
		{
			$db = JFactory::getDBO();
			$table = $this->getTable();
			JArrayHelper::toInteger($cid);
			$cids = implode( ',', $cid );
			$query = 'SELECT '. $db->quoteName($key) . 'AS fkid FROM ' . $db->quoteName($table->getTableName())
				. ' WHERE ' . $db->quoteName($key) . ' IN ( ' . $cids . ' ) GROUP BY ' . $db->quoteName($key);
			$db->setQuery($query);
			$list = $db->loadObjectList();

			$cidReferenced = array();
			if (count($list) > 0) {
				foreach($list as $item) 
					$cidReferenced[] = $item->fkid;
				$cid = array_diff($cid, $cidReferenced);
				JError::raiseWarning(500, JText::plural('VOLUNTEERSIGNUP_ITEMS_REFERENCED_NOT_DELETED', count($cidReferenced)));
			}
		}

		return true;
	}

As you can see, I chose to treat things as a warning and the In the language file I added this as the message:
VOLUNTEERSIGNUP_ITEMS_REFERENCED_NOT_DELETED="%s item(s) were referenced and not deleted."

And finally, in the item models where I wanted to restrict deleting referenced items, I changed the delete method to look something like this:
/**
	* Method to delete a event
	*
	* @access	public
	* @param	array	&$pks	The Ids of elements to delete.
	*
	* @return	boolean	True on success
	*/
	public function delete(&$pks = array())
	{
		if (!count( $pks ))
			return true;

		//Integrity : Restrict fk : event_id in session
		$model = JModel::getInstance('session', 'VolunteersignupModel');
		if (!$model->integrityRestrict('event_id', $pks))
			return false;

		if (!count( $pks ))
			return false;

		if (!parent::delete($pks))
			return false;

		return true;
	}

The important thing to note is that the integrityRestrict method is called before the delete and that this function modifies the cid array and removes any referenced items so that only those items that are not referenced get deleted.

Hopefully I explained things clearly ...

Dave
Last Edit: 04 Feb 2013 16:11 by dyoungers. Reason: code correction
The administrator has disabled public write access.
The following user(s) said Thank You: admin, JoomGuy

Re: Cascade delete 04 Feb 2013 17:20 #6629

  • JoomGuy
  • JoomGuy's Avatar
  • Offline
  • Moderator
  • Joomla Enthusiast, Lover of Cooking
  • Posts: 1115
  • Thank you received: 195
  • Karma: 64
Nice work @dyoungers an thanks for sharing! Sharing = karma++!

I haven't had a chance to test but all looks good to me!

Thanks again,

Gez
Need help with your Cook/Joomla Project? . PM me to find out what I can help with. NO time wasters please!!!
The administrator has disabled public write access.

Re: Cascade delete 06 Mar 2017 09:03 #15029

  • admin
  • admin's Avatar
  • Online
  • Administrator
  • Chef
  • Posts: 3711
  • Thank you received: 984
  • Karma: 140
Coding is now a piece of cake
The administrator has disabled public write access.
Time to create page: 0.151 seconds

Get Started