DBIx::Class
, also known as DBIC
, is one of the many Perl ORM (Object Relational Mapper), but it's commonly recognized as the best and most widely used.
This is a nice presentation from Leo : http://www.slideshare.net/ranguard/dbixclass-beginners-presentation
Basically, DBIC
allows you to interact with your SQL Database without writing any SQL.
To do that, you need a set of Schema classes that describes your database structure. Then you can use DBIC to create, update, delete, search, and do many more things on the data that are in your database.
From a Dancer web application, it is very easy to use DBIC, thanks to Dancer::Plugin::DBIC
. This article will implement a simple web application to demonstrate the use of Dancer::Plugin::DBIC
.
Let's consider a simple Dancer application that allows to search for authors or books. The application is connected to a database, that contains authors, and their books. The website will have one single page with a form, to query books or authors, and display the result.
To keep this article short, the HTML will be simplistic, and the implementation will be a bit stupid. However, I'll try to explain how to properly use Dancer::Plugin::DBIC.
The application will be structured as follow:
a Dancer route
/search
to handle the request, and decide if there is any search to perform, and send the results to the viewa view, that will display the search form, and the results if any.
a set of models, linked to a database, that will contain the books and authors. These models will be created using DBIC
Okay, that's easy enough:
$> dancer -a bookstore
We'll want to loop on results and display authors and books, and it's easier to use Template Toolkit to do that, rather than the default Dancer::Template::Simple
.
So let's specify in the configuration that we'll use Template Toolkit as template engine:
# add in bookstore/config.yml
template: template_toolkit
We need a view to display the search form, and below, the results, if any. The results will be fed by the route to the view as an arrayref
of results. Each result is a hashref, with a author
key containing the name of the author, and a books
key containing an arrayref of strings : the books names.
That explanation is probably hard to follow, so here is an example, much easier:
# example of a list of results
[ { author => 'author 1',
books => [ 'book 1', 'book 2' ],
},
{ author => 'author 2',
books => [ 'book 3', 'book 4' ],
}
]
So, what will look the view like? Here is a simple example, displaying the search form, and the results, if any. It's written in Template Toolkit, except that Dancer changes the [‰ %]
format to be <% %>
instead.
# bookstore/views/search.tt
<p>
<form action="/search">
Search query: <input type="text" name="query" />
</form>
</p>
<br>
<% IF query.length %>
<p>Search query was : <% query %>.</p>
<% IF results.size %>
Results:
<ul>
<% FOREACH result IN results %>
<li>Author: <% result.author %>
<ul>
<% FOREACH book IN result.books %>
<li><% book %>
<% END %>
</ul>
<% END %>
<% ELSE %>
No result
<% END %>
<% END %>
Let's create a simple Dancer route, to be added in the bookstore.pm
module:
# add in bookstore/lib/bookstore.pm
get '/search' => sub {
my $query = params->{query};
my @results = ();
if (length $query) {
@results = _perform_search($query);
}
template 'search', { query => $query,
results => \@results,
};
};
It's rather simple: get the parameter called query, if it exists perform the search, and in any case, call the search
view.
So, as you can see, we need to write the _perform_search()
method. But before we do that, let's create the database
I'll go with SQLite, as it fits well with the aim of simplicity of this example. Let's create the SQLite file database:
$> sqlite3 bookstore.db
CREATE TABLE author(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
firstname text default '' not null,
lastname text not null);
CREATE TABLE books(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
author_id INTEGER REFERENCES author (id),
title text default '' not null );
Simple stuff: we have 2 tables, one for authors, and one for books, that points to the author table.
Ian M. Banks
Richard Matheson
Frank Herbert
Instead of interacting with the database using SQL, let's configure DBIX::Class. DBIC needs to understand how your data are organized in your database. There are two ways of letting DBIC know:
either by writing a set of Perl modules, called schema modules: they will describe the database schema, each module describing one entity,
or by letting DBIC connect to the database, explore it, and generate the schema itself.
I'll demonstrate the use of the two solutions. I'm personally not a big fan of the detection method: on complex database, it doesn't get everything right, so one needs to help DBIC. I prefer describing the schema manually. But hey, TIMTOWTDI.
that will describe the
There are two ways of using DBIC. FirstDBIC needs a schema
We also need a view:
#
Let's add a route:
# add in bookstore/lib/bookstore.pm
But
way of writing the web application code
It's
=head1 SEE ALSO
dams: Damien Krotkine <dams@zarb.org>
Hey! The above document had some coding errors, which are explained below:
- Around line 91:
-
Non-ASCII character seen before =encoding in 'C<[‰'. Assuming UTF-8