Eric Belair
Eric Belair

Reputation: 10692

How can I re-use queries in CRUD OOP CFCs?

I have a simple CFC class that handles CRUD on a Product - Product.cfc.

I am extending the class to allow for additional properties based on the application - for instance CartProduct.cfc extends Product.cfc in order to allow for a Quantity property to be included.

In the Base Product.cfc class, I first pass in an ID, and use the ID in my read() method to retrieve the data from the database:

<cffunction name="read" returntype="Query">
    <cfquery name="qData" datasource="mydb">
        SELECT    description
        FROM      mySKUTable
        WHERE     id = '#VARIABLES.Sku#'
    </cfquery>

    <cfreturn qData />
</cffunction>

<cffunction name="setSku" returntype="Product">
    <cfargument name="Sku" type="String" required="true" />
    <cfscript>
        var qData = QueryNew("");

        VARIABLES.Sku = ARGUMENTS.Sku;

        qData = read();

        VARIABLES.description = qData.description;
    </cfscript>
</cffunction>

I want to extend this in CartProduct.cfc to retrieve and set the Quantity from a different table using the read() method:

<cffunction name="read" returntype="Query">
    <cfquery name="qData" datasource="mydb">
        SELECT    quantity
        FROM      myCartTable
        WHERE     id = '#VARIABLES.Sku#'
    </cfquery>

    <cfreturn qData />
</cffunction>

<cffunction name="setSku" returntype="Product">
    <cfargument name="Sku" type="String" required="true" />
    <cfscript>
        var qData = QueryNew("");

        THIS = SUPER.setSku(Sku);

        qData = read();

        VARIABLES.quantity = qData.quantity;
    </cfscript>
</cffunction>

When I do this, only the extended read() is called. This is fine, this is as designed. However, I'm looking for a way to have BOTH read() methods called, so I can first set the properties in the base class, and then set the Properties in the extended class.

Any thoughts on this?

p.s. I know I'm not using CFQUERYPARAM or validating my inputs, etc. I left that crap out in order to keep this simple, so please don't give me those suggestions right now.

Upvotes: 1

Views: 313

Answers (2)

Steve Bryant
Steve Bryant

Reputation: 1046

You can use the "Super" scope to reference the extended component. So, to call the "read" method of Product.cfc from within CartProduct.cfc, call Super.read().

Upvotes: 0

Eric Belair
Eric Belair

Reputation: 10692

Ok, here's what I came up with:

Instead of returning a Query from the read() method, I'm converting the Query row to a Struct and returning the Struct. That way I can call SUPER.read() from within read() and then copy the the keys and values from the parent Struct into the new Struct at every level. It's a little more code, but it gets the job done.

<cffunction name="read" returntype="Struct" output="false">
    <cfscript>
        var _qData = QueryNew("");
        var _properties = SUPER.read();
    </cfscript>

    <cfquery>
    ...
    </cfquery>

    <cfscript>
        StructAppend(
            _properties,
            REQUEST.UDFLib.Query.queryRowToStruct(_qData)
            );

        return _properties;
    </cfscript>
</cffunction>

Upvotes: 1

Related Questions