Reaction::Manual::Intro - Introduction to Reaction
-=head1 INTRODUCTION
+=head1 SYNOPSIS
-Reaction is basically an extended MVC:
+ Moose + Catalyst + Layered Models = eternal happiness
-=over
+=head1 MOTIVATION
-=item Domain Model
+While L<Catalyst> is a very powerful and flexible web app
+framework, many pieces end up being recoded for each
+new application: user interfaces, in particular.
-DBIx::Class::Schema, MyApp::Foo, MyApp::Bar, etc.
+Meanwhile, advances in Perl metaprogramming (especially L<Moose>)
+have opened up new possibilities in terms of introspection.
+Why not build user interfaces based on class metadata?
+This would allow the user interface templates to be very general
+where possible.
-=item Interface Model
+Thus, Reaction is basically an extended MVC framework, which
+leverages class metadata to reduce or eliminate UI coding.
-InterfaceModel::DBIC::Schema, InterfaceModel::Action,
-MyApp::InterfaceModel::Foo classes.
+But it's much more....
-=item Controller
+=head1 DOMAIN MODELS AND INTERFACE MODELS
-Mediation and navigation.
+Many programmers are now comfortable using ORMs of one sort or
+another - L<DBIx::Class>, L<Class::DBI>, Hibernate, etc. These systems
+are wonderful for bridging from the world of OO into the world of relational
+databases (or other datastores). This model is sometimes called a
+"domain model", because it models the "nouns" of a problem domain in
+the real world. Domain models are easily shared accross applications,
+and can enforce validation and other integrity constraints.
-=item ViewPort
+However, over time, many application developers find themselves adding
+business logic to the domain model. This business logic is often
+application-specific, and reduces the reusability of the domain model.
+Worse, business logic becomes spread between the model and the contoller.
-Event handling encapsulation.
+Reaction adds another layer, the Interface Model. Interface models provide an
+adaptor to the domain model, customized for a particular application (or group
+of use cases). This decouples the domain model from the application,
+allowing it to be reused more freely. Additionally, the Interface Model
+becomes the natural location for business logic.
-=item Widget
+Happily, Reaction again uses reflection to make the degenerate case easy - when your
+IM has no customized functionality, it can simply delegate all work to the DM. When
+you need to add custom business logic, you can add or replace functionality as needed.
-View logic.
+The DM/IM split is sometimes referred to as a FacadeModel - see L<http://www.twinforces.com/tf/docs/MFCV.html>, for example.
-=item Renderer
+=head1 WHAT YOU'LL NEED TO KNOW
-MyApp::View:: classes, renders viewports.
+Reaction is based on the L<Catalyst> web application framework. You'll certainly
+need to be familiar with L<Catalyst::Manual::Intro>.
-=back
-
-=head1 THE REACTION WAY
-
-The idea is you separate your domain model, which encapsulates the domain
-itself from your interface model, which is a model of how a particular app or
-class of apps interact with that domain and provides objects/methods to
-encapsulate the common operations it does.
-
-=head2 Domain Models vs Interface Models
-
-Domain models are expected to drive the application business logic and data.
-All domain models that need to be effectively displayed somehow at the user
-interface (a table, for instance) must interact with an interface model.
-These should provide the common methods needed in order to carry out
-user-generated events.
-
-=head1 SETTING UP A REACTION APPLICATION
-
-Reaction applications are set up just like Catalyst:
-
- $ catalyst.pl MyApp
- # output ommited
- $ cd MyApp
-
-=head2 Models
-
-Reaction provides a reflector component which automagically
-maps a L<DBIx::Class::Schema> into a set of Interface Models which can be used
-by Reaction to build the interface components. If you're not familiar with
-L<DBIx::Class> or don't have a schema handy, now is a good time to go through
-L<DBIx::Class::Manual::Intro> to get a schema set up.
-
-It is important that your Result-objects implement the meta-protocol of Moose
-One way to achive that is to do the following:
-
- package MyApp::Schema::Result::Bar;
- use base 'DBIx::Class';
- use Moose;
-
- has 'name' => (isa => 'Str', required => 1, rw => 1);
-
- use namespace::clean -except => [ 'meta' ];
-
- __PACKAGE__->load_components(qw(Core));
- __PACKAGE__->table('bar');
- __PACKAGE__->add_columns(
- name => {
- data_type => 'varchar',
- size => 255,
- is_nullable => 0,
- }
- );
- __PACKAGE__->primary_key('name');
- 1;
-
-Once you have your schema set up like that, you can create the InferfaceModel:
-
- package MyApp::InterfaceModel::DBIC;
-
- use base 'Reaction::InterfaceModel::Object';
- use Reaction::InterfaceModel::Reflector::DBIC;
-
- my $reflector = Reaction::InterfaceModel::Reflector::DBIC->new;
-
- $reflector->reflect_schema(
- model_class => __PACKAGE__,
- schema_class => 'MyApp::Schema',
- sources => [qw/Foo Baz/],
- );
-
- 1;
-
-Then you create a MyApp::Model that uses this InferfaceModel:
-
- package Myapp::Model::IM;
-
- use Reaction::Class;
-
- extends 'Catalyst::Model::Reaction::InterfaceModel::DBIC';
-
- 1;
-
-=head2 Controllers
-
-=head3 Root controller
-
-Your Reaction application must have a Root controller which inherits from
-C<Reaction::UI::Controller::Root>.
-
- package MyApp::Controller::Root;
-
- use warnings;
- use strict;
- use base qw/Reaction::UI::Controller::Root/;
-
- __PACKAGE__->config(
- view_name => 'Site',
- window_title => 'My Reaction App',
- namespace => ''
- );
-
- sub base : Chained('/') PathPart('') CaptureArgs(0) {
- # do some setup for every request
- # also provides a chain root for other controllers to use
- }
-
- 1;
-
-=head3 Individual controllers
-
-For each Collection(table?) in your DB, you need to create a controller
-
- package MyApp::Controller::Foo;
-
- use base 'Reaction::UI::Controller::Collection::CRUD';
- use Reaction::Class;
-
- __PACKAGE__->config(
- model_name => 'IM', # This corresponds to the name of the MyApp::Model you created earlier
- collection_name => 'Foo', # Name of one of the sources in your InterfaceModel
- action => {
- base => { Chained => '/base', # chain to the base action in the root controller
- PathPart => 'foo' },
- },
- );
-
- 1;
-
-XX TODO
-
-=head2 View
-
-One of the views in your application should look something like this:
+Currently, only L<DBIx::Class> is supported as a domain model. At least basic
+familiarity will be needed. L<DBIx::Class::Manual::Intro> is a good starting point.
- package MyApp::View::TT;
+The default view renderer is L<Template::Toolkit>. To edit your views, you'll
+need to know something about it.
- use Reaction::Class;
+While you don't need to know L<Moose> directly, a lot of the concepts of
+metaprogramming will keep coming up as you work with Reaction.
+Thus, getting to know L<Moose> will serve you well.
- extends 'Reaction::UI::View::TT';
+=head1 NEXT STEPS
- 1;
+If you'd like an example, see L<Reaction::Manual::Example>.
- __END__;
+If you're ready to dive in and start learning step by step, see L<Reaction::Manual::Tutorial>.
-
-XX TODO
+As you encounter unfamiliar terms, or want to see how a particular term is used in the context of the Reaction project, refer to the L<Reaction::Manual::Glossary>.
=head1 SEE ALSO