=head1 CREATE A NEW APPLICATION
The remainder of the tutorial will build an application called C<MyApp>.
-First use the Catalyst C<catalyst.pl> script to initialize the framework
+First use the Catalyst F<catalyst.pl> script to initialize the framework
for the C<MyApp> application (make sure you aren't still inside the
directory of the C<Hello> application from the previous chapter of the
tutorial or in a directory that already has a "MyApp" subdirectory):
object (generally written as C<$c>) that Catalyst passes to every
component throughout the framework.
-Take a look at the file C<lib/MyApp.pm> that the helper created above.
+Take a look at the file F<lib/MyApp.pm> that the helper created above.
By default, Catalyst enables three plugins/flags:
=over 4
C<-Debug> Flag
Enables the Catalyst debug output you saw when we started the
-C<script/myapp_server.pl> development server earlier. You can remove
+F<script/myapp_server.pl> development server earlier. You can remove
this item when you place your application into production.
To be technically correct, it turns out that C<-Debug> is not a plugin,
=item *
-the C<-d> option on the C<script/myapp_server.pl> script
+the C<-d> option on the F<script/myapp_server.pl> script
=item *
B<TIP>: Depending on your needs, it can be helpful to permanently remove
C<-Debug> from C<lib/MyApp.pm> and then use the C<-d> option to
-C<script/myapp_server.pl> to re-enable it when needed. We will not be
+F<script/myapp_server.pl> to re-enable it when needed. We will not be
using that approach in the tutorial, but feel free to make use of it in
your own projects.
Catalyst changed the default format from YAML to the more
straightforward C<Config::General> style. This tutorial uses the newer
C<myapp.conf> file for C<Config::General>. However, Catalyst supports
-both formats and will automatically use either C<myapp.conf> or
-C<myapp.yml> (or any other format supported by
+both formats and will automatically use either F<myapp.conf> or
+F<myapp.yml> (or any other format supported by
L<Catalyst::Plugin::ConfigLoader> and
L<Config::Any>). If you are using a version of
Catalyst::Devel prior to 1.06, you can convert to the newer format by
-simply creating the C<myapp.conf> file manually and deleting
-C<myapp.yml>. The default contents of the C<myapp.conf> you create
+simply creating the F<myapp.conf> file manually and deleting
+F<myapp.yml>. The default contents of the F<myapp.conf> you create
should only consist of one line:
name MyApp
=back
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
+this, edit F<lib/MyApp.pm> (this file is generally referred to as your
I<application class>) and delete the lines with:
use Catalyst qw/
=item *
C<__PACKAGE__> is just a shorthand way of referencing the name of the
-package where it is used. Therefore, in C<MyApp.pm>, C<__PACKAGE__> is
+package where it is used. Therefore, in F<MyApp.pm>, C<__PACKAGE__> is
equivalent to C<MyApp>.
=item *
=item *
If you want to see what the StackTrace error screen looks like, edit
-C<lib/MyApp/Controller/Root.pm> and put a C<die "Oops";> command in the
+F<lib/MyApp/Controller/Root.pm> and put a C<die "Oops";> command in the
C<sub index :Path :Args(0)> method. Then start the development server
and open C<http://localhost:3000/> in your browser. You should get a
screen that starts with "Caught exception in
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
+Then edit F<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
+the Tutorial, Catalyst has a separate directory under F<lib/MyApp> for
each of the three parts of MVC: C<Model>, C<View> and C<Controller>)
and add the following method to the controller:
B<:Path> -- C<:Path> actions let you map a method to an explicit URI
path. For example, "C<:Path('list')>" in
-C<lib/MyApp/Controller/Books.pm> would match on the URL
+F<lib/MyApp/Controller/Books.pm> would match on the URL
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
As mentioned in L<Chapter 2|Catalyst::Manual::Tutorial::02_CatalystBasics>
of the tutorial, views are where you render output, typically for
display in the user's web browser (but can generate other types of
-output such as PDF or JSON). The code in C<lib/MyApp/View> selects the
+output such as PDF or JSON). The code in F<lib/MyApp/View> selects the
I<type> of view to use, with the actual rendering template found in the
C<root> directory. As with virtually every aspect of Catalyst, options
abound when it comes to the specific view technology you adopt inside
controls the overall "look and feel" of your site from a single file or
set of files).
-Edit C<lib/MyApp/View/HTML.pm> and you should see something similar to
+Edit F<lib/MyApp/View/HTML.pm> and you should see something similar to
the following:
__PACKAGE__->config(
'.tt2'.
You can also configure components in your application class. For
-example, Edit C<lib/MyApp.pm> and you should see the default
+example, Edit F<lib/MyApp.pm> and you should see the default
configuration above the call to C<< _PACKAGE__->setup >> (your defaults
could be different depending on the version of Catalyst you are using):
);
This changes the base directory for your template files from C<root> to
-C<root/src>.
+F<root/src>.
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 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
+B<Note:> We will use F<root/src> as the base directory for our template
files, with a full naming convention of
-C<root/src/_controller_name_/_action_name_.tt2>. Another popular option
-is to use C<root/> as the base (with a full filename pattern of
-C<root/_controller_name_/_action_name_.tt2>).
+F<root/src/_controller_name_/_action_name_.tt2>. Another popular option
+is to use F<root/> as the base (with a full filename pattern of
+F<root/_controller_name_/_action_name_.tt2>).
=head2 Create a TT Template Page
$ mkdir -p root/src/books
-Then create C<root/src/books/list.tt2> in your editor and enter:
+Then create F<root/src/books/list.tt2> in your editor and enter:
[% # This is a TT comment. -%]
In this step, we make a text file with the required SQL commands to
create a database table and load some sample data. We will use SQLite
(L<http://www.sqlite.org>), a popular database that is lightweight and
-easy to use. Be sure to get at least version 3. Open C<myapp01.sql> in
+easy to use. Be sure to get at least version 3. Open F<myapp01.sql> in
your editor and enter:
--
INSERT INTO book_author VALUES (4, 7);
INSERT INTO book_author VALUES (5, 8);
-Then use the following command to build a C<myapp.db> SQLite database:
+Then use the following command to build a F<myapp.db> SQLite database:
$ sqlite3 myapp.db < myapp01.sql
issue the C<rm myapp.db> command to delete the database before you use
the C<< sqlite3 myapp.db < myapp01.sql >> command.
-Once the C<myapp.db> database file has been created and initialized, you
+Once the F<myapp.db> database file has been created and initialized, you
can use the SQLite command line environment to do a quick dump of the
database contents:
$ perl -MCatalyst::Model::DBIC::Schema\ 999
$ perl -MDBD::SQLite\ 999
-Before you continue, make sure your C<myapp.db> database file is in the
+Before you continue, make sure your F<myapp.db> database file is in the
application's topmost directory. Now use the model helper with the
C<create=static> option to read the database with
L<DBIx::Class::Schema::Loader> and
able to cut and paste the text as shown or need to remove the '\'
character to that the command is all on a single line.
-The C<script/myapp_create.pl> command breaks down like this:
+The F<script/myapp_create.pl> command breaks down like this:
=over 4
=item *
C<DB> is the name of the model class to be created by the helper in
-the C<lib/MyApp/Model> directory.
+the F<lib/MyApp/Model> directory.
=item *
=item *
C<MyApp::Schema> is the name of the DBIC schema file written to
-C<lib/MyApp/Schema.pm>.
+F<lib/MyApp/Schema.pm>.
=item *
C<create=static> causes L<DBIx::Class::Schema::Loader> to load the
schema as it runs and then write that information out into
-C<lib/MyApp/Schema.pm> and files under the C<lib/MyApp/Schema>
+F<lib/MyApp/Schema.pm> and files under the F<lib/MyApp/Schema>
directory.
=item *
L<DBIx::Class::Schema::Loader> create
foreign key relationships for us (this is not needed for databases such
as PostgreSQL and MySQL, but is required for SQLite). If you take a look
-at C<lib/MyApp/Model/DB.pm>, you will see that the SQLite pragma is
+at F<lib/MyApp/Model/DB.pm>, you will see that the SQLite pragma is
propagated to the Model, so that SQLite's recent (and optional) foreign
key enforcement is enabled at the start of every database connection.
=back
-If you look in the C<lib/MyApp/Schema.pm> file, you will find that it
+If you look in the F<lib/MyApp/Schema.pm> file, you will find that it
only contains a call to the C<load_namespaces> method. You will also
-find that C<lib/MyApp> contains a C<Schema> subdirectory, which then has
+find that F<lib/MyApp> contains a C<Schema> subdirectory, which then has
a subdirectory called "Result". This "Result" subdirectory then has
files named according to each of the tables in our simple database
-(C<Author.pm>, C<BookAuthor.pm>, and C<Book.pm>). These three files are
+(F<Author.pm>, F<BookAuthor.pm>, and F<Book.pm>). These three files are
called "Result Classes" (or
"L<ResultSource Classes|DBIx::Class::ResultSource>") in DBIx::Class
nomenclature. Although the Result Class files are named after tables in
L<Catalyst::Manual::Tutorial::04_BasicCRUD/EXPLORING THE POWER OF DBIC>).
The idea with the Result Source files created under
-C<lib/MyApp/Schema/Result> by the C<create=static> option is to only
+F<lib/MyApp/Schema/Result> by the C<create=static> option is to only
edit the files below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
warning. If you place all of your changes below that point in the file,
you can regenerate the automatically created information at the top of
Also note the "flow" of the model information across the various files
and directories. Catalyst will initially load the model from
-C<lib/MyApp/Model/DB.pm>. This file contains a reference to
-C<lib/MyApp/Schema.pm>, so that file is loaded next. Finally, the call
+F<lib/MyApp/Model/DB.pm>. This file contains a reference to
+F<lib/MyApp/Schema.pm>, so that file is loaded next. Finally, the call
to C<load_namespaces> in C<Schema.pm> will load each of the "Result
-Class" files from the C<lib/MyApp/Schema/Result> subdirectory. The
+Class" files from the F<lib/MyApp/Schema/Result> subdirectory. The
final outcome is that Catalyst will dynamically create three
table-specific Catalyst models every time the application starts (you
can see these three model files listed in the debug output generated
when you launch the application).
-Additionally, the C<lib/MyApp/Schema.pm> model can easily be loaded
+Additionally, the F<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
+jobs. F<lib/MyApp/Model/DB.pm> provides a very thin "bridge" between
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
=head1 ENABLE THE MODEL IN THE CONTROLLER
-Open C<lib/MyApp/Controller/Books.pm> and un-comment the model code we
+Open F<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->model('DB::Book')->all] >>
and delete the next 2 lines):
[info] MyApp powered by Catalyst 5.80020
HTTP::Server::PSGI: Accepting connections at http://0:3000
-B<NOTE:> Be sure you run the C<script/myapp_server.pl> command from the
-'base' directory of your application, not inside the C<script> directory
-itself or it will not be able to locate the C<myapp.db> database file.
+B<NOTE:> Be sure you run the F<script/myapp_server.pl> command from the
+'base' directory of your application, not inside the F<script> directory
+itself or it will not be able to locate the F<myapp.db> database file.
You can use a fully qualified or a relative path to locate the database
file, but we did not specify that when we ran the model helper earlier.
Next, to view the book list, change the URL in your browser to
L<http://localhost:3000/books/list>. You should get a list of the five
-books loaded by the C<myapp01.sql> script above without any formatting.
+books loaded by the F<myapp01.sql> script above without any formatting.
The rating for each book should appear on each row, but the "Author(s)"
column will still be blank (we will fill that in later).
-Also notice in the output of the C<script/myapp_server.pl> that
+Also notice in the output of the F<script/myapp_server.pl> that
L<DBIx::Class> used the following SQL to retrieve the data:
SELECT me.id, me.title, me.rating FROM book me
In order to create a wrapper, you must first edit your TT view and tell
it where to find your wrapper file.
-Edit your TT view in C<lib/MyApp/View/HTML.pm> and change it to match
+Edit your TT view in F<lib/MyApp/View/HTML.pm> and change it to match
the following:
__PACKAGE__->config(
Next you need to set up your wrapper template. Basically, you'll want
to take the overall layout of your site and put it into this file. For
-the tutorial, open C<root/src/wrapper.tt2> and input the following:
+the tutorial, open F<root/src/wrapper.tt2> and input the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" [%#
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.
+in the F<root/static/css/main.css> file we create below.
B<Notes:>
$ mkdir root/static/css
-Then open the file C<root/static/css/main.css> (the file referenced in
+Then open the file F<root/static/css/main.css> (the file referenced in
the stylesheet href link of our wrapper above) and add the following
content:
Hit "Reload" in your web browser and you should now see a formatted
version of our basic book list. (Again, the development server should
have automatically restarted when you made changes to
-C<lib/MyApp/View/HTML.pm>. If you are not using the "-r" option, you
+F<lib/MyApp/View/HTML.pm>. If you are not using the "-r" option, you
will need to hit C<Ctrl-C> and manually restart it. Also note that the
development server does I<NOT> need to restart for changes to the TT and
static files we created and edited in the C<root> directory -- those
If you take a look at the Schema files automatically generated by
L<DBIx::Class::Schema::Loader>, you will see that it has already defined
C<has_many> and C<belongs_to> relationships on each side of our foreign
-keys. For example, take a look at C<lib/MyApp/Schema/Result/Book.pm> and
+keys. For example, take a look at F<lib/MyApp/Schema/Result/Book.pm> and
notice the following code:
=head1 RELATIONS
C<belongs_to> relationships. We recommend upgrading to the versions
specified above. :-)
-Have a look at C<lib/MyApp/Schema/Result/BookAuthor.pm> and notice that
+Have a look at F<lib/MyApp/Schema/Result/BookAuthor.pm> and notice that
there is a C<belongs_to> relationship defined that acts as the "mirror
image" to the C<has_many> relationship we just looked at above:
automatically handle the C<has_many> and C<belongs_to> relationships,
C<many_to_many> relationship bridges (not technically a relationship)
currently need to be manually inserted. To add a C<many_to_many>
-relationship bridge, first edit C<lib/MyApp/Schema/Result/Book.pm> and
+relationship bridge, first edit F<lib/MyApp/Schema/Result/Book.pm> and
add the following text below the C<# You can replace this text...>
comment:
define a C<many_to_many> relationship bridge without also having the
C<has_many> relationship in place.
-Then edit C<lib/MyApp/Schema/Result/Author.pm> and add the reverse
+Then edit F<lib/MyApp/Schema/Result/Author.pm> and add the reverse
C<many_to_many> relationship bridge for C<Author> as follows (again, be
careful to put in above the C<1;> but below the C<# DO NOT MODIFY THIS
OR ANYTHING ABOVE!> comment):
Let's add a new column to our book list page that takes advantage of the
relationship information we manually added to our schema files in the
-previous section. Edit C<root/src/books/list.tt2> and replace the
+previous section. Edit F<root/src/books/list.tt2> and replace the
"empty" table cell "<td></td>" with the following:
...
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
+Also note in F<root/src/books/list.tt2> that we are using "| html", a
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 "|
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<script/myapp_test.pl> script. Just supply the URL you wish to
+F<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
response output. Catalyst uses
L<Catalyst::Action::RenderView> by default
to automatically perform this operation. If you look in
-C<lib/MyApp/Controller/Root.pm>, you should see the empty definition for
+F<lib/MyApp/Controller/Root.pm>, you should see the empty definition for
the C<sub end> method:
sub end : ActionClass('RenderView') {}
=item *
-C<Root.pm> is designed to hold application-wide logic.
+F<Root.pm> is designed to hold application-wide logic.
=item *
C<end> method that's appropriate. For example, if the controller for a
request has an C<end> method defined, it will be called. However, if
the controller does not define a controller-specific C<end> method, the
-"global" C<end> method in C<Root.pm> will be called.
+"global" C<end> method in F<Root.pm> will be called.
=item *
logic in C<RenderView>. However, you can easily extend the
C<RenderView> logic by adding your own code inside the empty method body
(C<{}>) created by the Catalyst Helpers when we first ran the
-C<catalyst.pl> to initialize our application. See
+F<catalyst.pl> to initialize our application. See
L<Catalyst::Action::RenderView> for more
detailed information on how to extend C<RenderView> in C<sub end>.
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>:
+in C<sub list> in F<lib/MyApp/Controller/Books.pm>:
$c->stash(template => 'books/list.tt2');
-Then delete the C<TEMPLATE_EXTENSION> line in C<lib/MyApp/View/HTML.pm>.
+Then delete the C<TEMPLATE_EXTENSION> line in F<lib/MyApp/View/HTML.pm>.
Check the L<http://localhost:3000/books/list> URL in your browser. It
should look the same manner as with earlier sections.