Symfony 2 meets Propel 1.5François Zaninotto
François ZaninottoHead of the Web Development Team at eTF1, editor the web properties of the leading TV network in France.Former symfony 1 contributorAuthor of “The Definitive Guide to Symfony” (APress)Lead Developer of Propel since October, 2009Interests: Web development, Usability, Agility, ROINot a developerTwitter: @francoisz, Github: fzaninotto
Propel 1.5
No surpriseBackwards compatible with Propel 1.3 and 1.4Faster than Propel 1.4, which was faster than Propel 1.3, which was...Very IDE friendlyBetter documentedMore robust (3 times as many unit tests as Propel 1.3)Fully integrated into symfony 1.3/1.4 (sfPropel15Plugin)
Surprise!Major new featuresModel QueriesCollectionsMany-to-many relationshipsMajor new behaviorsNested SetsConcrete Table InheritanceBetter Oracle Support
Surprise!Major new featuresModel QueriesCollectionsMany-to-many relationshipsMajor new behaviorsNested SetsConcrete Table InheritanceBetter Oracle SupportKiller FeatureKiller Feature
Model QueriesModel Queries are to the SQL query what ActiveRecord is to the table rowShift from the relational Paradigm to the Object paradigm in QueriesInspirations: SQL Alchemy, Doctrine, DbFinder, ArelCode generation makes it fast and IDE friendlyEasy to learn and useMUCH cleaner custom model codeBye bye, Criteria!
Model Queries$books = BookQuery::create()->filterByPublishedAt(array(    ‘max’ => time()  ))->filterByPublisher($publisher)->useAuthorQuery()->stillAlive()  ->endUse()->orderByTitle()->find();
 Concrete Table Inheritancecontentidtitlearticlebodyvideourlstructuredata
Concrete Table Inheritance: An Example$article = new Article();$article->setTitle(‘France loses World Cup’);$article->setBody(‘Lorem Ipsum’);$article->save();$video = new Video();$video->setTitle(‘World Cup Goals’);$video->setUrl(‘http://www.youtube.com/xxx’);$video->save();
> SELECT * FROMarticle;+----+------------------------+-------------+| id | title                  | body        |+----+------------------------+-------------+| 1  | France loses World Cup | Lorem Ipsum |+----+------------------------+-------------+> SELECT * FROMvideo;+----+-----------------+----------------------------+| id | title           | url                        |+----+-----------------+----------------------------+| 2  | World Cup goals | http://www.youtube.com/xxx |+----+-----------------+----------------------------+> SELECT * FROM content;+----+------------------------+| id | title                  |+----+------------------------+| 1  | France loses World Cup || 2  | World Cup goals        |+----+------------------------+
Design your model in a true object-oriented wayLet Propel do the mapping with the relational worldDenormalize with ease for optimal performanceLet PHP manipulate inheritance, not data replication.… Let PHP manipulate objects, not records.… Let PHP manipulate collections, not arrays.… Let PHP manipulate relations, not foreign keys.
Continuousimprovementsthroughminor versions1.5.1PropelObjectCollection::toKeyValue()One-to-manyjoinedhydration (no LIMIT support)CLI enhancements1.5.2Namespaces ! ModelQuery::findOneOrCreate()aggregate_columnbehaviorSQL Comments
Continuous improvements through minor versions1.5.1PropelObjectCollection::toKeyValue()One-to-many joined hydration (no LIMIT support)CLI enhancements1.5.2Namespaces ! ModelQuery::findOneOrCreate()aggregate_column behaviorSQL CommentsMust HaveKiller Feature
Namespaces// in schema.xml<table name="book"namespace="Bookstore">  ...</table>// in application codeuseBookstore\BookQuery;$book = BookQuery::create();->findOneByTitle(‘War And Peace’);echoget_class($book);  // Bookstore\Book$author = $book->getAuthor();echoget_class($author);  // Bookstore\People\Author
 Aggregate Table Behaviorauthoridnamebookidtitleauthor_id*<table name="author">  <behavior name="aggregate_column"><parameter name="name" value="nb_books" />    <parameter name="foreign_table" value="book" />    <parameter name="expression" value="COUNT(id)" />  </behavior>  ...</table>
 Aggregate Table Behaviorauthoridnamenb_booksbookidtitleauthor_id*<table name="author">  <behavior name="aggregate_column"><parameter name="name" value="nb_books" />    <parameter name="foreign_table" value="book" />    <parameter name="expression" value="COUNT(id)" />  </behavior>  ...</table>
Aggregate Table Behavior$author = new Author();$author->setName(‘Leo Tolstoi');$author->save();echo $author->getNbBooks(); // 0$book = new Book();$book->setTitle(‘War and Peace’);$book->setAuthor($author);$book->save();echo $author->getNbBooks(); // 1$book->delete();echo $author->getNbBooks(); // 0
No, really, Propel is definitely NOT DEAD
Propel 1.5 and Symfony
Propel Integration with symfony 1: sfPropel15Plugin Use sf configuration system (databases.yml, propel.ini) Use sf autoloading rather than Propel’s Use sf task system (and hides Phing, thank God) Adapt Propel to SF applications directory structureYAML format for the schema (and plugin override)
Web Debug Toolbar panel Form integration (Widgets, Validators, Model forms)Admin Generator Theme Routing integration (Model routes, Model route collections) Symfony BehaviorsPropel Integration with Symfony2: PropelBundle Use sf configuration system (config.yml, Dependency Injection) Use sf autoloading rather than Propel’s (thanks Namespaces) Use sf command system (and hides Phing, thank God) Adapt Propel to SF applications directory structureYAML format for the schema (and bundle override)Web Debug Toolbar Panel Form integration (Widgets, Validators, Model forms) Admin Generator ThemeRouting integration (Model routes, Model route collections)       Symfony Behaviors
Many of the symfony add-ons to Propel are now part of Propel 1.5Model hooks, query hooksBehavior system (at buildtime, for better performance and power)auto_add_pkbehaviortimestampable behaviorisPrimaryString column  attribute for automated __toString()No need for custom symfony code for these
Why you may want to use Propel rather than Doctrine 2No need to upgrade your Model codeIt’s fast (without any cache system - that’s code generation)It’s an ActiveRecord implementationIt has behaviorsIt’s IDE friendlyThe model code is easy to understand and debugIt has unique features (ModelQueries, concrete table inheritance, aggregate column behavior, etc.) It’s robust (3000+ unit tests) and already used by many developersIt’s not alpha, it’s not beta, it’s already stable
Installation
The PropelBundle is bundled with the Symfony2 FrameworkRegister the bundle in the kernel// in hello/HelloKernel.phpclassHelloKernelextendsKernel{public functionregisterBundles()  {    $bundles = array(      ...      new Symfony\Framework\PropelBundle\Bundle(),    );return $bundles;  }}
Add Propel and Phing libraries in src/vendor/> cd src/vendor> svn co http://svn.propelorm.org/branches/1.5/ propel> svn co http://svn.phing.info/tags/2.3.3 phingAdd Propel and Phing paths to the project configuration# in hello/config/config.ymlpropel.config:path:       %kernel.root_dir%/../src/vendor/propelphing_path: %kernel.root_dir%/../src/vendor/phing
Test the installation by calling the project console> hello/consoleSymfony version 2.0.0-DEV - helloUsage:  [options] command [arguments]propel:build        Hub for Propel build commands (model, sql):build-model  Build the Propel Object Model classes                   based on XML schemas:build-sql    Build the SQL generation code for all                 tables based on Propel XML schemas
Usage
Create an XML schema using namespaces// in src/Application/HelloBundle/Resources/config/schema.xml<?xml version="1.0" encoding="UTF-8"?><database name="default" namespace="Application\HelloBundle\Model" defaultIdMethod="native">  <table name="book">    <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />    <column name="title" type="varchar" primaryString="1" size="100" />    <column name="ISBN" type="varchar" size="20" />    <column name="author_id" type="integer" />    <foreign-key foreignTable="author">      <reference local="author_id" foreign="id" />    </foreign-key>  </table>  <table name="author">    <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />    <column name="first_name" type="varchar" size="100" />    <column name="last_name" type="varchar" size="100" />  </table></database>
Create an XML schemas using namespaces// in src/Application/HelloBundle/Resources/config/schema.xml<?xml version="1.0" encoding="UTF-8"?><database name="default" namespace="Application\HelloBundle\Model" defaultIdMethod="native">  <table name="book">    <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />    <column name="title" type="varchar" primaryString="1" size="100" />    <column name="ISBN" type="varchar" size="20" />    <column name="author_id" type="integer" />    <foreign-key foreignTable="author">      <reference local="author_id" foreign="id" />    </foreign-key>  </table>  <table name="author">    <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />    <column name="first_name" type="varchar" size="100" />    <column name="last_name" type="varchar" size="100" />  </table></database>
Build the model and SQL code> cd sandbox> hello/console propel:buildsrc/Application/HelloBundle/  Model/    map/    om/    Author.php    AuthorPeer.php    AuthorQuery.php    Book.php    BookPeer.php    BookQuery.phphello/propel/sql/  HelloBundle-schema.sql
// in sandbox/src/application/HelloBundle/Model/Book.phpnamespaceApplication\HelloBundle\Model;useApplication\HelloBundle\Model\Om\BaseBook;/** * Skeleton subclass for representing a row from the  * 'book' table. * * You should add additional methods to this class to meet * the application requirements. This class will only be * generated as long as it does not already exist in the * output directory. */classBookextendsBaseBook {} // Book
Setup your connection in the project configuration# in sandbox/hello/config/config.ymlpropel.dbal:driver:   mysqluser:     rootpassword: nulldsn:      mysql:host=localhost;dbname=test  options:  {}
Use models in your actions as with Propel 1.5 aloneSymfony handles the autoloading// in sandbox/src/Application/HelloBundle/Controller/HelloController.phpnamespaceApplication\HelloBundle\Controller;useSymfony\Framework\WebBundle\Controller;useApplication\HelloBundle\Model\AuthorQuery;classHelloControllerextendsController{public functionindexAction($name)  {    $author = AuthorQuery::create()      ->findOneByName($name);return $this->render('HelloBundle:Hello:index', array('author' => $author));  }}
That’s about itAll the Propel features are ready to use… in the Propel way
The Future of Propel 1.5 and Symfony2
Ask Fabien
A lot left to doYAML format for the schema (and bundle override)Web Debug Toolbar PanelForm integration (Widgets, Validators, Model forms)Admin Generator ThemeDocumentationUnit tests
And even moreEmbedded Relation FormsAdmin generator on steroidsEasy Custom FilterCross-module linksPlain text fieldsAdvanced Object RoutingCollection routesNested routesA thousand more ideas worth implementingcf. sfPropel15Plugincf. DbFinderPlugin
Not much time to do soI’m already developing PropelI’m already developing sfPropel15PluginI also have a full-time job…and a familyAny help is welcome!
Questions?Online Resourceshttp://github.com/fzaninotto/symfonyhttp://www.propelorm.org/http://www.symfony-project.org/plugins/sfPropel15PluginNews about all thathttp://propel.posterous.com/http://twitter.com/francoisz

Symfony2 meets propel 1.5

  • 1.
    Symfony 2 meetsPropel 1.5François Zaninotto
  • 2.
    François ZaninottoHead ofthe Web Development Team at eTF1, editor the web properties of the leading TV network in France.Former symfony 1 contributorAuthor of “The Definitive Guide to Symfony” (APress)Lead Developer of Propel since October, 2009Interests: Web development, Usability, Agility, ROINot a developerTwitter: @francoisz, Github: fzaninotto
  • 3.
  • 4.
    No surpriseBackwards compatiblewith Propel 1.3 and 1.4Faster than Propel 1.4, which was faster than Propel 1.3, which was...Very IDE friendlyBetter documentedMore robust (3 times as many unit tests as Propel 1.3)Fully integrated into symfony 1.3/1.4 (sfPropel15Plugin)
  • 5.
    Surprise!Major new featuresModelQueriesCollectionsMany-to-many relationshipsMajor new behaviorsNested SetsConcrete Table InheritanceBetter Oracle Support
  • 6.
    Surprise!Major new featuresModelQueriesCollectionsMany-to-many relationshipsMajor new behaviorsNested SetsConcrete Table InheritanceBetter Oracle SupportKiller FeatureKiller Feature
  • 7.
    Model QueriesModel Queriesare to the SQL query what ActiveRecord is to the table rowShift from the relational Paradigm to the Object paradigm in QueriesInspirations: SQL Alchemy, Doctrine, DbFinder, ArelCode generation makes it fast and IDE friendlyEasy to learn and useMUCH cleaner custom model codeBye bye, Criteria!
  • 8.
    Model Queries$books =BookQuery::create()->filterByPublishedAt(array( ‘max’ => time() ))->filterByPublisher($publisher)->useAuthorQuery()->stillAlive() ->endUse()->orderByTitle()->find();
  • 9.
    Concrete TableInheritancecontentidtitlearticlebodyvideourlstructuredata
  • 10.
    Concrete Table Inheritance:An Example$article = new Article();$article->setTitle(‘France loses World Cup’);$article->setBody(‘Lorem Ipsum’);$article->save();$video = new Video();$video->setTitle(‘World Cup Goals’);$video->setUrl(‘http://www.youtube.com/xxx’);$video->save();
  • 11.
    > SELECT *FROMarticle;+----+------------------------+-------------+| id | title | body |+----+------------------------+-------------+| 1 | France loses World Cup | Lorem Ipsum |+----+------------------------+-------------+> SELECT * FROMvideo;+----+-----------------+----------------------------+| id | title | url |+----+-----------------+----------------------------+| 2 | World Cup goals | http://www.youtube.com/xxx |+----+-----------------+----------------------------+> SELECT * FROM content;+----+------------------------+| id | title |+----+------------------------+| 1 | France loses World Cup || 2 | World Cup goals |+----+------------------------+
  • 12.
    Design your modelin a true object-oriented wayLet Propel do the mapping with the relational worldDenormalize with ease for optimal performanceLet PHP manipulate inheritance, not data replication.… Let PHP manipulate objects, not records.… Let PHP manipulate collections, not arrays.… Let PHP manipulate relations, not foreign keys.
  • 13.
    Continuousimprovementsthroughminor versions1.5.1PropelObjectCollection::toKeyValue()One-to-manyjoinedhydration (noLIMIT support)CLI enhancements1.5.2Namespaces ! ModelQuery::findOneOrCreate()aggregate_columnbehaviorSQL Comments
  • 14.
    Continuous improvements throughminor versions1.5.1PropelObjectCollection::toKeyValue()One-to-many joined hydration (no LIMIT support)CLI enhancements1.5.2Namespaces ! ModelQuery::findOneOrCreate()aggregate_column behaviorSQL CommentsMust HaveKiller Feature
  • 15.
    Namespaces// in schema.xml<tablename="book"namespace="Bookstore"> ...</table>// in application codeuseBookstore\BookQuery;$book = BookQuery::create();->findOneByTitle(‘War And Peace’);echoget_class($book); // Bookstore\Book$author = $book->getAuthor();echoget_class($author); // Bookstore\People\Author
  • 16.
    Aggregate TableBehaviorauthoridnamebookidtitleauthor_id*<table name="author"> <behavior name="aggregate_column"><parameter name="name" value="nb_books" /> <parameter name="foreign_table" value="book" /> <parameter name="expression" value="COUNT(id)" /> </behavior> ...</table>
  • 17.
    Aggregate TableBehaviorauthoridnamenb_booksbookidtitleauthor_id*<table name="author"> <behavior name="aggregate_column"><parameter name="name" value="nb_books" /> <parameter name="foreign_table" value="book" /> <parameter name="expression" value="COUNT(id)" /> </behavior> ...</table>
  • 18.
    Aggregate Table Behavior$author= new Author();$author->setName(‘Leo Tolstoi');$author->save();echo $author->getNbBooks(); // 0$book = new Book();$book->setTitle(‘War and Peace’);$book->setAuthor($author);$book->save();echo $author->getNbBooks(); // 1$book->delete();echo $author->getNbBooks(); // 0
  • 19.
    No, really, Propelis definitely NOT DEAD
  • 20.
  • 21.
    Propel Integration withsymfony 1: sfPropel15Plugin Use sf configuration system (databases.yml, propel.ini) Use sf autoloading rather than Propel’s Use sf task system (and hides Phing, thank God) Adapt Propel to SF applications directory structureYAML format for the schema (and plugin override)
  • 22.
    Web Debug Toolbarpanel Form integration (Widgets, Validators, Model forms)Admin Generator Theme Routing integration (Model routes, Model route collections) Symfony BehaviorsPropel Integration with Symfony2: PropelBundle Use sf configuration system (config.yml, Dependency Injection) Use sf autoloading rather than Propel’s (thanks Namespaces) Use sf command system (and hides Phing, thank God) Adapt Propel to SF applications directory structureYAML format for the schema (and bundle override)Web Debug Toolbar Panel Form integration (Widgets, Validators, Model forms) Admin Generator ThemeRouting integration (Model routes, Model route collections) Symfony Behaviors
  • 23.
    Many of thesymfony add-ons to Propel are now part of Propel 1.5Model hooks, query hooksBehavior system (at buildtime, for better performance and power)auto_add_pkbehaviortimestampable behaviorisPrimaryString column attribute for automated __toString()No need for custom symfony code for these
  • 24.
    Why you maywant to use Propel rather than Doctrine 2No need to upgrade your Model codeIt’s fast (without any cache system - that’s code generation)It’s an ActiveRecord implementationIt has behaviorsIt’s IDE friendlyThe model code is easy to understand and debugIt has unique features (ModelQueries, concrete table inheritance, aggregate column behavior, etc.) It’s robust (3000+ unit tests) and already used by many developersIt’s not alpha, it’s not beta, it’s already stable
  • 25.
  • 26.
    The PropelBundle isbundled with the Symfony2 FrameworkRegister the bundle in the kernel// in hello/HelloKernel.phpclassHelloKernelextendsKernel{public functionregisterBundles() { $bundles = array( ... new Symfony\Framework\PropelBundle\Bundle(), );return $bundles; }}
  • 27.
    Add Propel andPhing libraries in src/vendor/> cd src/vendor> svn co http://svn.propelorm.org/branches/1.5/ propel> svn co http://svn.phing.info/tags/2.3.3 phingAdd Propel and Phing paths to the project configuration# in hello/config/config.ymlpropel.config:path: %kernel.root_dir%/../src/vendor/propelphing_path: %kernel.root_dir%/../src/vendor/phing
  • 28.
    Test the installationby calling the project console> hello/consoleSymfony version 2.0.0-DEV - helloUsage: [options] command [arguments]propel:build Hub for Propel build commands (model, sql):build-model Build the Propel Object Model classes based on XML schemas:build-sql Build the SQL generation code for all tables based on Propel XML schemas
  • 29.
  • 30.
    Create an XMLschema using namespaces// in src/Application/HelloBundle/Resources/config/schema.xml<?xml version="1.0" encoding="UTF-8"?><database name="default" namespace="Application\HelloBundle\Model" defaultIdMethod="native"> <table name="book"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" /> <column name="title" type="varchar" primaryString="1" size="100" /> <column name="ISBN" type="varchar" size="20" /> <column name="author_id" type="integer" /> <foreign-key foreignTable="author"> <reference local="author_id" foreign="id" /> </foreign-key> </table> <table name="author"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" /> <column name="first_name" type="varchar" size="100" /> <column name="last_name" type="varchar" size="100" /> </table></database>
  • 31.
    Create an XMLschemas using namespaces// in src/Application/HelloBundle/Resources/config/schema.xml<?xml version="1.0" encoding="UTF-8"?><database name="default" namespace="Application\HelloBundle\Model" defaultIdMethod="native"> <table name="book"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" /> <column name="title" type="varchar" primaryString="1" size="100" /> <column name="ISBN" type="varchar" size="20" /> <column name="author_id" type="integer" /> <foreign-key foreignTable="author"> <reference local="author_id" foreign="id" /> </foreign-key> </table> <table name="author"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" /> <column name="first_name" type="varchar" size="100" /> <column name="last_name" type="varchar" size="100" /> </table></database>
  • 32.
    Build the modeland SQL code> cd sandbox> hello/console propel:buildsrc/Application/HelloBundle/ Model/ map/ om/ Author.php AuthorPeer.php AuthorQuery.php Book.php BookPeer.php BookQuery.phphello/propel/sql/ HelloBundle-schema.sql
  • 33.
    // in sandbox/src/application/HelloBundle/Model/Book.phpnamespaceApplication\HelloBundle\Model;useApplication\HelloBundle\Model\Om\BaseBook;/*** Skeleton subclass for representing a row from the * 'book' table. * * You should add additional methods to this class to meet * the application requirements. This class will only be * generated as long as it does not already exist in the * output directory. */classBookextendsBaseBook {} // Book
  • 34.
    Setup your connectionin the project configuration# in sandbox/hello/config/config.ymlpropel.dbal:driver: mysqluser: rootpassword: nulldsn: mysql:host=localhost;dbname=test options: {}
  • 35.
    Use models inyour actions as with Propel 1.5 aloneSymfony handles the autoloading// in sandbox/src/Application/HelloBundle/Controller/HelloController.phpnamespaceApplication\HelloBundle\Controller;useSymfony\Framework\WebBundle\Controller;useApplication\HelloBundle\Model\AuthorQuery;classHelloControllerextendsController{public functionindexAction($name) { $author = AuthorQuery::create() ->findOneByName($name);return $this->render('HelloBundle:Hello:index', array('author' => $author)); }}
  • 36.
    That’s about itAllthe Propel features are ready to use… in the Propel way
  • 37.
    The Future ofPropel 1.5 and Symfony2
  • 38.
  • 39.
    A lot leftto doYAML format for the schema (and bundle override)Web Debug Toolbar PanelForm integration (Widgets, Validators, Model forms)Admin Generator ThemeDocumentationUnit tests
  • 40.
    And even moreEmbeddedRelation FormsAdmin generator on steroidsEasy Custom FilterCross-module linksPlain text fieldsAdvanced Object RoutingCollection routesNested routesA thousand more ideas worth implementingcf. sfPropel15Plugincf. DbFinderPlugin
  • 41.
    Not much timeto do soI’m already developing PropelI’m already developing sfPropel15PluginI also have a full-time job…and a familyAny help is welcome!
  • 42.