You can choose the formatting of your choice as long as your choice is Template Toolkit or no formatting. To choose the latter, in the use statement that initially loads Gantry (or more likely an app which uses it) specify -TemplateEngine=Default:

use Gantry qw{ -TemplateEngine=Default }

Alternatively, you can turn off formatting for one page request in the relavent handler:

Once you have a database and a supported model for it, you can use Gantry's AutoCRUD. First,

use Gantry::Plugins::AutoCRUD;

This is more a mixin than a plugin. It exports do_add, do_edit, do_delete, and form_name into your module. The form_name method merely returns the text 'form.tt' which is the name of the default template for add/edit forms. If you want a different template, don't import form_name, instead implement your own form_name method.

For the exported AutoCRUD methods to work you must implement three methods:

Receives the site object and, during editing, the row object the user is modifying. Returns a hash reference suitable for direct use as the view.form of form.tt. See the comments in form.tt for a list of what you can put in the hash. (If your template is different consult it.)

See the docs in Gantry::Plugins::AutoCRUD for additional optional methods. The other methods give you control over things like where users are taken when they cancel a request.

If DBIx::Class is your object relational mapper (ORM), you need to implement get_orm_helper and have it return 'Gantry::Plugins::AutoCRUDHelper::DBIxClass'.

If your ORM does not conform to the either the Class::DBI API or the to DBIx::Class API, you need to read the AutoCRUDHelpers section of the docs in Gantry::Plugins::AutoCRUD and provide your on helper module.

Gantry::Plugins::AutoCRUD is somewhat rigid, but not as rigid as the above example makes it seem. For instance, suppose the above won't work because you need to specify a creation time for every add. AutoCRUD provides hooks.

Called after form data validation and before changing the data in the database. It receives the row object which is about to be changed and a hash reference of form parameters which are about to become the new values for that row. Make your changes in the params hash. For example, you could insert a new key:

Called after changing the data in the database with the row object as amended. Do whatever you like. A common pattern is to pair pre and post actions. For instance, we have an application which sends email only if the status field of a row has changed. Its edit hook methods look roughly like this:

Called after user confirmation and immediately before the doomed row is removed from the database. It receives the row object which is about to meet its maker. This is a good place to log its demise in some other table or die if something has gone awry.

While the answer to the last question shows a certain amount of flexibility in the AutoCRUD scheme, sometimes it just isn't enough. If you want control, but don't want to worry with the basics of displaying the form, validating results, etc. Gantry::Plugins::CRUD is for you.

To have a concrete example, suppose my controller posts comments on a blog entry, but only if the user is logged in.

Unlike its AutoCRUD counterpart, Gantry::Plugins::CRUD does not export anything. Instead it is an object oriented helper. Here's how it works. First, use it:

use Gantry::Plugins::CRUD;

Then make an instance of it, being explicit about what it should do when:

There are other keys you may use -- see the perldoc for Gantry::Plugins::CRUD for details.

We'll look at the actions in some detail below. First, let's examine the other hash keys here.

The form method must return a single value (usually a hash reference), which will go to the template that shows the form on the screen. The text_descr is used when asking the user to confirm a deletion.

All that remains is to implement your own do_ methods to catch the CRUD requests for your controller.

If the security check passes, the CRUD plugin's add method will take care of showing the comment form and validating the data on it. Once it is satisfied that the comment is valid, it will call add_comment (or whatever you registered as the add_action when you called the constructor). Here's an example:

You are completely responsible for updating the database in the add_action. A good model helps with this.

The other actions work similarly. Note that there is no need to be completely honest with the names. It would a good use of Gantry::Plugins::CRUD to implement do_delete so that it marked rows as invisible rather than deleting them. That wouldn't be possible with AutoCRUD.

As a final note, it is not necessary to define all the options for a Gantry::Plugins::CRUD object. It is fine to have only delete_action and the keys it needs. You may also have different objects for add, edit, and/or delete. This gives an easy way for add and edit to use different forms, for example.

This is really two questions. First, 'Can I use AutoCRUD with hand written models?' The answer is: Yes, so long as one of the following is true of your ORM. (1) it responds to dbi_commit, create and retrieve calls, the objects returned by retrieve respond to delete, and -- when your form is used for editing -- it expects a row object returned by your retrieve. (2) you implement a helper similar to Gantry::Plugins::AutoCRUDHelper::DBIxClass.

Second, 'Can I use CRUD if I wrote my own models?' The answer is: Yes. For CRUD above restrictions don't apply since it works even if there is no model.

When something in Gantry dies, the main handler traps the error and calls custom_error on the site object to generate the error page. Simply implement your own custom_error to change how the error output appears to your users. Note that it is often useful to change from a developer-friendly version to a user-friendly version as you move to production.

The custom_error method is invoked on the site object. It receives an array of error output lines.

By using Gantry::Utils::ModelHelper as shown, you can rely on the existing Gantry database connection scheme (keep reading for details or see Gantry::Docs::DBConn for complete info).

Impelement one module for each table which inherits from Gantry::Utils::DBIxClass. These will be very similar to modules which inherit from DBIx::Class, but will inherit to useful methods for Gantry CRUD schemes (get_listing and get_form_selections). Example:

Gantry has a utility which implements captchas. It even has a feature for disabled users. The user sees an image or its alt tag, then picks a description of it from a pull down menu. During form submission, the selected description is compared with encrypted text originally delivered with the form.

Perhaps a better answer a question: 'Why would you want to?' If you have a good answer for that, the short answer to the original question is: use Bigtop. Better yet, use the tentmaker and select Model Gantry on the 'Backends' tab. Gantry's models require a lot of code. They were designed to be generated.

Use gantry in a way that loads one of the mod_perl engines. There are multiple ways to do this. All of them involve a use statement like this:

use Gantry qw{ -Engine=MP13 -TemplateEngine=TT };

(Replace MP13 with MP20 if you use mod_perl 2.)

This statement can go in a <Perl> block above the root location. It could also go in your startup.pl. Finally, you could put it in the base module's .pm file. It makes no real difference on a single environment system. The first two methods are better if you might also deploy the app in a different environment (since then the app would never know which environment it was in, and so no code change would be needed to move environments).

Gantry::Conf provides a complete configuration scheme for both web and traditional programs. It allows you to share configuration between your web app and its cron scripts. It lets you run multiple instances of the same app in the same apache instance with separate configurations. It also lets you share configuration between apps even if they run on different servers (by allowing for http or https access to a single conf file).

See Gantry::Conf::Tutorial for how to set up your conf files among other details.

You should should use Gantry::Conf to configure your apps. On each system where you work, be it dev, qual, or prod, you should have a single directory where all the conf files live. We usually call it /etc/gantry.d, and I'll refer to it by that name below, but you could choose any directory that makes sense to you.

Once you create /etc/gantry.d to hold the conf files or symbolic links to them, put this single line in your master conf file:

include /etc/gantry.d/*.conf

We call our single master conf file /etc/gantry.conf. Pick a file name that makes sense to you, use that name consistently across your systems.

Finally, place one conf file for each app in the /etc/gantry.d directory. Alternatively, especially on dev systems, place a symbolic link in /etc/gantry.d which refers to the Gantry::Conf file bigtop regenerates for your application. Bigtop makes a conf file (if you request one) in the docs subdirectory of the build directory.

To manually build a Gantry::Conf file, use a text editor to make something likes this:

The format must be intelligible to Conf::General unless you tell Gantry::Conf to do something different. See Gantry::Conf for other ways to supply conf information.

How you inform Gantry of your instance name varies by deployment approach. See the next three questions.

Many apps need to be configured in different ways for different uses. For example, an app might need to contact one database server during development, but contact a different one in production. You might even have two instances of the same app presented to two different groups of production users. Gantry::Conf handles this with instances.

You could just add another instance to the Gantry::Conf file for your app. But, you could also use Bigtop to help you. In Bigtop's app section, you may have as many config blocks as you like. You want one with no name, list it first. This will have the common conf information that all the instances will share. Then make additional config blocks with names to hold the variations:

This will result in a single Gantry::Conf file with multiple instances. Each instance will have all the conf variables from the base config block (the one with no name) and the ones from the named conf block. If both blocks have the same variable, the value from the named block overrides the one from the base block. There will be an instance for the base block, which will be named for the app. The other instance names will have the base instance name as a prefix with _name as a suffix. If the app with the above configs were called HeavyLifter, the instances would be heavylifter, heavylifter_dev, and heavylifter_prod.

There are many other ways to use Gantry::Conf, see its POD or read Gantry::Conf::Tutorial for more information.

In each deployment, specify the proper instance in the appropriate manner as described in next three questions.

The answer depends somewhat on how you deploy the application. Under CGI it looks in the config section of the hash you passed to Gantry::Engine::CGI->new. Under mod_perl it looks for PerlSetVar statements.

In both cases the names it looks for are the same. Here are the ones Gantry.pm understands (these are highly integrated into the standard templates):

Change the methods as needed (to reflect your database names, user, and password or to allow the main package to fill in the values from command line args or config file info). This works for all models which inherit from Gantry::Utils::CDBI.

Note that some models which inherit from Gantry::Utils::CDBI might have foreign keys pointing to other models which inherit from Gantry::Utils::AuthCDBI. In that case, even though you don't directly see the need for auth, you do in fact need it.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.