Snap alpha, a ZF wrapper for PHP 5.3
Snap is a mini-framework on top of ZF inspired by the Sinatra framework. It makes heavy use of the new PHP 5.3 features to allow one to write concise code similar to Sinatra and Juno while taking full advantage of the well-tested ZF components.
Requirements
- PHP 5.3 RC2 or above
- Zend Framework 1.8 or above
- Apache
Setting up
Unpack or clone the project into your docroot. The directory structure should be like this:
htdocs
`-- snap
`-- forms
| `-- Hello.php
`-- library
| `-- snap (snap library files below this)
| `-- Zend (zend files below this)
`-- public
| `-- .htaccess
| `-- index.php
`-- views
`-- hello-world.phtml
`-- layout.phtml
Note that the Zend directory included in the project is just a subset of ZF 1.8.2. It’s basically just the MVC stack and Zend_Form plus their dependencies. It is recommended that you download ZF separately and put it in the library dir or add it directly to your php.ini include paths.
Writing the index.php file
The most basic index.php looks like this:
<?php
// public/index.php
namespace snap;
// setup the autoloader
require_once '../library/snap/Snap.php';
Snap::autoload('../library');
// define the routes and actions
action('*')->do(function () {
// this will match any url and any request method
echo 'Are you lost?';
});
get('/hello/:name')
->default('name', 'world')
->do(function ($con) {
// this will match urls like "/hello/mon". if the :name part is
// absent (i.e. the url is just "/hello") the default value for
// name is used. if you've used ZF then i'm sure you
// know what's happening.
$name = '<strong>' . ucfirst($con->name) . '</strong>';
echo 'Hello ' . $name . '!';
});
// run the application
dispatch();
This is not recommended for two reasons:
- It forces you to use the snap namespace in your index.
- It does a lot of things implicitly. Yes, simplifying the interface is one of the design goals, but this form doesn’t show which component does what and that makes debugging confusing.
Instead, I recommend the following method. It’s only slightly more verbose than the former.
<?php
// import the following classes into this namespace
use snap\Snap, snap\Loader, snap\Front;
// setup the autoloader
require_once '../library/snap/Loader.php';
Loader::addIncludePaths('../library');
Loader::autoload();
$front = Front::getInstance();
$front('*')->action(function () {
echo 'Are you lost?';
});
$front('/hello/:name')
->default('hello', 'world')
->get(function ($con) {
$name = '<strong>' . ucfirst($con->name) . '</strong>';
echo 'Hello ' . $name . '!';
});
$front->dispatch();
Harnessing the power of ZF
This uses Zend_View and follows the Zend MVC dispatch flow, you can use various Zend components in your application, including Zend_Form, Zend_Layout and all the existing Zend_View and controller action helpers. All other Zend components are also usable except maybe those related to the MVC stack like navigation or paginator (I haven’t tested them yet). Most of the objects and methods available to action controllers are accessible or have an analog in the container object ($con in the examples) passed to the callbacks. Here is a more complicated example. Proper documentation of all the methods would come later.
<?php
use snap\Snap, snap\Front;
require '../library/snap/Snap.php';
Snap::autoload('../library');
Snap::layout('layout');
$front = Front::getInstance();
$front('/:page/*')
->default('page', '')
->action(function ($con) {
if ('' === $con->page) {
echo 'This is the front page.';
} else {
echo 'You requested the page <tt>' . $con->page . '</tt>.';
}
});
$front('/foo/*')->get(function ($con) {
echo '<pre>';
var_dump($con->getParams());
echo '</pre>';
});
$front('/hello/:name', 'foo')
->default('name', 'world')
->view('hello-world')
->action(function ($con) {
$con->form = new \Form_Hello(array(
'action' => $con->helper->url()
));
$con->view->headTitle('Hello world!');
$con->view->name = ucfirst($con->name);
})
->get(function ($con) {
$con->view->form = $con->form;
})
->post(function ($con) {
$form = $con->form;
if ($form->isValid($con->request->getPost())) {
$con->redirect('/hello/' . $form->getValue('name'));
} else {
$con->view->form = $form;
}
});
$front->dispatch();
The project is currently hosted at github. An SVN mirror and package will be coming soon at googlecode.