Vous êtes sur la page 1sur 14

PHP + Symfony

Rapid application development



Jonathan Bell
Nov 18, 2010
A Developers User Story
Its 5:00pm on Sunday
Need to have a web app together for Monday
Want to sleep tonight
Want to have a complete app (validation,
security, etc)
Dont have time machine
EJB? No
.Net? No
Enter Symfony
Symfony is a code generator/MVC
framework for PHP. Sounds a lot like
ruby on rails. Why PHP?
PHP is super C-like, might be easier to
pick up
ORB mapping
(pluggable)
CRUD generation
Validation
Routing
Templating
Plugins
Unit Testing
Object Brokering (Model layer)
Automatically generates fully
documented PHP classes from config file
Removes need for repeated DB calls,
provides abstraction
schema.yml
propel:
weblog_post:
_attributes: { phpName: Post }
id:
title: varchar(255)
excerpt: longvarchar
body: longvarchar
created_at:
PHP Code
$p = new Post();
$p->setTitle(Test Post);
$p->setBody(the body);
$p->save();

$posts = PostPeer::doSelect(new
Criteria());
foreach($posts as $post)
{
print Post: .$post->getTitle();
}
CRUD Generation + Validation (Controller +
View)
Web programmers worst nightmare:
writing huge forms with dozens of
inputs, associated form processors
and validators
Symfony to the rescue: generates
template Create/Read/Update/Delete
Very, very easy to customize once
generated
symfony propel:generate-module admin findable FindableItem
indexSuccess.php:
<h1>Findable List</h1>

<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Cardinality</th>
<th>Points</th>
<th>Description</th>
<th>S findable category</th>
</tr>
</thead>
<tbody>
<?php foreach ($findable_item_list as $findable_item): ?>
<tr>
<td><a href="<?php echo url_for('findable/edit?id='.$findable_item->getId()) ?>"><?php echo $findable_item->getId() ?></a></td>
<td><?php echo $findable_item->getName() ?></td>
<td><?php echo $findable_item->getCardinality() ?></td>
<td><?php echo $findable_item->getPoints() ?></td>
<td><?php echo $findable_item->getDescription() ?></td>
<td><?php echo $findable_item->getSFindableCategoryId() ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

<a href="<?php echo url_for('findable/new') ?>">New</a>
actions.class.php:
public function executeIndex(sfWebRequest $request)
{
$this->findable_item_list = FindableItemPeer::doSelect(new Criteria());
}
Validation
Free with form generation!
We already defined the form widgets in
the original .yml file, including basic data
ranges
BaseFindableItemForm
$this->setValidators(array(
'id' => new sfValidatorPropelChoice(array('model' => 'FindableItem', 'column' => 'id', 'required' => false)),
'name' => new sfValidatorString(array('max_length' => 255, 'required' => false)),
'cardinality' => new sfValidatorInteger(array('required' => false)),
'points' => new sfValidatorInteger(array('required' => false)),
'description' => new sfValidatorString(array('required' => false)),
's_findable_category_id' => new sfValidatorPropelChoice(array('model' => 'FindableCategory', 'column' => 'id')),
));
Can easily override this in the implementation for
FindableItemForm with new validators. Or, dont
bother and leave it at default!
Aspect Oriented Development?
Symfony supports behaviors
Automatically creates many hook-spots
Classic example: paranoid behavior
Replace deletes with setting a flag
Augment selects to avoid records with that flag
Routing
Problem: We all love having simple
looking URLs:
http://cusearch09.com/user/image/5/320
Instead of
http://cusearch09.com/user/upload/imageT
humb.php?id=5&width=320
Solution:
Apache mod_rewrite
No... too complicated and hard to change on the
fly. Who wants to deal with RegExp?
Symfony:
routing.yml
resized_image:
url: image/:id/:width
param: {module: upload, action: imageThumb}
Templating
Generic template setup
Allows for partial templates
Inheritance!
Helpers
link_to()
img_tag()
Plugins
Easy to extend Symfony with plugins
Follow observer pattern
static public function
listenToSomeSortOfEvent(sfEvent $event)
Hooks your plugin to any part of Symfony
Uses: objects, aspects
Security? AJAX?
Free Lime Tests!
(note: not Limes Disease tests)
Unit test the model

Functional test the controllers (WOW!)
$t = new lime_test(1, new lime_output_color());
$t->diag('->retrieveByUsername()');
$user = UserPeer::retrieveByUsername('jbell');
$t->is($user->getLastName(), 'Bell', '->retrieveByUsername() returns the User for the given username');
$b = new sfTestBrowser();
$b->get('/foobar/edit/id/1');
$request = $b->getRequest();
$context = $b->getContext();
$response = $b->getResponse(); // Get access to the lime_test methods via the test() method
$b->test()->is($request->getParameter('id'), 1);
$b->test()->is($response->getStatuscode(), 200);
$b->test()->is($response->getHttpHeader('content-type'), 'text/html;charset=utf-8');
$b->test()->like($response->getContent(), '/edit/');
But wait, theres more!
Who would want to run each test
manually, or write a script even (bah!)
Put all tests in the unit folder
then...
$ symfony test:all
A code review: Rentpost
Managing landlord/tenant relations
PHP, Symfony, AJAX