environment where we can explore a variety of features used in virtually
all web applications.
-Source code for the tutorial in included in the F</root/Final> directory
-of the Tutorial Virtual machine (one subdirectory per chapter). There
-are also instructions for downloading the code in
+Source code for the tutorial in included in the F</home/catalyst/Final>
+directory of the Tutorial Virtual machine (one subdirectory per
+chapter). There are also instructions for downloading the code in
L<Catalyst::Manual::Tutorial::01_Intro>.
Please take a look at
=head1 EDIT THE LIST OF CATALYST PLUGINS
One of the greatest benefits of Catalyst is that it has such a large
-library of bases classes and plugins available that you can use easily
+library of base classes and plugins available that you can use to easily
add functionality to your application. Plugins are used to seamlessly
integrate existing Perl modules into the overall Catalyst framework. In
general, they do this by adding additional methods to the C<context>
Catalyst> line of your application class will be plugins, Catalyst
supports a limited number of flag options (of these, C<-Debug> is the
most common). See the documentation for
-C<https://metacpan.org/module/Catalyst|Catalyst.pm> to get details on
+L<https://metacpan.org/module/Catalyst|Catalyst.pm> to get details on
other flags (currently C<-Engine>, C<-Home>, C<-Log>, and C<-Stats>).
If you prefer, there are several other ways to enable debug output:
=item *
-Use the C<$c-E<gt>debug> method on the C<$c> Catalyst context object
+the C<< $c->debug >> method on the C<$c> Catalyst context object
=item *
-The C<-d> option to C<script/myapp_server.pl>
+the C<-d> option on the C<script/myapp_server.pl> script
=item *
-The C<CATALYST_DEBUG=1> environment variable (or use C<CATALYST_DEBUG=0>
-to temporarily disable debug output).
+the C<CATALYST_DEBUG=1> environment variable (or C<CATALYST_DEBUG=0>
+to temporarily disable debug output)
=back
=back
-For our application, we want to add one new plugin into the mix. To do
+For our application, we want to add one new plugin to the mix. To do
this, edit C<lib/MyApp.pm> (this file is generally referred to as your
I<application class>) and delete the lines with:
-Debug
ConfigLoader
Static::Simple
-
+
StackTrace
/;
screen that starts with "Caught exception in
MyApp::Controller::Root->index" with sections showing a stacktrace,
information about the Request and Response objects, the stash (something
-we will learn about soon), the applications configuration configuration.
+we will learn about soon), and the applications configuration.
B<Just don't forget to remove the die before you continue the tutorial!>
:-)
actions:
$ script/myapp_create.pl controller Books
- exists "/root/MyApp/script/../lib/MyApp/Controller"
- exists "/root/MyApp/script/../t"
- created "/root/MyApp/script/../lib/MyApp/Controller/Books.pm"
- created "/root/MyApp/script/../t/controller_Books.t"
+ exists "/home/catalyst/MyApp/script/../lib/MyApp/Controller"
+ exists "/home/catalyst/MyApp/script/../t"
+ created "/home/catalyst/MyApp/script/../lib/MyApp/Controller/Books.pm"
+ created "/home/catalyst/MyApp/script/../t/controller_Books.t"
Then edit C<lib/MyApp/Controller/Books.pm> (as discussed in
L<Chapter 2|Catalyst::Manual::Tutorial::02_CatalystBasics> of
the Tutorial, Catalyst has a separate directory under C<lib/MyApp> for
-each of the three parts of MVC: C<Model>, C<View>, and C<Controller>)
+each of the three parts of MVC: C<Model>, C<View> and C<Controller>)
and add the following method to the controller:
=head2 list
-
+
Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-
+
=cut
-
+
sub list :Local {
# Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
# 'Context' that's used to 'glue together' the various components
# that make up the application
my ($self, $c) = @_;
-
+
# Retrieve all of the book records as book model objects and store in the
# stash where they can be accessed by the TT template
# $c->stash(books => [$c->model('DB::Book')->all]);
# But, for now, use this code until we create the model later
$c->stash(books => '');
-
+
# Set the TT template to use. You will almost always want to do this
# in your action methods (action methods respond to user input in
# your controllers).
C<http://localhost:3000/books/list>, but "C<:Path('/list')>" would match
on C<http://localhost:3000/list> (because of the leading slash). You
can use C<:Args()> to specify how many arguments an action should
-accept. See L<Catalyst::Manual::Intro/Action_types> for more
+accept. See L<Catalyst::Manual::Intro/Action-types> for more
information and examples.
=item *
C<TT> style of view rendering:
$ script/myapp_create.pl view HTML TT
- exists "/root/MyApp/script/../lib/MyApp/View"
- exists "/root/MyApp/script/../t"
- created "/root/MyApp/script/../lib/MyApp/View/HTML.pm"
- created "/root/MyApp/script/../t/view_HTML.t"
+ exists "/home/catalyst/MyApp/script/../lib/MyApp/View"
+ exists "/home/catalyst/MyApp/script/../t"
+ created "/home/catalyst/MyApp/script/../lib/MyApp/View/HTML.pm"
+ created "/home/catalyst/MyApp/script/../t/view_HTML.t"
This creates a view called C<HTML> (the first argument) in a file called
C<HTML.pm> that uses L<Catalyst::View::TT> (the second argument) as the
You can also configure components in your application class. For
example, Edit C<lib/MyApp.pm> and you should see the default
-configuration above the call to C<_PACKAGE__-E<gt>setup> (your defaults
+configuration above the call to C<< _PACKAGE__->setup >> (your defaults
could be different depending on the version of Catalyst you are using):
__PACKAGE__->config(
Change this to match the following (insert a new
-C<__PACKAGE__-E<gt>config> below the existing statement):
+C<< __PACKAGE__->config >> below the existing statement):
__PACKAGE__->config(
name => 'MyApp',
Please stick with the settings above for the duration of the tutorial,
but feel free to use whatever options you desire in your applications
-(as with most things Perl, there's more than one way to do it...).
+(as with most things in Perl, there's more than one way to do it...).
B<Note:> We will use C<root/src> as the base directory for our template
files, with a full naming convention of
Then create C<root/src/books/list.tt2> in your editor and enter:
[% # This is a TT comment. -%]
-
+
[%- # Provide a title -%]
[% META title = 'Book List' -%]
-
+
[% # Note That the '-' at the beginning or end of TT code -%]
[% # "chomps" the whitespace/newline at that end of the -%]
[% # output (use View Source in browser to see the effect) -%]
-
+
[% # Some basic HTML with a loop to display books -%]
<table>
<tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
range of Perl operators down to the single dot (".") operator. This
applies to operations as diverse as method calls, hash lookups, and list
index values (see L<Template::Manual::Variables> for details and
-examples). In addition to the usual L<Template> module Pod
+examples). In addition to the usual L<Template::Toolkit> module Pod
documentation, you can access the TT manual at
L<https://metacpan.org/module/Template::Manual>.
If you need to create the database more than once, you probably want to
issue the C<rm myapp.db> command to delete the database before you use
-the C<sqlite3 myapp.db E<lt> myapp01.sql> command.
+the C<< sqlite3 myapp.db < myapp01.sql >> command.
Once the C<myapp.db> database file has been created and initialized, you
can use the SQLite command line environment to do a quick dump of the
$ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
create=static dbi:SQLite:myapp.db \
on_connect_do="PRAGMA foreign_keys = ON"
- exists "/root/MyApp/script/../lib/MyApp/Model"
- exists "/root/MyApp/script/../t"
- Dumping manual schema for MyApp::Schema to directory /root/MyApp/script/../lib ...
+ exists "/home/catalyst/MyApp/script/../lib/MyApp/Model"
+ exists "/home/catalyst/MyApp/script/../t"
+ Dumping manual schema for MyApp::Schema to directory /home/catalyst/MyApp/script/../lib ...
Schema dump completed.
- created "/root/MyApp/script/../lib/MyApp/Model/DB.pm"
- created "/root/MyApp/script/../t/model_DB.t"
+ created "/home/catalyst/MyApp/script/../lib/MyApp/Model/DB.pm"
+ created "/home/catalyst/MyApp/script/../t/model_DB.t"
Please note the '\' above. Depending on your environment, you might be
able to cut and paste the text as shown or need to remove the '\'
Additionally, the C<lib/MyApp/Schema.pm> model can easily be loaded
outside of Catalyst, for example, in command-line utilities and/or cron
jobs. C<lib/MyApp/Model/DB.pm> provides a very thin "bridge" between
-Catalyst this external database model. Once you see how we can add some
-powerful features to our DBIC model in
+Catalyst and this external database model. Once you see how we can
+add some powerful features to our DBIC model in
L<Chapter 4|Catalyst::Manual::Tutorial::04_BasicCRUD>, the elegance
of this approach will start to become more obvious.
=head1 ENABLE THE MODEL IN THE CONTROLLER
Open C<lib/MyApp/Controller/Books.pm> and un-comment the model code we
-left disabled earlier so that your version matches the following (un-
-comment the line containing C<[$c-E<gt>model('DB::Book')-E<gt>all]> and
-delete the next 2 lines):
+left disabled earlier so that your version matches the following
+(un-comment the line containing C<< [$c->model('DB::Book')->all] >>
+and delete the next 2 lines):
=head2 list
-
+
Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-
+
=cut
-
+
sub list :Local {
# Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
# 'Context' that's used to 'glue together' the various components
# that make up the application
my ($self, $c) = @_;
-
+
# Retrieve all of the book records as book model objects and store
# in the stash where they can be accessed by the TT template
$c->stash(books => [$c->model('DB::Book')->all]);
-
+
# Set the TT template to use. You will almost always want to do this
# in your action methods (action methods respond to user input in
# your controllers).
$c->stash(template => 'books/list.tt2');
}
-B<TIP>: You may see the C<$c-E<gt>model('DB::Book')> un-commented above
-written as C<$c-E<gt>model('DB')-E<gt>resultset('Book')>. The two are
-equivalent. Either way, C<$c-E<gt>model> returns a
+B<TIP>: You may see the C<< $c->model('DB::Book') >> un-commented above
+written as C<< $c->model('DB')->resultset('Book') >>. The two are
+equivalent. Either way, C<< $c->model >> returns a
L<DBIx::Class::ResultSet> which handles queries
against the database and iterating over the set of results that is
returned.
-We are using the C<-E<gt>all> to fetch all of the books. DBIC supports
+We are using the C<< ->all >> to fetch all of the books. DBIC supports
a wide variety of more advanced operations to easily do things like
filtering and sorting the results. For example, the following could be
used to sort the results by descending title:
C<setenv DBIC_TRACE 1>).
B<NOTE:> You can also set this in your code using
-C<$class-E<gt>storage-E<gt>debug(1);>. See
+C<< $class->storage->debug(1); >>. See
L<DBIx::Class::Manual::Troubleshooting> for details (including options
to log to a file instead of displaying to the Catalyst development
server log).
| Catalyst::Plugin::ConfigLoader 0.30 |
| Catalyst::Plugin::StackTrace 0.11 |
'----------------------------------------------------------------------------'
-
+
[debug] Loaded dispatcher "Catalyst::Dispatcher"
[debug] Loaded engine "Catalyst::Engine"
- [debug] Found home "/root/MyApp"
- [debug] Loaded Config "/root/MyApp/myapp.conf"
+ [debug] Found home "/home/catalyst/MyApp"
+ [debug] Loaded Config "/home/catalyst/MyApp/myapp.conf"
[debug] Loaded components:
.-----------------------------------------------------------------+----------.
| Class | Type |
| MyApp::Model::DB::BookAuthor | class |
| MyApp::View::HTML | instance |
'-----------------------------------------------------------------+----------'
-
+
[debug] Loaded Private actions:
.----------------------+--------------------------------------+--------------.
| Private | Class | Method |
| /books/index | MyApp::Controller::Books | index |
| /books/list | MyApp::Controller::Books | list |
'----------------------+--------------------------------------+--------------'
-
+
[debug] Loaded Path actions:
.-------------------------------------+--------------------------------------.
| Path | Private |
| /books | /books/index |
| /books/list | /books/list |
'-------------------------------------+--------------------------------------'
-
+
[info] MyApp powered by Catalyst 5.80020
HTTP::Server::PSGI: Accepting connections at http://0:3000
<title>[% template.title or "My Catalyst App!" %]</title>
<link rel="stylesheet" href="[% c.uri_for('/static/css/main.css') %]" />
</head>
-
+
<body>
<div id="outer">
<div id="header">
[%# Insert the page title -%]
<h1>[% template.title or site.title %]</h1>
</div>
-
+
<div id="bodyblock">
<div id="menu">
Navigation:
%]" title="Catalyst Welcome Page">Welcome</a></li>
</ul>
</div><!-- end menu -->
-
+
<div id="content">
[%# Status and error messages %]
<span class="message">[% status_msg %]</span>
[% content %]
</div><!-- end content -->
</div><!-- end bodyblock -->
-
+
<div id="footer">Copyright (c) your name goes here</div>
</div><!-- end outer -->
-
+
</body>
</html>
<span class="error">[% error_msg %]</span>
If we set either message in the Catalyst stash (e.g.,
-C<$c-E<gt>stash-E<gt>{status_msg} = 'Request was successful!'>) it will
+C<< $c->stash->{status_msg} = 'Request was successful!' >>) it will
be displayed whenever any view used by that request is rendered. The
C<message> and C<error> CSS styles can be customized to suit your needs
in the C<root/static/css/main.css> file we create below.
notice the following code:
=head1 RELATIONS
-
+
=head2 book_authors
-
+
Type: has_many
-
+
Related object: L<MyApp::Schema::Result::BookAuthor>
-
+
=cut
-
+
__PACKAGE__->has_many(
"book_authors",
"MyApp::Schema::Result::BookAuthor",
image" to the C<has_many> relationship we just looked at above:
=head1 RELATIONS
-
+
=head2 book
-
+
Type: belongs_to
-
+
Related object: L<MyApp::Schema::Result::Book>
-
+
=cut
-
+
__PACKAGE__->belongs_to(
"book",
"MyApp::Schema::Result::Book",
The C<many_to_many> relationship bridge is optional, but it makes it
easier to map a book to its collection of authors. Without it, we would
have to "walk" through the C<book_author> table as in
-C<$book-E<gt>book_author-E<gt>first-E<gt>author-E<gt>last_name> (we will
+C<< $book->book_author->first->author->last_name >> (we will
see examples on how to use DBIx::Class objects in your code soon, but
-note that because C<$book-E<gt>book_author> can return multiple authors,
+note that because C<< $book->book_author >> can return multiple authors,
we have to use C<first> to display a single author). C<many_to_many>
allows us to use the shorter
-C<$book-E<gt>author-E<gt>first-E<gt>last_name>. Note that you cannot
+C<< $book->author->first->last_name >>. Note that you cannot
define a C<many_to_many> relationship bridge without also having the
C<has_many> relationship in place.
$ DBIC_TRACE=1 script/myapp_server.pl -r
Make sure that the application loads correctly and that you see the
-three dynamically created model class (one for each of the Result
+three dynamically created model classes (one for each of the Result
Classes we created).
Then hit the URL L<http://localhost:3000/books/list> with your browser
DBIx::Class):
SELECT me.id, me.title, me.rating FROM book me:
- SELECT author.id, author.first_name, author.last_name FROM book_author me
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '1'
- SELECT author.id, author.first_name, author.last_name FROM book_author me
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '2'
- SELECT author.id, author.first_name, author.last_name FROM book_author me
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '3'
- SELECT author.id, author.first_name, author.last_name FROM book_author me
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '4'
- SELECT author.id, author.first_name, author.last_name FROM book_author me
+ SELECT author.id, author.first_name, author.last_name FROM book_author me
JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '5'
Also note in C<root/src/books/list.tt2> that we are using "| html", a
-type of TT filter, to escape characters such as E<lt> and E<gt> to <
+type of TT filter, to escape characters such as < and > to <
and > and avoid various types of dangerous hacks against your
application. In a real application, you would probably want to put "|
html" at the end of every field where a user has control over the
information that can appear in that field (and can therefore inject
markup or code if you don't "neutralize" those fields). In addition to
"| html", Template Toolkit has a variety of other useful filters that
-can found in the documentation for L<Template::Filters>. (While we are
-on the topic of security and escaping of dangerous values, one of the
-advantages of using tools like DBIC for database access or
+can be found in the documentation for L<Template::Filters>. (While we
+are on the topic of security and escaping of dangerous values, one of
+the advantages of using tools like DBIC for database access or
L<HTML::FormFu> for form management [see
-L<Chapter 9|Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormFu>
+L<Chapter 9|Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormFu>]
is that they automatically handle most escaping for you and therefore
dramatically increase the security of your app.)
In some situations, it can be useful to run your application and display
a page without using a browser. Catalyst lets you do this using the
-C<scripts/myapp_test.pl> script. Just supply the URL you wish to
+C<script/myapp_test.pl> script. Just supply the URL you wish to
display and it will run that request through the normal controller
dispatch logic and use the appropriate view to render the output
(obviously, complex pages may dump a lot of text to your terminal
You should get a page with the following message at the top:
- Caught exception in MyApp::Controller::Root->end "Forced debug -
+ Caught exception in MyApp::Controller::Root->end "Forced debug -
Scrubbed output at /usr/share/perl5/Catalyst/Action/RenderView.pm line 46."
Along with a summary of your application's state at the end of the
same name as your controller action, allowing you to save the step of
manually specifying the template name in each action. For example, this
would allow us to remove the
-C<$c-E<gt>stash-E<gt>{template} = 'books/list.tt2';>
+C<< $c->stash->{template} = 'books/list.tt2'; >>
line of our C<list> action in the Books controller.
Open C<lib/MyApp/Controller/Books.pm> in your editor and comment out
this line to match the following (only the
-C<$c-E<gt>stash-E<gt>{template}> line has changed):
+C<< $c->stash->{template} >> line has changed):
=head2 list
-
+
Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-
+
=cut
-
+
sub list :Local {
# Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
# 'Context' that's used to 'glue together' the various components
# that make up the application
my ($self, $c) = @_;
-
+
# Retrieve all of the book records as book model objects and store in the
# stash where they can be accessed by the TT template
$c->stash(books => [$c->model('DB::Book')->all]);
-
+
# Set the TT template to use. You will almost always want to do this
# in your action methods (actions methods respond to user input in
# your controllers).
You should now be able to access the L<http://localhost:3000/books/list>
URL as before.
-B<NOTE:> Please note that if you use the default template technique, you
-will B<not> be able to use either the C<$c-E<gt>forward> or the
-C<$c-E<gt>detach> mechanisms (these are discussed in Chapter 2 and
+B<NOTE:> If you use the default template technique, you
+will B<not> be able to use either the C<< $c->forward >> or the
+C<< $c->detach >> mechanisms (these are discussed in Chapter 2 and
Chapter 9 of the Tutorial).
-B<IMPORTANT:> Make sure that you do NOT skip the following section
+B<IMPORTANT:> Make sure that you do B<not> skip the following section
before continuing to the next chapter 4 Basic CRUD.
=head2 Return To A Manually Specified Template
-In order to be able to use C<$c-E<gt>forward> and C<$c-E<gt>detach>
+In order to be able to use C<< $c->forward >> and C<< $c->detach >>
later in the tutorial, you should remove the comment from the statement
in C<sub list> in C<lib/MyApp/Controller/Books.pm>: