Well, I had wanted to be able to do this with all my deletes by
default so I would be able to cascade delete and provide a list of
objects to ignore without writing custom methods to loop and drill
through all of the objects. Anyway, I hacked up the change myself if
anyone is interested in actually adding it to Transfer.

The changes are below (comments are provided where there changes are,
I only provided snippets showing the portion of the code that contains
changes). I'm sure I could have put the skip list in the visitingargs,
but I didn't delve that deeply into it. This works as expected though.
You call cascadeDelete with an additional argument, which is a comma-
delimited list of objects to ignore.

I call it this way:

                deleteThis = instance.Transfer.get("users.posts", 
arguments.postID);
                cdArgs = structNew();
                cdArgs.transfer = deleteThis;
                cdArgs.skip = "users.user";
                instance.Transfer.cascadeDelete(argumentCollection=cdArgs);

This deletes everything on both sides of the post except the
users.user object.

Here are the changes:



Transfer.cfc:
---------------------------------------------
<cffunction name="cascadeDelete" hint="does a cascade down the object
hierarchy, calling delete() as it goes" access="public"
returntype="void" output="false">
        <cfargument name="transfer" hint="The transferObject to create"
type="TransferObject" required="Yes">
        <cfargument name="depth" hint="the number of levels in which to
cascade, 0 is unlimited" type="numeric" required="No" default="0">
        <cfargument name="useTransaction" hint="deprecated: use
TransferFactory.getTransaction for transaction management. Whether or
not to use an internal transaction block" type="boolean" required="No"
default="true">
        // ******** ADDED SKIP ARGUMENT ********
        <cfargument name="skip" type="string" required="No">





<cffunction name="visitObjectGraph" hint="visit each of the objects in
the graph, calling 'visit({transfer:transferObject, visitArgs1...})'
on the visitor for each TransferObject in the graph" access="public"
returntype="void" output="false">
        <cfargument name="transfer" hint="the starting object to visit"
type="transfer.com.TransferObject" required="Yes">
        <cfargument name="visitor" hint="the visitor object" type="any"
required="Yes">
        <cfargument name="visitingMethod" hint="the name of the method that
is being visited" type="string" required="Yes">
        <cfargument name="visitArgs" hint="visiting arguments, if there are
any" type="struct" required="No" default="#StructNew()#">
        <cfargument name="depth" hint="the max depth to go to" type="numeric"
required="no" default="0">
        <cfargument name="topDown" hint="travel top down, rather than bottom
up" type="boolean" required="No" default="true">
        <cfargument name="forceLoading" hint="if not loaded, force loading"
type="boolean" required="No" default="false">
        // ******** ADDED SKIP ARGUMENT ********
        <cfargument name="skip" type="string" required="No">
---------------------------------------------



DynamicManager.cfc:
---------------------------------------------
<cffunction name="visitObjectGraph" hint="visit each of the objects in
the graph, calling 'visit({transfer:transferObject, visitArgs1...})'
on the visitor for each TransferObject in the graph" access="public"
returntype="void" output="false">
        <cfargument name="transfer" hint="the starting object to visit"
type="transfer.com.TransferObject" required="Yes">
        <cfargument name="visitor" hint="the visitor object" type="any"
required="Yes">
        <cfargument name="visitingMethod" hint="the name of the method that
is being visited" type="string" required="Yes">
        <cfargument name="visitArgs" hint="visiting arguments, if there are
any" type="struct" required="Yes">
        <cfargument name="depth" hint="the max depth to go to" type="numeric"
required="no" default="0">
        <cfargument name="topDown" hint="travel top down, rather than bottom
up" type="boolean" required="No" default="true">
        <cfargument name="forceLoading" hint="if not loaded, force loading"
type="boolean" required="No" default="false">
        // ******** ADDED SKIP ARGUMENT ********
        <cfargument name="skip" type="string" required="No">
---------------------------------------------



ObjectTreeWalker.cfc:
---------------------------------------------
<cffunction name="visit" hint="visit each of the objects in the graph"
access="public" returntype="void" output="false">
        <cfargument name="transfer" hint="the starting object to visit"
type="transfer.com.TransferObject" required="Yes">
        <cfargument name="visitor" hint="the visitor object" type="any"
required="Yes">
        <cfargument name="visitingMethod" hint="the name of the method that
is being visited" type="string" required="Yes">
        <cfargument name="visitArgs" hint="visiting arguments, if there are
any" type="struct" required="Yes">
        <cfargument name="depth" hint="the max depth to go to" type="numeric"
required="no" default="0">
        <cfargument name="topDown" hint="travel top down, rather than bottom
up" type="boolean" required="No" default="true">
        <cfargument name="forceLoading" hint="if not loaded, force loading"
type="boolean" required="No" default="false">
        // ******** ADDED SKIP ARGUMENT ********
        <cfargument name="skip" type="string" required="No" default="">

        <cfscript>
                // ******** ADDED SKIP ARGUMENT AND 0 and structNew() for
currentDepth and visitedHashs to be passed to traverse() ********
                // ******** traverse() is expecting the argument after
forceLoading to be depth, I supplied the default value here ********
                // ******** and did the same with visitedHashs ********
                traverse(arguments.transfer,
                                arguments.visitor,
                                arguments.visitingMethod,
                                arguments.visitArgs,
                                arguments.depth,
                                arguments.topDown,
                                arguments.forceLoading,
                                0,
                                structNew(),
                                arguments.skip
                                );
        </cfscript>





<cffunction name="traverse" hint="traverses the object graph"
access="private" returntype="void" output="false">
        <cfargument name="transfer" hint="the starting object to visit"
type="transfer.com.TransferObject" required="Yes">
        <cfargument name="visitor" hint="the visitor object" type="any"
required="Yes">
        <cfargument name="visitingMethod" hint="the name of the method that
is being visited" type="string" required="Yes">
        <cfargument name="visitArgs" hint="visiting arguments, if there are
any" type="struct" required="Yes">
        <cfargument name="maxDepth" hint="the max depth to go to"
type="numeric" required="yes">
        <cfargument name="topDown" hint="travel top down, rather than bottom
up" type="boolean" required="yes">
        <cfargument name="forceLoading" hint="if not loaded, force loading"
type="boolean" required="yes">
        <cfargument name="currentDepth" hint="the max depth to go to"
type="numeric" required="no" default="0">
        <cfargument name="visitedHashs" hint="A struct of the identity hash
codes, so we know what has been hit" type="struct" required="No"
default="#StructNew()#">
        // ******** ADDED SKIP ARGUMENT ********
        <cfargument name="skip" type="string" required="No">





<cffunction name="visitTransfer" hint="visit a single object with the
method that is provided" access="private" returntype="void"
output="false">
        <cfargument name="transfer" hint="the starting object to visit"
type="transfer.com.TransferObject" required="Yes">
        <cfargument name="visitor" hint="the visitor object" type="any"
required="Yes">
        <cfargument name="visitingMethod" hint="the name of the method that
is being visited" type="string" required="Yes">
        <cfargument name="visitArgs" hint="visiting arguments, if there are
any" type="struct" required="Yes">
        // ******** ADDED SKIP ARGUMENT ********
        <cfargument name="skip" type="string" required="No">


        <cfscript>
                arguments.visitArgs.transfer = arguments.transfer;
        </cfscript>

// SET CLASSNAME OF OBJECT FOR CHECKING AGAINST SKIP LIST
<cfif #isDefined("arguments.visitargs.transfer")#>
<cfset skipThis = "#arguments.visitargs.transfer.getClassName()#">
<cfelse>
<cfset skipThis = "none">
</cfif>

// ******** CHECK CLASSNAME AGAINST SKIPLIST TO ALLOW OR DENY DELETE
********
        <cfscript>
if (NOT isDefined("arguments.skip") or (isDefined("arguments.skip")
AND listFindNoCase(arguments.skip, "#skipThis#") eq 0)) {
                getMethodInvoker().invokeMethod(arguments.visitor,
arguments.visitingMethod, arguments.visitArgs);
}
        </cfscript>
</cffunction>


On Jun 19, 8:59 am, Chris Peterson <[email protected]> wrote:
> Why not write a decorator method to handle it, so you can do post.delete(),
> then have your method troll down the tree and clean up all the related
> objects?
>
> I <3 decorators =)
>
> Chris Peterson
>
> On 6/19/09 10:26 AM, "whostheJBoss" <[email protected]> wrote:
>
>
>
> > Has anyone here come up with a way (or written a custom method) to use
> > cascadeDelete() and specify a list of objects to ignore? (on the way
> > "up" and "down")
>
> > My basic issue is this (example):
>
> > I have table of users who can make posts. The posts can have comments.
> > The comments can have multiple responses, the responses can have
> > ratings, etc
>
> > Basically, lots of relationships between objects.
>
> > The posts are tied to users via onetomany, so multiple posts per user.
>
> > I have a function for a user to delete a specific post. Of course,
> > there are all kinds of other things I want to delete when this post is
> > deleted (the comments, responses, raitings, etc)
>
> > If I use cascadeDelete() it works... except that it wipes out the user
> > object too since it's related to the post. Obviously I don't want to
> > delete my user, just the post.
>
> > Writing a custom function to dig down through and find all the
> > comments and run delete on each one, then dig down and find the
> > responses to the comments and delete each one, and so on seems like an
> > awful lot of extra work when cascadeDelete() ALMOST pulls this off.
>
> > I need something like an additional argument to specify objects NOT to
> > delete during the cascade. Basically to do something like this:
>
> > Transfer.cascadeDelete(post, "users.user");
>
> > where "users.user" is the object (or comma-delimited list of objects)
> > to skip over in the delete process.
>
> > Has anyone else got an elegant solution for this? Thanks!
--~--~---------~--~----~------------~-------~--~----~
Before posting questions to the group please read:
http://groups.google.com/group/transfer-dev/web/how-to-ask-support-questions-on-transfer

You received this message because you are subscribed to the Google Groups 
"transfer-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/transfer-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to