Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Port sf2 & propel in real life in rst format

  • Loading branch information...
commit 38f8fc0e7be799dee14b3207a9e1485a54b88114 1 parent eab527e
@rouffj rouffj authored weaverryan committed
Showing with 435 additions and 0 deletions.
  1. +1 −0  book/index.rst
  2. +1 −0  book/map.rst.inc
  3. +433 −0 book/propel.rst
View
1  book/index.rst
@@ -12,6 +12,7 @@ The Book
routing
templating
doctrine
+ propel
testing
validation
forms
View
1  book/map.rst.inc
@@ -6,6 +6,7 @@
* :doc:`/book/routing`
* :doc:`/book/templating`
* :doc:`/book/doctrine`
+* :doc:`/book/propel`
* :doc:`/book/testing`
* :doc:`/book/validation`
* :doc:`/book/forms`
View
433 book/propel.rst
@@ -0,0 +1,433 @@
+.. index::
+ single: Propel
+
+Databases and Propel ("The model")
+==================================
+
+Let's face it, one of the most common and challenging tasks for any application involves persisting and reading
+information to and from a database. Unfortunately, Symfony2 does not come integrated with Propel but it's really
+easy to integrate Propel into Symfony2. To get started, read [how to set up Propel into Symfony2](working-with-symfony2.html#installation).
+
+A Simple Example: A Product
+---------------------------
+
+In this section, you'll configure your database, create a ``Product`` object, persist it to the database and fetch it back out.
+
+.. sidebar:: Code along with the example
+
+ If you want to follow along with the example in this chapter, create an ``AcmeStoreBundle`` via: ``php app/console generate:bundle --namespace=Acme/StoreBundle``.
+
+Configuring the Database
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before you really begin, you'll need to configure your database connection information.
+By convention, this information is usually configured in an ``app/config/parameters.ini`` file:
+
+.. code-block:: ini
+
+ ;app/config/parameters.ini
+ [parameters]
+ database_driver = mysql
+ database_host = localhost
+ database_name = test_project
+ database_user = root
+ database_password = password
+ database_charset = UTF8
+
+.. note::
+
+ Defining the configuration via ``parameters.ini`` is just a convention. The parameters defined in that file are referenced by the main configuration file when setting up Propel:
+
+ .. code-block:: yaml
+ propel:
+ dbal:
+ driver: %database_driver%
+ user: %database_user%
+ password: %database_password%
+ dsn: %database_driver%:host=%database_host%;dbname=%database_name%;charset=%database_charset%
+
+Now that Propel knows about your database, you can have it create the database for you:
+
+.. code-block:: bash
+
+ php app/console propel:database:create
+
+.. note::
+
+ In this example, you have one configured connection, named ``default``. If you want to configure more than one connection, read the `PropelBundle configuration section <working-with-symfony2.html#project_configuration>`_.
+
+Creating a Model Class
+~~~~~~~~~~~~~~~~~~~~~~
+
+In Symfony2 world, **Model classes** also known as ActiveRecord classes in Propel are called **entities**.
+With Propel, it's better to call them **Model classes** as generated Propel classes contain some business logic.
+
+Suppose you're building an application where products need to be displayed. Let's writing a ``schema.xml`` inside
+the ``Resources/config/`` directory of your ``AcmeStoreBundle``:
+
+.. code-block:: xml
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <database name="default" namespace="Acme\StoreBundle\Model" defaultIdMethod="native">
+ <table name="product">
+ <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
+ <column name="name" type="varchar" primaryString="1" size="100" />
+ <column name="price" type="decimal" />
+ <column name="description" type="longvarchar" />
+ </table>
+ </database>
+
+Building the Model
+~~~~~~~~~~~~~~~~~~
+
+Once you wrote your ``schema.xml``, you just have to generate it:
+
+.. code-block:: bash
+
+ php app/console propel:model:build
+
+It will generate all classes to quickly develop your application in the ``Model/`` directory of your ``AcmeStoreBundle`` bundle.
+
+Creating the Database Tables/Schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You now have a usable ``Product`` class and all you need to persist it. Of course, you don't yet have the corresponding
+``product`` table in your database.
+Fortunately, Propel can automatically create all the database tables needed for every known entity in your application.
+To do this, run:
+
+.. code-block:: bash
+
+ php app/console propel:sql:build
+
+ php app/console propel:sql:insert --force
+
+
+Your database now has a fully-functional ``product`` table with columns that match the schema you've specified.
+
+.. tip::
+
+ You can run the last three commands in once by using the following command: ``php app/console propel:build --insert-sql``.
+
+Persisting Objects to the Database
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now that you have a ``Product`` object and corresponding ``product`` table, you're ready to persist data to the database.
+From inside a controller, this is pretty easy. Add the following method to the ``DefaultController`` of the bundle:
+
+.. code-block:: php
+
+ <?php
+ // src/Acme/StoreBundle/Controller/DefaultController.php
+ use Acme\StoreBundle\Model\Product;
+ use Symfony\Component\HttpFoundation\Response;
+ // ...
+
+ public function createAction()
+ {
+ $product = new Product();
+ $product->setName('A Foo Bar');
+ $product->setPrice(19.99);
+ $product->setDescription('Lorem ipsum dolor');
+
+ $product->save();
+
+ return new Response('Created product id '.$product->getId());
+ }
+
+In this piece of code, you instantiate and work with the ``$product`` object. When you call the ``save()`` method on it, you persist
+it in the database. No need to use other services, the object knows how to persist it itself.
+
+.. note::
+
+ If you're following along with this example, you'll need to create a route that points to this action to see it in work.
+
+Fetching Objects from the Database
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Fetching an object back out of the database is even easier. For example, suppose you've configured a route to display
+a specific ``Product`` based on its ``id`` value:
+
+.. code-block:: php
+ <?php
+
+ use Acme\StoreBundle\Model\ProductQuery;
+
+ public function showAction($id)
+ {
+ $product = ProductQuery::create()
+ ->findPk($id);
+
+ if (!$product) {
+ throw $this->createNotFoundException('No product found for id '.$id);
+ }
+
+ // do something, like pass the $product object into a template
+ }
+
+Updating an Object
+~~~~~~~~~~~~~~~~~~
+
+Once you've fetched an object from Propel, updating it is easy. Suppose you have a route that maps a product id
+to an update action in a controller:
+
+.. code-block:: php
+ <?php
+
+ use Acme\StoreBundle\Model\ProductQuery;
+
+ public function updateAction($id)
+ {
+ $product = ProductQuery::create()
+ ->findPk($id);
+
+ if (!$product) {
+ throw $this->createNotFoundException('No product found for id '.$id);
+ }
+
+ $product->setName('New product name!');
+ $product->save();
+
+ return $this->redirect($this->generateUrl('homepage'));
+ }
+
+Updating an object involves just three steps:
+
+1. fetching the object from Propel;
+2. modifying the object;
+3. saving it.
+
+Deleting an Object
+~~~~~~~~~~~~~~~~~~
+
+Deleting an object is very similar, but requires a call to the `delete()` method on the object:
+
+.. code-block:: php
+
+ <?php
+
+ $product->delete();
+ {% endhighlight %}
+
+
+ ## Querying for Objects ##
+
+ Propel provides `Query` classes to run both basic and complex queries without any work:
+
+ {% highlight php %}
+ <?php
+
+ \Acme\StoreBundle\Model\ProductQuery::create()->findPk($id);
+
+ \Acme\StoreBundle\Model\ProductQuery::create()
+ ->filterByName('Foo')
+ ->findOne();
+
+Imaging that you want to query for products, but only return products that cost more than 19.99,
+ordered from cheapest to most expensive. From inside a controller, do the following:
+
+.. code-block:: php
+ <?php
+
+ $products = \Acme\StoreBundle\Model\ProductQuery::create()
+ ->filterByPrice(19.99, \Criteria::GREATER_THAN)
+ ->orderByPrice()
+ ->find();
+
+In one line, you get your products in a powerful oriented object way.
+No need to waste your time with SQL or whatever, Symfony2 is fully object oriented programming and Propel
+respects the same philosophy by providing an awesome abstraction layer.
+
+If you want to reuse some queries, you can add your own methods to the ``ProductQuery``:
+
+.. code-block:: php
+
+ <?php
+ // src/Acme/StoreBundle/Model/ProductQuery.php
+
+ class ProductQuery extends BaseProductQuery
+ {
+ public function filterByExpensivePrice()
+ {
+ return $this
+ ->filterByPrice(1000, \Criteria::GREATER_THAN);
+ }
+ }
+
+But note that Propel generates a lot of methods for you and a simple ``findAllOrderedByName()`` can be written without
+any effort:
+
+.. code-block:: php
+ <?php
+
+ \Acme\StoreBundle\Model\ProductQuery::create()
+ ->orderByName()
+ ->find();
+
+Relationships/Associations
+--------------------------
+
+Suppose that the products in your application all belong to exactly one "category". In this case,
+you'll need a ``Category`` object and a way to relate a ``Product`` object to a ``Category`` object.
+
+Start by adding the ``category`` definition in your ``schema.xml``:
+
+.. code-block:: xml
+
+ <database name="default" namespace="Acme\StoreBundle\Model" defaultIdMethod="native">
+ <table name="product">
+ <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
+ <column name="name" type="varchar" primaryString="1" size="100" />
+ <column name="price" type="decimal" />
+ <column name="description" type="longvarchar" />
+
+ <column name="category_id" type="integer" />
+ <foreign-key foreignTable="category">
+ <reference local="category_id" foreign="id" />
+ </foreign-key>
+ </table>
+
+ <table name="category">
+ <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
+ <column name="name" type="varchar" primaryString="1" size="100" />
+ </table>
+ </database>
+
+Create the classes:
+
+.. code-block:: bash
+
+ php app/console propel:model:build
+
+Assuming you have products in your database, you won't to loose them. Thanks to migrations, Propel will
+be able to update your database without loosing existing data.
+
+.. code-block:: php
+
+ php app/console propel:migration:generate-diff
+
+ php app/console propel:migration:migrate
+
+Your database has been updated, you can continue to write your application.
+
+Saving Related Objects
+~~~~~~~~~~~~~~~~~~~~~~
+
+Now, let's see the code in action. Imagine you're inside a controller:
+
+.. code-block:: php
+ <?php
+ // ...
+ use Acme\StoreBundle\Model\Category;
+ use Acme\StoreBundle\Model\Product;
+ use Symfony\Component\HttpFoundation\Response;
+ // ...
+
+ class DefaultController extends Controller
+ {
+ public function createProductAction()
+ {
+ $category = new Category();
+ $category->setName('Main Products');
+
+ $product = new Product();
+ $product->setName('Foo');
+ $product->setPrice(19.99);
+ // relate this product to the category
+ $product->setCategory($category);
+
+ // save the whole
+ $product->save();
+
+ return new Response(
+ 'Created product id: '.$product->getId().' and category id: '.$category->getId()
+ );
+ }
+ }
+
+Now, a single row is added to both the ``category`` and product tables. The ``product.category_id`` column for the
+new product is set to whatever the id is of the new category. Propel manages the persistence of this relationship for you..
+
+Fetching Related Objects
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+When you need to fetch associated objects, your workflow looks just like it did before.
+First, fetch a ``$product`` object and then access its related ``Category``:
+
+.. code-block:: php
+
+ <?php
+ // ...
+ use Acme\StoreBundle\Model\ProductQuery;
+
+ public function showAction($id)
+ {
+ $product = ProductQuery::create()
+ ->joinWithCategory()
+ ->findPk($id);
+
+ $categoryName = $product->getCategory()->getName();
+
+ // ...
+ }
+
+Note, in the above example, only one query was made.
+
+More information on Associations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You will find more information on relations by reading the dedicated chapter on `relationships <http://www.propelorm.org/documentation/04-relationships.html>`_.
+
+
+Lifecycle Callbacks
+-------------------
+
+Sometimes, you need to perform an action right before or after an object is inserted, updated, or deleted.
+These types of actions are known as "lifecycle" callbacks or "hooks", as they're callback methods that you need
+to execute during different stages of the lifecycle of an object (e.g. the object is inserted, updated, deleted, etc).
+
+To add a hook, just add a new method to the object class:
+
+.. code-block:: php
+ <?php
+ // src/Acme/StoreBundle/Model/Product.php
+
+ // ...
+
+ class Product extends BaseProduct
+ {
+ public function preInsert(\PropelPDO $con = null)
+ {
+ // do something before the object is inserted
+ }
+ }
+
+Propel provides the following hooks:
+
+* ``preInsert()`` code executed before insertion of a new object
+* ``postInsert()`` code executed after insertion of a new object
+* ``preUpdate()`` code executed before update of an existing object
+* ``postUpdate()`` code executed after update of an existing object
+* ``preSave()`` code executed before saving an object (new or existing)
+* ``postSave()`` code executed after saving an object (new or existing)
+* ``preDelete()`` code executed before deleting an object
+* ``postDelete()`` code executed after deleting an object
+
+
+Behaviors
+---------
+
+All bundled behaviors in Propel are working with Symfony2. To get more information about how to use Propel behaviors,
+look at the `behaviors reference section <http://www.propelorm.org/documentation/#behaviors_reference>`_.
+
+Commands
+--------
+
+You should read the dedicated section for `Propel commands in Symfony2 <http://www.propelorm.org/cookbook/symfony2/working-with-symfony2#commands>`_.
+
+
+Summary
+-------
+
+This documentation is quite similar with the `official Symfony2 Model chapter <http://symfony.com/doc/current/book/doctrine.html>`_.
+It shows you that Propel is well integrated into Symfony2 and it really works. All you can do with Propel is possible in Symfony2.
Please sign in to comment.
Something went wrong with that request. Please try again.