PHP + Symfony Rapid application development Jonathan Bell Nov 18, 2010.
-
Upload
kamryn-newby -
Category
Documents
-
view
230 -
download
1
Transcript of PHP + Symfony Rapid application development Jonathan Bell Nov 18, 2010.
A Developer’s User Story
• It’s 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)• Don’t have time machine• EJB? No…• .Net? No…
Enter SymfonySymfony 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.ymlpropel: 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 programmer’s 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 rangesBaseFindableItemForm$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, don’t 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/imageThumb.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 Lime’s 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, there’s 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