3 Reaction::Manual::Tutorial.pod - Step by Step Tutorial
7 This document aims at giving simple step-by-step leading to an example application
8 using the common functionality provided by L<Reaction>.
10 =head1 CREATING A NEW APPLICATION
12 At first we have to create a new application. For this we use the C<catalyst.pl>
13 script as we would for any other Catalyst application:
16 [lots "created ..." messages]
18 There is nothing to change in the application class file.
22 Since we are not just rendering templates with Reaction, but layouts and widgets,
23 a simple TT view won't suffice. We need to create our own C<lib/MyApp/View/Site.pm>:
25 package MyApp::View::Site;
28 use namespace::clean -except => 'meta';
30 extends 'Reaction::UI::View::TT';
32 __PACKAGE__->meta->make_immutable;
36 The C<use Reaction::Class> line will import L<Moose>, L<strict> and L<warnings> into
37 our file and might perform some Reaction specific setups.
39 We make sure that we don't provide imported functions as methods at runtime by using
40 L<namespace::clean>. But we need to C<-except> the C<meta> method that was exported
43 In its simplest version, our view just needs to do a C<extends 'Reaction::UI::View::TT'>
44 to make a new subclass of it.
46 We chose to call C<make_immutable> on the class' meta class instance to have it inline
47 methods for runtime speed improvements.
49 =head1 THE ROOT CONTROLLER
51 As usual in Catalyst, our root controller (at C<lib/MyApp/Controller/Root.pm> represents
52 the root namespace for our application. For this purpose, it should look like this:
54 package MyApp::Controller::Root;
57 use parent 'Reaction::UI::Controller::Root';
59 use aliased 'Reaction::UI::ViewPort';
60 use aliased 'Reaction::UI::ViewPort::SiteLayout';
62 use namespace::clean -except => 'meta';
66 window_title => 'MyApp Window',
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')),
78 sub root: Chained('base') PathPart('') Args(0) {
79 my ($self, $ctx) = @_;
80 $self->push_viewport(ViewPort, layout => 'root');
85 The effects of L<strict>, L<warnings>, L<parent>, L<aliased> and L<namespace::clean> should
86 be clear by now. Let's take a look at the configuration.
88 The C<view_name> determines which view to use. We set it to C<Site>, which is our only view
89 by now. Be careful to set C<view_name> and not C<view>, which would fail telling you it
92 The C<window_title> is the title given to the L<Reaction::UI::Window> instance that will be
93 stored in C<$ctx-E<gt>stash-E<gt>{window}> by the C<begin> action provided by
94 L<Reaction::UI::Controller::Root>.
96 The C<namespace> setting anchors the root controller at C</>.
98 The C<base> action here acts as a general point all other actions can chain off of. It
99 pushes the L<Reaction::UI::ViewPort::SiteLayout> viewport onto the
100 L<focus stack|Reaction::UI::FocusStack>. As arguments we see a C<title> that will be used
101 as page title later. The C<static_base_uri> is used for static links like CSS and JavaScript
102 files. Since we didn't specify a layout C<site_layout> will be used.
104 We also defined a C<root> action serving as application index. It chains off the C<base>
105 action. It is only pushing the root viewport L<Reaction::UI::ViewPort> on the focus stack,
106 but this time we specified a layout named C<root>.
108 Reaction will try to find our layout files in C<share/skin/$skin_name/layout/*>, so the next
109 thing to do is to create a new skin and the layout files.
113 If your version of Catalyst still creates a C<root> instead of a C<share> directory, you
114 might want to rename it. This is regarded as a best practice and follows the conventions
115 of this tutorial and other Reaction documentation.
117 First we need to create a directory for our new skin:
119 $ mkdir -p share/skin/myapp/layout
121 Next we need to configure our new skin. This is done in the C<share/skin/myapp/skin.conf>
122 file. At the moment, all it should contain is
124 extends /Reaction/default
126 Note that this C<extends> specification contains the distribution name of the
127 library or application of which to use the templates as base. You can also give it
132 and it would try to extend a skin named C<foo> in your own application's C<share/skin>
135 Now we create C<share/skin/defaults.conf> to allow settings that concern all skins of
136 the application. It should contain only this:
138 widget_search_path MyApp::View::Site::Widget
139 widget_search_path Reaction::UI::Widget
141 This will tell Reaction to look in C<Reaction::UI::Widget::*> and
142 C<MyApp::View::Site::Widget::*> for widget classes. That means that our layout named
143 C<root> will check for C<MyApp::View::Site::Widget::Root> first and then look if
144 C<Reaction::UI::Widget> exists.
146 We want the first line to be able to create our own widgets and the second line to
147 have Reaction find its own widgets.
149 Now we need to tell Reaction what skin it should use. We do this by adding this section
150 to our C<myapp.conf>:
156 The value should be the name of the target directory under C<share/skin/>.
160 We will need two layout files to begin with. One controlling the site layout and one
163 The first will be created as C<share/skin/myapp/layout/site_layout.tt>:
169 <h1>Welcome to MyApp</h1>
177 The C<=extends> directive specifies that this layout file is an extension of another
178 layout file. The C<NEXT> value here tells Reaction that this extends the C<site_layout>
179 layout in the base skin, which we have defined as C</Reaction/default>. That means, you
180 can take a look at the layout we are extending at C<share/skin/default/layout/site_layout.tt>
181 in the L<Reaction> distribution.
183 The C<=for layout> directives allows us to set a layout fragment. We define a C<body> fragment
184 containing the common C<body> for all pages using this site layout. The C<[% inner %]> is
185 where the deeper parts of the stack will be included, in the case of our C<root> action that
186 would be the C<Reaction::UI::ViewPort> with the C<root> layout.
188 If we wanted to override a specific fragment, we could do just that. And inside that fragment
189 we could call C<[% next_call %]> to include the layout fragment from the extended layout.
191 The layout representing the root action is called C<share/skin/myapp/layout/root.tt>:
199 This one is rather simple. The C<=for layout widget> directive is special in that the
200 C<widget> fragment will always be where the rendering starts. In fact, our C<site_layout>
201 layout too contains a C<widget> fragment, you just don't see it because you inherited it from
202 your base skin (or your base skin's base skin, for that matter) instead of defining it yourself.
204 =head1 A SIMPLE WIDGET
206 If we wanted to use a different kind of widget than that assumed automatically by Reaction, we
211 directive at the top of the layout file. But for now, we will instead create our own
212 widget at C<lib/MyApp/View/Site/Widget/Root.pm>:
214 package MyApp::View::Site::Widget::Root;
215 use Reaction::UI::WidgetClass;
217 use namespace::clean -except => 'meta';
219 __PACKAGE__->meta->make_immutable;
223 This adds no new functionality at the moment. It just uses C<Reaction::UI::WidgetClass> to ease
224 and automate the setup of a new widget class. The widget can provide functionality and fragments
225 to the layout. In a way, it can be seen as the Perl code backend to the layout file.
227 You can now start your C<script/myapp_server.pl> and visit
229 http://localhost:3000/
231 to view your "Hello, World" page.
233 =head1 ADDING A SCHEMA
235 The next part of the tutorial will be about adding data storage to our application. While most
236 L<Catalyst> web applications today (or at least they should) abstract their database schema
237 with L<DBIx::Class::Schema> into a separate module separated from the webapplication, Reaction
238 takes this one step further by introducing so called interface models. The interface model
239 defines the layer between your application and your domain model (in this case, the L<DBIx::Class>
242 The first thing we will need is a schema class:
244 package MyApp::Schema;
248 use parent 'DBIx::Class::Schema';
250 __PACKAGE__->load_classes;
254 The schema class itself is built like a typical L<DBIx::Class::Schema>. The difference in class
255 definition starts at the result classes. For the example's sake, let's make a SQLite database
256 called C<example.sqlite>:
258 $ cat > example.sqlite.sql
260 id INTEGER PRIMARY KEY AUTOINCREMENT,
261 first_name VARCHAR NOT NULL,
262 last_name VARCHAR NOT NULL
266 $ sqlite3 example.sqlite < example.sqlite.sql
269 The result class for this table combines the usual style of L<DBIx::Class> with L<Moose> meta
272 package MyApp::Schema::Foo;
274 use MooseX::Types::Moose qw( Int );
275 use Reaction::Types::Core qw( NonEmptySimpleStr );
277 use namespace::clean -except => 'meta';
279 extends 'DBIx::Class';
282 (is => 'ro', isa => Int, required => 1);
285 (is => 'rw', isa => NonEmptySimpleStr, required => 1);
288 (is => 'rw', isa => NonEmptySimpleStr, required => 1);
290 __PACKAGE__->load_components(qw( IntrospectableM2M Core ));
291 __PACKAGE__->table('foo');
293 __PACKAGE__->add_columns(
295 data_type => 'integer',
296 is_auto_increment => 1,
298 first_name => { data_type => 'varchar' },
299 last_name => { data_type => 'varchar' },
302 __PACKAGE__->set_primary_key('id');
306 The L<MooseX::Types::Moose> and L<Reaction::Types::Core> modules export L<Moose> type
307 constraints (See also L<MooseX::Types> and L<Moose::Util::TypeConstraints>). Note that
308 we are using L<Moose/extends> here instead of L<base> or L<parent> to extend
311 Next we see our columns in form of Moose attribute definitions. The C<is>, C<isa> and
312 C<required> attribute parameters will all be used for introspection and interface
313 building later. The C<required> is rather straight-forward. The C<is> will decide whether
314 this attribute (or column) can be edited (C<ro> means that it can't, C<rw> means it can).
315 The C<isa> attribute will be used for validation and rendering of input fields.
317 The imported C<NonEmptySimpleStr> for example gives us a simple single-line input box,
318 while a C<Str> from L<MooseX::Types::Moose> would give us a textbox.
320 Following that, we have the usual L<DBIx::Class> result class definitions. The only thing
321 different might be the new L<DBIx::Class::IntrospectableM2M> which will allow us to
322 inspect many-to-many relations later on.
324 =head1 CREATING AN INTERFACE MODEL
326 The interface model should be separated from the application and the schema, since it
327 will tie both together. In this case, we will use a reflector to set up the usual interface
328 model actions for our schema (C<Create>, C<Update>, C<Delete>, C<DeleteAll>):
330 package MyApp::InterfaceModel::DBIC;
333 use parent 'Reaction::InterfaceModel::Object';
336 use Reaction::InterfaceModel::Reflector::DBIC;
338 use namespace::clean -except => 'meta';
340 my $reflector = Reaction::InterfaceModel::Reflector::DBIC->new;
342 $reflector->reflect_schema(
343 model_class => __PACKAGE__,
344 schema_class => 'MyApp::Schema',
347 __PACKAGE__->meta->make_immutable;
351 The L<parent> import must happen before the L<Reaction::Class> one in this case. Other
352 than that, the only thing we do here is create a new L<Reaction::InterfaceModel::Reflector::DBIC>
353 and call C<reflect_schema> to build our C<MyApp::InterfaceModel::DBIC::*> namespace out of our
356 =head1 TIEING THE INTERFACE MODEL TO THE APPLICATION
358 Next on the list is the integration of our new interface model into our application. For
359 this we create a simple catalyst model in C<lib/MyApp/Model/DBIC.pm>:
361 package MyApp::Model::DBIC;
364 use namespace::clean -except => 'meta';
366 extends 'Catalyst::Model::Reaction::InterfaceModel::DBIC';
368 __PACKAGE__->meta->make_immutable;
371 im_class => 'MyApp::InterfaceModel::DBIC',
372 db_dsn => 'dbi:SQLite:example.sqlite',
377 This model L<extends|Moose> the L<Catalyst::Model::Reaction::InterfaceModel::DBIC> base class
378 shipped with Reaction. It's configuration must contain the C<im_class> naming our interface
379 model and the C<db_dsn>. Of course, since this is Catalyst, this can also easily be specified
380 via your application config file under the C<Model::DBIC> key.
382 =head1 BUILDING A SIMPLE CRUD CONTROLLER
384 Now, since we have defined our interface model as well as our domain model including meta
385 data, it isn't very hard (at least not for us) to build a basic (but extendable) CRUD controller:
387 package MyApp::Controller::Foo;
391 use parent 'Reaction::UI::Controller::Collection::CRUD';
394 use namespace::clean -except => 'meta';
397 model_name => 'DBIC',
398 collection_name => 'Foo',
400 base => { Chained => '/base', PathPart => 'foo' },
406 This controller subclasses L<Reaction::UI::Controller::Collection::CRUD>, which is itself a
407 subclass of L<Reaction::UI::Controller::Collection>, a class to ease the creation of controllers
408 who act on collections of things.
410 As you can see, for the simplest case we don't need any code; we simply configure our controller.
412 The C<model_name> is the name of our interface model sans the C<MyApp::Model::> prefix. This means
413 this entry points to C<MyApp::Model::DBIC> in this case. The C<collection_name> is the name of
414 the collection in the specified interface model. For us, this would be C<Foo>, like the result
415 class we created above and want to manage.
417 The C<actions> part of the configuration is not Reaction, but rather Catalyst specific. This
418 configures the actions inherited from L<Reaction::UI::Controller::Collection::CRUD>. For it to
419 work, we only need to tell the C<base> action where to chain off from, and what C<PathPart>
420 to use. We chain it to the C<base> action in our root controller. The C<foo> path part is rather
423 Now you can restart your application and visit
425 http://localhost:3000/foo
427 and you have a complete CRUD interface for C<Foo> with listing, viewing, creating, updating
428 and deleting capabilities.
430 =head1 WHERE TO GO NEXT
434 =item L<Reaction::Manual::Templates>
436 When a viewport tries to render a layout, it will involve the view to figure out the corresponding
437 template (or any other kind of GUI description) and render it. The template documentation is concerned
438 mostly with the C<Reaction::UI::View::TT> implementation allowing the developer to use the L<Template>
439 engine to render the layouts.
441 =item L<Reaction::Manual::Widgets>
443 A widget is the backend Perl object providing the Perl view logic to a layout. What the rendered
444 output actually looks like is determined by the layout. The widget is concerned with storing, providing
445 and managing data used and rendered by the layout.
453 =item * L<Reaction::Manual>
455 =item * L<Reaction::Manual::Intro>
457 =item * L<Reaction::Manual::Overview>
459 =item * L<Reaction::Manual::Templates>
461 =item * L<Reaction::Manual::RenderPage>
463 =item * L<Reaction::UI::View::TT>
465 =item * L<Reaction::UI::Controller::Root>
467 =item * L<Reaction::UI::WidgetClass>
473 See L<Reaction::Class> for authors.
477 See L<Reaction::Class> for the license.