Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
symfony
                                    Simplify your professional
                                    web development...
Sensio
  • French Web Agency, founded in 1998
          – 150 people
          – 30 people dedicated to Web technologies

...
Sensio Labs
  • Open-Source technologies
          – Linux
          – Apache
          – MySQL / PostgreSQL
          – P...
The symfony Framework
  •     PHP 5 Web Framework
  •     Based on 9 years of Sensio experience
  •     Based on well-know...
The symfony Goals
  • Bring together the « Entreprise World »
    and the Open-Source World

  • Develop Faster

  • Don’t...
Develop Faster
  • Each line of code has a cost
          – To write the line                                             ...
Don’t Reinvent the Wheel
  • Follow best practices
  • MVC Pattern : Model / View / Controller

  • Unit and functional te...
Main Selling Points
  • symfony is about good code but also …

  • Documentation
          – GFDL book (450p)
          – ...
Let’s see some features




International PHP 2007 Conference   www.symfony-project.com   fabien.potencier@sensio.com   ww...
Controller
  # apps/frontend/modules/blog/actions/actions.class.php
  class blogActions extends sfActions
  {             ...
Controller
  class blogActions extends sfActions
  {                                                                      ...
Controller (Doctrine)
  # apps/frontend/modules/blog/actions/actions.class.php
  class blogActions extends sfActions
  {
 ...
Model (Propel)
  // lib/model/Author.php
  class Author extends BaseAuthor
  {
    function getFullName()
    {
      retu...
Model (Doctrine)
  // lib/model/doctrine/lib/Author.php
  class Author extends BaseAuthor
  {
    function getFullName()
 ...
View / Template
  # apps/frontend/modules/post/templates/showSuccess.php
  <h1 class="title">
    <?php echo $post->getTit...
Routing
                                    homepage:
              /                       param: { module: blog, action:...
Routing in a Template
  <?php echo link_to($post->getTitle(), '@post?id='.$post->getId()) ?>




  <a href="<?php echo url...
Tests: Database Fixtures
  • Test data
            # data/fixtures/data.yml
            Author:
              fabien:
    ...
Functional Tests
  • Navigation simulation
          // test/functional/frontend/blogActionsTest.php
          $browser = ...
Be Happy… or not
  $ ./symfony test-functional frontend
  # get /
  ok 1 - status code is 200
  not ok 2 - response select...
Functional Tests
  # simple CSS selectors
  checkResponseElement('h1.title', '/IPC 2007 Conference/')
  checkResponseEleme...
Functional Tests
  class ApplicationBrowser extends sfTestBrowser
  {
    public function signin($user, $password)
    {
 ...
Admin Generator: Backend Creation
  • Automatic generation of an Administration
    Backend, ready for production usage
  ...
Admin Generator
  • Generated code is MVC and customizable
          – Configuration file (generator.yml)
          – Exte...
Admin Generator: Configurability
  # apps/frontend/modules/post/config/generator.yml
      generator:
         class:     ...
Admin Generator
  • List




International PHP 2007 Conference   www.symfony-project.com   fabien.potencier@sensio.com   w...
Admin Generator
  • Edition




   __toString()


                                                              widgets   ...
Admin Generator: Extensibility
  • Module extension
          class postActions extends autoPostActions
          {
      ...
Debugging Tools
  • Web Debug Toolbar




International PHP 2007 Conference   www.symfony-project.com   fabien.potencier@s...
Debugging Tools
  • Error messages




International PHP 2007 Conference   www.symfony-project.com   fabien.potencier@sens...
What’s New in symfony 1.1?
  • A new task framework
  • Decoupling
          – Remove singletons
          – Remove depend...
New Task Framework
  •     Easier to extend the symfony tasks
  •     Task namespaces
  •     Built-in help system
  •    ...
Task Namespaces
  generate
    :app                              Generates               a   new    application (init-app)...
Task Help
  $ ./symfony help plugin:install
  Usage:
   symfony plugin:install [--stability|-s="..."] [--release|-r="..."]...
Task Help
  Description:
   The plugin:install task installs a plugin:

      ./symfony plugin:install sfGuargPlugin

   B...
Task Calls in your Code
  # Somewhere in your code
  $task = new sfCacheClearTask($dispatcher);
  $task->run();




Intern...
symfony 1.0 Dependencies
                          sfView

                                                     sfResponse...
symfony 1.1 Dependencies
                                            sfRequest                    sfView
                 ...
sfEventDispatcher
  • Based on Cocoa Notification Center
  // sfUser
  $event = new sfEvent($this, 'user.change_culture', ...
Form & Validation Framework
  •     Not a refactoring
  •     A different approach
  •     Almost no shared code
  •     S...
The New Approach
  • Form as a first class object
  • Widget classes for form helpers
  • Validators validate arrays (it d...
Validators
  • Every validator extends sfValidator
  • A validator cleans and validates input values
  • sfValidator provi...
Validators
  // create a new string validator
  $v = new sfValidatorString(array('min_length' => 4));

  // clean and vali...
Custom Validator
  class CustomValidator extends sfValidator
  {
    protected function configure($options = array(), $mes...
Validators
  $v = new sfValidatorString(array('min_length' => 4));

  // throws a sfValidatorError
  $v->clean('Jon');

  ...
Errors Internationalization
  $v = new sfValidatorString(array('min_length' => 4));

  try
  {
    $value = $v->clean('Jon...
sfValidator(All|Any)
  • You can aggregate validators to create a new validator:
          – sfValidatorAll: All validator...
sfValidator(All|Any)
  • As they are validators themselves, you can create
    complex logic to validate your values:
    ...
sfValidatorSchema
  • A validator schema is composed of fields
  • A field is a named validator

  $v1 = new sfValidatorSt...
sfValidatorSchema
  • The clean() method takes an array of named
    values and returns an array:
       $v->clean(array(
...
sfValidatorSchema
  • It collects all errors for all fields
  • It throws an exception with all errors

     sfValidatorEr...
sfValidatorSchema
  • A named validator does not have access to the
    whole array of inputs, just its named value
  • Tw...
sfValidatorSchema
  $v2 = new sfValidatorSchemaCompare(
     'password', '==', 'password_bis'
  );

  $v = new sfValidator...
sfValidatorSchema
  • sfValidatorSchema is a sfValidator, so you can nest them

  $authorValidator = new sfValidatorSchema...
sfValidatorSchema
  $bookValidator->clean(array(
    'title'     => 'The symfony book',
    'sub_title' => 'The definitive...
sfValidatorSchema
  • Secure by default
          – allow_extra_fields (false by default)
          – filter_extra_fields ...
sfValidatorSchemaForEach
  $choiceValidator = new sfValidatorSchema(array(
    'choice' => $v1,
  ));

  $choicesValidator...
sfValidatorSchemaForEach
  $pollValidator->clean(array(
    'question' => 'Do you like symfony?',
    'choices' => array(
...
Validators as Strings
  $postValidator = new sfValidatorOr(array(
    new sfValidatorSchemaFilter('age', new sfValidatorIn...
Available Validators
  •     Boolean                                                •    All
  •     Choice               ...
Widgets
  • Every widget extends sfWidget
  • A widget is an object that can be rendered as an HTML
    string
  • sfWidge...
sfWidgetForm
  • Base class for all form widgets
  • Some more properties like isHidden()
  • Generates an id if none prov...
sfWidgetForm classes
  // create a new input widget
  $w = new sfWidgetFormInput();

  // render widget
  echo $w->render(...
sfWidgetForm classes
  // add default HTML attributes
  $w = new sfWidgetFormInput(array('class' => 'foo'));

  // render ...
sfWidgetFormSchema
  • A widget schema is composed of fields
  • A field is a named widget

  $w1 = new sfWidgetFormInput(...
sfWidgetFormSchema
  • The render() method takes an array of named
    values and returns an HTML string:
       $w->rende...
sfWidgetFormSchema
  • sfWidgetFormSchema is a sfWidget, so you can nest
    them

  $authorWidget = new sfWidgetFormSchem...
sfWidgetFormSchema
  $bookWidget->render(null, array(
    'title'     => 'The symfony book',
    'sub_title' => 'The defin...
sfWidgetFormSchema
  • The render() method can also render
          – Errors
          – Nested form schema
  • The rende...
Forms
  • A sfForm is the glue between
          – A validator schema
          – A widget schema

  $validator = new sfVa...
sfForm
  • You can also create your own form class

  class BookForm extends sfForm
  {
    public function configure()
  ...
A Form in a Form
  $authorForm = new AuthorForm();

  $bookForm->embedForm($authorForm);



  $choiceForm = new ChoiceForm...
sfForm
  $form = new AuthorForm();

  $input = array('first_name' => 'Fabien', 'last_name' => 'Potencier');
  $form->bind(...
sfForm
  • sfForm can take default values
       $form = new AuthorForm(array('first_name' => 'Fabien'));



  • sfFormFie...
sfForm
  $form = new AuthorForm();

  echo $form->getFormField('first_name')->render();
  // ===
  echo $form['first_name'...
For the laziest




                                                       echo $form




International PHP 2007 Conferenc...
Customize your Forms
                                                       $bookForm['author']

  <table>                ...
Forms: In a symfony Action
  class bookActions extends sfActions
  {
    public function executeEdit($request)
    {
     ...
sfFormPropel
  • Generated forms for Propel objects
  • Fully customizable
  • Introspects the Propel schema
          – M...
sfFormPropel
  class bookActions                 extends sfActions
  {
    public function                 executeEdit($re...
Customize Propel Forms
  class BookForm extends BaseBookForm
  {
    public function configure()
    {
      $this->embedI...
A Professional Web Framework
  • Built from experience
  • 1.0 stable, maintained with commercial support
  • Growing comm...
Yahoo! uses symfony
  • Yahoo! Bookmarks
          – 20 millions users
          – Web 2.0 / AJAX


  • del.icio.us
      ...
Next symfony Workshops


   En français : Paris, France - Dec 05, 2007

      In English : Paris, France - Feb 13, 2008

 ...
Join Us
  • Sensio Labs is recruiting in France
          – project managers
          – web developers
  • You have a pas...
SENSIO S.A.
                                          26, rue Salomon de Rothschild
                                      ...
Upcoming SlideShare
Loading in …5
×

symfony: Simplify your professional web development with PHP (IPC Frankfurt 2007)

6,009 views

Published on

Published in: Technology
  • This is a very thoroughly prepared presentation, thanks! Today PHP and Symfony are used, but every day new and really effective technologies appear and they quickly gain its popularity. That’s why it is really important to be always up to date in order to be highly competitive and work on challenging projects and become a part of Kyiv, Toronto, Berlin or Frankfurt web developers, like we do it, and there are a lot of reasons for it, which we indicated here: https://mobilunity.com/blog/how-to-hire-developers-in-germany-without-spending-a-fortune/.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

symfony: Simplify your professional web development with PHP (IPC Frankfurt 2007)

  1. 1. symfony Simplify your professional web development with PHP Fabien Potencier http://www.symfony-project.com/ http://www.sensiolabs.com/ International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  2. 2. Sensio • French Web Agency, founded in 1998 – 150 people – 30 people dedicated to Web technologies SENSIO Web Agency Web Webmarketing Technologies Open Source Technologies (Framework PHP) International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  3. 3. Sensio Labs • Open-Source technologies – Linux – Apache – MySQL / PostgreSQL – PHP / Perl / Python • Open-Source dedicated team • Big company customers – Web Consulting symfony PHP Framework – Audit / Training – Web Development International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  4. 4. 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 fabien.potencier@sensio.com www.sensiolabs.com
  5. 5. 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 fabien.potencier@sensio.com www.sensiolabs.com
  6. 6. Develop Faster • Each line of code has a cost – To write the line less code  – To test it less complexity – To maintain it  less bugs • Write less code  – Architecture : controller, ORM, … more productivity  – Configuration more time – Autoloading – Generators – Helpers • More time for business rules, edge cases, … International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  7. 7. 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) Simplify • Admin Generator your Dev. Life International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  8. 8. 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) 1.0 – Commercial support International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  9. 9. Let’s see some features International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  10. 10. Controller # apps/frontend/modules/blog/actions/actions.class.php class blogActions extends sfActions { Controller blog/show function executeShow() { $id = $this->getRequestParameter('id'); Model call (Propel) $this->post = PostPeer::retrieveByPk($id); For the View $this->forward404Unless($this->post); } Shortcut } International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  11. 11. Controller class blogActions extends sfActions { 1.0 function executeShow() { $this->forward404Unless( $this->post = PostPeer::retrieveByPk($this->getRequestParameter('id')) ); } } class blogActions extends sfActions { 1.1 function showAction($request) { $this->forward404Unless( $this->post = PostPeer::retrieveByPk($request->getParameter('id')) ); } } International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  12. 12. Controller (Doctrine) # apps/frontend/modules/blog/actions/actions.class.php class 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 fabien.potencier@sensio.com www.sensiolabs.com
  13. 13. Model (Propel) // lib/model/Author.php class 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 fabien.potencier@sensio.com www.sensiolabs.com
  14. 14. Model (Doctrine) // lib/model/doctrine/lib/Author.php class Author extends BaseAuthor { function getFullName() { return $this->getFirstName().' '.$this->getLastName(); } } $author = new Author(); $author->setFirstName('Fabien'); $author->setLastName('Potencier'); Same as in Propel $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')); International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  15. 15. 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> Escaped Escaped <p> <?php echo $post->getHtmlContent(ESC_RAW) ?> </p> Raw Value International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  16. 16. Routing homepage: / param: { module: blog, action: recent } url_for('@homepage') url: / homepage: / param: { module: blog, action: list } url: / recent: /recent param: { module: blog, action: recent } url: /recent post: link_to( param: { module: blog, action: show } /blog/1 $post->getTitle(), requirements: '@post?id='.$post->getId() id: d+ ) url: /blog/:id International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  17. 17. 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/') ?> <a href="http://www.google.com/">Google</a> Be pragmatic International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  18. 18. 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 fabien.potencier@sensio.com www.sensiolabs.com
  19. 19. Functional Tests • Navigation simulation // test/functional/frontend/blogActionsTest.php $browser = new sfTestBrowser(); $browser->initialize(); $browser-> get('/blog/1')-> Fluent isStatusCode(200)-> Interface checkResponseElement('h1.title', '/IPC 2007 Conference/'); The power of CSS selectors TDD Test Driven Development International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  20. 20. Be Happy… or not $ ./symfony test-functional frontend # get / ok 1 - status code is 200 not 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 200 ok 2 - response selector h1 matches regex /IPC 2007 Conference/ 1..2 Looks like everything went fine. International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  21. 21. Functional Tests # simple CSS selectors checkResponseElement('h1.title', '/IPC 2007 Conference/') checkResponseElement('#title', '/IPC 2007 Conference/') # attribute selectors checkResponseElement('ul li a[class~="title"]', '/IPC 2007 Conference/') # combinators: > and + checkResponseElement('ul > li', '/IPC 2007 Conference/') # some CSS3 selectors checkResponseElement('#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 fabien.potencier@sensio.com www.sensiolabs.com
  22. 22. Functional Tests class 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'); } DSL } Your own specific browser International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  23. 23. Admin Generator: Backend Creation • Automatic generation of an Administration Backend, ready for production usage – Lists – Filters – Pagination – Validation – Sorting – CRUD $ ./symfony propel-init-admin frontend post Post 1) Creates a post module 2) Generates configuration International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  24. 24. 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 fabien.potencier@sensio.com www.sensiolabs.com
  25. 25. 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 fabien.potencier@sensio.com www.sensiolabs.com
  26. 26. Admin Generator • List International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  27. 27. Admin Generator • Edition __toString() widgets m2m relationship International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  28. 28. Admin Generator: Extensibility • Module extension class postActions extends autoPostActions { protected function addFiltersCriteria($c) Generated { module parent::addFiltersCriteria($c); $c->add(PostPeer::IS_PUBLISHED, true); } } • Template customization _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 fabien.potencier@sensio.com www.sensiolabs.com
  29. 29. Debugging Tools • Web Debug Toolbar International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  30. 30. Debugging Tools • Error messages International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  31. 31. 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 fabien.potencier@sensio.com www.sensiolabs.com
  32. 32. 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 fabien.potencier@sensio.com www.sensiolabs.com
  33. 33. Task Namespaces generate :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 fabien.potencier@sensio.com www.sensiolabs.com
  34. 34. 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 fabien.potencier@sensio.com www.sensiolabs.com
  35. 35. Task Help Description: 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 fabien.potencier@sensio.com www.sensiolabs.com
  36. 36. Task Calls in your Code # Somewhere in your code $task = new sfCacheClearTask($dispatcher); $task->run(); International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  37. 37. symfony 1.0 Dependencies sfView sfResponse sfContext sfI18N sfRequest sfLogger sfStorage sfUser sfRouting Cleanup dependency Dependencies singleton International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  38. 38. symfony 1.1 Dependencies sfRequest sfView sfResponse sfI18N sfEventDispatcher sfUser sfRouting sfStorage sfLogger sfContext Cleanup dependency Dependencies singleton International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  39. 39. 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 fabien.potencier@sensio.com www.sensiolabs.com
  40. 40. 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 fabien.potencier@sensio.com www.sensiolabs.com
  41. 41. 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 model object) • 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 fabien.potencier@sensio.com www.sensiolabs.com
  42. 42. 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 fabien.potencier@sensio.com www.sensiolabs.com
  43. 43. 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 fabien.potencier@sensio.com www.sensiolabs.com
  44. 44. Custom Validator class 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 fabien.potencier@sensio.com www.sensiolabs.com
  45. 45. 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 codes or error messages International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  46. 46. 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 messages are i18n ready International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  47. 47. 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 fabien.potencier@sensio.com www.sensiolabs.com
  48. 48. 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 fabien.potencier@sensio.com www.sensiolabs.com
  49. 49. 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 fabien.potencier@sensio.com www.sensiolabs.com
  50. 50. 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 fabien.potencier@sensio.com www.sensiolabs.com
  51. 51. 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 fabien.potencier@sensio.com www.sensiolabs.com
  52. 52. 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 fabien.potencier@sensio.com www.sensiolabs.com
  53. 53. 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 fabien.potencier@sensio.com www.sensiolabs.com
  54. 54. 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 fabien.potencier@sensio.com www.sensiolabs.com
  55. 55. 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 fabien.potencier@sensio.com www.sensiolabs.com
  56. 56. 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, sfValidatorSchema will throw an error • If you switch allow_extra_fields to true, then extra fields won’t trigger an error but will be removed from the cleaned values • If you also switch filter_extra_fields to false, then extra fields won’t be removed from the cleaned values International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  57. 57. 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 fabien.potencier@sensio.com www.sensiolabs.com
  58. 58. 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 fabien.potencier@sensio.com www.sensiolabs.com
  59. 59. 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 fabien.potencier@sensio.com www.sensiolabs.com
  60. 60. Available Validators • Boolean • All • Choice • Any • ChoiceMany • Callback • Date • Decorator • DateTime • Pass • Email • FromDescription • Integer • Number • Schema • Regex • SchemaForEach • String • SchemaCompare • Time • SchemaFilter • Url International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  61. 61. 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 fabien.potencier@sensio.com www.sensiolabs.com
  62. 62. 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 fabien.potencier@sensio.com www.sensiolabs.com
  63. 63. sfWidgetForm classes // create a new input widget $w = new sfWidgetFormInput(); // render widget echo $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 objects are stateless International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  64. 64. sfWidgetForm classes // add default HTML attributes $w = new sfWidgetFormInput(array('class' => 'foo')); // render widget with some HTML attributes echo $w->render('first_name', 'Fabien', array('class' => 'foo')); International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  65. 65. 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 fabien.potencier@sensio.com www.sensiolabs.com
  66. 66. 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 fabien.potencier@sensio.com www.sensiolabs.com
  67. 67. 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 fabien.potencier@sensio.com www.sensiolabs.com
  68. 68. 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 fabien.potencier@sensio.com www.sensiolabs.com
  69. 69. 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 fabien.potencier@sensio.com www.sensiolabs.com
  70. 70. 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 fabien.potencier@sensio.com www.sensiolabs.com
  71. 71. 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 fabien.potencier@sensio.com www.sensiolabs.com
  72. 72. 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 fabien.potencier@sensio.com www.sensiolabs.com
  73. 73. 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 fabien.potencier@sensio.com www.sensiolabs.com
  74. 74. sfForm • sfForm can take default values $form = new AuthorForm(array('first_name' => 'Fabien')); • sfFormField objects are widgets bound to the input or default values echo $form->getFormField('first_name')->render(); International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  75. 75. 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 attributes echo $form['first_name']->render(array('class' => 'foo')); International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  76. 76. For the laziest echo $form International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  77. 77. Customize your Forms $bookForm['author'] <table> $bookForm['author']['first_name']->renderRow() <tr> <th> $bookForm['author']['first_name']->renderLabel() <label for="book_author_first_name">First Name</label> $bookForm['author']['first_name']->renderLabelName() </th> <td> <ul class="error_list"> <li>Required.</li> $bookForm['author']['first_name']->renderError() </ul> <input type="text" name="book[author][first_name]" id="book_author_first_name" /> $bookForm['author']['first_name'] </td> </tr> ... </table> International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  78. 78. Forms: In a symfony Action class 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 fabien.potencier@sensio.com www.sensiolabs.com
  79. 79. sfFormPropel • Generated forms for Propel objects • Fully customizable • Introspects the Propel schema – Maps Propel/Creole types to symfony validators and widgets – Foreign keys – Many to many relationships – Internationalized tables International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  80. 80. sfFormPropel class 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 fabien.potencier@sensio.com www.sensiolabs.com
  81. 81. Customize Propel Forms class 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 fabien.potencier@sensio.com www.sensiolabs.com
  82. 82. 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 fabien.potencier@sensio.com www.sensiolabs.com
  83. 83. 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 fabien.potencier@sensio.com www.sensiolabs.com
  84. 84. 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 fabien.potencier@sensio.com www.sensiolabs.com
  85. 85. 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 to participate to development of Web 2.0 sites using the best frameworks available. – Project Manager : You have more than 5 years experience as a developer and/or a project manager and you want to manage complex Web projects for prestigious clients. International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com
  86. 86. SENSIO S.A. 26, rue Salomon de Rothschild 92 286 SURESNES cedex FRANCE Tél. : +33 1 40 99 80 80 Fax : +33 1 40 99 83 34 Contact Fabien Potencier fabien.potencier@sensio.com http://www.sensiolabs.com/ http://www.symfony-project.com/ International PHP 2007 Conference www.symfony-project.com fabien.potencier@sensio.com www.sensiolabs.com

×