Organizing Slim Framework Applications post
Influenced by discussion with Ed I have decided to use Slim as the framework for a PHP application I am building that is an addition to what is found on the web site for the simulation baseball league I have belonged to for 14 seasons. I've never really used a microframework in PHP before. I used Flask for a Python project that I did to experiment with using Google App Engine. The principles seem to be quite similar (although I will admit that having decorators in PHP would be ineresting) but the trade-off with a microframework is that you usually have to figure out an application layout for yourself.
I decided to use the following things for this app:
- Slim (using latest stable version, 1.5.0 at this writing)
- Pimple as a dependency injection container
- Twig for a templating engine
I also decided to use Composer as a way to install the above dependencies. Slim is not in Packagist so I was forced to do a little reorganizing work after getting some help in IRC from Jake Smith. Here's what I did to get all three of those things playing nicely together with Composer's autoloader:
- moved the directory that contains Slim into the vendor directory
- altered vendor/.composer/autoload_namespaces.php to look for Slim
// autoload_namespace.php generated by Composer
$vendorDir = dirname(__DIR__);
return array(
'Twig_Extensions_' => $vendorDir . '/twig/extensions/lib/',
'Twig_' => $vendorDir . '/twig/twig/lib/',
'Pimple' => $vendorDir . '/pimple/pimple/lib/',
'Slim' => $vendorDir .'/slim/slim'
);
I've come to the opinion that if you are using a tool that provides an autoload you are probably better off using the one they provide rather then trying to make those two co-exist. I'm sure I could've used the autoloader from the Phix project but I didn't feel like screwing around with it. The composer one works and it was easy to tell it to use Slim. Once I start creating the models that I will use for this application I will add their location to that file too.
With that out of the way, it came time to discuss how to actually organize this application. I have a templates directory for my Twig templates, which totally makes sense. But what to do with the index.php file that Slim relies on. Like any front-controller-driven application all our requests, after being folded and mutilated by a web server rewrite rule, go through index.php. In the sample Slim app they have something like this in their index.php file:
$app = new Slim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name!";
});
$app->run();
This might be all Kool and the Gang if you only have a bunch of really small actions. This app will be interacting with models a lot, and I'm positive that despite my best efforts to roll with a "fat models, skinny controllers" paradigm that some of those actions will end up being lots of code. Smashing all that stuff together in one file strikes me as an abomination against best coding practices. Ed told me how the FictiveKin folks are organizing their Slim apps, so I have created something similar to it.
All my routes are going to go into a routes directory and then I will specifically include the routes I want via require calls. One route per file and I will try and name them something sensible.
<?php
require './bootstrap.php';
// Load all our routes
require './routes/main.php';
require './routes/hello.php';
$app->run();
Inside each one of these files will be an app->get|post|whatever call
<?php
$app->get('/', function() {
echo 'MAIN PAGE';
});
Yes, that default route sucks but getting the structure in place was more important to me than having something useful stubbed out.
I'm sure there is more than one way to organize a Slim application, but this is one that I think works best for me.