Re: RFC: Apache::Controller
by Joost (Canon) on Dec 02, 2004 at 23:26 UTC
|
First things first: I don't think the "perfect" framework for web applications has been invented yet, so ++ for giving it a shot.
One thing I don't like is that the template is too tightly coupled to the action - it's entirely possible that several related actions want to use the same template, or for an action to have more than one resulting template.
For instance:
form -> (submit action) -> form again, with missing data highlighted -> (submit action) -> confirmation screen.
By deriving the template name from the classname of the action you need to create extra templates that will probably only include the "real" template.
Also, I'm sceptical about using classes to describe actions. See my comment in the CGI::Prototype thread.
Lastly, I would like more hooks in the code - some place to do general setup or session management would be nice for instance (maybe by inheriting from the Apache::Controller). See CGI::Application and CGI::Prototype for examples :-)
| [reply] |
|
Thanks for your comments! I will definitely give them some more thought, but here are some of my initial reactions.
First things first: I don't think the "perfect" framework for web applications has been invented yet
I agree, but before we start off with the wrong idea, I'm not really attempting to build an entire framework. I'm only trying to make one part of it -- the controller. And a very limited controller at that.
One thing I don't like is that the template is too tightly coupled to the action - it's entirely possible that several related actions want to use the same template
This is true, and probably something I'll put in eventually. I could easily extend the contructor to take in template names for the actions, along with the module names. I'd keep the default behavior of template name being the same as action name, though, because it's quite convenient.
or for an action to have more than one resulting template.
I'm not so sure about this. I would either make the template flexible enough to handle everything the action needs, or to create two different actions.
Also, I'm sceptical about using classes to describe actions.
Well, I don't know if this has any bearing on your argument or not, but I'm not really using classes. Just plain old Perl packages. The main purpose they serve is to contain the handler subroutines, but they also make for a nice separation at the filesystem level, which I like.
Lastly, I would like more hooks in the code - some place to do general setup or session management would be nice for instance
This is a perfect example of why I don't like the name I've chosen. I'm not attempting to write an end-all, be-all solution, just something that lets me get some stuff done. These features would definitely be useful in many applications, but for what I'm doing, they'd just get in the way. Maybe there's a better way to name my module that conveys that message?
| [reply] [d/l] |
|
or for an action to have more than one resulting template.
I'm not so sure about this. I would either make the template flexible enough to handle everything the action needs, or to create two different actions
But how do you know what action is going to get run, then?
See my example about form validation above. Basically, you recieve data from "form 1" ( to an action) , and you want to either a) go back to a form 1. b) proceed to form 2, and try to submit that (repeat for form 2, 3 etc.).
In your system you will need to include form 1 and form 2 into one template just because the action can't choose the template for you. It's certainly possible to do that, but I think it will get ugly very quickly.
| [reply] |
|
Re: RFC: Apache::Controller
by hardburn (Abbot) on Dec 03, 2004 at 05:03 UTC
|
If you're aiming for using such a beast directly as an Apache handler, you could say:
package My::App;
use base 'CGI::Application';
sub handler
{
my $r = shift;
__PACKAGE__->new->run;
}
# Rest of CGI::Application code
Nothing to it, really. No need for wheel-reinvention when this wheel will do what you want.
"There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.
| [reply] [d/l] |
|
Hmm, of course it looks simple and obvious when someone else does it. Maybe they should put an example like this in the CGI::Application docs. The only mention I saw of mod_perl said that it could be used with Apache::Registry, which caused me to immediately look elsewhere.
| [reply] [d/l] |
|
Re: C::A and mod_perl. I guess the best place to go after the docs is the Wiki entry on using a mod_perl handler. Alas, the wiki doesn't seem to be as well known as it should be....
| [reply] |
Re: RFC: Apache::Controller
by perrin (Chancellor) on Dec 02, 2004 at 22:28 UTC
|
If your problem with CGI::Application was that you don't want to waste your time with Apache::Registry and little .cgi files, check out CGI::Application::Plugin::Apache, written by one of my co-workers. It makes CGI::Application fit into mod_perl much more naturally. | [reply] |
|
If your problem with CGI::Application was that you don't want to waste your time with Apache::Registry and little .cgi files
Yes, that was my main problem with it.
check out CGI::Application::Plugin::Apache, written by one of my co-workers. It makes CGI::Application fit into mod_perl much more naturally.
Ah, if only I'd known about that before I started, it would have saved me a few hours of work. But at this point, I probably won't make the effort to switch over.
I'm still curious if my module would be of interest to anyone else. So far it doesn't seem like it, so I'm leaning towards not releasing it...
| [reply] |
Re: RFC: Apache::Controller
by domm (Chaplain) on Dec 03, 2004 at 09:27 UTC
|
I'm in a hurry right now, so I haven't read your node completly, but what I read sounds a bit like Apache::Dispatch
--
#!/usr/bin/perl
for(ref bless{},just'another'perl'hacker){s-:+-$"-g&&print$_.$/}
| [reply] [d/l] |
|
| [reply] |
Re: RFC: Apache::Controller
by sri (Vicar) on Dec 04, 2004 at 03:26 UTC
|
Funny, this looks a bit similar to a project i'll release very soon called Catalyst.
I started the project while i maintained Maypole, it was supposed to fix some design flaws and become Maypole 3.0.
But it has fast grown into something very different from Maypole, so it became a subproject which now completely aims at enterprise class applications.
There are still lots of features from Maypole present but i also added many things from Struts, Struts-Chain, Struts-Delegate(Action mapping, Chain of Responsibility, Forms, Decorators, Filters), Tomcat(Contexts, Sessions, elegant api for headers, cookies and uploads...), SpringMVC(AOP features...), Ruby on Rails (Multiple controller support) and WebWork2.
Stuff like exception handling, roles based security, i18n, mod_perl1/mod_perl2/CGI support with unified api, simple debugging and profiling is naturally built in.
It also has many benefits for development in big teams and refactoring. (separation of flow and code, splitting code into small pieces...)
Here is an example for a Controller class.
package PetStore;
use strict;
use Catalyst '-Debug';
# Application name
PetStore->config->name('Catalyst PetStore');
# Root directory for additional files
PetStore->config->root('/home/sri/PetStore/web');
# Base uri for our application
PetStore->config->base('http://localhost/petstore');
# Session settings
PetStore->config->session(
class => 'Apache::Session::Postgres',
options => {
DataSource => 'dbi:Pg:dbname=petstore',
TableName => 'session',
UserName => 'postgres',
Password => 0,
Commit => 1
}
);
# Actions
PetStore->action(
# Built in action that'll get called at the end of a request,
# we use it for the view here,
# which in this case is YAML REST or TT2
_end => sub {
# form() returns a Data::FormValidator::Results object that
# will be automatically initialised when you use it
if ( form->valid('rest') ) {
# trunk is our universal data container to exchange
# informations between actions and methods
trunk( content_type => 'text/plain' );
call('PetStore::View::REST');
}
else {
# Set a default template
trunk( template => 'index.tt' );
call('PetStore::View::TT');
}
},
# Built in action that'll get called once at startup time to
# initialze your environment
'_setup' => sub {
# setup initializes a Catalyst component for you
setup('PetStore::Model::Cart');
setup(
'PetStore::Model::CDBI',
base => 'Catalyst::Model::CDBI',
dsn => 'dbi:Pg:dbname=petstore',
user => 'postgres',
password => '',
options => { AutoCommit => 1 }
);
setup( 'PetStore::View::REST',
base => 'Catalyst::View::REST::YAML' );
setup( 'PetStore::View::TT', base => 'Catalyst::View::TT' );
},
# Private action to publish the cart
_cart_to_objects => sub {
call(qw(PetStore::Model::Cart items_to_objects));
call(qw(PetStore::Model::CDBI::Item describe_cart_items));
call(qw(PetStore::Model::CDBI::Category describe_cart_items));
},
# Private action to to publish categories
_categories_to_objects => sub {
call(qw(PetStore::Model::CDBI::Category list));
},
# Start page
'index.html' => sub {
trunk( template => 'index.tt' );
# Merge with the existing Data::FormValidator::Results object
# or create a new one
form( required => ['yada'] );
# Include a private action at this point
include('_categories_to_objects');
},
# Show and edit the cart
'cart.html' => sub {
trunk( template => 'cart.tt' );
call(qw(PetStore::Model::Cart add)) if form->valid('add');
call(qw(PetStore::Model::Cart update))
if form->valid('update');
include('_cart_to_objects');
},
# Show products in category
'category.html' => sub {
roles(qw(foo bar));
trunk( template => 'category.tt' );
call(qw(PetStore::Controller::CDBI::Product list));
}
);
1;
The code is almost done and i'm currently writing documentation and examples for it, so if you're interested just hang out at #maypole on irc.perl.org (i'm searching testers;) or wait for the release, which will happen soon. | [reply] [d/l] |
|
Funny, this looks a bit similar to a project i'll release very soon called Catalyst.
Only if you would say a jetliner is "a bit similar" to a hang glider. :-) I must say, your project is much more ambitious than mine. I was attempting to be one humble piece of a very small pie, but what you have seems to be an entire pie with ice cream and chocolate sauce on the side. [Hmm, what other strained metaphors can I come up with?]
What you've shown looks very nice, and it would probably save a lot of time and effort in a large project, but for some projects it would be major overkill. I was trying to build the module that's useful for the smaller projects. It works well with the small, extremely simple application that I'm building, and attempts to follow the "do one thing and do it well" philosophy.
The problem is, I don't know if the small, simple solution would really be useful for anyone else. Based on the replies to this Meditation, the answer is "nah, we're happy with what we've already got." So I'll avoid releasing it unless someone asks.
| [reply] |
Re: RFC: Apache::Controller
by Mutant (Priest) on May 03, 2005 at 10:44 UTC
|
Just to add another module to the list (since this node came up in a search for this sort of stuff), there's also CGI::Application::Dispatch. | [reply] |