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