Viewing Category:   [clear category selection]

Mach-II Breadcrumbs filter

I created a breadcrumb filter to work in Mach-II a while back. The Google Group list had a question or two about this, so here's what I have.

Example code can be downloaded below (see Download Enclosure). See also: [ DEMO ]

To use the filter, define it in the <event-filters> section of your config.xml:
  <event-filter name="BreadCrumbsFilter" type="CrumbsExample.filters.BreadCrumbsFilter">
   <parameters>
    <parameter name="HomeEvent" value="Home" />
    <parameter name="HomeText" value="Home" />
    <parameter name="TrailMax" value="6" />
   </parameters>
  </event-filter>
HomeEvent is the name of your default or home event name. 
HomeText can be something more user friendly. This is what will display in crumb trail.
TrailMax is arbitrary, but could be useful if you need it.

To have an evet show up in the crumb trail, within an <event-handler>, put this:
   <filter name="BreadCrumbsFilter">
    <parameter name="page" value="Home" />
    <parameter name="isEntryPoint" value="true" />
   </filter>
The page parameter is what will be displayed in the crumb trail.
isEntryPoint is optional and defaults to false. Setting it to true will reset the trail and make that event the first in the trail (after Home).

The output can be found in the views\nav.cfm page. Put it where ever makes sense for your layout.

In the filter, you'll see some code referring to window number or "wn". This was my attempt to handle links that open new windows or tabs. I did not get too far with this and for now everything defaults to 1.

Feel free to ask questions here or on the email list.

1 Comment  |  Download Enclosure  ( 15 KB) |  CF General, Mach II  |  Send
Posted 8/29/08 @ 3:16 PM by Matt Williams

Mach II 1.6 - Message Subscribing for cfthread-ing

The past week or so I've been upgrading an app to Mach II version 1.6 and CF 8. The first task was to take advantage of cfthread for some auditing. Basically just like a hit counter we have an audit filter that logs when certain events are requested. This writes a record to the db and can easily be handled by a new thread since nothing after it is dependent on its completion.

To use cfthread I decided to try out the Publish-Subscribe Listener Method Invocation. It was easy enough to convert the filter to a listener by just changing some of the parameter references to event arg references. I then added a new <message-subscriber> block to replace the <filter>. Within that I specified multithreaded="true" and waitForThreads="false".

Then, in the events that previously had a <filter name="audit"> reference I changed that to <publish message="audit">. Any parameters that used to be sent to the filter via the <parameter> command can easily be changed to <event-arg> so the new listener can access it.

 

And that was all it took to take advantage of some threading. I didn't even have to learn the syntax and usage of cfthread. Maybe this is good, maybe not. I did look at how the Mach-II core files were doing it though, just out of curiousity.

Team Mach-II did a good job of wrapping up that functionality so that it can be used by other parts of the framework when appropriate.

I hope to blog some more about some of Mach-II's new features. I've also been trying to help out with some docs on the wiki, so check it out when you're ready for the new version.

2 Comments  |  CF General, Mach II  |  Send
Posted 6/16/08 @ 5:41 PM by Matt Williams

Mach II event round trip

This is a post I just made on the Mach II google group list. Someone there is looking at MachBlog code to learn about Mach II. He had a question about calling the getUserByID() function and how it gets the data from the database.

-From the admin, when you are viewing the list of User Accounts, you
have the [edit] link by each name. Clicking that calls the
showUserForm event. To see what will happen with that event, view the
mach-ii.xml file.

- After the security filter and a qForm flag is set, the getUserByID
method in the userListener is called.

- That takes the userID which was part of the [edit] link and
subsequently put into the Mach II event object (the framework does
this behind the scenes) and passes it to the getUserByID method in the
UserService.

- The getUserByID method in UserService first creates a new instance
of the User bean and calls the init() method on it, passing in the
userID. This new instance now has that userID that originally came
from the [edit] link. So the bean, which represents a single record in
the table, has the ID, but no other data from the table.

- We now pass that bean into the read() method of the UserDAO. It will
use that bean to simply pull the userID out so it can read the record
from the machblog_user table.

- After the query is run, we populate the rest of the user bean with
the data from the query. This is done with <cfset
arguments.user.init(.... long list of variables ....) />.

- Now, nothing is returned by the read method. That's where "pass
by reference" takes effect. The instance of the User
bean that was created in UserService is the same instance that we just
populated with the query values.

- Going back to the UserService, you see that we do return the user
bean. That goes back to the UserListener which in turn returns it to
the M2 framework.

- Back in the mach-ii.xml file, you'll see that the <notify> line has
resultArg="user". That means that the framework will take whatever is
returned from the getUserByID method will be put into the event object
with a name of "user".

- So then in the view page for showing the user form
(views\admin\userForm.cfm), we can get a reference to that with this
line of code:
<cfset variables.user = event.getArg("user") />

- Now in the view (for additional code go to the skins folder) you can
get to the data that the bean has (which came from the machblog_user
table) by making calls to variables.user.getUserID(),
variables.user.getFirstName(), etc.

Kind of a long post, but that is a Mach II round trip for getting the
record from the database given a userID. There is a bit more going on
behind the scenes with ColdSpring and all, but that can be ignored for
this basic scenario.

1 Comment  |  Mach II  |  Send
Posted 2/15/08 @ 9:23 AM by Matt Williams

Working on sample Service/DAO/Bean files

I'm working on a set of CFCs that is the basic idea of a Person that has multiple Addresses (simple database with 2 tables: Person and Address).  Because there seem to have been quite a few questions (on the CF-Talk, Model-Glue, etc. lists) regarding Service Objects lately, I'll try to post this as sample code this weekend. I probably won't do a full app, or even tie it to a framework. Instead, there will be a simple cfm file that makes calls against the Service CFC.

The first iteration will be standalone, but a ColdSpring version may follow as I feel using ColdSpring makes implementing a Service layer much cleaner. And if anyone is interested, I could demo how this can tie into Mach-II or Model-Glue.

If anyone has any suggestions or ideas for this type of sample code, please leave a comment.

Mach II, Model-Glue, OOP  |  Send
Posted 5/5/06 @ 5:58 AM by Matt Williams

Note on using Model-Glue or Mach-II with ColdSpring and Reactor

Just a reminder that in order to use Model-Glue or Mach-II with ColdSpring and Reactor you must get the latest version of all of the above. The most recent versions of MG and M-II are available at their respective web sites as they are the most recent 'stable' version. For ColdSpring and Reactor, however, you'll have to go to version control repositories. ColdSpring has the CVS login details on its website (Eclipse has a built in CVS checkout client). Reactor is harder to find. I downloaded the Tortoise SVN client (google it, download it, install it). It's repository is at svn://alagad.com/reactor/trunk (this is listed in the Reactor documentation).

There have been a lot of recent changes to the repository versions of both ColdSpring and Reactor so there is no guarantee you can get this combo to work. I do have a version of CS and Reactor that work with at least one sample application (see previous blog entry). And remember that they are both in alpha, meaning issues are being found and fixed all the time.

I'll be happy to email zips of these to whoever needs it. I'd post them here, but I don't think this free blog gives me enough file space or bandwidth. If you need them emailed, leave a comment and I can get to your email address.

ColdSpring, Mach II, Model-Glue, Reactor  |  Send
Posted 4/20/06 @ 5:56 AM by Matt Williams

Mach-II / ColdSpring / Reactor port of Brian's bookstore

Last week Brian Kotek posted a Model Glue / ColdSpring / Reactor version of his bookstore sample application. One of the comments was from Sami Hoda and how he hasn't been able to find a Mach-II / ColdSpring / Reactor sample application. I volunteered to port Brian's app to Mach II. So here is the Mach-II / ColdSpring / Reactor port of Brian's bookstore.

Converting from M-G to M-II is fairly straight forward. I didn't touch the the model cfcs, the Reactor config or the ColdSpring config. Because Brian reassigned the Model-Glue view state variables in each view template, those were easy fixes (Find 'viewstate.getvalue'; Replace with 'event.getArg'). The biggest difference is that Model Glue has onRequestStart capabilities in each of its controllers. I used Mach II plugins to mimick those.

The install should be easy enough. There is a readme file included to help you get going.

ColdSpring, Mach II, Reactor  |  Send
Posted 4/19/06 @ 5:54 AM by Matt Williams

Mach II variables and views

So in trying to tweak and make things better in the app I'm working on, I am playing with where data returned from the model should be grabbed in the view. The first thing I noticed was that with multiple view-pages, any variable declared in a view is available to subsequent views. For example, my event does getPerson, the model does its thing, getting the Person Bean/Object populated with data, and sticking it into the event (via event.setArg('obj_Person',obj_Person)). At the top of a view (cfm page) that creates my header, I grab that object out of the event and stick it into a variable. This just makes the output easier to read and having event.getArg().getXXX() scattered everywhere is messy in my opinion. So at the top of the view page, I do <cfset thePerson = event.getArg('obj_Person') />

Now any views within this event-handler can access thePerson object and its methods. I may actually use this knowledge to create a view page that does nothing but set the variables for the subsequent views. I could have more than one of these files that declares only the needed variables. Or I could just have one that uses cfifs to determine what is needed. I'll keep thinking on this...

Mach II  |  Send
Posted 4/11/06 @ 5:52 AM by Matt Williams

Controlling the Mach II (or Model Glue) xml file size

I found a blog entry by Wayne Graham on the mach-ii.info web site. It explains how you can use XML Entities to "include" external xml files. In the case of Mach II and Model-Glue, you could separate out parts of the config file into different xml files. The short of it is you end up with a config file that looks like this (example is for Model-Glue, but can apply to Mach II):
<!DOCTYPE [
   <!ENTITY mapping "/modelgluesamples">

   <!ENTITY appName "StockQuote">
   <!ENTITY folder "stockquote">
   <!ENTITY hello "HelloWorld">
   <!ENTITY config SYSTEM "c:/websites/localhost/modelgluesamples/templates/config.xml">
   <!ENTITY controllers SYSTEM "http://localhost/modelgluesamples/templates/stockquote/controllers.xml">
   <!ENTITY events SYSTEM "http://localhost/modelgluesamples/templates/stockquote/event-handler.xml">
]>

<modelglue>
   &config;
   &controllers;
   &events;
</modelglue>

Mach II, Model-Glue, XML  |  Send
Posted 3/31/06 @ 5:47 AM by Matt Williams

Populating a bean within Read function of DAO

In most Data Access Object (DAO) examples I've seen, the Read function gets the data via a query, then populates the Bean by calling the init function and listing all the fields for that table. I didn't like this because this adds one more place to change if the table gets a new field. Plus, in a table of 30 or so fields, listing those out just looks ugly, even if you use a code generator.

So I did the following to dynamically create a structure of all the table columns and their value (we're only talking about 1 record here).
At the top of the function... <cfset var struct_Params = StructNew() />

After the query...
<cfloop list="#var.qry_Read.ColumnList#" index="col">
  <cfset var.struct_Params[col] = qry_Read[col][1]>
 </cfloop>

Then just use argumentcollection to pass the struct to the bean's init function...
<cfset arguments.myBean.init(argumentCollection = struct_Params) />

This way, if a new field is added to my table, I should only have to add the getter/setter to my Bean, the setter call in the init function, and any possible changes to View pages.

Mach II, OOP  |  Send
Posted 3/22/06 @ 5:40 AM by Matt Williams

Service Layer part 2: thoughts on Mach II's event-bean

The event-bean term in Mach II allows you to create an object in the mach-ii.xml file. It pulls any url or form variables and will put them into a bean object if the getter and setter are defined. I was using this before doing calling the read function in my DAO, but have changed my mind.

My Mach II code looked like:
<event-handler event="getPerson">
    <event-bean name="obj_PersonBean" type="myApp.model.Beans.PersonBean" />
    <notify listener="PersonListener" method="getPerson" />
    ...other stuff and the view thing...
</event-handler>

The person listener then passed the obj_PersonBean to the PersonService.cfc using event.getArg('obj_PersonBean').

In my quest to make my the Service Layer more independent of Mach II, I decided to take out the event-bean creation in Mach II, and let the Service Layer handle it. Now my Listener just passes the Primary Key which gets into the event from the form or url. The service cfc now takes the Primary Key as an argument instead of the object. The Service layer already has the PersonBean as an object courtesy of ColdSpring Dependency Injection. The getPerson function just runs the init, passing in the Primary Key. Then the Read Function of the DAO gets the rest of the data and populates the rest of the object.

Now I need to do something similar to my update Events which still have event-bean. I guess I'll have to pass in event.getArgs() to the Service.

ColdSpring, Mach II, OOP  |  Send
Posted 3/20/06 @ 5:39 AM by Matt Williams

Canvas Wiki using Mach II

I have been trying to learn the various frameworks in the past couple of months. For my own benefit, I converted Ray Camden's Canvas Wiki to Mach-II. Surprisingly, it only took about an 1 hour to convert. I'm posting it here as yet another example application that can be used to compare frameworks.

As I am just learning Mach-II and frameworks in general, I will not say that this version of Canvas Wiki uses Mach-II best practices. The one semi-hack I did (partly because I didn't want to spend too much time on it) had to do with the OnRequestStart method in the Controller.cfc. Apparently Model-Glue fires this before each event. Mach-II uses plugins for this approach. Since other methods in the Controller refer to an object created in the OnRequestStart, I couldn't figure out how to get a plugin to work. My semi-hack was just to add another notify listener line within each event that calls the OnRequestStart in Controller.cfc.

Anyway, the link to the code is below.
NOTE: THIS IS NOT RAY CAMDEN'S OFFICIAL RELEASE. CODE HAS BEEN MODIFIED TO WORK WITH MACH-II.

Mach II  |  Send
Posted 3/9/06 @ 5:28 AM by Matt Williams

Liking Mach II

I'm liking Mach II so far. Although I do have some reservations mostly due to my own lack of OOP understanding. The following is a comment I posted on Matt Woodward's blog. Putting it here for my own reference.

This is great. I've been following your and other examples as I begin a rewrite for a spaghetti-code application. I really appreciate you taking the time to do these explanations.

The contact manager looks nice and simple as there is only one table. As I get into my app which has a ton of tables, it seems I am going to have a Listener, DAO, Gateway, and Bean for every table. And just last weekend I decided to give ColdSpring a go which added a Service cfc between the Listener and the other objects. Although bean generators and copy-paste-search-replace keep from typing much code, I feel like there is a lot of redundancy.

Having only started on the rewrite, I already have 7 Listeners, 7 Services, 10 DAOs/Gateways, and 6 Beans. I am keeping these organized in their respective directories.

Currently my hope lies in the fact that I'll be at cf.Objective where you and others will help me see the light.

Mach II  |  Send
Posted 3/3/06 @ 5:25 AM by Matt Williams

Now trying Mach-II

After some time away from working on the TKS rewrite (due to Christmas and other more urgent projects), I started looking at it again last week. I'm finding Fusebox to be a bit cumbersome, at least to do in the OO way I am attempting. It seemed unclear where to put various pieces of code and such. Working in about 3 or 4 circuit.xml files got confusing.

So now I am trying to learn and use Mach-II which is a framework created by at least one of the same developers that created Fusebox. Mach-II is meant to encourage/enforce a more Object-Oriented type of development. It has one mach-ii.xml file where events, listeners and views go. So far I've only been working on a login form, but I think I understand the basic setup.

That's it for now. Oh, and of course this post was instigated by an email threatening to shut down my blog if there wasn't some sort of entry. :)

Mach II, TKS  |  Send
Posted 2/13/06 @ 5:23 AM by Matt Williams