logo       

Best practices in a thin-controller application: msg#00098

php.zend.framework.mvc

Subject: Best practices in a thin-controller application

Hello!

(I apologize if this gets sent out more than once...my other email
address, Adam.Jensen-gkxvx00wFtQ@xxxxxxxxxxxxxxxx, does not seem to be able to
post to the
lists anymore.)

I'm trying to rethink some of my controller code due to Bill Karwin's
"ActiveRecord does not suck" post, and I'm having some trouble
figuring out where to put what.

Here's an example. Say we're building an application for tracking the
travel schedules of employees. There are two kinds of domain objects:
Trips and Destinations. Every Destination has a Trip, and every Trip
has many Destinations. Users interact with the domain on the Trip
level…they can list, view, add, edit, and delete Trips, adding and/or
removing Destinations in the process. Each of these is represented in
the controller by an appropriately-named action.

So, at this point we have the following classes in the library:

* Travel_Trip
* Travel_Trip_Destination
* Travel_TripsController

The first problem arises when I try to write the "list" action. Each
of the domain objects listed above represents a single entity…none of
the indicated classes is designed to represent a collection. So we
need to add another class for managing the collection:

* Travel_Trip_Collection

Feels a little strange to me, as I've always considered the collection
to be the root of the domain, at least when treating tables and domain
models as though they were the same thing. Is there a better way?

The other problem here is that, while the Travel_Trip_Collection
represents the total collection of Trips in the system, it will need
to return smaller collections of trips in response to particular
method calls. For instance,
Travel_Trip_Collection::fetchAllByCountry('FR') will need to return a
collection containing all trips to France. It doesn't seem right to
use the same collection for this, so we add another class:

* Travel_Trip_List

The semantics at this point are confusing, because Collection is sort
of like a table, whereas List is sort of like a rowset...but their
names don't clearly imply this fact.

Moving on, my next problem is handling user errors in the remaining
methods. Take a look at this:

[code]
public function viewAction()
{
try {
$this->view->trip = new Travel_Trip($this->_getParam('id', null));
} catch (Travel_Trip_Exception_NotFound $e) {
throw new Zend_Controller_Action_Exception('Requested trip not
found.', 404);
}
}
[/code]

This works, but seems a little inappropriate on a couple of levels.
First, I don't think exceptions were meant to be used this way;
they're functioning almost like goto statements, and that makes me
uncomfortable.

Second, we don't get much feedback from the model as to what exactly
the problem is with the user's input. It could be one of several
things:

* The user did not provide an ID parameter.
* The user provided an invalid ID parameter.
* The provided ID number is valid, but does not correspond to any Trip
in the Collection.

In the past I've always tried to do something slightly different for
each of these circumstances, so that the user always knows what was
wrong about his/her request. In order to do this with domain model
exceptions (as above), I'd need three separate exception subclasses,
right?

I suppose the other option for error handling is to have the model
keep track of its own error state…but that introduces extra controller
code for checking the error state, a la…

[code]
public function viewAction()
{
$this->view->trip = new Travel_Trip($this->_getParam('id', null));
if ($this->view->trip->failed == Travel_Trip::NOTFOUND) {
throw new Zend_Controller_Action_Exception('Not found', 404);
}
// check for other error codes as well…
}
[/code]

That's a mouthful; I think I like the exceptions better :)

Anyway, I'm sorry that my questions are not more specific; I'm really
just looking for some clarification as to how the domain layer is
supposed to be implemented, as it's not something I've had much
opportunity to study. Does it look like I'm on the right track, or is
there something I'm missing?

Thanks!

Adam Jensen, Zend Certified Engineer
Web Development
UNT International

jazzslider-Re5JQEeQqe8AvxtiuMwx3w@xxxxxxxxxxxxxxxx
http://www.international.unt.edu



<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise