Wow, this is a long one.  As usual, everyone has slightly different
ideas about how to do MVC, so keep a grain of salt handy.

> This basic pattern repeated ad infinitum.  It's grown way out of
> control, is a pain to work with, and just feels wrong, very wrong. :-)

We've all been there.

> 1.  Is there one Controller or many?

Usually there are many.

> Should I have one for each main
> area of my site?  /myapp/admin/ goes to an Admin Controller,
> /myapp/reports to another controller, etc...

That's how I would do it.  The idea is to group the things that are
related together, since they tend to change at the same time.

> 2.  Does the first part of my code above even remotely resemble a
> Controller?

Sort of.  It does choose a view and it does parse some user input, but a
controller is more than just a dispatcher.  It would include some of the
code that you're currently putting into your doDoctorActivity() sub.
The idea is that the model objects represent just the data in your
application (the nouns) and the controller understands how to translate
user input into a series of method calls on the model objects to carry
out the user's request.

It's hard to give a good example that is short, but let's say you were
building an application to sell concert tickets.  The act of buying the
ticket might involve model objects representing a concert, a user, a
form of payment, etc.  The concert object knows how to reserve a
specific seat (or call a seat object to do that).  The payment object
knows how to verify and charge a credit card.  The user object has a
mailing address.  The controller knows how to turn the user's form data
into a bunch of method calls on these objects that accomplish reserving
the ticket and charging the user.  If you find yourself writing a
"BuyTicket" module, that's a controller not a model object.

> 3.  How do you prevent a Controller from just becoming another big if
> statement, or is this their purpose in life?

If you break up your app into multiple controllers, there will probably
only be a few different actions that each one handles.  That's a pretty
small if statement, or you could use a dispatch table.  Modules like
CGI::Application have already written the dispatch table code for you,
so you just provide the configuration that maps actions to subroutines.

> 4.  In the case of a form, what perl structure is used to pass the
data
> into the model?

You don't pass a form directly to a model object.  You parse the form,
then you use the API provided by the model object.  Remember, we want to
be able to use these same model objects from a cron job.

my $hospital = $apr->param('hospital');
$doctor->set_hospital($hospital);

> 5.  Do you create an actual class for each form?

Similar to #1, each form might have it's own controller class, or you
might group some related forms (that act on the same data) together in a
single controller.

> 6.  Do you need to create objects at all?  Is OO a prerequisite to
MVC?

Modelling your data as objects is sort of an underlying assumption in
MVC.  You could do a clean design without using OO, but it would be a
little odd and the model objects might not be very reusable.

> 6.5.  (thought of while proofreading :-)  Is the statement "there is
one
> set of controllers for each defined view" correct?

No.

> In other words, if
> we someday want to output the "reports" section of the site as Excel
> spreadsheets in addition to HTML, would we define a new set of
> controllers or how would that work?

You would make your existing controllers understand the piece of user
input or context that means they want Excel format, and have them pass
the model data to a different view in that case.

> 7a.  Is it insane to leave my SQL hard-coded in there?

You're going to have SQL somewhere, but if you wrap it up into objects
that represent your data, it's easier to maintain.  It hides all of that
specific database knowledge from the rest of the application and avoids
repitition.

At eToys we had a tremendous amount of data associated with each
product.  It spanned many tables and was not very easy to work with.
However, once I had written an object representing a product, the search
code, shopping cart code, product page code, etc. could all use it.
When we added new properties, I only had to do it one place.

OO modelling is a big subject and lots of good books have been written
on it, so I won't say more about it here.

> 7b.  Should I really investigate real object persistence like
discussed
> at the POOP site (I have used Tangram with some success on tiny side
> projects but nothing remotely this size)?

Only if you like what it does for you.  I generally prefer to write the
SQL myself because of the tuning opportunities it affords, but this is
the sort of topic that many people have strong opinions on.  Anyway,
objects that contain hand-coded SQL are just as real as objects that use
a POOP module to generate the SQL for them.

> Begging the question, should
> I really be migrating to more of an OO style of programming?

My advice is yes.  OO helps focus your attention on interfaces and
abstraction, and that's the whole point of this stuff.

> 7c.  Is there some middle ground that would consolidate our database
> query code but not be a full abstraction layer which I simply think is
> overkill for what we need and for our current talents?

You could make modules that gather the SQL for doing certain things into
discrete chunks with defined API calls, like create_doctor(),
load_doctor(), update_doctor(), remove_doctor().  It's sort of slouching
towards OO.  It's not perfect, but it gives you a little bit more
abstraction than what you have.

> 7d.  Or do I -really- want an object/structure that represents every
> result set we need to get back from the database?

If you're using templates, you already have a structure for at least
most of these.  You just need to put each one in a module and turn the
operations that fetch and modify it into methods in that module.  It's
simpler than it sounds.

> 8a.  What structures are used to pass back the data from the model
> through the controller to the view?

You pass the model objects to the view.  If you're using HTML::Template
to implement the view, you would probably have a little bit of code that
would ask the model objects for a data structure representing themselves
to use in the templates.

> 8b.  The view is expecting HTML::Template style hashes and arrays, do
I
> form these in the model (which seems to be too much knowledge of the
> view while still in the model) or does the controller convert it to
the
> structures expected by the HTML::Template view?

The model doesn't know what the template is going to do with its data.
It just hands you a structure.  There should not be anything related to
display in that structure.

> 8c.  The model is getting DBI record sets from the db.  I have to put
> this data into -something-, why not the exact format that
HTML::Template
> view needs rather than process it twice?

By all means.

> 9.  Does the bottom half of my code resemble a model layer at all?

Not really.  You basically just have a controller with no model layer.

>  Would each of those subs typically become a separate mod_perl module,
> or all live in a library of some sort, etc...begs the question again,
is
> this all really supposed to be OO and I'm supposed to have a bunch of
> MyApp::Model::DoctorActivity modules that the controller 'use's?

The model objects would definitely all be separate modules.  What you
have now is more like a bunch of "actions", so you might group some of
them into a single controller module.

> getTemplate sets a number of
> standard parameters on each and every template.  Kind of publishing
the
> user's session to the template for the template designers to use.

If parts of the presentation depend on this, then that makes sense.

> templates often look like this:
>
> menu option #1
> menu option #2
> <tmpl_if admin_user>
>   Super secret option only admin can see
> </tmpl_if>
>
> How does this fit into the MVC model?  Is this an appropriate use of
the
> view?  Doesn't "feel" like it is.

It looks fine to me.  The important thing is to pass data that has the
right level of abstraction, so that you don't end up doing application
logic in the template.  For example, if both the admins and editors get
to see the "edit content" button, don't do a bunch of ifs in the
template to express that.  Pass something called "user_can_edit".

> Some
> stripped-down code samples would be nice

Again, I would urge people to look at things like OpenInteract.  There's
also tons of articles out there, like this one about doing something
close to MVC with the XML::Application module:
http://www.xml.com/pub/a/2001/12/12/cgi-xml.html

- Perrin

Reply via email to