The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Reaction::Manual::Example - Simple Reaction example

DESCRIPTION

This tutorial will guide you through the process of setting up and testing a very basic CRUD application based on the database from DBIx::Class::Manual::Example.

You need at least a fairly basic understanding of DBIx::Class::Schema for this example to have value for you.

Installation

Install DBIx::Class via CPAN.

Install Reaction from http://code2.0beta.co.uk/reaction/svn via SVN or SVK.

Set up the database as mentioned in DBIx::Class::Manual::Example. Don't do any of the DBIx::Class related stuff, only the SQLite database.

Create the application

  catalyst.pl Test::Reaction 
  cd Test-Reaction
  script/test_reaction_create.pl Model Test::Reaction DBIC::Schema Test::Reaction::DB

Also, remember to include Catalyst::Plugin::I18N in your plugin list, like this:

  use Catalyst qw/-Debug ConfigLoader Static::Simple I18N/;

Set up DBIx::Class::Schema

In addition to the normal DBIC stuff, you need to moosify your DBIC classes.

Change directory back from db to the directory app:

  cd lib/Test/Reaction
  mkdir DB

Then, create the following DBIx::Class::Schema classes:

DB.pm:

  package Test::Reaction::DB;

  use base 'DBIx::Class::Schema';
  
  __PACKAGE__->load_classes;
  
  1;

DB/Artist.pm:

  package Test::Reaction::DB::Artist;
  
  use base 'DBIx::Class';
  use Reaction::Class;
  
  has 'artistid' => ( isa => 'Int', is => 'ro', required => 1 );
  has 'name' => ( isa => 'NonEmptySimpleStr', is => 'rw', required => 1 );
  
  sub display_name {
      my $self = shift;
      return $self->name;
  }
  
  __PACKAGE__->load_components(qw/PK::Auto Core/);
  __PACKAGE__->table('artist');
  __PACKAGE__->add_columns(qw/ artistid name /);
  __PACKAGE__->set_primary_key('artistid');
  __PACKAGE__->has_many( 'cds' => 'Test::Reaction::DB::Cd' );
  
  1;

DB/Cd.pm:

  package Test::Reaction::DB::Cd;

  use base 'DBIx::Class';
  use Reaction::Class;
  
  has 'cdid' => ( isa => 'Int', is => 'ro', required => 1 );
  has 'artist' =>
      ( isa => 'Test::Reaction::DB::Artist', is => 'rw', required => 1 );
  has 'title' => ( isa => 'NonEmptySimpleStr', is => 'rw', required => 1 );
  
  sub display_name {
      my $self = shift;
      return $self->title;
  }
  
  __PACKAGE__->load_components(qw/PK::Auto Core/);
  __PACKAGE__->table('cd');
  __PACKAGE__->add_columns(qw/ cdid artist title/);
  __PACKAGE__->set_primary_key('cdid');
  __PACKAGE__->belongs_to( 'artist' => 'Test::Reaction::DB::Artist' );
  __PACKAGE__->has_many( 'tracks' => 'Test::Reaction::DB::Track' );
  
  1;

DB/Track.pm:

  package Test::Reaction::DB::Track;
  
  use base 'DBIx::Class';
  use Reaction::Class;
  
  has 'trackid' => ( isa => 'Int', is => 'ro', required => 1 );
  has 'cd'    => ( isa => 'Test::Reaction::DB::Cd', is => 'rw', required => 1 );
  has 'title' => ( isa => 'NonEmptySimpleStr',      is => 'rw', required => 1 );
  
  __PACKAGE__->load_components(qw/PK::Auto Core/);
  __PACKAGE__->table('track');
  __PACKAGE__->add_columns(qw/ trackid cd title/);
  __PACKAGE__->set_primary_key('trackid');
  __PACKAGE__->belongs_to( 'cd' => 'Test::Reaction::DB::Cd' );
  
  1;

Reaction attributes

See Reaction::Types::Core

The rest

Reaction will use sub display_name for displaying when there is a 1:Many or Many:Many relation. It will return a suitable text representation.

Models

Create Test::Reaction::Model::Action

Still in lib/Test/Reaction, create

Model/Action.pm:

  package Test::Reaction::Model::Action;
  
  use Reaction::Class;
  
  use Test::Reaction::DB;
  
  use aliased 'Reaction::InterfaceModel::Action::DBIC::ActionReflector';
  
  my $r = ActionReflector->new;
  
  $r->reflect_actions_for( 'Test::Reaction::DB::Artist' => __PACKAGE__ );
  $r->reflect_actions_for( 'Test::Reaction::DB::Cd'     => __PACKAGE__ );
  $r->reflect_actions_for( 'Test::Reaction::DB::Track'  => __PACKAGE__ );
  
  1;

Controllers

Reaction controllers inherit from Reaction::UI::CRUDController, like this:

Controller/Artist.pm

  package Test::Reaction::Controller::Artist;
  
  use strict;
  use warnings;
  use base 'Reaction::UI::CRUDController';
  use Reaction::Class;
  
  __PACKAGE__->config(
    model_base => 'Test::Reaction',
    model_name => 'Artist',
    action => { base => { Chained => '/base', PathPart => 'artist' } }
  );
  
  1;

Controller/Cd.pm

  package Test::Reaction::Controller::Cd;
  
  use strict;
  use warnings;
  use base 'Reaction::UI::CRUDController';
  use Reaction::Class;
  
  __PACKAGE__->config(
    model_base => 'Test::Reaction',
    model_name => 'Cd',
    action => { base => { Chained => '/base', PathPart => 'cd' } }
  );
  
  1;

Controller/Track.pm

  package Test::Reaction::Controller::Track;
  
  use strict;
  use warnings;
  use base 'Reaction::UI::CRUDController';
  use Reaction::Class;
  
  __PACKAGE__->config(
    model_base => 'Test::Reaction',
    model_name => 'Track',
    action => { base => { Chained => '/base', PathPart => 'track' } }
  );
  
  1;

Finally, change Controller/Root.pm to

  package Test::Reaction::Controller::Root;
  
  use strict;
  use warnings;
  use base 'Reaction::UI::RootController';
  use Reaction::Class;
  
  use aliased 'Reaction::UI::ViewPort';
  use aliased 'Reaction::UI::ViewPort::ListView';
  use aliased 'Reaction::UI::ViewPort::ActionForm';
  
  __PACKAGE__->config->{namespace} = '';
  
  sub base :Chained('/') :PathPart('') :CaptureArgs(0) {
    my ($self, $c) = @_;
  
    $self->push_viewport(ViewPort, layout => 'xhtml');
  }
  
  sub root :Chained('base') :PathPart('') :Args(0) {
    my ($self, $c) = @_;
  
    $self->push_viewport(ViewPort, layout => 'index');
  }
  
  1;

View

View/XHTML.pm looks like this

  package Test::Reaction::View::XHTML;
  
  use Reaction::Class;
  
  extends 'Reaction::UI::Renderer::XHTML';
  
  1;

This is all the perly stuff. Now return to the base Test-Reaction directory and create root/index:

  [%
  
  main_block = 'index';
  
  BLOCK index;
  
  %]<p><a href="[% ctx.uri_for('/artist') %]">artist</a></p>
  <p><a href="[% ctx.uri_for('/cd') %]">cd</a></p>
  <p><a href="[% ctx.uri_for('/track') %]">track</a></p>[%
  
  END;
  
  %]

Running

Now all that remains is to tell Catalyst about the root and the model. Let test_reaction.yml look like this:

 ---
 name: Test::Reaction
 Controller::Root:
     view_name:  'XHTML'
     window_title: 'Reaction Test App'
 Model::Test::Reaction:
     schema_class: 'Test::Reaction::DB'
     connect_info:
         - 'dbi:SQLite:dbname=database/example.db'

The finals step for this example is to link to Reaction's templates:

 ln -s <path to reaction install directory>/root/base/ root/base

At last you're now ready to run the server

  script/test_reaction_server.pl

Notes

TODO

AUTHORS

See Reaction::Class for authors.

LICENSE

See Reaction::Class for the license.