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