symfony: simplify your professional web development with php (ipc frankfurt 2007)
TRANSCRIPT
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
symfonySimplify your professional
web development with PHP
Fabien Potencierhttp://www.symfony-project.com/
http://www.sensiolabs.com/
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Sensio• French Web Agency, founded in 1998
– 150 people– 30 people dedicated to Web technologies
Webmarketing
Open SourceTechnologies
(Framework PHP)
WebTechnologies
SENSIOWeb Agency
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Sensio Labs• Open-Source technologies
– Linux– Apache– MySQL / PostgreSQL– PHP / Perl / Python
• Open-Source dedicated team• Big company customers
– Web Consulting– Audit / Training– Web Development
symfony PHP Framework
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
The symfony Framework• PHP 5 Web Framework• Based on 9 years of Sensio experience• Based on well-known projets (Mojavi, Propel, Prado)
• Open-Source• Built for :
– Professional Websites– Complex needs– Demanding environments Licence
MIT
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
The symfony Goals
• Bring together the « Entreprise World »and the Open-Source World
• Develop Faster
• Don’t Reinvent the Wheel
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Develop Faster• Each line of code has a cost
– To write the line– To test it– To maintain it
• Write less code– Architecture : controller, ORM, …– Configuration– Autoloading– Generators– Helpers
• More time for business rules, edge cases, …
less code
less complexity
less bugs
more productivity
more time
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Don’t Reinvent the Wheel• Follow best practices• MVC Pattern : Model / View / Controller
• Unit and functional test framework
• Environment and deployment support• Configurability• Security (XSS and CSRF protection by default)• Extensible (plugin system)• Admin Generator Simplify
your Dev. Life
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Main Selling Points• symfony is about good code but also …
• Documentation– GFDL book (450p)– The askeet tutorial (250p)
• 1.0 maintained for a long time– 1 release a month (only bug fixes)– Commercial support
1.0
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Let’s see some features
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Controller# apps/frontend/modules/blog/actions/actions.class.phpclass blogActions extends sfActions{ function executeShow() { $id = $this->getRequestParameter('id'); $this->post = PostPeer::retrieveByPk($id);
$this->forward404Unless($this->post); }}
Shortcut
Controller blog/show
For the View
Model call (Propel)
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Controllerclass blogActions extends sfActions{ function executeShow() { $this->forward404Unless( $this->post = PostPeer::retrieveByPk($this->getRequestParameter('id')) ); }}
class blogActions extends sfActions{ function showAction($request) { $this->forward404Unless( $this->post = PostPeer::retrieveByPk($request->getParameter('id')) ); }}
1.0
1.1
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Controller (Doctrine)# apps/frontend/modules/blog/actions/actions.class.phpclass blogActions extends sfActions{ function executeShow() { $id = $this->getRequestParameter('id'); $this->post = Doctrine::getTable('Post')->find($id);
$this->forward404Unless($this->post); }}
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Model (Propel)// lib/model/Author.phpclass Author extends BaseAuthor{ function getFullName() { return $this->getFirstName().' '.$this->getLastName(); }}
$author = new Author();$author->setFirstName('Fabien');$author->setLastName('Potencier');$author->save();
$post = new Post();$post->setAuthor($author);$post->setPublishedOn('tomorrow 12:00');$post->isPublished(true);$post->save();
$posts = PostPeer::doSelect(new Criteria());
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Model (Doctrine)// lib/model/doctrine/lib/Author.phpclass Author extends BaseAuthor{ function getFullName() { return $this->getFirstName().' '.$this->getLastName(); }}
$author = new Author();$author->setFirstName('Fabien');$author->setLastName('Potencier');$author->save();
$post = new Post();$post->setAuthor($author);$post->setPublishedOn('tomorrow 12:00');$post->isPublished(true);$post->save();
$posts = Doctrine::getTable('Post')->findAll();
$post = Doctrine::getTable('Post')->find($request->getParameter('id'));
Same as in Propel
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
View / Template# apps/frontend/modules/post/templates/showSuccess.php<h1 class="title"> <?php echo $post->getTitle() ?></h1>
<h2> par <?php echo $post->getAuthor()->getFullName() ?></h2>
<p> <?php echo $post->getHtmlContent(ESC_RAW) ?></p>
Raw Value
Escaped Escaped
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Routing
link_to( $post->getTitle(), '@post?id='.$post->getId())
post: param: { module: blog, action: show } requirements: id: \d+ url: /blog/:id
url_for('@homepage')homepage: param: { module: blog, action: recent } url: /
/blog/1
/
homepage: param: { module: blog, action: list } url: /recent: param: { module: blog, action: recent } url: /recent
/
/recent
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Routing in a Template<?php echo link_to($post->getTitle(), '@post?id='.$post->getId()) ?>
<a href="<?php echo url_for('@post?id='.$post->getId()) ?>">Next Post</a>
<?php echo link_to('Google', 'http://www.google.com/') ?>
Be pragmatic
<a href="http://www.google.com/">Google</a>
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Tests: Database Fixtures• Test data # data/fixtures/data.yml Author: fabien: first_name: Fabien last_name: Potencier Post: first_post: author_id: fabien title: IPC 2007 Conference
$ ./symfony propel-load-data frontend
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Functional Tests• Navigation simulation // test/functional/frontend/blogActionsTest.php $browser = new sfTestBrowser(); $browser->initialize(); $browser-> get('/blog/1')-> isStatusCode(200)-> checkResponseElement('h1.title', '/IPC 2007 Conference/');
TDDTest Driven Development
The power of CSS selectors
FluentInterface
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Be Happy… or not$ ./symfony test-functional frontend# get /ok 1 - status code is 200not ok 2 - response selector h1 does not match regex /IPC 2007 Conference/1..2 Looks like you failed 1 tests of 2.
$ ./symfony test-functional frontend# get /ok 1 - status code is 200ok 2 - response selector h1 matches regex /IPC 2007 Conference/1..2 Looks like everything went fine.
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Functional Tests# simple CSS selectorscheckResponseElement('h1.title', '/IPC 2007 Conference/')checkResponseElement('#title', '/IPC 2007 Conference/')
# attribute selectorscheckResponseElement('ul li a[class~="title"]', '/IPC 2007 Conference/')
# combinators: > and +checkResponseElement('ul > li', '/IPC 2007 Conference/')
# some CSS3 selectorscheckResponseElement('#list li:first-child', '/IPC 2007 Conference/')checkResponseElement('#list li:nth-child(3)', '/IPC 2007 Conference/')checkResponseElement('#list li:contains("IPC 2007 Conference")')
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Functional Testsclass ApplicationBrowser extends sfTestBrowser{ public function signin($user, $password) { return $this-> post('/signin', array('username' => $user, 'password' => $password))-> isRedirect()-> followRedirect()-> checkResponseElement('div.username', 'Welcome back Fabien'); }
public function signout() { return $this->get('/signout'); }}
DSLYour own specific browser
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Admin Generator: Backend Creation• Automatic generation of an Administration
Backend, ready for production usage– Lists– Pagination– Sorting
$ ./symfony propel-init-admin frontend post Post
1) Creates a post module2) Generates configuration
– Filters– Validation– CRUD
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Admin Generator• Generated code is MVC and customizable
– Configuration file (generator.yml)– Extend the Controller– Override some Templates / Partials
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Admin Generator: Configurability# apps/frontend/modules/post/config/generator.yml generator: class: sfPropelAdminGenerator param: model_class: Post list: display: [=title, author, created_at] filters: [title, author_id, published_on] max_per_page: 5
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Admin Generator• List
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Admin Generator• Edition
__toString()
widgets m2m relationship
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Admin Generator: Extensibility• Module extension class postActions extends autoPostActions { protected function addFiltersCriteria($c) { parent::addFiltersCriteria($c); $c->add(PostPeer::IS_PUBLISHED, true); } }
• Template customization
Generatedmodule
_edit_* : actions, footer, form, header, messages_list_* : footer, header, messages, td_actions, t(d|h)_stacked, t(d|h)_tabular_filters, editSuccess, listSuccess
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Debugging Tools• Web Debug Toolbar
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Debugging Tools• Error messages
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
What’s New in symfony 1.1?• A new task framework• Decoupling
– Remove singletons– Remove dependencies between core classes– New Event Dispatcher system
• Form / Validation framework
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
New Task Framework• Easier to extend the symfony tasks• Task namespaces• Built-in help system• Tasks are decoupled from the CLI
– Can be called from the CLI– … or from your own code… easily
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Task Namespacesgenerate :app Generates a new application (init-app) :batch Generates a new batch (init-batch) :controller Generates a new controller (init-controller) :module Generates a new module (init-module) :project Generates a new project (init-project)
test :all Launches all tests :functional Launches functional tests :unit Launches unit tests
i18n :extract Extracts i18n strings from php files :find Finds non "i18n ready" strings in an application
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Task Help$ ./symfony help plugin:install
Usage: symfony plugin:install [--stability|-s="..."] [--release|-r="..."] [--channel|-
c="..."] [--install_deps|-d] name
Aliases: plugin-install
Arguments: name The plugin name
Options: --stability (-s) The preferred stability (stable, beta, alpha) --release (-r) The preferred version --channel (-c) The PEAR channel name --install_deps (-d) Whether to force installation of required dependencies
Description: …
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Task HelpDescription: The plugin:install task installs a plugin:
./symfony plugin:install sfGuargPlugin
By default, it installs the latest stable release.
If you want to install a plugin that is not stable yet, use the stability option:
./symfony plugin:install --stability=beta sfGuargPlugin ./symfony plugin:install -s beta sfGuargPlugin
You can also force the installation of a specific version:
./symfony plugin:install --release=1.0.0 sfGuargPlugin ./symfony plugin:install -r 1.0.0 sfGuargPlugin
To force installation of all required dependencies, use the install_deps flag:
./symfony plugin:install --install-deps sfGuargPlugin ./symfony plugin:install -d sfGuargPlugin
By default, the PEAR channel used is symfony-plugins (plugins.symfony-project.org).
You can specify another channel with the channel option:
./symfony plugin:install --channel=mypearchannel sfGuargPlugin ./symfony plugin:install -c mypearchannel sfGuargPlugin…
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Task Calls in your Code# Somewhere in your code
$task = new sfCacheClearTask($dispatcher);$task->run();
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
symfony 1.0 Dependencies
CleanupDependencies
sfRequest
sfResponse
sfContext
sfUsersfStorage
sfRouting
sfI18NsfLogger
sfView
singleton dependency
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
symfony 1.1 Dependencies
CleanupDependencies
sfRequestsfResponse
sfContext
sfUser
sfStorage
sfRouting
sfI18N
sfLogger
sfEventDispatcher
sfView
singleton dependency
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfEventDispatcher• Based on Cocoa Notification Center// sfUser$event = new sfEvent($this, 'user.change_culture', array('culture' => $culture));$dispatcher->notify($event);
// sfI18N$callback = array($this, 'listenToChangeCultureEvent');$dispatcher->connect('user.change_culture', $callback);
• sfI18N and sfUser are decoupled• « Anybody » can listen to any event• You can notify existing events or create new ones
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Form & Validation Framework• Not a refactoring• A different approach• Almost no shared code• Symfony 1.1 can still use the old system
– set compat_10: on in settings.yml (off by default)– you can use the new and the old system in the same
application– symfony 1.0 sfValidator class has been renamed to
sfValidatorBase to avoid class name conflicts
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
The New Approach• Form as a first class object• Widget classes for form helpers• Validators validate arrays (it doesn’t care if it
comes from a request, an XML file or a modelobject)
• A decoupled system– Can be used without any other symfony class– 3 differents sub-systems
• Validators: can be used by themselves• Widgets: can be used by themselves• Form: glue between validators and widgets
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Validators• Every validator extends sfValidator• A validator cleans and validates input values• sfValidator provides some common features
– required (validation) > true by default– trim (cleaning) > false by default
• Each validator can have options:– sfValidatorString: max_length, min_length
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Validators// create a new string validator$v = new sfValidatorString(array('min_length' => 4));
// clean and validate data$value = $v->clean('Fabien');
// returns the input value$value == 'Fabien'
// change some option$v->setOption('trim', true);
$value = $v->clean(' Fabien ');
// trims the input value$value == 'Fabien' Validator objects
are stateless
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Custom Validatorclass CustomValidator extends sfValidator{ protected function configure($options = array(), $messages = array()) { $this->setOption('min_length', null); $this->setMessage('min_length', 'Too short.'); }
protected function doClean($value) { if (strlen($value) < $this->getOption('min_length')) { throw sfValidatorError($this, 'min_length', array('value' => $value)); }
return $value; }}
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Validators$v = new sfValidatorString(array('min_length' => 4));
// throws a sfValidatorError$v->clean('Jon');
$e->getCode() == 'min_length'$e->getMessage() == '"Jon" is too short (4 characters min).'
$v->setMessage('min_length', 'Too short (%name%).');$e->getMessage() == 'Too short (Jon).'
Use error codesor error messages
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Errors Internationalization$v = new sfValidatorString(array('min_length' => 4));
try{ $value = $v->clean('Jon');}catch (sfValidatorError $e){ echo $i18n->__($e->getMessageFormat(), $e->getArguments())."\n"; // or echo $i18n->__($e->getCode(), $e->getArguments())."\n";}
Error messagesare i18n ready
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidator(All|Any)• You can aggregate validators to create a new validator:
– sfValidatorAll: All validators must pass– sfValidatorAny: At least one validator must pass
$v1 = new sfValidatorString(array('min_length' => 4));$v2 = new sfValidatorString(array('max_length' => 10));
$v = new sfValidatorAll(array($v1, $v2));
// values must validate both validators$v->clean('Fabien');
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidator(All|Any)• As they are validators themselves, you can create
complex logic to validate your values:
// v1 && (v2 || v3) $v = new sfValidatorAll( array($v1, sfValidatorAny($v2, $v3)) );
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchema• A validator schema is composed of fields• A field is a named validator
$v1 = new sfValidatorString(array('min_length' => 4));
$v = new sfValidatorSchema(array( 'first_name' => $v1, 'last_name' => $v1, ));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchema• The clean() method takes an array of named
values and returns an array:
$v->clean(array( 'first_name' => 'Fabien', 'last_name' => 'Potencier', ));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchema
• It collects all errors for all fields• It throws an exception with all errors
sfValidatorErrorSchema: first_name: "Jon" is too short (4 characters min). last_name: "Jon" is too short (4 characters min). in ….php on line …
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchema• A named validator does not have access to the
whole array of inputs, just its named value• Two special validators:
– _pre_validator and _post_validator– They takes the array of values as input– They throw « global » errors
Isolation
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchema$v2 = new sfValidatorSchemaCompare( 'password', '==', 'password_bis');
$v = new sfValidatorSchema(array( 'password' => $v1, 'password_bis' => $v1,
'_post_validator' => $v2,));
sfValidatorErrorSchema: "pass" does not match "word". in ….php on line …
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchema• sfValidatorSchema is a sfValidator, so you can nest them
$authorValidator = new sfValidatorSchema(array( 'first_name' => $v1, 'last_name' => $v1,));
$bookValidator = new sfValidatorSchema(array( 'title' => $v1, 'sub_title' => $v1, 'author' => $authorValidator,));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchema$bookValidator->clean(array( 'title' => 'The symfony book', 'sub_title' => 'The definitive guide', 'author' => array( 'first_name' => 'Fabien', 'last_name' => 'Potencier', ),));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchema• Secure by default
– allow_extra_fields (false by default)– filter_extra_fields (true by default)
• If you pass a value with no matching validator, sfValidatorSchemawill throw an error
• If you switch allow_extra_fields to true, then extra fields won’ttrigger an error but will be removed from the cleaned values
• If you also switch filter_extra_fields to false, then extra fields won’tbe removed from the cleaned values
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchemaForEach$choiceValidator = new sfValidatorSchema(array( 'choice' => $v1,));
$choicesValidator = new sfValidatorSchemaForEach($choiceValidator, 3);
$pollValidator = new sfValidatorSchema(array( 'question' => $v1, 'choices' => $choicesValidator,));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfValidatorSchemaForEach$pollValidator->clean(array( 'question' => 'Do you like symfony?', 'choices' => array( array('choice' => 'Yes'), array('choice' => 'This is the best'), array('choice' => 'A lot'), ),));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Validators as Strings$postValidator = new sfValidatorOr(array( new sfValidatorSchemaFilter('age', new sfValidatorInteger(array('min' => 18))), new sfValidatorAll(array( new sfValidatorSchemaFilter('age', new sfValidatorInteger(array('max' => 18))), new sfValidatorSchemaFilter('is_young', new sfValidatorBoolean(array('required' => true))), )),));
$string = $postValidator->asString();' age:Integer({min: 18}) or age:Integer({max: 18}) and is_young:Boolean({required: true})'
$postValidator = new sfValidatorFromDescription($string);
$postValidator->asPhp();
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Available Validators• Boolean• Choice• ChoiceMany• Date• DateTime• Email• Integer• Number• Regex• String• Time• Url
• All• Any• Callback• Decorator• Pass• FromDescription
• Schema• SchemaForEach• SchemaCompare• SchemaFilter
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Widgets• Every widget extends sfWidget• A widget is an object that can be rendered as an HTML
string• sfWidget provides some common features
– renderTag()– renderContentTag()– Charset support– XHTML or HTML closing tags
• Each widget can have HTML attributes:– Takes care of escaping– Fixes double escaping problems
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfWidgetForm• Base class for all form widgets• Some more properties like isHidden()• Generates an id if none provided and the widget
has a name– Default id is the widget name– Can be customized
$w = new sfWidgetFormInput(); $w->setIdFormat('id_%s');
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfWidgetForm classes// create a new input widget$w = new sfWidgetFormInput();
// render widgetecho $w->render('first_name', 'Fabien');
// returns the widget as HTML<input type="text" name="first_name" value="Fabien" id="first_name" />
// change some attributes$w->setAttribute('class', 'foo');
<input … class="foo" /> Widget objectsare stateless
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfWidgetForm classes// add default HTML attributes$w = new sfWidgetFormInput(array('class' => 'foo'));
// render widget with some HTML attributesecho $w->render('first_name', 'Fabien', array('class' => 'foo'));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfWidgetFormSchema• A widget schema is composed of fields• A field is a named widget
$w1 = new sfWidgetFormInput();
$w = new sfWidgetFormSchema(array( 'first_name' => $w1, 'last_name' => $w1, ));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfWidgetFormSchema• The render() method takes an array of named
values and returns an HTML string:
$w->render(null, array( 'first_name' => 'Fabien', 'last_name' => 'Potencier', ));
• You can also render individual fields
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfWidgetFormSchema• sfWidgetFormSchema is a sfWidget, so you can nest
them
$authorWidget = new sfWidgetFormSchema(array( 'first_name' => $w1, 'last_name' => $w1,));
$bookWidget = new sfWidgetFormSchema(array( 'title' => $w1, 'sub_title' => $w1, 'author' => $authorValidator,));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfWidgetFormSchema$bookWidget->render(null, array( 'title' => 'The symfony book', 'sub_title' => 'The definitive guide', 'author' => array( 'first_name' => 'Fabien', 'last_name' => 'Potencier', ),));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfWidgetFormSchema• The render() method can also render
– Errors– Nested form schema
• The render() method uses a formatter class– sfWidgetFormSchemaFormatterList– sfWidgetFormSchemaFormatterTable– Or build your own
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Forms• A sfForm is the glue between
– A validator schema– A widget schema
$validator = new sfValidatorSchema();$widget = new sfWidgetFormSchema();
$form = new sfForm();$form->setValidatorSchema($validator);$form->setWidgetSchema($widget);
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfForm• You can also create your own form class
class BookForm extends sfForm{ public function configure() { $validator = new BookValidatorSchema(); $widget = new BookWidgetFormSchema();
$this->setValidatorSchema($validator); $this->setWidgetSchema($widget); }}
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
A Form in a Form$authorForm = new AuthorForm();
$bookForm->embedForm($authorForm);
$choiceForm = new ChoiceForm();
$pollForm->embedFormForEach($choiceForm, 4);
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfForm$form = new AuthorForm();
$input = array('first_name' => 'Fabien', 'last_name' => 'Potencier');
$form->bind($input);if ($form->isValid()){ // do something with the cleaned values $form->getValues();}else{ // do something with the errors $form->getErrorSchema();}
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfForm• sfForm can take default values
$form = new AuthorForm(array('first_name' => 'Fabien'));
• sfFormField objects are widgets bound to theinput or default values
echo $form->getFormField('first_name')->render();
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfForm
$form = new AuthorForm();
echo $form->getFormField('first_name')->render();// ===echo $form['first_name']->render();// ===echo $form['first_name'];
// name and value are bound to the sfFormField object<input type="text" name="first_name" value="Fabien" id="first_name" />
// add some HTML attributesecho $form['first_name']->render(array('class' => 'foo'));
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
For the laziest
echo $form
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Customize your Forms<table>
<tr> <th>
<label for="book_author_first_name">First Name</label>
</th> <td> <ul class="error_list"> <li>Required.</li> </ul> <input type="text" name="book[author][first_name]" id="book_author_first_name" />
</td> </tr> ...</table>
$bookForm['author']
$bookForm['author']['first_name']->renderLabel()
$bookForm['author']['first_name']->renderLabelName()
$bookForm['author']['first_name']->renderError()
$bookForm['author']['first_name']
$bookForm['author']['first_name']->renderRow()
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Forms: In a symfony Actionclass bookActions extends sfActions{ public function executeEdit($request) { $this->form = new AuthorForm();
if ($request->isMethod('post')) { $this->form->bind($request->getParameter('book')); if ($this->form->isValid()) { $values = $this->form->getValues();
$this->redirect('@homepage'); } } }}
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfFormPropel• Generated forms for Propel objects• Fully customizable• Introspects the Propel schema
– Maps Propel/Creole types to symfony validators andwidgets
– Foreign keys– Many to many relationships– Internationalized tables
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
sfFormPropelclass bookActions extends sfActions{ public function executeEdit($request) { $this->book = BookPeer::retrieveByPk($request->getParameter('id')); $this->form = new AuthorForm($this->book);
if ($request->isMethod('post')) { $this->form->bind($request->getParameter('book'); if ($this->form->isValid()) { $book = $this->form->save();
$this->redirect('@book?id='.$book->getId()); } } }}
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Customize Propel Formsclass BookForm extends BaseBookForm{ public function configure() { $this->embedI18n(array('en', 'fr'));
$this->widgetSchema['en']->setLabel('en', 'English');
unset($this['created_at']);
$this->validatorSchema['foo'] = new sfValidatorPass(); $this->widgetSchema['foo'] = new sfWidgetIdentity();
$this->setDefault('published_on', time()); }}
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
A Professional Web Framework
• Built from experience• 1.0 stable, maintained with commercial support• Growing community
– Developers in more than 80 countries– 200 000 visitors per month on symfony-project.com– 200 plugins in just 8 months
• Open-Source Documentation– The book (450 pages - GFDL)– Askeet Tutorial (250 pages)
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Yahoo! uses symfony• Yahoo! Bookmarks
– 20 millions users– Web 2.0 / AJAX
• del.icio.us– New beta on symfony– preview.delicious.com
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Next symfony Workshops
En français : Paris, France - Dec 05, 2007
In English : Paris, France - Feb 13, 2008
More info on www.sensiolabs.com
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
Join Us• Sensio Labs is recruiting in France
– project managers– web developers
• You have a passion for the web?– Web Developer : You have a minimum of 3 years experience in
web development with Open-Source projects and you wish toparticipate to development of Web 2.0 sites using the bestframeworks available.
– Project Manager : You have more than 5 years experience as adeveloper and/or a project manager and you want to managecomplex Web projects for prestigious clients.
International PHP 2007 Conference www.symfony-project.com [email protected] www.sensiolabs.com
SENSIO S.A.26, rue Salomon de Rothschild
92 286 SURESNES cedexFRANCE
Tél. : +33 1 40 99 80 80Fax : +33 1 40 99 83 34
ContactFabien Potencier
http://www.sensiolabs.com/ http://www.symfony-project.com/