Working With Symfony2 - Introduction

    If you are interested to work with Propel2 with Symfony2, you should consider using the PropelBundle.

    Installation

    The recommended way to install this bundle is to rely on Composer:

    "require": {
        "propel/propel": "2.0.*@dev",
        "propel/propel-bundle": "~2.0@dev"
    }
    

    The second step is to register this bundle in the AppKernel class:

    <?php
    
    public function registerBundles()
    {
        $bundles = array(
            // ...
            new Propel\Bundle\PropelBundle\PropelBundle(),
        );
    
        // ...
    }
    

    You are almost ready, the next steps are:

    Now, you can build your model classes, and SQL by running the following command:

    $ php app/console propel:build [--classes] [--sql] [--insert-sql]
    

    To insert SQL statements, use the propel:sql:insert command:

    $ php app/console propel:sql:insert
    

    Congratulations! You’re done; just use the Model classes as any other class in Symfony2:

    <?php
    
    class HelloController extends Controller
    {
        public function indexAction($name)
        {
            $author = new \Acme\DemoBundle\Model\Author();
            $author->setFirstName($name);
            $author->save();
    
            return $this->render('AcmeDemoBundle:Hello:index.html.twig', array(
                'name' => $name, 'author' => $author)
            );
        }
    }
    

    Bundle Inheritance

    The PropelBundle makes use of the bundle inheritance. Currently only schema inheritance is provided.

    Schema Inheritance

    You can override the defined schema of a bundle from within its child bundle. To make use of the inheritance you only need to drop a schema file in the Resources/config folder of the child bundle.

    Each file can be overridden without interfering with other schema files. If you want to remove parts of a schema, you only need to add an empty schema file.

    Configuration

    Basic configuration

    If you have just one database connection, your configuration will look like as following:

    # app/config/config*.yml
    propel:
        database:
            connections:
                default:
                    adapter:    mysql
                    user:       sandbox
                    password:   null
                    dsn:        mysql:host=localhost;dbname=sandbox;charset=UTF8
    

    The recommended way to fill in these information is to use parameters:

    # app/config/config*.yml
    # define the parameters in app/config/parameters.yml
    propel:
        database:
            connections:
                default:
                    adapter:    %database_driver%
                    user:       %database_user%
                    password:   %database_password%
                    dsn:        %database_driver%:host=%database_host%;dbname=%database_name%;charset=UTF8
    

    Configure Multiple Connections

    If you have more than one connection the configuration will look like:

    # app/config/config*.yml
    propel:
        database:
            connections:
                default:
                    adapter:    mysql
                    user:       sandbox
                    password:   null
                    dsn:        mysql:host=localhost;dbname=sandbox;charset=UTF8
                other:
                    adapter:    mysql
                    user:       other
                    password:   null
                    dsn:        mysql:host=localhost;dbname=other;charset=UTF8
        runtime:
            defaultConnection: default
            connections:       [ default, other ]
        generator:
            defaultConnection: default
            connections:       [ default, other ]
    

    Attributes, Options, Settings

    # app/config/config*.yml
    # define the parameters in app/config/parameters.yml
    propel:
        database:
            connections:
                default:
                    # ...
                    options:
                        ATTR_PERSISTENT: false
                    attributes:
                        ATTR_EMULATE_PREPARES: true
                    settings:
                        charset:        { value: UTF8 }
                        queries:        { query: 'INSERT INTO BAR ('hey', 'there')' }
    

    See the configuration reference for further details.

    XML Schema

    Place the following schema in src/Acme/DemoBundle/Resources/config/schema.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <database name="default" namespace="Acme\DemoBundle\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>
    

    If you are working with an existing database, please check the related section.

    The Commands

    The PropelBundle provides a lot of commands to manage migrations, database/table manipulations, and so on.

    Database Manipulations

    You can create a database:

    $ php app/console propel:database:create [--connection[=""]]
    

    As usual, --connection allows you to specify a connection.

    You can drop a database:

    $ php app/console propel:database:drop [--connection[=""]] [--force]
    

    Note that the --force option is needed to actually execute the SQL statements.

    Form Types

    You can generate stub classes based on your schema.xml in a given bundle:

    $ php app/console propel:form:generate [-f|--force] bundle [models1] ... [modelsN]
    

    It will write Form Type classes in src/YourVendor/YourBundle/Form/Type.

    You can choose which Form Type to build by specifying Model names:

    $ php app/console propel:form:generate @AcmeDemoBundle Book Author
    

    Graphviz

    You can generate Graphviz file for your project by using the following command line:

    $ php app/console propel:graphviz:generate
    

    It will write files in ./generated-graphviz.

    Migrations

    Generates SQL diff between the XML schemas and the current database structure:

    $ php app/console propel:migration:generate-diff
    

    Executes the migrations:

    $ php app/console propel:migration:migrate
    

    Executes the next migration up:

    $ php app/console propel:migration:migrate --up
    

    Executes the previous migration down:

    $ php app/console propel:migration:migrate --down
    

    Lists the pending migrations:

    $ php app/console propel:migration:status
    

    Table Manipulations

    You can drop one or several tables:

    $ php app/console propel:table:drop [--force] [--connection[="..."]] [table1] ... [tableN]
    

    The table arguments define which tables will be deleted, by default all tables are deleted.

    Note that the --force option is needed to actually execute the deletion.

    Working with existing databases

    Run the following command to generate an XML schema from your default database:

    $ php app/console propel:reverse
    

    You can define which connection to use:

    $ php app/console propel:reverse --connection=default
    

    This will create your schema file under ./generated-schemas. You need to move/copy it to the corresponding bundle config directory. For example: src/Acme/DemoBundle/Resources/config/.

    The Fixtures

    Fixtures are data you usually write to populate your database during the development, or static content like menus, labels, etc. you need by default in your production database.

    Loading Fixtures

    The following command is designed to load fixtures:

    $ php app/console propel:fixtures:load [-d|--dir[="..."]] [--xml] [--sql] [--yml] [--connection[="..."]] [bundle]
    

    As you can see, there are many options to allow you to easily load fixtures.

    As usual, --connection allows to specify a connection. The --dir option allows to specify a directory containing the fixtures (default is: app/propel/fixtures/). Note that the --dir expects a relative path from the root dir (which is app/).

    The --xml parameter allows you to load only XML fixtures. The --sql parameter allows you to load only SQL fixtures. The --yml parameter allows you to load only YAML fixtures.

    You can mix --xml, --yml and --sql parameters to load XML, YAML and SQL fixtures at the same time. If none of these parameters are set, all YAML, XML and SQL files in the directory will be loaded.

    You can pass a bundle name to load fixtures from it. A bundle’s name starts with @ like @AcmeDemoBundle.

    $ php app/console propel:fixtures:load @AcmeDemoBundle
    

    XML Fixtures

    A valid XML fixtures file is:

    <Fixtures>
        <Object Namespace="Awesome">
            <o1 Title="My title" MyFoo="bar" />
        </Object>
        <Related Namespace="Awesome">
            <r1 ObjectId="o1" Description="Hello world !" />
        </Related>
    </Fixtures>
    

    YAML Fixtures

    A valid YAML fixtures file is:

    Awesome\Object:
         o1:
             Title: My title
             MyFoo: bar
    
    Awesome\Related:
         r1:
             ObjectId: o1
             Description: Hello world !
    
    Awesome\Tag:
        t1:
            name: Foo
        t2:
            name: Baz
    
    Awesome\Post:
        p1:
            title: A Post with tags (N-N relation)
            tags: [ t1, t2 ]
    

    Using Faker in YAML Fixtures

    If you use Faker with its Symfony2 integration, then the PropelBundle offers a facility to use the Faker generator in your YAML files:

    Acme\DemoBundle\Model\Book:
        Book1:
            name:        "Awesome Feature"
            description: <?php $faker('text', 500); ?>
    

    The aim of this feature is to be able to mix both real and fake data in the same file. Fake data is interesting to quickly add data to your application, but most of the time you need to rely on real data. Integrating Faker within your YAML files allows you to write strong fixtures efficiently.

    Dumping data

    You can dump data from your database into YAML fixtures file by using this command:

    $ php app/console propel:fixtures:dump [--connection[="..."]]
    

    Dumped files will be written in the fixtures directory: app/propel/fixtures/ with the following name: fixtures_99999.yml where 99999 is a timestamp.

    Once done, you will be able to load these files by using the propel:fixtures:load command.

    The PropelParamConverter

    You can use the PropelParamConverter with the SensioFrameworkExtraBundle. You just need to put the right Annotation on top of your controller:

    <?php
    
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
    use BlogBundle\Model\Post;
    
    /**
     * @ParamConverter("post", class="BlogBundle\Model\Post")
     */
    public function myAction(Post $post)
    {
    }
    

    Your request needs to have an id parameter or any field as parameter (e.g. slug, title).

    The Annotation is optional if your parameter is typed you could only have this:

    <?php
    
    use BlogBundle\Model\Post;
    
    public function myAction(Post $post)
    {
    }
    

    New with last version of SensioFrameworkExtraBundle, you can omit the class parameter if your controller parameter is typed, this is useful when you need to set extra options.

    <?php
    
    use BlogBundle\Model\Post;
    
    /**
     * @ParamConverter("post")
     */
    public function myAction(Post $post)
    {
    }
    

    Exclude some parameters

    You can exclude some attributes from being used by the converter:

    If you have a route like /my-route/{slug}/{name}/edit/{id} you can exclude name and slug by setting the option “exclude”:

    <?php
    
    /**
     * @ParamConverter("post", class="BlogBundle\Model\Post", options={"exclude"={"name", "slug"}})
     */
    public function myAction(Post $post)
    {
    }
    

    Custom mapping

    You can map route parameters directly to model columns to be used for filtering.

    If you have a route like /my-route/{postUniqueName}/{AuthorId} the mapping option overwrite any other automatic mapping.

    <?php
    
    /**
     * @ParamConverter("post", class="BlogBundle\Model\Post", options={"mapping"={"postUniqueName":"name"}})
     * @ParamConverter("author", class="BlogBundle\Model\Author", options={"mapping"={"AuthorId":"id"}})
     */
    public function myAction(Post $post, $author)
    {
    }
    

    You could hydrate related object with the “with” option:

    <?php
    
    /**
     * @ParamConverter("post", class="BlogBundle\Model\Post", options={"with"={"Comments"}})
     */
    public function myAction(Post $post)
    {
    }
    

    You can set multiple with "with"={"Comments", "Author", "RelatedPosts"}.

    The default join is an “inner join” but you can configure it to be a left join or right join instead:

    <?php
    
    /**
     * @ParamConverter("post", class="BlogBundle\Model\Post", options={"with"={ {"Comments", "left join" } }})
     */
    public function myAction(Post $post)
    {
    }
    

    Accepted parameters for join:

    • left, LEFT, left join, LEFT JOIN, left_join, LEFT_JOIN
    • right, RIGHT, right join, RIGHT JOIN, right_join, RIGHT_JOIN
    • inner, INNER, inner join, INNER JOIN, inner_join, INNER_JOIN

    What’s Next?

    Now you are ready to use Propel with Symfony2. If you are interested, you can also checkout these cookbooks: