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