r30359@martha (orig r1198): groditi | 2009-08-01 16:57:29 -0400
[catagits/Reaction.git] / lib / Reaction / Manual / Tutorial.pod
CommitLineData
63bb30b4 1=head1 NAME
2
3Reaction::Manual::Tutorial.pod - Step by Step Tutorial
4
5=head1 DESCRIPTION
6
7This document aims at giving simple step-by-step leading to an example application
8using the common functionality provided by L<Reaction>.
9
10=head1 CREATING A NEW APPLICATION
11
12At first we have to create a new application. For this we use the C<catalyst.pl>
13script as we would for any other Catalyst application:
14
15 $ catalyst.pl MyApp
16 [lots "created ..." messages]
17
18There is nothing to change in the application class file.
19
139b74f7 20As you work through this tutorial you'll be creating several new files in
21various directories. You can save some time by creating the directories now,
22like this:
23
24 mkdir -p share/skin/myapp/layout lib/MyApp/View/Site/Widget lib/MyApp/Schema lib/MyApp/InterfaceModel
25
63bb30b4 26=head1 THE VIEW
27
28Since we are not just rendering templates with Reaction, but layouts and widgets,
29a simple TT view won't suffice. We need to create our own C<lib/MyApp/View/Site.pm>:
30
31 package MyApp::View::Site;
32 use Reaction::Class;
33
91c2674b 34 use namespace::autoclean;
63bb30b4 35
36 extends 'Reaction::UI::View::TT';
37
38 __PACKAGE__->meta->make_immutable;
39
40 1;
41
42The C<use Reaction::Class> line will import L<Moose>, L<strict> and L<warnings> into
43our file and might perform some Reaction specific setups.
44
45We make sure that we don't provide imported functions as methods at runtime by using
91c2674b 46L<namespace::autoclean>.
63bb30b4 47
48In its simplest version, our view just needs to do a C<extends 'Reaction::UI::View::TT'>
49to make a new subclass of it.
50
51We chose to call C<make_immutable> on the class' meta class instance to have it inline
52methods for runtime speed improvements.
53
54=head1 THE ROOT CONTROLLER
55
56As usual in Catalyst, our root controller (at C<lib/MyApp/Controller/Root.pm> represents
57the root namespace for our application. For this purpose, it should look like this:
58
59 package MyApp::Controller::Root;
60 use strict;
61 use warnings;
62 use parent 'Reaction::UI::Controller::Root';
63
64 use aliased 'Reaction::UI::ViewPort';
65 use aliased 'Reaction::UI::ViewPort::SiteLayout';
66
91c2674b 67 use namespace::autoclean;
63bb30b4 68
69 __PACKAGE__->config(
70 view_name => 'Site',
71 window_title => 'MyApp Window',
72 namespace => '',
73 );
74
75 sub base: Chained('/') PathPart('') CaptureArgs(0) {
76 my ($self, $ctx) = @_;
77 $self->push_viewport(SiteLayout,
78 title => 'MyApp Test Title',
79 static_base_uri => join('', $ctx->uri_for('/static')),
158404c5 80 meta_info => {
81 http_header => {
82 'Content-Type' => 'text/html;charset=utf-8',
83 },
84 },
63bb30b4 85 );
86 }
87
88 sub root: Chained('base') PathPart('') Args(0) {
89 my ($self, $ctx) = @_;
90 $self->push_viewport(ViewPort, layout => 'root');
91 }
92
93 1;
94
91c2674b 95The effects of L<strict>, L<warnings>, L<parent>, L<aliased> and L<namespace::autoclean>
96should be clear by now. Let's take a look at the configuration.
63bb30b4 97
98The C<view_name> determines which view to use. We set it to C<Site>, which is our only view
99by now. Be careful to set C<view_name> and not C<view>, which would fail telling you it
100expected an object.
101
102The C<window_title> is the title given to the L<Reaction::UI::Window> instance that will be
103stored in C<$ctx-E<gt>stash-E<gt>{window}> by the C<begin> action provided by
104L<Reaction::UI::Controller::Root>.
105
106The C<namespace> setting anchors the root controller at C</>.
107
108The C<base> action here acts as a general point all other actions can chain off of. It
109pushes the L<Reaction::UI::ViewPort::SiteLayout> viewport onto the
110L<focus stack|Reaction::UI::FocusStack>. As arguments we see a C<title> that will be used
111as page title later. The C<static_base_uri> is used for static links like CSS and JavaScript
112files. Since we didn't specify a layout C<site_layout> will be used.
113
114We also defined a C<root> action serving as application index. It chains off the C<base>
115action. It is only pushing the root viewport L<Reaction::UI::ViewPort> on the focus stack,
116but this time we specified a layout named C<root>.
117
118Reaction will try to find our layout files in C<share/skin/$skin_name/layout/*>, so the next
119thing to do is to create a new skin and the layout files.
120
121=head1 A NEW SKIN
122
123If your version of Catalyst still creates a C<root> instead of a C<share> directory, you
124might want to rename it. This is regarded as a best practice and follows the conventions
125of this tutorial and other Reaction documentation.
126
127First we need to create a directory for our new skin:
128
129 $ mkdir -p share/skin/myapp/layout
130
131Next we need to configure our new skin. This is done in the C<share/skin/myapp/skin.conf>
132file. At the moment, all it should contain is
133
134 extends /Reaction/default
135
136Note that this C<extends> specification contains the distribution name of the
137library or application of which to use the templates as base. You can also give it
138a relative name like
139
140 extends foo
141
142and it would try to extend a skin named C<foo> in your own application's C<share/skin>
143directory.
144
145Now we create C<share/skin/defaults.conf> to allow settings that concern all skins of
146the application. It should contain only this:
147
148 widget_search_path MyApp::View::Site::Widget
149 widget_search_path Reaction::UI::Widget
150
151This will tell Reaction to look in C<Reaction::UI::Widget::*> and
152C<MyApp::View::Site::Widget::*> for widget classes. That means that our layout named
153C<root> will check for C<MyApp::View::Site::Widget::Root> first and then look if
154C<Reaction::UI::Widget> exists.
155
156We want the first line to be able to create our own widgets and the second line to
157have Reaction find its own widgets.
158
159Now we need to tell Reaction what skin it should use. We do this by adding this section
160to our C<myapp.conf>:
161
162 <View Site>
163 skin_name myapp
164 </View>
165
166The value should be the name of the target directory under C<share/skin/>.
167
168=head1 LAYOUTS
169
170We will need two layout files to begin with. One controlling the site layout and one
171for the root action.
172
173The first will be created as C<share/skin/myapp/layout/site_layout.tt>:
174
175 =extends NEXT
176
177 =for layout body
178
179 <h1>Welcome to MyApp</h1>
180
181 <div id="content">
182 [% inner %]
183 </div>
184
185 =cut
186
187The C<=extends> directive specifies that this layout file is an extension of another
188layout file. The C<NEXT> value here tells Reaction that this extends the C<site_layout>
189layout in the base skin, which we have defined as C</Reaction/default>. That means, you
190can take a look at the layout we are extending at C<share/skin/default/layout/site_layout.tt>
191in the L<Reaction> distribution.
192
193The C<=for layout> directives allows us to set a layout fragment. We define a C<body> fragment
194containing the common C<body> for all pages using this site layout. The C<[% inner %]> is
195where the deeper parts of the stack will be included, in the case of our C<root> action that
196would be the C<Reaction::UI::ViewPort> with the C<root> layout.
197
198If we wanted to override a specific fragment, we could do just that. And inside that fragment
1639407f 199we could call C<[% call_next %]> to include the layout fragment from the extended layout.
63bb30b4 200
201The layout representing the root action is called C<share/skin/myapp/layout/root.tt>:
202
203 =for layout widget
204
205 <p>Hello, World!</p>
206
207 =cut
208
209This one is rather simple. The C<=for layout widget> directive is special in that the
210C<widget> fragment will always be where the rendering starts. In fact, our C<site_layout>
211layout too contains a C<widget> fragment, you just don't see it because you inherited it from
212your base skin (or your base skin's base skin, for that matter) instead of defining it yourself.
213
214=head1 A SIMPLE WIDGET
215
216If we wanted to use a different kind of widget than that assumed automatically by Reaction, we
217could add a
218
219 =widget ClassName
220
221directive at the top of the layout file. But for now, we will instead create our own
222widget at C<lib/MyApp/View/Site/Widget/Root.pm>:
223
224 package MyApp::View::Site::Widget::Root;
225 use Reaction::UI::WidgetClass;
226
91c2674b 227 use namespace::autoclean;
63bb30b4 228
229 __PACKAGE__->meta->make_immutable;
230
231 1;
232
233This adds no new functionality at the moment. It just uses C<Reaction::UI::WidgetClass> to ease
234and automate the setup of a new widget class. The widget can provide functionality and fragments
235to the layout. In a way, it can be seen as the Perl code backend to the layout file.
236
237You can now start your C<script/myapp_server.pl> and visit
238
239 http://localhost:3000/
240
241to view your "Hello, World" page.
242
243=head1 ADDING A SCHEMA
244
245The next part of the tutorial will be about adding data storage to our application. While most
246L<Catalyst> web applications today (or at least they should) abstract their database schema
247with L<DBIx::Class::Schema> into a separate module separated from the webapplication, Reaction
248takes this one step further by introducing so called interface models. The interface model
249defines the layer between your application and your domain model (in this case, the L<DBIx::Class>
250schema).
251
139b74f7 252The first thing we will need is a schema class in C<lib/MyApp/Schema.pm>:
63bb30b4 253
254 package MyApp::Schema;
255 use strict;
256 use warnings;
257
258 use parent 'DBIx::Class::Schema';
259
260 __PACKAGE__->load_classes;
261
262 1;
263
264The schema class itself is built like a typical L<DBIx::Class::Schema>. The difference in class
265definition starts at the result classes. For the example's sake, let's make a SQLite database
266called C<example.sqlite>:
267
268 $ cat > example.sqlite.sql
269 CREATE TABLE foo (
270 id INTEGER PRIMARY KEY AUTOINCREMENT,
271 first_name VARCHAR NOT NULL,
272 last_name VARCHAR NOT NULL
273 );
274 <Ctrl-D>
275
276 $ sqlite3 example.sqlite < example.sqlite.sql
277 $
278
279The result class for this table combines the usual style of L<DBIx::Class> with L<Moose> meta
139b74f7 280data additions in C<lib/MyApp/Schema/Foo.pm>:
63bb30b4 281
282 package MyApp::Schema::Foo;
283 use Moose;
284 use MooseX::Types::Moose qw( Int );
285 use Reaction::Types::Core qw( NonEmptySimpleStr );
286
91c2674b 287 use namespace::autoclean;
63bb30b4 288
289 extends 'DBIx::Class';
290
291 has id =>
292 (is => 'ro', isa => Int, required => 1);
293
294 has first_name =>
295 (is => 'rw', isa => NonEmptySimpleStr, required => 1);
296
297 has last_name =>
298 (is => 'rw', isa => NonEmptySimpleStr, required => 1);
299
300 __PACKAGE__->load_components(qw( IntrospectableM2M Core ));
301 __PACKAGE__->table('foo');
302
303 __PACKAGE__->add_columns(
304 id => {
305 data_type => 'integer',
306 is_auto_increment => 1,
307 },
308 first_name => { data_type => 'varchar' },
309 last_name => { data_type => 'varchar' },
310 );
311
312 __PACKAGE__->set_primary_key('id');
313
314 1;
315
316The L<MooseX::Types::Moose> and L<Reaction::Types::Core> modules export L<Moose> type
317constraints (See also L<MooseX::Types> and L<Moose::Util::TypeConstraints>). Note that
318we are using L<Moose/extends> here instead of L<base> or L<parent> to extend
319L<DBIx::Class>.
320
321Next we see our columns in form of Moose attribute definitions. The C<is>, C<isa> and
322C<required> attribute parameters will all be used for introspection and interface
323building later. The C<required> is rather straight-forward. The C<is> will decide whether
324this attribute (or column) can be edited (C<ro> means that it can't, C<rw> means it can).
325The C<isa> attribute will be used for validation and rendering of input fields.
326
327The imported C<NonEmptySimpleStr> for example gives us a simple single-line input box,
328while a C<Str> from L<MooseX::Types::Moose> would give us a textbox.
329
330Following that, we have the usual L<DBIx::Class> result class definitions. The only thing
331different might be the new L<DBIx::Class::IntrospectableM2M> which will allow us to
332inspect many-to-many relations later on.
333
334=head1 CREATING AN INTERFACE MODEL
335
336The interface model should be separated from the application and the schema, since it
337will tie both together. In this case, we will use a reflector to set up the usual interface
139b74f7 338model actions for our schema (C<Create>, C<Update>, C<Delete>, C<DeleteAll>) in
339C<lib/MyApp/InterfaceModel/DBIC.pm>:
63bb30b4 340
341 package MyApp::InterfaceModel::DBIC;
342
343 # keep this on top
344 use parent 'Reaction::InterfaceModel::Object';
345
346 use Reaction::Class;
347 use Reaction::InterfaceModel::Reflector::DBIC;
348
91c2674b 349 use namespace::autoclean;
63bb30b4 350
351 my $reflector = Reaction::InterfaceModel::Reflector::DBIC->new;
352
353 $reflector->reflect_schema(
354 model_class => __PACKAGE__,
355 schema_class => 'MyApp::Schema',
356 );
357
358 __PACKAGE__->meta->make_immutable;
359
360 1;
361
362The L<parent> import must happen before the L<Reaction::Class> one in this case. Other
363than that, the only thing we do here is create a new L<Reaction::InterfaceModel::Reflector::DBIC>
364and call C<reflect_schema> to build our C<MyApp::InterfaceModel::DBIC::*> namespace out of our
365C<MyApp::Schema>.
366
367=head1 TIEING THE INTERFACE MODEL TO THE APPLICATION
368
369Next on the list is the integration of our new interface model into our application. For
370this we create a simple catalyst model in C<lib/MyApp/Model/DBIC.pm>:
371
372 package MyApp::Model::DBIC;
373 use Reaction::Class;
374
91c2674b 375 use namespace::autoclean;
63bb30b4 376
377 extends 'Catalyst::Model::Reaction::InterfaceModel::DBIC';
378
379 __PACKAGE__->meta->make_immutable;
380
381 __PACKAGE__->config(
382 im_class => 'MyApp::InterfaceModel::DBIC',
383 db_dsn => 'dbi:SQLite:example.sqlite',
384 );
385
386 1;
387
388This model L<extends|Moose> the L<Catalyst::Model::Reaction::InterfaceModel::DBIC> base class
389shipped with Reaction. It's configuration must contain the C<im_class> naming our interface
0a0813dd 390model and the C<db_dsn>. If you're using a different kind of database then you
391may neeb to add config for C<db_user>, C<db_password>, and C<db_params>.
392All these get passed to the schema's connect() method.
393
394Of course, since this is Catalyst, all this can also easily be specified
63bb30b4 395via your application config file under the C<Model::DBIC> key.
396
397=head1 BUILDING A SIMPLE CRUD CONTROLLER
398
399Now, since we have defined our interface model as well as our domain model including meta
139b74f7 400data, it isn't very hard (at least not for us) to build a basic (but extendable)
401CRUD controller in C<lib/MyApp/Controller/Foo.pm>:
63bb30b4 402
403 package MyApp::Controller::Foo;
404 use strict;
405 use warnings;
406
407 use parent 'Reaction::UI::Controller::Collection::CRUD';
408 use Reaction::Class;
409
91c2674b 410 use namespace::autoclean;
63bb30b4 411
412 __PACKAGE__->config(
413 model_name => 'DBIC',
414 collection_name => 'Foo',
415 actions => {
416 base => { Chained => '/base', PathPart => 'foo' },
417 },
418 );
419
420 1;
421
422This controller subclasses L<Reaction::UI::Controller::Collection::CRUD>, which is itself a
423subclass of L<Reaction::UI::Controller::Collection>, a class to ease the creation of controllers
424who act on collections of things.
425
426As you can see, for the simplest case we don't need any code; we simply configure our controller.
427
428The C<model_name> is the name of our interface model sans the C<MyApp::Model::> prefix. This means
429this entry points to C<MyApp::Model::DBIC> in this case. The C<collection_name> is the name of
0a0813dd 430the collection in the specified interface model. For us, this would be C<Foo>, to match the result
63bb30b4 431class we created above and want to manage.
432
433The C<actions> part of the configuration is not Reaction, but rather Catalyst specific. This
434configures the actions inherited from L<Reaction::UI::Controller::Collection::CRUD>. For it to
435work, we only need to tell the C<base> action where to chain off from, and what C<PathPart>
436to use. We chain it to the C<base> action in our root controller. The C<foo> path part is rather
437obvious.
438
439Now you can restart your application and visit
440
441 http://localhost:3000/foo
442
443and you have a complete CRUD interface for C<Foo> with listing, viewing, creating, updating
444and deleting capabilities.
445
f9b32c83 446=head1 WHERE TO GO NEXT
447
448=over
449
450=item L<Reaction::Manual::Templates>
451
452When a viewport tries to render a layout, it will involve the view to figure out the corresponding
453template (or any other kind of GUI description) and render it. The template documentation is concerned
454mostly with the C<Reaction::UI::View::TT> implementation allowing the developer to use the L<Template>
455engine to render the layouts.
456
457=item L<Reaction::Manual::Widgets>
458
459A widget is the backend Perl object providing the Perl view logic to a layout. What the rendered
460output actually looks like is determined by the layout. The widget is concerned with storing, providing
461and managing data used and rendered by the layout.
462
463=back
464
63bb30b4 465=head1 SEE ALSO
466
467=over
468
469=item * L<Reaction::Manual>
470
471=item * L<Reaction::Manual::Intro>
472
473=item * L<Reaction::Manual::Overview>
474
475=item * L<Reaction::Manual::Templates>
476
477=item * L<Reaction::Manual::RenderPage>
478
479=item * L<Reaction::UI::View::TT>
480
481=item * L<Reaction::UI::Controller::Root>
482
483=item * L<Reaction::UI::WidgetClass>
484
485=back
486
487=head1 AUTHORS
488
489See L<Reaction::Class> for authors.
490
491=head1 LICENSE
492
493See L<Reaction::Class> for the license.
494
495=cut