Chapter 4. Expanding the Application

In this chapter, we will continue to work with our address book application and add some features that almost every application needs. We'll see how to move the configuration options out of application code and into an easy-to-maintain configuration file. We'll also learn how to search a database and create search results that span multiple pages. To bulk up our database so that searching is more meaningful, we'll write a script to import CSV files into the address book. We will also add sessions to our application, so that data can persist between requests. Finally, we'll explore authentication and authorization by implementing page-level and record-level access control.

Configuration files

The first new feature we'll add to our address book is the ability to be configured from an outside configuration file. This will allow us to easily change configurable aspects of our application without having to touch any of the application code. This is helpful during development, but really shines when a non-programmer (like an end user or a system administrator) needs to change a minor setting when the application is in production.

This feature will also be the easiest to add. Catalyst is set to read configuration from a file by default, and it creates an example configuration file in the application's main directory. In our case, the file is called addressbook.conf. This file is in the default configuration format and you can use other formats as mentioned in Chapter 2, Creating a Catalyst Application, if you choose to.

The simplest piece of configuration data you can add to your application is a single key-value pair (KVP). In YAML syntax, a configuration option foo set to bar will look like:

foo "bar"

Inside your application, you can access the value of foo via the config method in the application object:

print "Foo is: ". $c->config->{foo};

You can also configure individual components (Models, Views, and Controllers) from the config file by creating opening and closing tags. For example, the configuration for MyApp::Model::MyDatabase would be between the<Model::MyDatabase> and</Model::MyDatabase> tags. Setting the key foo to value bar inside MyDatabase would look like the following:

<Model::MyDatabase>
foo "bar"
</Model::MyDatabase>

You can also configure directly inside the application class as follows:

package MyApp;
use Catalyst qw(...);
# ...
__PACKAGE__->config('Model::MyDatabase' => { foo => 'bar' });
# ...
__PACKAGE__->setup;
1;

To get at the form inside Model::MyDatabase, you can simply access a piece of class data with the name of the key as follows:

my_$foo = $self->{foo};

Though you can directly get the values of a configuration using the hash, it is always better to create an accessor, as follows:

Example:

package MyApp::Model::MyDatabase;
use parent 'Catalyst::Model';
PACKAGE ->mk_ro_accessors('foo'),
sub show_foo {
my $self = shift;
print "foo is equal to ". $self->foo;
}

In this example, we didn't need to access anything from a hash because Catalyst automatically created a (read-only) accessor method. The advantage of creating a method to access the data is that mistyping the name in your code somewhere will result in an error (instead of silently returning an undefined value). We also gain the ability to prevent writing, or perhaps return a default value if one isn't specified in the config file.

Note

It is also possible to define Moose attributes in a Controller that can be set from the config file. These also allow for type constraints and value coercions. We will see more of this in Chapter 8.

Configuring the address book

At this point, our address book doesn't have many options to configure. However, there is one critical option, the location of the database. Looking inside AddressBook::Model::AddressDB, we can see that the database's location is hardcoded to the value that we initially specified. Fortunately, if we specify a database in the config file, it will override the hardcoded value. This means we don't have to modify any code to use a different database; we simply need to add the following option to our addressbook.conf file:

name AddressBook
<Model::AddressDB>
connect_info dbi:mysql:__HOME__database
</Model::AddressDB>

The configuration information is an array of four elements. The first element is the DBI connection string. The second and third elements are the database username and password, respectively. The final element is a hash of configuration attributes to pass onto the database driver. DBIx::Class and Catalyst don't actually interpret this data, they just pass the array onto a DBI->connect call.

As SQLite doesn't use usernames or passwords, we haven't specified them in our configuration.

A configuration entry for a MySQL database (which does use usernames and passwords) would look similar to the following:

name AddressBook
<Model::AddressDB>
connect_info dbi:SQLite:__HOME__database
connect_info yourusernamefordb
connect_info yourpasswordfordb
</Model::AddressDB>

More information on the connect configuration can be found at http://search.cpan.org/~rkitover/Catalyst-Model-DBIC-Schema-0.40/lib/Catalyst/Model/DBIC/Schema.pm#connect_info

The variable __HOME __ is replaced with the path to the application by config loader.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.146.155