Symfony2 meets propel 1.5

Post on 16-Apr-2017

16.453 views 1 download

Transcript of Symfony2 meets propel 1.5

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 features

Model QueriesCollectionsMany-to-many relationships

Major new behaviorsNested SetsConcrete Table Inheritance

Better Oracle Support

Surprise!Major new features

Model QueriesCollectionsMany-to-many relationships

Major new behaviorsNested SetsConcrete Table Inheritance

Better Oracle Support

Killer Feature

Killer 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 Inheritancecontentidtitle

articlebody

videourl

structure data

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 * FROM article;+----+------------------------+-------------+| id | title | body |+----+------------------------+-------------+| 1 | France loses World Cup | Lorem Ipsum |+----+------------------------+-------------+

> SELECT * FROM video;+----+-----------------+----------------------------+| 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 way

Let Propel do the mapping with the relational world

Denormalize with ease for optimal performance

Let 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.

Continuous improvements through minor versions

1.5.1PropelObjectCollection::toKeyValue()One-to-many joined hydration (no LIMIT

support)CLI enhancements

1.5.2Namespaces ! ModelQuery::findOneOrCreate()aggregate_column behaviorSQL Comments

Continuous improvements through minor versions

1.5.1PropelObjectCollection::toKeyValue()One-to-many joined hydration (no LIMIT

support)CLI enhancements

1.5.2Namespaces ! ModelQuery::findOneOrCreate()aggregate_column behaviorSQL Comments

Killer Feature

Must Have

Namespaces// in schema.xml<table name="book" namespace="Bookstore"> ...</table>

// in application codeuse Bookstore\BookQuery;

$book = BookQuery::create(); ->findOneByTitle(‘War And Peace’);echo get_class($book); // Bookstore\Book

$author = $book->getAuthor();echo get_class($author); // Bookstore\People\Author

Aggregate Table Behaviorauthoridname

bookidtitleauthor_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_books

bookidtitleauthor_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 Behaviors

Propel 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 Theme Routing 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_pk behaviortimestampable behaviorisPrimaryString column attribute for automated __toString()

No need for custom symfony code for these

Why you may want to use Propel rather than Doctrine 2

No 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 developers

It’s not alpha, it’s not beta, it’s already stable

Installation

The PropelBundle is bundled with the Symfony2 Framework

Register the bundle in the kernel// in hello/HelloKernel.phpclass HelloKernel extends Kernel{ public function registerBundles() { $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 phing

Add Propel and Phing paths to the project configuration

# in hello/config/config.ymlpropel.config: path: %kernel.root_dir%/../src/vendor/propel phing_path: %kernel.root_dir%/../src/vendor/phing

Test the installation by calling the project console> hello/consoleSymfony version 2.0.0-DEV - hello

Usage: [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:build

src/Application/HelloBundle/ Model/ map/ om/ Author.php AuthorPeer.php AuthorQuery.php Book.php BookPeer.php BookQuery.php

hello/propel/sql/ HelloBundle-schema.sql

// in sandbox/src/application/HelloBundle/Model/Book.php

namespace Application\HelloBundle\Model;use Application\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. */class Book extends BaseBook {

} // Book

Setup your connection in the project configuration

# in sandbox/hello/config/config.ymlpropel.dbal: driver: mysql user: root password: null dsn: mysql:host=localhost;dbname=test options: {}

Use models in your actions as with Propel 1.5 alone

Symfony handles the autoloading// in sandbox/src/Application/HelloBundle/Controller/HelloController.phpnamespace Application\HelloBundle\Controller;

use Symfony\Framework\WebBundle\Controller;use Application\HelloBundle\Model\AuthorQuery;

class HelloController extends Controller{ public function indexAction($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 steroids

Easy Custom FilterCross-module linksPlain text fields

Advanced Object RoutingCollection routesNested routes

A thousand more ideas worth implementing

cf. sfPropel15Plugin

cf. DbFinderPlugin

Not much time to do so

I’m already developing PropelI’m already developing sfPropel15PluginI also have a full-time job…and a family

Any help is welcome!

Questions?

Online Resourceshttp://github.com/fzaninotto/symfonyhttp://www.propelorm.org/http://www.symfony-project.org/plugins/

sfPropel15PluginNews about all that

http://propel.posterous.com/http://twitter.com/francoisz