[Catalyst] Instant CRUD with DBIC::Schema
Peter Karman
peter at peknet.com
Wed Mar 12 13:55:31 GMT 2008
On 03/12/2008 05:50 AM, Zbigniew Lukasiak wrote:
> After some more playing with CatalystX::CRUD I think I can formulate
> my arguments a bit more clearly.
>
> I believe the objects that users of CatalystX::CRUD get in their
> controller should be the real things - i.e. objects from their models
> not CatalystX::CRUD::Model::Objects. This would be the minimal
> interface and minimal hassle for injecting CatalystX::CRUD::Controller
> actions to a legacy Catalyst controller.
>
Let me outline the problem I was trying to solve, and maybe you can suggest an alternate
solution. Or explain why the problem I see is not the problem you see.
My original idea for CX::CRUD was to design an API that was high-level enough that a CRUD
Controller would not need to know anything specific about a CRUD Model, except what was
defined by the CX::CRUD API. That is, if I was using Rose::HTML::Objects to manage my
forms, my Controller could exchange DBIC for RDBO as its Model and not need to change any
Controller code. Likewise, the Model need not know anything about the Controller except
what was defined by the API. Ideally, all the logic for Controller and Model is
encapsulated within each, and they talk to each other minimally and only through
well-defined methods.
Some levels of indirection were thus required. CX::CRUD is duct tape, but it ought to be
sensible and predictable how the duct tape works.
So then the questions began. Assuming I have a $form and an $object:
(1) where and how should they interact? Should they interact in the Controller or the
Model? Or somewhere not either of those?
(2) should the $form and $object have any expectations about the methods available on the
other object? Or how else can they interact in a relatively agnostic way?
>From a programming philosophy perspective, I could be persuaded about the answer to (1). I
don't have strong opinions. IME, it's more practical for me in my Cat apps to put workflow
kinds of code in a Controller, make my Models as thin as possible, and put as much code as
possible in classes outside of Catalyst altogether. For CX::CRUD, I compromised, based on
the pattern I followed in Catalyst::Controller::CRUD, and put the basic $form/$object
interaction in the Controller, and made the Model a thin/convenient wrapper around the
non-Catalyst model class(es). I did this because, to my way of thinking, it makes a
sensible parallel construction to implement Form processing in the Controller and storage
processing (business logic, whatever you want to call it) in the Model. The Model knows
nothing about Forms; the Form is just one way of getting data to and from the Model, and
since facilitating workflow is what a Controller does, the Form belongs in the Controller.
Since I decided to put the $form/$object code in the Controller, the answer to (2) became
more obvious to me: the objects should have some common expectations about each other. In
the case of the $object, the $form should expect the $object to implement the basic CRUD
methods: create() read() update() delete(). That's where CatalystX::CRUD::Object came
from. It abstracts those 4 methods and leaves it up to CX::CRUD::Model authors to
implement them for their particular model package (ORM, whatever).
In the case of the $form, the $object should expect some way of getting and setting data
(moving data to/from) the $form. That's where the CX::CRUD::Controller config values for
'init_form' and 'init_object' come from, and why the form_to_object() method is not
implemented in the base Controller but left up to the specific Form implementation (like
in CX::CRUD::Controller::RHTMLO).
Now granted, a lot of my API ideas are influenced by how RHTMLO and RDBO work. I don't
apologize for that; I like those APIs, which is why I use those packages.
But I can understand that the DBIC/FormFu folks think differently, which is why there is
more than one ORM and Form package out there. :)
So, assuming I have identified the design problems correctly, I can imagine an alternate
solution. Get rid of CatalystX::CRUD::Object. Put the create/read/update/delete methods in
CatalystX::CRUD::Model instead. Change the base Controller behaviour to do this:
$c->model( $self->model_name )->create( $object );
instead of this (what it does currently):
$object->create;
Now, I like the current implementation because it is (a) terser and (b) seems clearer to
me what is happening.
But if the design goal of common expectations for $form and $object is to be achieved, we
need some way of defining that API. I'm open to suggestions of how to get rid of
CX::CRUD::Object and still defining a way for Controllers to be Model agnostic.
--
Peter Karman . peter at peknet.com . http://peknet.com/
More information about the Catalyst
mailing list