Warning! This page has the following tags:
- This page is deprecated, and is only useful for developers using Agavi 0.9.
- This page exists for reference purposes only.
Using Propel with Agavi
This article will introduce you to using Propel and Creole together with Propel. It assumes you are running bleeding-edge versions of Propel, Creole and Agavi. There's a small section at the very bottom of this document that describes how to make all of what's following below using Agavi 0.9.0, Propel 1.1.0 and Creole 1.0.1.
Before We Begin
I assume you know how to build Propel, how to install all the stuff, and that you have a basic understanding of how Agavi works, i.e. you know how to create a Module and an Action etc. I'll use Default as the module name throughout this text.
Setup Propel
Since we're using "unstable" versions for this tutorial, we can benefit from the recently added advanced Propel support in Agavi (see PropelIntegration?). I assume you already have your Propel generator installed and that you created an Agavi project (the command line tool now even works on Windows). If you don't have all the stuff in your include_path already, either do so now, or throw Propel, Creole and Agavi into the "libs" dir of your project and point your include_path to it, for example like this:
set_include_path(get_include_path() . PATH_SEPARATOR . AG_WEBAPP_DIR . '/lib/' . PATH_SEPARATOR . AG_WEBAPP_DIR . '/../libs/');
We'll be using Propel's bookstore example project for this tutorial, so now is just about time to build the example "bookstore" project (make sure to edit "build.properties" to contain the right DBMS type etc, and alter "runtime-conf.xml" so it reflects your database credentials) and copy the generated "build/classes/bookstore" folder to your "webapp/lib" directory. Copy "build/conf/bookstore-conf.php" to "webapp/config". And, of course, use the generated SQL to setup the tables in your RDBMS :)
So there's only one last thing remaining: tell Agavi to use your Propel project. First, make sure these lines are in your "webapp/config/autoload.ini":
Propel = %MO_APP_DIR%/database/PropelAutoload.php Criteria = propel/util/Criteria.php
Next, we add the Object Model classes to the autoload.ini file, for maximum convenience:
Author = Author.php AuthorPeer = AuthorPeer.php Book = Book.php BookClubList = BookClubList.php BookClubListPeer = BookClubListPeer.php BookListRel = BookListRel.php BookListRelPeer = BookListRelPeer.php BookPeer = BookPeer.php Media = Media.php MediaPeer = MediaPeer.php Publisher = Publisher.php PublisherPeer = PublisherPeer.php Review = Review.php ReviewPeer = ReviewPeer.php
We're almost there. Now the only thing left is to tell Agavi the location of your Propel configuration file. So open up "webapp/config/databases.ini":
[databases]
default = "Default"
[Default]
class = "PropelDatabase"
param.config = "%AG_WEBAPP_DIR%/config/bookstore-conf.php"
Nice Decoration
I'll be using decorators in this example. Because it's easier, and because you'll learn how to use them on the fly :) Create a "webapp/modules/Default/templates/Master.php" with this content:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?=$template['_title']?></title>
</head>
<body>
<p><a href="<?=$this->getContext()->getController()->genURL(null, array(AG_MODULE_ACCESSOR => "Default", AG_ACTION_ACCESSOR => "ListAuthors"))?>">List Authors</a> · <a href="<?=$this->getContext()->getController()->genURL(null, array(AG_MODULE_ACCESSOR => "Default", AG_ACTION_ACCESSOR => "AddAuthor"))?>">Add a new Author</a></p><hr />
<?=$template['content']?>
</body>
</html>
It's Time For Some Action
We're only gonna do three things here: List all authors, add a new author, and edit an author. So, please create a "ListAuthors?", an "AddAuthor?" and an "EditAuthor?" action. We'll begin with printing a list of all users. Open up your "webapp/modules/whatever/actions/ListAuthorsAction.class.php" and make it look like this:
class ListAuthorsAction extends Action
{
public function execute()
{
$c = new Criteria();
$c->addAscendingOrderByColumn(AuthorPeer::LAST_NAME);
$this->getContext()->getRequest()->setAttribute('authors', AuthorPeer::doSelect($c));
return View::SUCCESS;
}
}
What we did was create a new Criteria and tell it to order the results by the author's last name. This way the results will look a little nicer. Then we passed this Criteria (Criteria are usually used to add conditions to queries, but here we don't need that since we want all authors) to AuthorPeer::doSelect() to fetch all authors. This result is directly set as an attribute in the request. We do that because we want to have the authors in our View, where we can pass it on to the template for display.
"webapp/modules/whatever/views/ListAuthorsSuccessView.class.php" is our next victim:
class ListAuthorsSuccessView extends PHPView
{
public function execute()
{
$this->setDecoratorTemplate('Master.php');
$this->setTemplate('ListAuthorsSuccess.php');
$this->setAttribute('_title', 'A List of all Authors');
$this->setAttribute('authors', $this->getContext()->getRequest()->getAttribute('authors'));
}
}
And finally, the template ("webapp/modules/whatever/templates/ListAuthorsSuccess.php"):
<ul> <?php foreach($template['authors'] as $author): ?> <li><a href="<?=$this->getContext()->getController()->genURL(null, array(AG_MODULE_ACCESSOR => "Default", AG_ACTION_ACCESSOR => "EditAuthor", 'id' => $author->getId()))?>"><?=$author->getFirstName()?> <?=$author->getLastName()?></a></li> <?php endforeach; ?> </ul>
You might have noticed that I'm using an alternative PHP syntax inside the template - it improves readability a lot.
Gaping Landscapes
So, if you now bring up http://yourmachine/dir/to/your/project/index.php?module=Default&action=ListAuthors you'll see... that's right. Nothing. Don't panic - this is just because there's no data in our database yet! So the next logical step will be to add an Author to the database - not by hand, mind you. We'll create an Action/View/Template combo for that.

