do not include .git directory
[catagits/Reaction.git] / old / Manual / Example.pod
1 =head1 NAME
2
3 Reaction::Manual::Example - Simple Reaction example
4
5 =head1 DESCRIPTION
6
7 This tutorial will guide you through the process of setting up and testing a
8 very basic CRUD application based on the database from
9 L<DBIx::Class::Manual::Example>.
10
11 You need at least a fairly basic understanding of L<DBIx::Class::Schema> for
12 this example to have value for you.
13
14 =head2 Installation
15
16 Install L<DBIx::Class> via CPAN.
17
18 Install Reaction from http://code2.0beta.co.uk/reaction/svn via SVN or SVK.
19
20 Set up the database as mentioned in L<DBIx::Class::Manual::Example>. Don't do
21 any of the DBIx::Class related stuff, only the SQLite database.
22
23 =head2 Create the application
24
25   catalyst.pl Test::Reaction 
26   cd Test-Reaction
27   script/test_reaction_create.pl Model Test::Reaction DBIC::Schema Test::Reaction::DB
28
29 Also, remember to include Catalyst::Plugin::I18N in your plugin list, like
30 this:
31
32   use Catalyst qw/-Debug ConfigLoader Static::Simple I18N/;
33
34 =head2 Set up DBIx::Class::Schema
35
36 In addition to the normal DBIC stuff, you need to moosify your DBIC classes.
37
38 Change directory back from db to the directory app:
39
40   cd lib/Test/Reaction
41   mkdir DB
42
43 Then, create the following DBIx::Class::Schema classes:
44
45 DB.pm:
46     
47   package Test::Reaction::DB;
48
49   use base 'DBIx::Class::Schema';
50   
51   __PACKAGE__->load_classes;
52   
53   1;
54
55 DB/Artist.pm:
56
57   package Test::Reaction::DB::Artist;
58   
59   use base 'DBIx::Class';
60   use Reaction::Class;
61   
62   has 'artistid' => ( isa => 'Int', is => 'ro', required => 1 );
63   has 'name' => ( isa => 'NonEmptySimpleStr', is => 'rw', required => 1 );
64   
65   sub display_name {
66       my $self = shift;
67       return $self->name;
68   }
69   
70   __PACKAGE__->load_components(qw/PK::Auto Core/);
71   __PACKAGE__->table('artist');
72   __PACKAGE__->add_columns(qw/ artistid name /);
73   __PACKAGE__->set_primary_key('artistid');
74   __PACKAGE__->has_many( 'cds' => 'Test::Reaction::DB::Cd' );
75   
76   1;
77
78 DB/Cd.pm:
79
80   package Test::Reaction::DB::Cd;
81
82   use base 'DBIx::Class';
83   use Reaction::Class;
84   
85   has 'cdid' => ( isa => 'Int', is => 'ro', required => 1 );
86   has 'artist' =>
87       ( isa => 'Test::Reaction::DB::Artist', is => 'rw', required => 1 );
88   has 'title' => ( isa => 'NonEmptySimpleStr', is => 'rw', required => 1 );
89   
90   sub display_name {
91       my $self = shift;
92       return $self->title;
93   }
94   
95   __PACKAGE__->load_components(qw/PK::Auto Core/);
96   __PACKAGE__->table('cd');
97   __PACKAGE__->add_columns(qw/ cdid artist title/);
98   __PACKAGE__->set_primary_key('cdid');
99   __PACKAGE__->belongs_to( 'artist' => 'Test::Reaction::DB::Artist' );
100   __PACKAGE__->has_many( 'tracks' => 'Test::Reaction::DB::Track' );
101   
102   1;
103
104 DB/Track.pm:
105
106   package Test::Reaction::DB::Track;
107   
108   use base 'DBIx::Class';
109   use Reaction::Class;
110   
111   has 'trackid' => ( isa => 'Int', is => 'ro', required => 1 );
112   has 'cd'    => ( isa => 'Test::Reaction::DB::Cd', is => 'rw', required => 1 );
113   has 'title' => ( isa => 'NonEmptySimpleStr',      is => 'rw', required => 1 );
114   
115   __PACKAGE__->load_components(qw/PK::Auto Core/);
116   __PACKAGE__->table('track');
117   __PACKAGE__->add_columns(qw/ trackid cd title/);
118   __PACKAGE__->set_primary_key('trackid');
119   __PACKAGE__->belongs_to( 'cd' => 'Test::Reaction::DB::Cd' );
120   
121   1;
122
123 =head3 Reaction attributes
124
125 See L<Reaction::Types::Core>
126
127 =head3 The rest
128
129 Reaction will use I<sub display_name> for displaying when there is a 1:Many or
130 Many:Many relation. It will return a suitable text representation.
131
132 =head2 Models
133
134 =head3 Create Test::Reaction::Model::Action
135
136 Still in lib/Test/Reaction, create 
137
138 Model/Action.pm:
139
140   package Test::Reaction::Model::Action;
141   
142   use Reaction::Class;
143   
144   use Test::Reaction::DB;
145   
146   use aliased 'Reaction::InterfaceModel::Action::DBIC::ActionReflector';
147   
148   my $r = ActionReflector->new;
149   
150   $r->reflect_actions_for( 'Test::Reaction::DB::Artist' => __PACKAGE__ );
151   $r->reflect_actions_for( 'Test::Reaction::DB::Cd'     => __PACKAGE__ );
152   $r->reflect_actions_for( 'Test::Reaction::DB::Track'  => __PACKAGE__ );
153   
154   1;
155
156 =head2 Controllers
157
158 Reaction controllers inherit from Reaction::UI::CRUDController, like this:
159
160 Controller/Artist.pm
161
162   package Test::Reaction::Controller::Artist;
163   
164   use strict;
165   use warnings;
166   use base 'Reaction::UI::CRUDController';
167   use Reaction::Class;
168   
169   __PACKAGE__->config(
170     model_base => 'Test::Reaction',
171     model_name => 'Artist',
172     action => { base => { Chained => '/base', PathPart => 'artist' } }
173   );
174   
175   1;
176
177 Controller/Cd.pm
178
179   package Test::Reaction::Controller::Cd;
180   
181   use strict;
182   use warnings;
183   use base 'Reaction::UI::CRUDController';
184   use Reaction::Class;
185   
186   __PACKAGE__->config(
187     model_base => 'Test::Reaction',
188     model_name => 'Cd',
189     action => { base => { Chained => '/base', PathPart => 'cd' } }
190   );
191   
192   1;
193
194 Controller/Track.pm
195
196   package Test::Reaction::Controller::Track;
197   
198   use strict;
199   use warnings;
200   use base 'Reaction::UI::CRUDController';
201   use Reaction::Class;
202   
203   __PACKAGE__->config(
204     model_base => 'Test::Reaction',
205     model_name => 'Track',
206     action => { base => { Chained => '/base', PathPart => 'track' } }
207   );
208   
209   1;
210
211 Finally, change Controller/Root.pm to
212
213   package Test::Reaction::Controller::Root;
214   
215   use strict;
216   use warnings;
217   use base 'Reaction::UI::RootController';
218   use Reaction::Class;
219   
220   use aliased 'Reaction::UI::ViewPort';
221   use aliased 'Reaction::UI::ViewPort::ListView';
222   use aliased 'Reaction::UI::ViewPort::ActionForm';
223   
224   __PACKAGE__->config->{namespace} = '';
225   
226   sub base :Chained('/') :PathPart('') :CaptureArgs(0) {
227     my ($self, $c) = @_;
228   
229     $self->push_viewport(ViewPort, layout => 'xhtml');
230   }
231   
232   sub root :Chained('base') :PathPart('') :Args(0) {
233     my ($self, $c) = @_;
234   
235     $self->push_viewport(ViewPort, layout => 'index');
236   }
237   
238   1;
239
240 =head2 View
241
242 View/XHTML.pm looks like this
243
244   package Test::Reaction::View::XHTML;
245   
246   use Reaction::Class;
247   
248   extends 'Reaction::UI::Renderer::XHTML';
249   
250   1;
251
252 This is all the perly stuff. Now return to the base Test-Reaction directory and
253 create root/index:
254
255   [%
256   
257   main_block = 'index';
258   
259   BLOCK index;
260   
261   %]<p><a href="[% ctx.uri_for('/artist') %]">artist</a></p>
262   <p><a href="[% ctx.uri_for('/cd') %]">cd</a></p>
263   <p><a href="[% ctx.uri_for('/track') %]">track</a></p>[%
264   
265   END;
266   
267   %]
268
269 =head2 Running
270
271 Now all that remains is to tell Catalyst about the root and the model. Let
272 test_reaction.yml look like this:
273
274  ---
275  name: Test::Reaction
276  Controller::Root:
277      view_name:  'XHTML'
278      window_title: 'Reaction Test App'
279  Model::Test::Reaction:
280      schema_class: 'Test::Reaction::DB'
281      connect_info:
282          - 'dbi:SQLite:dbname=database/example.db'
283
284 The finals step for this example is to link to Reaction's templates:
285
286  ln -s <path to reaction install directory>/root/base/ root/base
287
288 At last you're now ready to run the server
289
290   script/test_reaction_server.pl
291
292 =head1 Notes
293
294 =head1 TODO
295
296 =head1 AUTHORS
297
298 See L<Reaction::Class> for authors.
299
300 =head1 LICENSE
301
302 See L<Reaction::Class> for the license.
303
304 =cut