Controller Cache

I am sure that I am doing something wrong here but not quite sure what
it is! I have a post controller that auto wires transfer and a post
service for me. I am not sure what I am caching or where but every
time I call my show method the post object is cached. If I update the
database im still getting the old object (same data). Is it transfer
thats getting cached or is this controller getting cached?

Anyways, im sure I am doing something wrong so if someone can point
out whats wrong here that would be a big help!

Thanks

<cfcomponent name="post" extends="coldbox.system.eventhandler"
output="false" hint="Post Controller" autowire="true">

  <cfproperty name="Transfer" type="ocm" scope="instance" />
  <cfproperty name="PostService" type="ioc" scope="instance" />

  <cffunction name="index" access="public" output="false"
returntype="void">
    <cfset setNextRoute("post/list")>
  </cffunction>

  <cffunction name="list" access="public" output="true"
returntype="any">
    <cfargument name="event" type="coldbox.system.beans.requestContext"
required="true">
    <cfscript>
      var orderby = event.getValue("orderby","posted");
      var sortAsc = event.getValue("orderSort",false);
      var posts = instance.transfer.list("post",orderby,sortAsc);

      page = {pageTitle="List Posts",posts=posts};
      event.collectionAppend(page,false);
    </cfscript>
  </cffunction>

  <cffunction name="show" access="public" output="true"
returntype="any">
    <cfargument name="event" type="coldbox.system.beans.requestContext"
required="true">
    <cfscript>
      var postId = event.getValue("id",0);

      if(!postId){
        event.setValue("message","User with an id of #postId# was not
found");
        event.setValue("pageTitle", "List Posts");
        setNextRoute("post/list","orderby");
      } else {
        // update the views count
        instance.postService.updateViews(postId);
        // post instance - do after update so we have correct view count
        post = instance.transfer.get("post",postId);
        // place our post into the event
        event.setValue("post", post);
      }
    </cfscript>
  </cffunction>

</cfcomponent>

Few observations. All controllers are cached by default. If you do not want controller caching then set the settings: HandlerCaching to false. However, we recommend that it always is set to true in production environments.

Few things here:

On the list event, the variable “page” is not var scoped. Therefore it could bleed into other requests as actually “variables.page” and interfere with the persistence of the controller. Please var scope it.

2nd. On the show event, the “post” object again is not var scoped. Therefore it becomes “variables.post” and all instances executing the post method will have access to it. This is the big difference between ColdBox and Grails, in that Grails re-creates the controllers on each request. To me, that is inefficiency, therefore, our default is to NOT recreate the controller layer, but time persisted if possible. Again, Grails does not have an enterprise cache like ColdBox, so we can do More than just create singleton controllers, but time persisted controllers and take advantage of a more dynamic memory footprint. In conclusion, if you want to treat your controllers in a mere create-destroy fashion, then set the HandlerCaching setting to false and your controllers will be re-created on each request. If you want persistence, extra optimization and dynamic footprints, then set it to True, but be very careful with your scoping. ALWAYS var scope variables inside of methods.

Luis

Thanks for the information. The handlerCache is already set to false.
I think that transfer is caching the object. Though im not sure how to
fix that. Anyone have any ideas?

Hi Dan,

By default, Transfer will indeed cache the object, and if you are
updating the corresponding record outside the scope of Transfer (e.g.,
by manually updating the DB or executing a SQL statement), then you
will need to discard the object from the Transfer cache for the
changes to be reflected:

http://docs.transfer-orm.com/wiki/Managing_the_Cache.cfm

If you update the object using the save() or update() methods of the
Transfer factory, then the cached object will be updated
automatically.

You could also disable the cache, but this will of course result in
slower performance.

HTH,

Ezra Parker

Ok, that totally makes sense. Here is what I am doing and I understand
why thats happening now. I set up a new service in (service/
postService.cfc) and set it up in lightwire. Because this does not
extend the ColdBox like the handler does I am uncertain how to get at
everything. If I update my service method to use transfer and update
the views method, everything should work back in my controller.

<cfcomponent output="false">

  <cffunction name="updateViews" access="public" output="false"
returntype="void">
    <cfargument name="postId" type="numeric" required="true">
    <cfset var uView = "">

    <cfquery name="uView" datasource="coldblog">
    UPDATE Post
    SET
      views = views + 1
    WHERE id = <cfqueryparam value="#arguments.postId#"
cfsqltype="cf_sql_integer">
    </cfquery>

  </cffunction>

</cfcomponent>

Post Controller
<cfcomponent name="post" extends="coldbox.system.eventhandler"
output="false" hint="Post Controller" autowire="true">

  <cfproperty name="Transfer" type="ocm" scope="instance" />
  <cfproperty name="PostService" type="ioc" scope="instance" />

  <cffunction name="index" access="public" output="false"
returntype="void">
    <cfset setNextRoute("post/list")>
  </cffunction>

  <cffunction name="list" access="public" output="true"
returntype="any">
    <cfargument name="event" type="coldbox.system.beans.requestContext"
required="true">
    <cfscript>
      var orderby = event.getValue("orderby","posted");
      var sortAsc = event.getValue("sortAsc",false);
      var posts = instance.transfer.list("post",orderby,sortAsc);
      var page = {pageTitle="List Posts",posts=posts};
      event.collectionAppend(page,false);
    </cfscript>
  </cffunction>

  <cffunction name="show" access="public" output="true"
returntype="any">
    <cfargument name="event" type="coldbox.system.beans.requestContext"
required="true">
    <cfscript>
      var post = "";
      var postId = event.getValue("id",0);

      if(!postId){
        event.setValue("message","User with an id of #postId# was not
found");
        setNextRoute(route:"post/list",persist:"message");
      } else {
        // update the views count
        instance.postService.updateViews(postId);
        // post instance - do after update so we have correct view count
        post = instance.transfer.get("post",postId);
        // place our post into the event
        event.setValue("post", post);
      }
    </cfscript>
  </cffunction>

  <cffunction name="save" access="public" output="false"
returntype="any">
    <cfargument name="event" type="coldbox.system.beans.requestContext"
required="true">
    <cfscript>
      var postId = event.getValue("postId",0);
      if(!postId){
        // new post
        create(event);
      } else {
        // update post
        update(event);
      }
    </cfscript>
  </cffunction>

  <cffunction name="create" access="public" output="false"
returntype="any">
    <cfargument name="event" type="coldbox.system.beans.requestContext"
required="true">
    <cfscript>

    </cfscript>
  </cffunction>

  <cffunction name="update" access="public" output="false"
returntype="any">
    <cfargument name="event" type="coldbox.system.beans.requestContext"
required="true">
    <cfscript>

    </cfscript>
  </cffunction>

  <cffunction name="delete" access="public" output="false"
returntype="any">

  </cffunction>

  <cffunction name="onMissingAction" access="public" output="true"
returntype="void">
    <cfargument name="event" type="coldbox.system.beans.requestContext"
required="true">
    <cfargument name="missingAction" type="string" required="true" />

    <cfscript>
      var rc = event.getCollection();
      var params = {action=event.getCurrentAction(),controller=
event.getCurrentHandler()};

      event.collectionAppend(params);
      event.setView("missing");
    </cfscript>
  </cffunction>

</cfcomponent>