SlideShare uma empresa Scribd logo
1 de 97
Baixar para ler offline
Zend Framework 1 +
    Doctrine 2
Jonathan H. Wage
    •PHP Developer for over 10 years
    •Symfony Contributor
    •Doctrine Contributor
    •Published Author
    •Business Owner
    •Nashville, TN Resident

          •http://www.twitter.com/jwage
          •http://www.facebook.com/jwage




2   Zend Framework 1 + Doctrine 2
I work at OpenSky




      •What is OpenSky?
         “a social commerce platform”


      •Based in New York and is a major open
      •source software advocate


      •http://www.shopopensky.com



3   Zend Framework 1 + Doctrine 2
OpenSky Technologies
    •PHP 5.3.2
    •Apache2
    •Symfony2
    •Doctrine2
    •jQuery
    •mule, stomp, hornetq
    •MongoDB
    •nginx
    •varnish


4   Zend Framework 1 + Doctrine 2
Ralph Schindler
    •Software Engineer on the Zend Framework team
     At Zend for almost 3 years
     Before that TippingPoint/3Com
    •Programming PHP for 12+ years
    •Live in New Orleans, LA.
     Lived in Austin, Tx for 5 years
    •Where To Find Me:
     http://ralphschindler.com
     http://twitter.com/ralphschindler
     http://github.com/ralphschindler
     ralphschindler on freenode




5    Zend Framework 1 + Doctrine 2
Guilherme Blanco
    •Programming Experience
      12+ years web development experience
      9 years with PHP
    •Software Engineer at Yahoo!
    •Open Source Evangelist
      Contributes regularly to the Doctrine Project,
        Symfony, and Zend Framework
    •Where to find me:
      http://twitter.com/guilhermeblanco
      http://github.com/guilhermeblanco




6   Zend Framework 1 + Doctrine 2
Doctrine 2




7   The Doctrine Project
What is Doctrine?
    • Open Source PHP Project started in 2006
    • Specializes in database functionality

       Database Abstraction Layer (DBAL)
       Database Migrations
       Object Relational Mapper (DBAL)
       MongoDB Object Document Manager (ODM)
       CouchDB Object Document Manager (ODM)




8   Zend Framework 1 + Doctrine 2
Who is on the team?

                                    • Roman S. Borschel

                                    • Guilherme Blanco

                                    • Benjamin Eberlei

                                    • Bulat Shakirzyanov

                                    • Jonathan H. Wage



9   Zend Framework 1 + Doctrine 2
Project History
     • First commit April 13th 2006
     • First stable version finished and Released September 1st
      2008
     • One of the first ORM implementations for PHP
     • 1.0 is First LTS(long term support) release. Maintained
      until March 1st 2010
     • Integrated with many popular frameworks: Symfony, Zend
      Framework, Code Igniter




10   Zend Framework 1 + Doctrine 2
Doctrine Libraries
     • Database Abstraction Layer
     • Database Migrations
     • Object Relational Mapper
     • MongoDB Object Document Manager
     • CouchDB Object Document Manager




11   Zend Framework 1 + Doctrine 2
DBAL
                 Database Abstraction Layer




12   Zend Framework 1 + Doctrine 2
Database Abstraction Layer
     • The Doctrine Database Abstraction
     • Layer (DBAL) is a thin layer on top of
     • PDO, it offers:
        select, update, delete, transactions
        database schema introspection
        schema management




13   Zend Framework 1 + Doctrine 2
Can be used standalone




14   Zend Framework 1 + Doctrine 2
Evolved fork of PEAR MDB, MDB2, Zend_Db,
       etc.




15   Zend Framework 1 + Doctrine 2
Download
     •You can download a standalone
     •package to get started using the DBAL:




                     http://www.doctrine-project.org/projects/dbal/download

16   Zend Framework 1 + Doctrine 2
Autoloader
     •To use any Doctrine library you must
     •register an autoloader:




           use DoctrineCommonClassLoader;

           require '/path/to/doctrine-common/lib/Doctrine/Common/ClassLoader.php';

           $classLoader = new ClassLoader('DoctrineDBAL', '/path/to/doctrine-dbal/lib');
           $classLoader->register();




17   Zend Framework 1 + Doctrine 2
Create a Connection


                         $config = new DoctrineDBALConfiguration();
                         //..
                         $connectionParams = array(
                              'dbname' => 'mydb',
                              'user' => 'user',
                              'password' => 'secret',
                              'host' => 'localhost',
                              'driver' => 'pdo_mysql',
                         );
                         $conn = DriverManager::getConnection($connectionParams);




18   Zend Framework 1 + Doctrine 2
Data API
     • prepare($sql) - Prepare a given sql statement and return the DoctrineDBALDriverStatement
       instance.
     • executeUpdate($sql, array $params) - Executes a prepared statement with the given sql and
       parameters and returns the affected rows count.
     • execute($sql, array $params) - Creates a prepared statement for the given sql and passes the
       parameters to the execute method, then returning the statement.
     • fetchAll($sql, array $params) - Execute the query and fetch all results into an array.
     • fetchArray($sql, array $params) - Numeric index retrieval of first result row of the given query.
     • fetchBoth($sql, array $params) - Both numeric and assoc column name retrieval of the first result
       row.
     • fetchColumn($sql, array $params, $colnum) - Retrieve only the given column of the first result row.
     • fetchRow($sql, array $params) - Retrieve assoc row of the first result row.
     • select($sql, $limit, $offset) - Modify the given query with a limit clause.
     • delete($tableName, array $identifier) - Delete all rows of a table matching the given identifier,
       where keys are column names.
     • insert($tableName, array $data) - Insert a row into the given table name using the key value pairs of
       data.




19    Zend Framework 1 + Doctrine 2
Very Similar to PDO




                   $users = $conn->fetchAll('SELECT * FROM users');




20   Zend Framework 1 + Doctrine 2
Schema Manager
     •Learn about and modify your database
     •through the SchemaManager:




                                 $sm = $conn->getSchemaManager();




21   Zend Framework 1 + Doctrine 2
Introspection API
     •listDatabases()
     •listFunctions()
     •listSequences()
     •listTableColumns($tableName)
     •listTableConstraints($tableName)
     •listTableDetails($tableName)
     •listTableForeignKeys($tableName)
     •listTableIndexes($tableName)
     •listTables()


22   Zend Framework 1 + Doctrine 2
Introspection API



                  $tables = $sm->listTables();
                  foreach ($tables as $table) {
                    $columns = $sm->listTableColumns($table);
                    // ...
                  }




23   Zend Framework 1 + Doctrine 2
DDL Statements
     •Progromatically issue DDL statements:


                 $columns = array(
                     'id' => array(
                         'type' => DoctrineDBALType::getType('integer'),
                         'autoincrement' => true,
                         'primary' => true,
                         'notnull' => true
                     ),
                     'test' => array(
                         'type' => DoctrineDBALType::getType('string'),
                         'length' => 255
                     )
                 );

                 $options = array();

                 $sm->createTable('new_table', $columns, $options);

24   Zend Framework 1 + Doctrine 2
DDL Statements
       •Progromatically issue DDL statements:




                              $definition = array(
                                  'name' => 'user_id_fk',
                                  'local' => 'user_id',
                                  'foreign' => 'id',
                                  'foreignTable' => 'user'
                              );
                              $sm->createForeignKey('profile', $definition);




25   Zend Framework 1 + Doctrine 2
Try a Method
     •You can try a method and return true if
     •the operation was successful:




                  if ($sm->tryMethod('createTable', 'new_table', $columns, $options)) {
                    // do something
                  }




26   Zend Framework 1 + Doctrine 2
Drop and Create Database



                 try {
                   $sm->dropDatabase('test_db');
                 } catch (Exception $e) {}

                 $sm->createDatabase('test_db');




27   Zend Framework 1 + Doctrine 2
Drop and Create Database
     •A little better! Every drop and create
     •functionality in the API has a method
     •that follows the dropAndCreate pattern:




                  $sm->dropAndCreateDatabase('test_db');




28   Zend Framework 1 + Doctrine 2
Schema Representation
                  $platform = $em->getConnection()->getDatabasePlatform();

                  $schema = new DoctrineDBALSchemaSchema();
                  $myTable = $schema->createTable("my_table");
                  $myTable->addColumn("id", "integer", array("unsigned" => true));
                  $myTable->addColumn("username", "string", array("length" => 32));
                  $myTable->setPrimaryKey(array("id"));

                  // get queries to create this schema.
                  $queries = $schema->toSql($platform);




                  Array
                  (
                     [0] => CREATE TABLE my_table (id INTEGER NOT NULL, username VARCHAR(32) NOT
                  NULL, PRIMARY KEY("id"))
                  )




29   Zend Framework 1 + Doctrine 2
Schema Representation


                  // ......
                       Array
                       (
                  // get queries to safely delete this schema.
                  $dropSchema => $schema->toDropSql($platform);
                          [0] = DROP TABLE my_table
                       )




                                     Array
                                     (
                                        [0] => DROP TABLE my_table
                                     )



                              Returns the reverse SQL of what toSql() returns

30   Zend Framework 1 + Doctrine 2
Comparing Schemas
                           $fromSchema = new DoctrineDBALSchemaSchema();
                           $myTable = $fromSchema->createTable("my_table");
                           $myTable->addColumn("id", "integer", array("unsigned" => true));
                           $myTable->addColumn("username", "string", array("length" => 32));
                           $myTable->setPrimaryKey(array("id"));

                           $toSchema = new DoctrineDBALSchemaSchema();
                           $myTable = $toSchema->createTable("my_table");
                           $myTable->addColumn("id", "integer", array("unsigned" => true));
                           $myTable->addColumn("username", "string", array("length" => 32));
                           $myTable->addColumn("email", "string", array("length" => 255));
                           $myTable->setPrimaryKey(array("id"));

                           $comparator = new DoctrineDBALSchemaComparator();
                           $schemaDiff = $comparator->compare($fromSchema, $toSchema);

                           // queries to get from one to another schema.
                           $queries = $schemaDiff->toSql($platform);

                           print_r($queries);




                           ALTER TABLE my_table ADD email VARCHAR(255) NOT NULL



31   Zend Framework 1 + Doctrine 2
ORM
       Object Relational Mapper




32   Zend Framework 1 + Doctrine 2
What is ORM?


     •“Technique for converting data between incompatible type
      systems in object-oriented programming languages.”




           http://en.wikipedia.org/wiki/Object-relational_mapping




33   Zend Framework 1 + Doctrine 2
The ORM is built on top of Common and
       DBAL




34   Zend Framework 1 + Doctrine 2
ORM Goals
     •   Maintain transparency
     •   Keep domain and persistence layer separated
     •   Performance
     •   Consistent and decoupled API
     •   Well defined semantics




35   Zend Framework 1 + Doctrine 2
Download




          http://www.doctrine-project.org/projects/orm/download


36   Zend Framework 1 + Doctrine 2
Architecture
     •Entities
     •   Lightweight persistent domain object
     • Regular PHP class
     • Does not extend any base Doctrine class
     • Cannot be final or contain final methods
     • Any two entities in a hierarchy of classes must not have a
      mapped property with the same name
     • Supports inheritance, polymorphic associations and
      polymorphic queries.
     • Both abstract and concrete classes can be entities
     • Entities may extend non-entity classes as well as entity
      classes, and non-entity classes may extend entity classes

37   Zend Framework 1 + Doctrine 2
Architecture
     • No more base class required
     • Values stored in object properties
     • Persistence is done transparently



                                     namespace Entities;

                                     class User
                                     {
                                         private $id;
                                         private $name;
                                     }




38   Zend Framework 1 + Doctrine 2
Architecture
     • The EntityManager
     • Central access point to the ORM functionality provided by Doctrine
      2. API is used to manage the persistence of your objects and to
      query for persistent objects.
     • Employes transactional write behind strategy that delays the
      execution of SQL statements in order to execute them in the most
      efficient way
     • Execute at end of transaction so that all write locks are quickly
      releases
     • Internally an EntityManager uses a UnitOfWork to keep track of your
      objects




39   Zend Framework 1 + Doctrine 2
Create EntityManager
     • Create a new EntityManager instance:




          $config = new DoctrineORMConfiguration();
          $config->setMetadataCacheImpl(new DoctrineCommonCacheArrayCache);
          $driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities"));
          $config->setMetadataDriverImpl($driverImpl);

          $config->setProxyDir(__DIR__ . '/Proxies');
          $config->setProxyNamespace('Proxies');

          $em = DoctrineORMEntityManager::create($conn, $config);




40   Zend Framework 1 + Doctrine 2
Map entities to RDBMS tables
       • Entities are just regular PHP objects


                                     namespace Entities;

                                     class User
                                     {
                                         private $id;
                                         private $name;
                                     }




41   Zend Framework 1 + Doctrine 2
Map entities to RDBMS tables
     • Entities are just regular PHP objects
       Mapped By:
           •Annotations


                             namespace Entities;

                             /**
                               * @Entity @Table(name="users")
                               */
                             class User
                             {
                                  /** @Id @Column(type="integer") @GeneratedValue */
                                  private $id;

                                     /** @Column(length=50) */
                                     private $name;
                             }




42   Zend Framework 1 + Doctrine 2
Map entities to RDBMS tables
       • Entities are just regular PHP objects:
          Mapped By:
               •Annotations
                                     EntitiesUser:
               •YAML                   type: entity
                                       table: users
                                       id:
                                         id:
                                           type: integer
                                           generator:
                                             strategy: AUTO
                                       fields:
                                         name:
                                           type: string
                                           length: 255




43   Zend Framework 1 + Doctrine 2
Map entities to RDBMS tables
       • Entities are just regular PHP objects:
          Mapped By:
               •Annotations
               •YAML                 <?xml version="1.0" encoding="UTF-8"?>
                                     <doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
               •XML                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                           xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                                                         http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

                                         <entity name="EntitiesUser" table="users">
                                             <id name="id" type="integer">
                                                 <generator strategy="AUTO"/>
                                             </id>
                                             <field name="name" type="string" length="50"/>
                                         </entity>

                                     </doctrine-mapping>




44   Zend Framework 1 + Doctrine 2
Mapping Performance
     • Only parsed once
     • Cached using configured cache driver
     • Subsequent requests pull mapping information from configured
      cache driver




45   Zend Framework 1 + Doctrine 2
Working with Objects
     • Use the $em to manage the persistence of your entities:




                             $user = new User;
                             $user->setName('Jonathan H. Wage');

                             $em->persist($user);
                             $em->flush();




46   Zend Framework 1 + Doctrine 2
Working with Objects
     • Updating an object:




                   $user = $em->getRepository('User')
                       ->find(array('name' => 'jwage'));

                   // modify the already managed object
                   $user->setPassword('changed');
                   $em->flush(); // issues update




47   Zend Framework 1 + Doctrine 2
Working with Objects
     • Removing an object:




                   $user = $em->getRepository('User')
                       ->find(array('name' => 'jwage'));

                   // schedule for deletion
                   $em->remove($user);
                   $em->flush(); // issues delete




48   Zend Framework 1 + Doctrine 2
Transactions
     • Implicit:


                                $user = new User;
                                $user->setName('George');
                                $em->persist($user);
                                $em->flush();


     •EntityManager#flush() will begin and commit/rollback a transaction




49   Zend Framework 1 + Doctrine 2
Transactions
     • Explicit:


               // $em instanceof EntityManager
               $em->getConnection()->beginTransaction(); // suspend auto-commit
               try {
                   //... do some work
                   $user = new User;
                   $user->setName('George');
                   $em->persist($user);
                   $em->flush();
                   $em->getConnection()->commit();
               } catch (Exception $e) {
                   $em->getConnection()->rollback();
                   $em->close();
                   throw $e;
               }




50   Zend Framework 1 + Doctrine 2
Transactions
     • A more convenient explicit transaction:




                            // $em instanceof EntityManager
                            $em->transactional(function($em) {
                                //... do some work
                                $user = new User;
                                $user->setName('George');
                                $em->persist($user);
                            });




51   Zend Framework 1 + Doctrine 2
Transactions and Performance


                            for ($i = 0; $i < 20; ++$i) {
                                $user = new User;
                                $user->name = 'Jonathan H. Wage';
                                $em->persist($user);
                            }

                            $s = microtime(true);
                            $em->flush();
                            $e = microtime(true);
                            echo $e - $s;




52   Zend Framework 1 + Doctrine 2
Transactions and Performance
     • How you use transactions can greatly affect performance. Here
      is the same thing using raw PHP code:




            $s = microtime(true);
            for ($i = 0; $i < 20; ++$i) {
                mysql_query("INSERT INTO users (name) VALUES
            ('Jonathan H. Wage')", $link);
            }
            $e = microtime(true);
            echo $e - $s;



53   Zend Framework 1 + Doctrine 2
Which is faster?
     • The one using no ORM, and no abstraction at all?


     • Or the one using the Doctrine ORM?




54   Zend Framework 1 + Doctrine 2
Which is faster?
       • The one using no ORM, and no abstraction at all?


       • Or the one using the Doctrine ORM?



                               Doctrine2    0.0094 seconds

                               mysql_query 0.0165 seconds


       • Doctrine2 wins! How?



55   Zend Framework 1 + Doctrine 2
Not Faster
     • Doctrine just automatically performed the inserts inside one
      transaction. Here is the code updated to use transactions:




            $s = microtime(true);
            mysql_query('START TRANSACTION', $link);
            for ($i = 0; $i < 20; ++$i) {
                mysql_query("INSERT INTO users (name) VALUES ('Jonathan H. Wage')",
            $link);
            }
            mysql_query('COMMIT', $link);
            $e = microtime(true);
            echo $e - $s;




56   Zend Framework 1 + Doctrine 2
Much Faster
     • Transactions matter and can affect performance greater than
      any code optimization!




                               Doctrine2    0.0094 seconds
                                           0.0028
                               mysql_query 0.0165 seconds



57   Zend Framework 1 + Doctrine 2
Locking Support
     • Optimistic locking with integer:




                              class User
                              {
                                  // ...
                                  /** @Version @Column(type="integer") */
                                  private $version;
                                  // ...
                              }




58   Zend Framework 1 + Doctrine 2
Locking Support
     • Optimistic locking with timestamp:




                              class User
                              {
                                  // ...
                                  /** @Version @Column(type="datetime") */
                                  private $version;
                                  // ...
                              }




59   Zend Framework 1 + Doctrine 2
Locking Support
     • Verify version when finding:



        use DoctrineDBALLockMode;
        use DoctrineORMOptimisticLockException;

        $theEntityId = 1;
        $expectedVersion = 184;

        try {
            $entity = $em->find('User', $theEntityId, LockMode::OPTIMISTIC, $expectedVersion);

             // do the work

            $em->flush();
        } catch(OptimisticLockException $e) {
            echo "Sorry, but someone else has already changed this entity. Please apply the changes again!";
        }




60   Zend Framework 1 + Doctrine 2
Locking Support
     • Example implementation:



        $post = $em->find('BlogPost', 123456);

        echo '<input type="hidden" name="id" value="' . $post->getId() . '" />';
        echo '<input type="hidden" name="version" value="' . $post->getCurrentVersion() . '" />';




        $postId = (int) $_GET['id'];
        $postVersion = (int) $_GET['version'];

        $post = $em->find('BlogPost', $postId, DoctrineDBALLockMode::OPTIMISTIC, $postVersion);




61   Zend Framework 1 + Doctrine 2
DQL
                    Doctrine Query Language




62   Zend Framework 1 + Doctrine 2
DQL
     • DQL stands for Doctrine Query Language and is an Object
      Query Language derivate that is very similar to the Hibernate
      Query Language (HQL) or the Java Persistence Query
      Language (JPQL).


     • DQL provides powerful querying capabilities over your object
      model. Imagine all your objects lying around in some storage
      (like an object database). When writing DQL queries, think
      about querying that storage to find a certain subset of your
      objects.




63   Zend Framework 1 + Doctrine 2
DQL Parser
     • Parser completely re-written from scratch


     • Parsed by top down recursive descent lexer parser that
      constructs an AST(Abstract Syntax Tree)


     • Platform specific SQL is generated from AST




64   Zend Framework 1 + Doctrine 2
Doctrine Query Language




                $q = $em->createQuery('SELECT u FROM User u');
                $users = $q->execute();




65   Zend Framework 1 + Doctrine 2
Query Builder
       • Same query built using the QueryBuilder




                       $qb = $em->createQueryBuilder()
                           ->select('u')
                           ->from('User', 'u');

                       $q = $qb->getQuery();
                       $users = $q->execute();




66   Zend Framework 1 + Doctrine 2
More Examples

                                     $query = $em->createQuery(
                                         'SELECT u, g, FROM User u ' .
                                         'LEFT JOIN u.Groups g ' .
                                         'ORDER BY u.name ASC, g.name ASC'
                                     );
                                     $users = $query->execute();




                                     $qb = $em->createQueryBuilder()
                                         ->select('u, g')
                                         ->from('User', 'u')
                                         ->leftJoin('u.Groups', 'g')
                                         ->orderBy('u.name', 'ASC')
                                         ->addOrderBy('g.name', 'ASC');

                                     $query = $qb->getQuery();


67   Zend Framework 1 + Doctrine 2
Executing Queries
     • Executing and getting results




                     $users = $query->execute();

                     foreach ($users as $user) {
                         // ...
                         foreach ($user->getGroups() as $group) {
                             // ...
                         }
                     }




68   Zend Framework 1 + Doctrine 2
Executing Queries
     • Execute query and iterate over results keeping memory usage
      low:




                     foreach ($query->iterate() as $user) {
                         // ...
                         foreach ($user->getGroups() as $group) {
                             // ...
                         }
                     }




69   Zend Framework 1 + Doctrine 2
Result Cache
     • Optionally cache the results of your queries in your driver of
      choice:




           $cacheDriver = new DoctrineCommonCacheApcCache();
           $config->setResultCacheImpl($cacheDriver);

           $query = $em->createQuery('select u from EntitiesUser u');
           $query->useResultCache(true, 3600, 'my_query_name');

           $users = $query->execute();

           $users = $query->execute(); // 2nd time pulls from cache




70   Zend Framework 1 + Doctrine 2
Inheritance
     • Doctrine supports mapping entities that use inheritance with
      the following strategies:

        Mapped Superclass
        Single Table Inheritance
        Class Table Inheritance




71   Zend Framework 1 + Doctrine 2
Mapped Superclasses

                            /** @MappedSuperclass */
                            abstract class MappedSuperclassBase
                            {
                                /** @Column(type="integer") */
                                private $mapped1;
                                /** @Column(type="string") */
                                private $mapped2;
                                /**
                                 * @OneToOne(targetEntity="MappedSuperclassRelated1")
                                 * @JoinColumn(name="related1_id", referencedColumnName="id")
                                 */
                                private $mappedRelated1;

                                // ... more fields and methods
                            }

                            /** @Entity */
                            class EntitySubClass extends MappedSuperclassBase
                            {
                                /** @Id @Column(type="integer") */
                                private $id;
                                /** @Column(type="string") */
                                private $name;

                                // ... more fields and methods
                            }




72   Zend Framework 1 + Doctrine 2
Single Table Inheritance

               /**
                 * @Entity
                 * @InheritanceType("SINGLE_TABLE")
                 * @DiscriminatorColumn(name="discr", type="string")
                 * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
                 */
               class Person
               {
                    // ...
               }

               /**
                 * @Entity
                 */
               class Employee extends Person
               {
                    // ...
               }




73   Zend Framework 1 + Doctrine 2
Single Table Inheritance
     • All entities share one table.


     • To distinguish which row represents which type in the
      hierarchy a so-called discriminator column is used.




74   Zend Framework 1 + Doctrine 2
Class Table Inheritance

               /**
                 * @Entity
                 * @InheritanceType("JOINED")
                 * @DiscriminatorColumn(name="discr", type="string")
                 * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
                 */
               class Person
               {
                    // ...
               }

               /** @Entity */
               class Employee extends Person
               {
                   // ...
               }




75   Zend Framework 1 + Doctrine 2
Class Table Inheritance
     • Each class in a hierarchy is mapped to several
      tables: its own table and the tables of all parent
      classes.

     • The table of a child class is linked to the table of a
      parent class through a foreign key constraint.

     • A discriminator column is used in the topmost table
      of the hierarchy because this is the easiest way to
      achieve polymorphic queries.


76   Zend Framework 1 + Doctrine 2
Bulk Inserts with Domain
     • Insert 10000 objects batches of 20:



               $batchSize = 20;
               for ($i = 1; $i <= 10000; ++$i) {
                   $user = new User;
                   $user->setStatus('user');
                   $user->setUsername('user' . $i);
                   $user->setName('Mr.Smith-' . $i);
                   $em->persist($user);
                   if ($i % $batchSize == 0) {
                       $em->flush();
                       $em->clear(); // Detaches all objects from Doctrine!
                   }
               }




77   Zend Framework 1 + Doctrine 2
Bulk Update with DQL




      $q = $em->createQuery('update Manager m set m.salary = m.salary * 0.9');
      $numUpdated = $q->execute();




78   Zend Framework 1 + Doctrine 2
Bulk Update with Domain
       • Update objects in batches of 20:


                      $batchSize = 20;
                      $i = 0;
                      $q = $em->createQuery('select u from User u');
                      $iterableResult = $q->iterate();
                      foreach($iterableResult AS $row) {
                          $user = $row[0];
                          $user->increaseCredit();
                          $user->calculateNewBonuses();
                          if (($i % $batchSize) == 0) {
                              $em->flush(); // Executes all updates.
                              $em->clear(); // Detaches all objects from Doctrine!
                          }
                          ++$i;
                      }




79   Zend Framework 1 + Doctrine 2
Bulk Delete with DQL




       $q = $em->createQuery('delete from Manager m where m.salary > 100000');
       $numDeleted = $q->execute();




80   Zend Framework 1 + Doctrine 2
Bulk Delete with Domain


                         $batchSize = 20;
                         $i = 0;
                         $q = $em->createQuery('select u from User u');
                         $iterableResult = $q->iterate();
                         while (($row = $iterableResult->next()) !== false) {
                             $em->remove($row[0]);
                             if (($i % $batchSize) == 0) {
                                 $em->flush(); // Executes all deletions.
                                 $em->clear(); // Detaches all objects from Doctrine!
                             }
                             ++$i;
                         }




81   Zend Framework 1 + Doctrine 2
Events
     •Doctrine triggers events throughout the
     •lifecycle of objects it manages:
        preRemove
        postRemove
        prePersist
        postPersist
        preUpdate
        postUpdate
        preLoad
        postLoad




82   Zend Framework 1 + Doctrine 2
Example

                                     /**
                                       * @Entity
                                       * @HasLifecycleCallbacks
                                       */
                                     class BlogPost
                                     {
                                          // ...

                                         /** @PreUpdate */
                                         public function prePersist()
                                         {
                                             $this->createdAt = new DateTime();
                                         }

                                         /** @PreUpdate */
                                         public function preUpdate()
                                         {
                                             $this->updatedAt = new DateTime();
                                         }
                                     }




83   Zend Framework 1 + Doctrine 2
Using Raw SQL
     • Write a raw SQL string


     • Map the result set of the SQL query using a ResultSetMapping
      instance




84   Zend Framework 1 + Doctrine 2
Using Raw SQL


                        $sql = 'SELECT id, name FROM users WHERE username = ?';

                        $rsm = new ResultSetMapping;
                        $rsm->addEntityResult('User', 'u');
                        $rsm->addFieldResult('u', 'id', 'id');
                        $rsm->addFieldResult('u', 'name', 'name');

                        $query = $this->_em->createNativeQuery($sql, $rsm);
                        $query->setParameter(1, 'jwage');

                        $users = $query->getResult();




85   Zend Framework 1 + Doctrine 2
Why use an object mapper?



86   Zend Framework 1 + Doctrine 2
Encapsulation
       Encapsulate your domain in an object oriented interface




87   Zend Framework 1 + Doctrine 2
Maintainability
       The organization of your domain logic in an OO way improved
       maintainability




88   Zend Framework 1 + Doctrine 2
Testability
       Keeping a clean OO domain model makes your business logic
       easily testable for improved stability




89   Zend Framework 1 + Doctrine 2
Portability
          Write portable and thin application controller code and
                                fat models.




90   Zend Framework 1 + Doctrine 2
Demo Time




91   The Doctrine Project
What we are going to accomplish
     •Start with a vanilla Zend Framework Project
     •Ensure all dependencies are met
     •Configure out application to utilize Doctrine
     •Create an Entity (in our library) with Annotations
     •Generate the Database
     •Generate Proxies + Repositories
     •Create a Controller for basic crud
     •Talk about what would happen next




92   Zend Framework 1 + Doctrine 2
Where To Get The Code
     •http://github.com/ralphschindler/NOLASnowball
       Self contained Project
       Branches:
           •master - Clean ZF Project, with ZF embedded in library/ folder
           •non-model-artifacts - Authentication service, Login form
           •doctrine2-managed
                – Has following libraries: Doctrine2, Symfony (Copied into library), Bisna (ZF1 +
                  Doctrine2 Integration library)
                – Has the following entity created: NOLASnowballEntityStand
                – Has the proper application.ini settings
                – Has scripts/doctrine.php setup for easy use
           •doctrine2-managed-crud
                – Created Stand Controller, actions are complete, view scripts complete
                – Proxies & Repositories are generated
                – Assumes you’ve generated the SQL (locally would need to change db credentials)

93   Zend Framework 1 + Doctrine 2
Lets look at code!
     •Demo time




94   Zend Framework 1 + Doctrine 2
Exercises and Things To Implement
     •flush() could be a postDispatch() function call
     •All interaction with Entities could be moved into a Service
      Layer
       Once such implementation: https://github.com/guilhermeblanco/
         ZF1-Doctrine2-ServiceLayer
     •Add relationships, and alter forms accordingly




95   Zend Framework 1 + Doctrine 2
Recommended Reading
     •Doctrine Website & Manual (Also has download)
       http://www.doctrine-project.org/
     •Zend Framework Web & Manual (With download)
       http://framework.zend.com/
     •Ralph Schindler’s Sample Application
       https://github.com/ralphschindler/NOLASnowball
     •Guilherme Blanco’s ZF1 + D2 Integration code
       https://github.com/guilhermeblanco/ZendFramework1-Doctrine2




96   Zend Framework 1 + Doctrine 2
Questions?
     •Q & A Time




97   Zend Framework 1 + Doctrine 2

Mais conteúdo relacionado

Mais procurados

ZendCon2010 Doctrine MongoDB ODM
ZendCon2010 Doctrine MongoDB ODMZendCon2010 Doctrine MongoDB ODM
ZendCon2010 Doctrine MongoDB ODMJonathan Wage
 
Erlang for data ops
Erlang for data opsErlang for data ops
Erlang for data opsmnacos
 
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)Stephen Chin
 
Symfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODMSymfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODMJonathan Wage
 
JavaFX and Scala - Like Milk and Cookies
JavaFX and Scala - Like Milk and CookiesJavaFX and Scala - Like Milk and Cookies
JavaFX and Scala - Like Milk and CookiesStephen Chin
 
Hacking JavaFX with Groovy, Clojure, Scala, and Visage
Hacking JavaFX with Groovy, Clojure, Scala, and VisageHacking JavaFX with Groovy, Clojure, Scala, and Visage
Hacking JavaFX with Groovy, Clojure, Scala, and VisageStephen Chin
 
Drupal II: The SQL
Drupal II: The SQLDrupal II: The SQL
Drupal II: The SQLddiers
 
Hidden Treasures of the Python Standard Library
Hidden Treasures of the Python Standard LibraryHidden Treasures of the Python Standard Library
Hidden Treasures of the Python Standard Librarydoughellmann
 
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRick Copeland
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)Night Sailer
 
iPhone Development Intro
iPhone Development IntroiPhone Development Intro
iPhone Development IntroLuis Azevedo
 
Working With JQuery Part1
Working With JQuery Part1Working With JQuery Part1
Working With JQuery Part1saydin_soft
 

Mais procurados (20)

ZendCon2010 Doctrine MongoDB ODM
ZendCon2010 Doctrine MongoDB ODMZendCon2010 Doctrine MongoDB ODM
ZendCon2010 Doctrine MongoDB ODM
 
Erlang for data ops
Erlang for data opsErlang for data ops
Erlang for data ops
 
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
Cleaner APIs, Cleaner UIs with Visage (33rd Degrees)
 
Symfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODMSymfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODM
 
JavaFX and Scala - Like Milk and Cookies
JavaFX and Scala - Like Milk and CookiesJavaFX and Scala - Like Milk and Cookies
JavaFX and Scala - Like Milk and Cookies
 
Perl object ?
Perl object ?Perl object ?
Perl object ?
 
Hacking JavaFX with Groovy, Clojure, Scala, and Visage
Hacking JavaFX with Groovy, Clojure, Scala, and VisageHacking JavaFX with Groovy, Clojure, Scala, and Visage
Hacking JavaFX with Groovy, Clojure, Scala, and Visage
 
Drupal II: The SQL
Drupal II: The SQLDrupal II: The SQL
Drupal II: The SQL
 
Hidden Treasures of the Python Standard Library
Hidden Treasures of the Python Standard LibraryHidden Treasures of the Python Standard Library
Hidden Treasures of the Python Standard Library
 
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
 
Phactory
PhactoryPhactory
Phactory
 
Arrays in PHP
Arrays in PHPArrays in PHP
Arrays in PHP
 
J query
J queryJ query
J query
 
iPhone Development Intro
iPhone Development IntroiPhone Development Intro
iPhone Development Intro
 
J query1
J query1J query1
J query1
 
Clojure Deep Dive
Clojure Deep DiveClojure Deep Dive
Clojure Deep Dive
 
Drupal7 dbtng
Drupal7  dbtngDrupal7  dbtng
Drupal7 dbtng
 
Working With JQuery Part1
Working With JQuery Part1Working With JQuery Part1
Working With JQuery Part1
 

Semelhante a Zend Framework 1 + Doctrine 2

Symfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 IntegrationSymfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 IntegrationJonathan Wage
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redisjimbojsb
 
Building node.js applications with Database Jones
Building node.js applications with Database JonesBuilding node.js applications with Database Jones
Building node.js applications with Database JonesJohn David Duncan
 
DBIx::Class vs. DBix::DataModel
DBIx::Class vs. DBix::DataModelDBIx::Class vs. DBix::DataModel
DBIx::Class vs. DBix::DataModelLaurent Dami
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
 
Introducing PHP Data Objects
Introducing PHP Data ObjectsIntroducing PHP Data Objects
Introducing PHP Data Objectswebhostingguy
 
Drupal Camp Porto - Developing with Drupal: First Steps
Drupal Camp Porto - Developing with Drupal: First StepsDrupal Camp Porto - Developing with Drupal: First Steps
Drupal Camp Porto - Developing with Drupal: First StepsLuís Carneiro
 
Php on the desktop and php gtk2
Php on the desktop and php gtk2Php on the desktop and php gtk2
Php on the desktop and php gtk2Elizabeth Smith
 
Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!Herman Peeren
 
Python and Oracle : allies for best of data management
Python and Oracle : allies for best of data managementPython and Oracle : allies for best of data management
Python and Oracle : allies for best of data managementLaurent Leturgez
 
Andriy Podanenko.Drupal database api.DrupalCamp Kyiv 2011
Andriy Podanenko.Drupal database api.DrupalCamp Kyiv 2011Andriy Podanenko.Drupal database api.DrupalCamp Kyiv 2011
Andriy Podanenko.Drupal database api.DrupalCamp Kyiv 2011camp_drupal_ua
 
Addressing Scenario
Addressing ScenarioAddressing Scenario
Addressing ScenarioTara Hardin
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormMichelangelo van Dam
 
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...dotNet Miami
 
Yii, frameworks and where PHP is heading to
Yii, frameworks and where PHP is heading toYii, frameworks and where PHP is heading to
Yii, frameworks and where PHP is heading toAlexander Makarov
 
Entity Framework: Code First and Magic Unicorns
Entity Framework: Code First and Magic UnicornsEntity Framework: Code First and Magic Unicorns
Entity Framework: Code First and Magic UnicornsRichie Rump
 

Semelhante a Zend Framework 1 + Doctrine 2 (20)

Symfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 IntegrationSymfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 Integration
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redis
 
Libertyvasion2010
Libertyvasion2010Libertyvasion2010
Libertyvasion2010
 
Building node.js applications with Database Jones
Building node.js applications with Database JonesBuilding node.js applications with Database Jones
Building node.js applications with Database Jones
 
DBIx::Class vs. DBix::DataModel
DBIx::Class vs. DBix::DataModelDBIx::Class vs. DBix::DataModel
DBIx::Class vs. DBix::DataModel
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Introducing PHP Data Objects
Introducing PHP Data ObjectsIntroducing PHP Data Objects
Introducing PHP Data Objects
 
Drupal Camp Porto - Developing with Drupal: First Steps
Drupal Camp Porto - Developing with Drupal: First StepsDrupal Camp Porto - Developing with Drupal: First Steps
Drupal Camp Porto - Developing with Drupal: First Steps
 
Php on the desktop and php gtk2
Php on the desktop and php gtk2Php on the desktop and php gtk2
Php on the desktop and php gtk2
 
Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!
 
Python and Oracle : allies for best of data management
Python and Oracle : allies for best of data managementPython and Oracle : allies for best of data management
Python and Oracle : allies for best of data management
 
Andriy Podanenko.Drupal database api.DrupalCamp Kyiv 2011
Andriy Podanenko.Drupal database api.DrupalCamp Kyiv 2011Andriy Podanenko.Drupal database api.DrupalCamp Kyiv 2011
Andriy Podanenko.Drupal database api.DrupalCamp Kyiv 2011
 
Addressing Scenario
Addressing ScenarioAddressing Scenario
Addressing Scenario
 
Fatc
FatcFatc
Fatc
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 
Doctrine and NoSQL
Doctrine and NoSQLDoctrine and NoSQL
Doctrine and NoSQL
 
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
dotNet Miami - June 21, 2012: Richie Rump: Entity Framework: Code First and M...
 
Magento code audit
Magento code auditMagento code audit
Magento code audit
 
Yii, frameworks and where PHP is heading to
Yii, frameworks and where PHP is heading toYii, frameworks and where PHP is heading to
Yii, frameworks and where PHP is heading to
 
Entity Framework: Code First and Magic Unicorns
Entity Framework: Code First and Magic UnicornsEntity Framework: Code First and Magic Unicorns
Entity Framework: Code First and Magic Unicorns
 

Mais de Ralph Schindler

Extending ZF & Extending With ZF
Extending ZF & Extending With ZFExtending ZF & Extending With ZF
Extending ZF & Extending With ZFRalph Schindler
 
Zend_Tool In ZF 1.8 Webinar
Zend_Tool In ZF 1.8 WebinarZend_Tool In ZF 1.8 Webinar
Zend_Tool In ZF 1.8 WebinarRalph Schindler
 
Zend Framework 1.8 Features Webinar
Zend Framework 1.8 Features WebinarZend Framework 1.8 Features Webinar
Zend Framework 1.8 Features WebinarRalph Schindler
 
Software Engineering In PHP
Software Engineering In PHPSoftware Engineering In PHP
Software Engineering In PHPRalph Schindler
 
Zend_Layout & Zend_View Enhancements
Zend_Layout & Zend_View EnhancementsZend_Layout & Zend_View Enhancements
Zend_Layout & Zend_View EnhancementsRalph Schindler
 
Zend_Tool: Rapid Application Development with Zend Framework
Zend_Tool: Rapid Application Development with Zend FrameworkZend_Tool: Rapid Application Development with Zend Framework
Zend_Tool: Rapid Application Development with Zend FrameworkRalph Schindler
 

Mais de Ralph Schindler (12)

Zend Code in ZF 2.0
Zend Code in ZF 2.0Zend Code in ZF 2.0
Zend Code in ZF 2.0
 
Zend Di in ZF 2.0
Zend Di in ZF 2.0Zend Di in ZF 2.0
Zend Di in ZF 2.0
 
484 Days of PHP 5.3
484 Days of PHP 5.3484 Days of PHP 5.3
484 Days of PHP 5.3
 
Modeling best practices
Modeling best practicesModeling best practices
Modeling best practices
 
What's New in ZF 1.10
What's New in ZF 1.10What's New in ZF 1.10
What's New in ZF 1.10
 
Extending ZF & Extending With ZF
Extending ZF & Extending With ZFExtending ZF & Extending With ZF
Extending ZF & Extending With ZF
 
Extending Zend_Tool
Extending Zend_ToolExtending Zend_Tool
Extending Zend_Tool
 
Zend_Tool In ZF 1.8 Webinar
Zend_Tool In ZF 1.8 WebinarZend_Tool In ZF 1.8 Webinar
Zend_Tool In ZF 1.8 Webinar
 
Zend Framework 1.8 Features Webinar
Zend Framework 1.8 Features WebinarZend Framework 1.8 Features Webinar
Zend Framework 1.8 Features Webinar
 
Software Engineering In PHP
Software Engineering In PHPSoftware Engineering In PHP
Software Engineering In PHP
 
Zend_Layout & Zend_View Enhancements
Zend_Layout & Zend_View EnhancementsZend_Layout & Zend_View Enhancements
Zend_Layout & Zend_View Enhancements
 
Zend_Tool: Rapid Application Development with Zend Framework
Zend_Tool: Rapid Application Development with Zend FrameworkZend_Tool: Rapid Application Development with Zend Framework
Zend_Tool: Rapid Application Development with Zend Framework
 

Zend Framework 1 + Doctrine 2

  • 1. Zend Framework 1 + Doctrine 2
  • 2. Jonathan H. Wage •PHP Developer for over 10 years •Symfony Contributor •Doctrine Contributor •Published Author •Business Owner •Nashville, TN Resident •http://www.twitter.com/jwage •http://www.facebook.com/jwage 2 Zend Framework 1 + Doctrine 2
  • 3. I work at OpenSky •What is OpenSky? “a social commerce platform” •Based in New York and is a major open •source software advocate •http://www.shopopensky.com 3 Zend Framework 1 + Doctrine 2
  • 4. OpenSky Technologies •PHP 5.3.2 •Apache2 •Symfony2 •Doctrine2 •jQuery •mule, stomp, hornetq •MongoDB •nginx •varnish 4 Zend Framework 1 + Doctrine 2
  • 5. Ralph Schindler •Software Engineer on the Zend Framework team At Zend for almost 3 years Before that TippingPoint/3Com •Programming PHP for 12+ years •Live in New Orleans, LA. Lived in Austin, Tx for 5 years •Where To Find Me: http://ralphschindler.com http://twitter.com/ralphschindler http://github.com/ralphschindler ralphschindler on freenode 5 Zend Framework 1 + Doctrine 2
  • 6. Guilherme Blanco •Programming Experience 12+ years web development experience 9 years with PHP •Software Engineer at Yahoo! •Open Source Evangelist Contributes regularly to the Doctrine Project, Symfony, and Zend Framework •Where to find me: http://twitter.com/guilhermeblanco http://github.com/guilhermeblanco 6 Zend Framework 1 + Doctrine 2
  • 7. Doctrine 2 7 The Doctrine Project
  • 8. What is Doctrine? • Open Source PHP Project started in 2006 • Specializes in database functionality  Database Abstraction Layer (DBAL)  Database Migrations  Object Relational Mapper (DBAL)  MongoDB Object Document Manager (ODM)  CouchDB Object Document Manager (ODM) 8 Zend Framework 1 + Doctrine 2
  • 9. Who is on the team? • Roman S. Borschel • Guilherme Blanco • Benjamin Eberlei • Bulat Shakirzyanov • Jonathan H. Wage 9 Zend Framework 1 + Doctrine 2
  • 10. Project History • First commit April 13th 2006 • First stable version finished and Released September 1st 2008 • One of the first ORM implementations for PHP • 1.0 is First LTS(long term support) release. Maintained until March 1st 2010 • Integrated with many popular frameworks: Symfony, Zend Framework, Code Igniter 10 Zend Framework 1 + Doctrine 2
  • 11. Doctrine Libraries • Database Abstraction Layer • Database Migrations • Object Relational Mapper • MongoDB Object Document Manager • CouchDB Object Document Manager 11 Zend Framework 1 + Doctrine 2
  • 12. DBAL Database Abstraction Layer 12 Zend Framework 1 + Doctrine 2
  • 13. Database Abstraction Layer • The Doctrine Database Abstraction • Layer (DBAL) is a thin layer on top of • PDO, it offers:  select, update, delete, transactions  database schema introspection  schema management 13 Zend Framework 1 + Doctrine 2
  • 14. Can be used standalone 14 Zend Framework 1 + Doctrine 2
  • 15. Evolved fork of PEAR MDB, MDB2, Zend_Db, etc. 15 Zend Framework 1 + Doctrine 2
  • 16. Download •You can download a standalone •package to get started using the DBAL: http://www.doctrine-project.org/projects/dbal/download 16 Zend Framework 1 + Doctrine 2
  • 17. Autoloader •To use any Doctrine library you must •register an autoloader: use DoctrineCommonClassLoader; require '/path/to/doctrine-common/lib/Doctrine/Common/ClassLoader.php'; $classLoader = new ClassLoader('DoctrineDBAL', '/path/to/doctrine-dbal/lib'); $classLoader->register(); 17 Zend Framework 1 + Doctrine 2
  • 18. Create a Connection $config = new DoctrineDBALConfiguration(); //.. $connectionParams = array( 'dbname' => 'mydb', 'user' => 'user', 'password' => 'secret', 'host' => 'localhost', 'driver' => 'pdo_mysql', ); $conn = DriverManager::getConnection($connectionParams); 18 Zend Framework 1 + Doctrine 2
  • 19. Data API • prepare($sql) - Prepare a given sql statement and return the DoctrineDBALDriverStatement instance. • executeUpdate($sql, array $params) - Executes a prepared statement with the given sql and parameters and returns the affected rows count. • execute($sql, array $params) - Creates a prepared statement for the given sql and passes the parameters to the execute method, then returning the statement. • fetchAll($sql, array $params) - Execute the query and fetch all results into an array. • fetchArray($sql, array $params) - Numeric index retrieval of first result row of the given query. • fetchBoth($sql, array $params) - Both numeric and assoc column name retrieval of the first result row. • fetchColumn($sql, array $params, $colnum) - Retrieve only the given column of the first result row. • fetchRow($sql, array $params) - Retrieve assoc row of the first result row. • select($sql, $limit, $offset) - Modify the given query with a limit clause. • delete($tableName, array $identifier) - Delete all rows of a table matching the given identifier, where keys are column names. • insert($tableName, array $data) - Insert a row into the given table name using the key value pairs of data. 19 Zend Framework 1 + Doctrine 2
  • 20. Very Similar to PDO $users = $conn->fetchAll('SELECT * FROM users'); 20 Zend Framework 1 + Doctrine 2
  • 21. Schema Manager •Learn about and modify your database •through the SchemaManager: $sm = $conn->getSchemaManager(); 21 Zend Framework 1 + Doctrine 2
  • 22. Introspection API •listDatabases() •listFunctions() •listSequences() •listTableColumns($tableName) •listTableConstraints($tableName) •listTableDetails($tableName) •listTableForeignKeys($tableName) •listTableIndexes($tableName) •listTables() 22 Zend Framework 1 + Doctrine 2
  • 23. Introspection API $tables = $sm->listTables(); foreach ($tables as $table) { $columns = $sm->listTableColumns($table); // ... } 23 Zend Framework 1 + Doctrine 2
  • 24. DDL Statements •Progromatically issue DDL statements: $columns = array( 'id' => array( 'type' => DoctrineDBALType::getType('integer'), 'autoincrement' => true, 'primary' => true, 'notnull' => true ), 'test' => array( 'type' => DoctrineDBALType::getType('string'), 'length' => 255 ) ); $options = array(); $sm->createTable('new_table', $columns, $options); 24 Zend Framework 1 + Doctrine 2
  • 25. DDL Statements •Progromatically issue DDL statements: $definition = array( 'name' => 'user_id_fk', 'local' => 'user_id', 'foreign' => 'id', 'foreignTable' => 'user' ); $sm->createForeignKey('profile', $definition); 25 Zend Framework 1 + Doctrine 2
  • 26. Try a Method •You can try a method and return true if •the operation was successful: if ($sm->tryMethod('createTable', 'new_table', $columns, $options)) { // do something } 26 Zend Framework 1 + Doctrine 2
  • 27. Drop and Create Database try { $sm->dropDatabase('test_db'); } catch (Exception $e) {} $sm->createDatabase('test_db'); 27 Zend Framework 1 + Doctrine 2
  • 28. Drop and Create Database •A little better! Every drop and create •functionality in the API has a method •that follows the dropAndCreate pattern: $sm->dropAndCreateDatabase('test_db'); 28 Zend Framework 1 + Doctrine 2
  • 29. Schema Representation $platform = $em->getConnection()->getDatabasePlatform(); $schema = new DoctrineDBALSchemaSchema(); $myTable = $schema->createTable("my_table"); $myTable->addColumn("id", "integer", array("unsigned" => true)); $myTable->addColumn("username", "string", array("length" => 32)); $myTable->setPrimaryKey(array("id")); // get queries to create this schema. $queries = $schema->toSql($platform); Array ( [0] => CREATE TABLE my_table (id INTEGER NOT NULL, username VARCHAR(32) NOT NULL, PRIMARY KEY("id")) ) 29 Zend Framework 1 + Doctrine 2
  • 30. Schema Representation // ...... Array ( // get queries to safely delete this schema. $dropSchema => $schema->toDropSql($platform); [0] = DROP TABLE my_table ) Array ( [0] => DROP TABLE my_table ) Returns the reverse SQL of what toSql() returns 30 Zend Framework 1 + Doctrine 2
  • 31. Comparing Schemas $fromSchema = new DoctrineDBALSchemaSchema(); $myTable = $fromSchema->createTable("my_table"); $myTable->addColumn("id", "integer", array("unsigned" => true)); $myTable->addColumn("username", "string", array("length" => 32)); $myTable->setPrimaryKey(array("id")); $toSchema = new DoctrineDBALSchemaSchema(); $myTable = $toSchema->createTable("my_table"); $myTable->addColumn("id", "integer", array("unsigned" => true)); $myTable->addColumn("username", "string", array("length" => 32)); $myTable->addColumn("email", "string", array("length" => 255)); $myTable->setPrimaryKey(array("id")); $comparator = new DoctrineDBALSchemaComparator(); $schemaDiff = $comparator->compare($fromSchema, $toSchema); // queries to get from one to another schema. $queries = $schemaDiff->toSql($platform); print_r($queries); ALTER TABLE my_table ADD email VARCHAR(255) NOT NULL 31 Zend Framework 1 + Doctrine 2
  • 32. ORM Object Relational Mapper 32 Zend Framework 1 + Doctrine 2
  • 33. What is ORM? •“Technique for converting data between incompatible type systems in object-oriented programming languages.” http://en.wikipedia.org/wiki/Object-relational_mapping 33 Zend Framework 1 + Doctrine 2
  • 34. The ORM is built on top of Common and DBAL 34 Zend Framework 1 + Doctrine 2
  • 35. ORM Goals • Maintain transparency • Keep domain and persistence layer separated • Performance • Consistent and decoupled API • Well defined semantics 35 Zend Framework 1 + Doctrine 2
  • 36. Download http://www.doctrine-project.org/projects/orm/download 36 Zend Framework 1 + Doctrine 2
  • 37. Architecture •Entities • Lightweight persistent domain object • Regular PHP class • Does not extend any base Doctrine class • Cannot be final or contain final methods • Any two entities in a hierarchy of classes must not have a mapped property with the same name • Supports inheritance, polymorphic associations and polymorphic queries. • Both abstract and concrete classes can be entities • Entities may extend non-entity classes as well as entity classes, and non-entity classes may extend entity classes 37 Zend Framework 1 + Doctrine 2
  • 38. Architecture • No more base class required • Values stored in object properties • Persistence is done transparently namespace Entities; class User { private $id; private $name; } 38 Zend Framework 1 + Doctrine 2
  • 39. Architecture • The EntityManager • Central access point to the ORM functionality provided by Doctrine 2. API is used to manage the persistence of your objects and to query for persistent objects. • Employes transactional write behind strategy that delays the execution of SQL statements in order to execute them in the most efficient way • Execute at end of transaction so that all write locks are quickly releases • Internally an EntityManager uses a UnitOfWork to keep track of your objects 39 Zend Framework 1 + Doctrine 2
  • 40. Create EntityManager • Create a new EntityManager instance: $config = new DoctrineORMConfiguration(); $config->setMetadataCacheImpl(new DoctrineCommonCacheArrayCache); $driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities")); $config->setMetadataDriverImpl($driverImpl); $config->setProxyDir(__DIR__ . '/Proxies'); $config->setProxyNamespace('Proxies'); $em = DoctrineORMEntityManager::create($conn, $config); 40 Zend Framework 1 + Doctrine 2
  • 41. Map entities to RDBMS tables • Entities are just regular PHP objects namespace Entities; class User { private $id; private $name; } 41 Zend Framework 1 + Doctrine 2
  • 42. Map entities to RDBMS tables • Entities are just regular PHP objects Mapped By: •Annotations namespace Entities; /** * @Entity @Table(name="users") */ class User { /** @Id @Column(type="integer") @GeneratedValue */ private $id; /** @Column(length=50) */ private $name; } 42 Zend Framework 1 + Doctrine 2
  • 43. Map entities to RDBMS tables • Entities are just regular PHP objects: Mapped By: •Annotations EntitiesUser: •YAML type: entity table: users id: id: type: integer generator: strategy: AUTO fields: name: type: string length: 255 43 Zend Framework 1 + Doctrine 2
  • 44. Map entities to RDBMS tables • Entities are just regular PHP objects: Mapped By: •Annotations •YAML <?xml version="1.0" encoding="UTF-8"?> <doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" •XML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> <entity name="EntitiesUser" table="users"> <id name="id" type="integer"> <generator strategy="AUTO"/> </id> <field name="name" type="string" length="50"/> </entity> </doctrine-mapping> 44 Zend Framework 1 + Doctrine 2
  • 45. Mapping Performance • Only parsed once • Cached using configured cache driver • Subsequent requests pull mapping information from configured cache driver 45 Zend Framework 1 + Doctrine 2
  • 46. Working with Objects • Use the $em to manage the persistence of your entities: $user = new User; $user->setName('Jonathan H. Wage'); $em->persist($user); $em->flush(); 46 Zend Framework 1 + Doctrine 2
  • 47. Working with Objects • Updating an object: $user = $em->getRepository('User') ->find(array('name' => 'jwage')); // modify the already managed object $user->setPassword('changed'); $em->flush(); // issues update 47 Zend Framework 1 + Doctrine 2
  • 48. Working with Objects • Removing an object: $user = $em->getRepository('User') ->find(array('name' => 'jwage')); // schedule for deletion $em->remove($user); $em->flush(); // issues delete 48 Zend Framework 1 + Doctrine 2
  • 49. Transactions • Implicit: $user = new User; $user->setName('George'); $em->persist($user); $em->flush(); •EntityManager#flush() will begin and commit/rollback a transaction 49 Zend Framework 1 + Doctrine 2
  • 50. Transactions • Explicit: // $em instanceof EntityManager $em->getConnection()->beginTransaction(); // suspend auto-commit try { //... do some work $user = new User; $user->setName('George'); $em->persist($user); $em->flush(); $em->getConnection()->commit(); } catch (Exception $e) { $em->getConnection()->rollback(); $em->close(); throw $e; } 50 Zend Framework 1 + Doctrine 2
  • 51. Transactions • A more convenient explicit transaction: // $em instanceof EntityManager $em->transactional(function($em) { //... do some work $user = new User; $user->setName('George'); $em->persist($user); }); 51 Zend Framework 1 + Doctrine 2
  • 52. Transactions and Performance for ($i = 0; $i < 20; ++$i) { $user = new User; $user->name = 'Jonathan H. Wage'; $em->persist($user); } $s = microtime(true); $em->flush(); $e = microtime(true); echo $e - $s; 52 Zend Framework 1 + Doctrine 2
  • 53. Transactions and Performance • How you use transactions can greatly affect performance. Here is the same thing using raw PHP code: $s = microtime(true); for ($i = 0; $i < 20; ++$i) { mysql_query("INSERT INTO users (name) VALUES ('Jonathan H. Wage')", $link); } $e = microtime(true); echo $e - $s; 53 Zend Framework 1 + Doctrine 2
  • 54. Which is faster? • The one using no ORM, and no abstraction at all? • Or the one using the Doctrine ORM? 54 Zend Framework 1 + Doctrine 2
  • 55. Which is faster? • The one using no ORM, and no abstraction at all? • Or the one using the Doctrine ORM? Doctrine2 0.0094 seconds mysql_query 0.0165 seconds • Doctrine2 wins! How? 55 Zend Framework 1 + Doctrine 2
  • 56. Not Faster • Doctrine just automatically performed the inserts inside one transaction. Here is the code updated to use transactions: $s = microtime(true); mysql_query('START TRANSACTION', $link); for ($i = 0; $i < 20; ++$i) { mysql_query("INSERT INTO users (name) VALUES ('Jonathan H. Wage')", $link); } mysql_query('COMMIT', $link); $e = microtime(true); echo $e - $s; 56 Zend Framework 1 + Doctrine 2
  • 57. Much Faster • Transactions matter and can affect performance greater than any code optimization! Doctrine2 0.0094 seconds 0.0028 mysql_query 0.0165 seconds 57 Zend Framework 1 + Doctrine 2
  • 58. Locking Support • Optimistic locking with integer: class User { // ... /** @Version @Column(type="integer") */ private $version; // ... } 58 Zend Framework 1 + Doctrine 2
  • 59. Locking Support • Optimistic locking with timestamp: class User { // ... /** @Version @Column(type="datetime") */ private $version; // ... } 59 Zend Framework 1 + Doctrine 2
  • 60. Locking Support • Verify version when finding: use DoctrineDBALLockMode; use DoctrineORMOptimisticLockException; $theEntityId = 1; $expectedVersion = 184; try { $entity = $em->find('User', $theEntityId, LockMode::OPTIMISTIC, $expectedVersion); // do the work $em->flush(); } catch(OptimisticLockException $e) { echo "Sorry, but someone else has already changed this entity. Please apply the changes again!"; } 60 Zend Framework 1 + Doctrine 2
  • 61. Locking Support • Example implementation: $post = $em->find('BlogPost', 123456); echo '<input type="hidden" name="id" value="' . $post->getId() . '" />'; echo '<input type="hidden" name="version" value="' . $post->getCurrentVersion() . '" />'; $postId = (int) $_GET['id']; $postVersion = (int) $_GET['version']; $post = $em->find('BlogPost', $postId, DoctrineDBALLockMode::OPTIMISTIC, $postVersion); 61 Zend Framework 1 + Doctrine 2
  • 62. DQL Doctrine Query Language 62 Zend Framework 1 + Doctrine 2
  • 63. DQL • DQL stands for Doctrine Query Language and is an Object Query Language derivate that is very similar to the Hibernate Query Language (HQL) or the Java Persistence Query Language (JPQL). • DQL provides powerful querying capabilities over your object model. Imagine all your objects lying around in some storage (like an object database). When writing DQL queries, think about querying that storage to find a certain subset of your objects. 63 Zend Framework 1 + Doctrine 2
  • 64. DQL Parser • Parser completely re-written from scratch • Parsed by top down recursive descent lexer parser that constructs an AST(Abstract Syntax Tree) • Platform specific SQL is generated from AST 64 Zend Framework 1 + Doctrine 2
  • 65. Doctrine Query Language $q = $em->createQuery('SELECT u FROM User u'); $users = $q->execute(); 65 Zend Framework 1 + Doctrine 2
  • 66. Query Builder • Same query built using the QueryBuilder $qb = $em->createQueryBuilder() ->select('u') ->from('User', 'u'); $q = $qb->getQuery(); $users = $q->execute(); 66 Zend Framework 1 + Doctrine 2
  • 67. More Examples $query = $em->createQuery( 'SELECT u, g, FROM User u ' . 'LEFT JOIN u.Groups g ' . 'ORDER BY u.name ASC, g.name ASC' ); $users = $query->execute(); $qb = $em->createQueryBuilder() ->select('u, g') ->from('User', 'u') ->leftJoin('u.Groups', 'g') ->orderBy('u.name', 'ASC') ->addOrderBy('g.name', 'ASC'); $query = $qb->getQuery(); 67 Zend Framework 1 + Doctrine 2
  • 68. Executing Queries • Executing and getting results $users = $query->execute(); foreach ($users as $user) { // ... foreach ($user->getGroups() as $group) { // ... } } 68 Zend Framework 1 + Doctrine 2
  • 69. Executing Queries • Execute query and iterate over results keeping memory usage low: foreach ($query->iterate() as $user) { // ... foreach ($user->getGroups() as $group) { // ... } } 69 Zend Framework 1 + Doctrine 2
  • 70. Result Cache • Optionally cache the results of your queries in your driver of choice: $cacheDriver = new DoctrineCommonCacheApcCache(); $config->setResultCacheImpl($cacheDriver); $query = $em->createQuery('select u from EntitiesUser u'); $query->useResultCache(true, 3600, 'my_query_name'); $users = $query->execute(); $users = $query->execute(); // 2nd time pulls from cache 70 Zend Framework 1 + Doctrine 2
  • 71. Inheritance • Doctrine supports mapping entities that use inheritance with the following strategies:  Mapped Superclass  Single Table Inheritance  Class Table Inheritance 71 Zend Framework 1 + Doctrine 2
  • 72. Mapped Superclasses /** @MappedSuperclass */ abstract class MappedSuperclassBase { /** @Column(type="integer") */ private $mapped1; /** @Column(type="string") */ private $mapped2; /** * @OneToOne(targetEntity="MappedSuperclassRelated1") * @JoinColumn(name="related1_id", referencedColumnName="id") */ private $mappedRelated1; // ... more fields and methods } /** @Entity */ class EntitySubClass extends MappedSuperclassBase { /** @Id @Column(type="integer") */ private $id; /** @Column(type="string") */ private $name; // ... more fields and methods } 72 Zend Framework 1 + Doctrine 2
  • 73. Single Table Inheritance /** * @Entity * @InheritanceType("SINGLE_TABLE") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"}) */ class Person { // ... } /** * @Entity */ class Employee extends Person { // ... } 73 Zend Framework 1 + Doctrine 2
  • 74. Single Table Inheritance • All entities share one table. • To distinguish which row represents which type in the hierarchy a so-called discriminator column is used. 74 Zend Framework 1 + Doctrine 2
  • 75. Class Table Inheritance /** * @Entity * @InheritanceType("JOINED") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"}) */ class Person { // ... } /** @Entity */ class Employee extends Person { // ... } 75 Zend Framework 1 + Doctrine 2
  • 76. Class Table Inheritance • Each class in a hierarchy is mapped to several tables: its own table and the tables of all parent classes. • The table of a child class is linked to the table of a parent class through a foreign key constraint. • A discriminator column is used in the topmost table of the hierarchy because this is the easiest way to achieve polymorphic queries. 76 Zend Framework 1 + Doctrine 2
  • 77. Bulk Inserts with Domain • Insert 10000 objects batches of 20: $batchSize = 20; for ($i = 1; $i <= 10000; ++$i) { $user = new User; $user->setStatus('user'); $user->setUsername('user' . $i); $user->setName('Mr.Smith-' . $i); $em->persist($user); if ($i % $batchSize == 0) { $em->flush(); $em->clear(); // Detaches all objects from Doctrine! } } 77 Zend Framework 1 + Doctrine 2
  • 78. Bulk Update with DQL $q = $em->createQuery('update Manager m set m.salary = m.salary * 0.9'); $numUpdated = $q->execute(); 78 Zend Framework 1 + Doctrine 2
  • 79. Bulk Update with Domain • Update objects in batches of 20: $batchSize = 20; $i = 0; $q = $em->createQuery('select u from User u'); $iterableResult = $q->iterate(); foreach($iterableResult AS $row) { $user = $row[0]; $user->increaseCredit(); $user->calculateNewBonuses(); if (($i % $batchSize) == 0) { $em->flush(); // Executes all updates. $em->clear(); // Detaches all objects from Doctrine! } ++$i; } 79 Zend Framework 1 + Doctrine 2
  • 80. Bulk Delete with DQL $q = $em->createQuery('delete from Manager m where m.salary > 100000'); $numDeleted = $q->execute(); 80 Zend Framework 1 + Doctrine 2
  • 81. Bulk Delete with Domain $batchSize = 20; $i = 0; $q = $em->createQuery('select u from User u'); $iterableResult = $q->iterate(); while (($row = $iterableResult->next()) !== false) { $em->remove($row[0]); if (($i % $batchSize) == 0) { $em->flush(); // Executes all deletions. $em->clear(); // Detaches all objects from Doctrine! } ++$i; } 81 Zend Framework 1 + Doctrine 2
  • 82. Events •Doctrine triggers events throughout the •lifecycle of objects it manages:  preRemove  postRemove  prePersist  postPersist  preUpdate  postUpdate  preLoad  postLoad 82 Zend Framework 1 + Doctrine 2
  • 83. Example /** * @Entity * @HasLifecycleCallbacks */ class BlogPost { // ... /** @PreUpdate */ public function prePersist() { $this->createdAt = new DateTime(); } /** @PreUpdate */ public function preUpdate() { $this->updatedAt = new DateTime(); } } 83 Zend Framework 1 + Doctrine 2
  • 84. Using Raw SQL • Write a raw SQL string • Map the result set of the SQL query using a ResultSetMapping instance 84 Zend Framework 1 + Doctrine 2
  • 85. Using Raw SQL $sql = 'SELECT id, name FROM users WHERE username = ?'; $rsm = new ResultSetMapping; $rsm->addEntityResult('User', 'u'); $rsm->addFieldResult('u', 'id', 'id'); $rsm->addFieldResult('u', 'name', 'name'); $query = $this->_em->createNativeQuery($sql, $rsm); $query->setParameter(1, 'jwage'); $users = $query->getResult(); 85 Zend Framework 1 + Doctrine 2
  • 86. Why use an object mapper? 86 Zend Framework 1 + Doctrine 2
  • 87. Encapsulation Encapsulate your domain in an object oriented interface 87 Zend Framework 1 + Doctrine 2
  • 88. Maintainability The organization of your domain logic in an OO way improved maintainability 88 Zend Framework 1 + Doctrine 2
  • 89. Testability Keeping a clean OO domain model makes your business logic easily testable for improved stability 89 Zend Framework 1 + Doctrine 2
  • 90. Portability Write portable and thin application controller code and fat models. 90 Zend Framework 1 + Doctrine 2
  • 91. Demo Time 91 The Doctrine Project
  • 92. What we are going to accomplish •Start with a vanilla Zend Framework Project •Ensure all dependencies are met •Configure out application to utilize Doctrine •Create an Entity (in our library) with Annotations •Generate the Database •Generate Proxies + Repositories •Create a Controller for basic crud •Talk about what would happen next 92 Zend Framework 1 + Doctrine 2
  • 93. Where To Get The Code •http://github.com/ralphschindler/NOLASnowball Self contained Project Branches: •master - Clean ZF Project, with ZF embedded in library/ folder •non-model-artifacts - Authentication service, Login form •doctrine2-managed – Has following libraries: Doctrine2, Symfony (Copied into library), Bisna (ZF1 + Doctrine2 Integration library) – Has the following entity created: NOLASnowballEntityStand – Has the proper application.ini settings – Has scripts/doctrine.php setup for easy use •doctrine2-managed-crud – Created Stand Controller, actions are complete, view scripts complete – Proxies & Repositories are generated – Assumes you’ve generated the SQL (locally would need to change db credentials) 93 Zend Framework 1 + Doctrine 2
  • 94. Lets look at code! •Demo time 94 Zend Framework 1 + Doctrine 2
  • 95. Exercises and Things To Implement •flush() could be a postDispatch() function call •All interaction with Entities could be moved into a Service Layer Once such implementation: https://github.com/guilhermeblanco/ ZF1-Doctrine2-ServiceLayer •Add relationships, and alter forms accordingly 95 Zend Framework 1 + Doctrine 2
  • 96. Recommended Reading •Doctrine Website & Manual (Also has download) http://www.doctrine-project.org/ •Zend Framework Web & Manual (With download) http://framework.zend.com/ •Ralph Schindler’s Sample Application https://github.com/ralphschindler/NOLASnowball •Guilherme Blanco’s ZF1 + D2 Integration code https://github.com/guilhermeblanco/ZendFramework1-Doctrine2 96 Zend Framework 1 + Doctrine 2
  • 97. Questions? •Q & A Time 97 Zend Framework 1 + Doctrine 2