sfDoctrinePlugin
Doctrine is a PHP ORM (object relational mapper) for PHP 5.2.3+ that sits on top of a powerful PHP DBAL (database abstraction layer). One of its key features is the ability to optionally write database queries in an OO (object oriented) SQL-dialect called DQL inspired by Hibernate's HQL. This provides developers with a powerful alternative to SQL that maintains a maximum of flexibility without requiring needless code duplication.
This symfony plugin allows you to use Doctrine as your ORM instead of Propel in your symfony projects. Below are the exact details on how to get your project converted to Doctrine.
- Wikipedia Page - http://en.wikipedia.org/wiki/Doctrine_%28PHP%29
- Documentation - http://www.phpdoctrine.org/documentation/manual
- Schema Files Chapter - http://www.phpdoctrine.org/documentation/manual/0_11/?one-page#schema-files
- Data Fixtures - http://www.phpdoctrine.org/documentation/manual/0_11/?one-page#data-fixtures
- Working with Objects - http://www.phpdoctrine.org/documentation/manual/0_11/?one-page#working-with-objects
- Migrations - http://www.phpdoctrine.org/documentation/manual/0_11/?one-page#migration
- DQL(Doctrine Query Language) - http://www.phpdoctrine.org/documentation/manual/0_11/?one-page#dql-doctrine-query-language
- Trac - http://trac.phpdoctrine.org
- Community - http://www.phpdoctrine.org/community
- Blog - http://www.phpdoctrine.org/blog
Versions
sfDoctrinePlugin is available for both symfony 1.0.x and symfony 1.1-x (work in progress).
- for Symfony 1.0.x use http://svn.symfony-project.com/plugins/sfDoctrinePlugin/branches/1.0 (uses Doctrine 0.11)
- for Symfony 1.1-x use http://svn.symfony-project.com/plugins/sfDoctrinePlugin/trunk (uses Doctrine 0.11)
Installation
The sfDoctrinePlugin can be installed only with svn currently. Use the commands below to get your symfony project running with Doctrine instead of Propel.
Create new symfony app
$ mkdir symfony_app $ cd symfony_app $ symfony new symfony_app $ symfony init-app frontend
Check out the sfDoctrinePlugin to your plugins folder
symfony 1.0.x
$ cd plugins $ svn co http://svn.symfony-project.com/plugins/sfDoctrinePlugin/branches/1.0 sfDoctrinePlugin
symfony 1.1-x
$ cd plugins $ svn co http://svn.symfony-project.com/plugins/sfDoctrinePlugin/trunk sfDoctrinePlugin
Now you must setup a few files and directories.
$ cd .. $ mkdir config/doctrine $ mkdir data/fixtures $ vi config/databases.yml
Inside of databases.yml, place the following yaml syntax.
all:
connection_name:
class: sfDoctrineDatabase
param:
dsn: mysql://root:@localhost/dbname
Now the plugin is setup and ready to go inside of your symfony application. If you run the symfony command with no arguments, it will now show you the additional command line tasks available. The commands are listed below:
$ symfony available pake tasks: clear-cache > clear cached information clear-controllers > clear controllers disable > disables an application in a given environment doctrine-build-all > Create database, generate models, insert sql doctrine-build-all-load > Create database, generate models, insert sql, and load data from fixtures. doctrine-build-all-reload > Drops database, creates database, generate models, and loads data from fixtures. doctrine-build-all-reload-test-all > Drops database, creates database, generate models, loads data from fixtures, and runs all tests. doctrine-build-db > Create database doctrine-build-model > Build all Doctrine records doctrine-build-schema > Build yaml schema from an existing database doctrine-build-sql > Export sql for doctrine schemas to data/sql doctrine-convert-schema > Convert 0.1 schema to new Doctrine schema syntax doctrine-dql > Execute dql from the command line doctrine-drop-db > Drop database doctrine-dump-data > Dump data to yaml fixtures file doctrine-generate-crud > Creates Doctrine CRUD Module doctrine-generate-migration > Generate migration class template doctrine-generate-migrations-db > Generate migration classes from databases doctrine-generate-migrations-models > Generate migration classes from models doctrine-init-admin > Initialize a new doctrine admin module doctrine-insert-sql > Insert sql for doctrine schemas in to database doctrine-load-data > Load data from yaml fixtures file doctrine-migrate > Migrate database to current version or a specified version. doctrine-rebuild-db > Drop database and rebuild it downgrade > downgrade to a previous symfony release enable > enables an application in a given environment fix-perms > fix directories permissions freeze > freeze symfony libraries init-app > initialize a new symfony application init-batch > initialize a new symfony batch script init-controller > initialize a new symfony controller script init-module > initialize a new symfony module init-project > initialize a new symfony project log-purge > purges an applications log files log-rotate > rotates an applications log files plugin-install > install a new plugin plugin-list > list installed plugins plugin-uninstall > uninstall a plugin plugin-upgrade > upgrade a plugin propel-build-all > generate propel model and sql and initialize database propel-build-all-load > generate propel model and sql and initialize database, and load data propel-build-db > create database for current model propel-build-model > create classes for current model propel-build-schema > create schema.xml from existing database propel-build-sql > create sql for current model propel-convert-xml-schema > create schema.yml from schema.xml propel-convert-yml-schema > create schema.xml from schema.yml propel-dump-data > dump data to fixtures directory propel-generate-crud > generate a new propel CRUD module propel-init-admin > initialize a new propel admin module propel-init-crud > initialize a new propel CRUD module propel-insert-sql > insert sql for current model propel-load-data > load data from fixtures directory sync > synchronise project with another machine test-all > launch all tests test-functional > launch functional tests for an application test-unit > launch unit tests unfreeze > unfreeze symfony libraries upgrade > upgrade to a new symfony release task aliases: app = pake init-app batch = pake init-batch cc = pake clear-cache controller = pake init-controller module = pake init-module new = pake init-project
Now we need to setup some schema files and some data fixtures.
Create and edit config/doctrine/schema.yml. Place the following yaml syntax in schema.yml
---
User:
columns:
id:
primary: true
autoincrement: true
type: integer(4)
username:
type: string(255)
password:
type: string(255)
relations:
Groups:
class: Group
refClass: UserGroup
foreignAlias: Users
Group:
tableName: groups
columns:
id:
primary: true
autoincrement: true
type: integer(4)
name:
type: string(255)
UserGroup:
columns:
user_id:
type: integer(4)
group_id:
type: integer(4)
relations:
User:
onDelete: CASCADE
Group:
onDelete: CASCADE
Now place the followig yaml syntax in the data/fixtures/data.yml file
---
User:
zyne:
username: zYne-
password: changeme
Groups: [founder, lead, documentation]
jwage:
username: jwage
password: changeme
Groups: [lead, documentation]
Group:
founder:
name: Founder
lead:
name: Lead
documentation:
name: Documentation
Now that your schema files and data fixtures are in place you can run a few commands to get your database setup.
$ symfony doctrine-build-model >> doctrine Generated models successfully $ symfony cc $ symfony doctrine-build-all-reload >> doctrine Are you sure you wish to drop your databases? (y/n) y >> doctrine Could not drop database for con... Unknown database 'symfony_app' >> doctrine Successfully created database f...ction_name" named "symfony_app" >> doctrine Generated models successfully >> doctrine Created tables successfully >> doctrine Data was successfully loaded
Now you can run this DQL query from the command line to see the data that was loaded in the database
$ symfony doctrine-dql "FROM User u, u.Groups g" >> doctrine executing: "FROM User u, u.Groups g" () >> doctrine - >> doctrine id: 1 >> doctrine username: zYne- >> doctrine password: changeme >> doctrine Groups: >> doctrine - >> doctrine id: 1 >> doctrine name: Founder >> doctrine - >> doctrine id: 2 >> doctrine name: Lead >> doctrine - >> doctrine id: 3 >> doctrine name: Documentation >> doctrine - >> doctrine id: 2 >> doctrine username: jwage >> doctrine password: changeme >> doctrine Groups: >> doctrine - >> doctrine id: 2 >> doctrine name: Lead >> doctrine - >> doctrine id: 3 >> doctrine name: Documentation
Example Usage
// Create new user and assign a new group
$user = new User();
$user->username = 'jwage';
$user->password = 'changeme';
$user->Groups[0]->name = 'New Group';
$user->save();
print_r($user->toArray(true)); // prints user data and all relationship data
$group = Doctrine::getTable('Group')->findOneByName('New Group'); // Find a Group record by its name
$users = $group->Users; // Get the groups users
print_r($users->toArray(true)); // Prints the users from the group
$userTable = Doctrine::getTable('User');
$user = $userTable->find(1);
$user = $userTable->findOneById(1);
$user = $userTable->findByUsername('jwage');
$user = $userTable->find(1);
$user->delete();
$query = new Doctrine_Query();
$user = $query->from('User u')->where("u.username = 'jwage'")->limit(1)->execute()->getFirst();
$query = new Doctrine_Query();
$query->delete('User')->from('User u')->where("u.username = 'jwage'")->execute();
/* Do a Transaction */
Doctrine_Manager::getInstance()->getCurrentConnection()->beginTransaction();
$user = new User();
$user->username = 'jwage';
$user->save();
$user = new User();
$user->username = 'isleshocky77';
$user->save();
// Neither have been written to the database yet
Doctrine_Manager::getInstance()->getCurrentConnection()->commit();
// Both have now been written to the database
Admin Generators
The sfDoctrinePlugin offers the ability to create admin generators powered by Doctrine, just like you can with propel. Run the commands below to setup the admin generators for the user and group models.
$ symfony doctrine-init-admin frontend users User $ symfony doctrine-init-admin frontend groups Group
Using Doctrine in Batch files
define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/..'));
define('SF_APP', 'public');
define('SF_ENVIRONMENT', 'cli');
define('SF_DEBUG', false);
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
# This is needed to initialize the db connections
sfContext::getInstance()->getDatabaseManager()->initialize();
Community
- There is an active IRC channel where users and developers of Doctrine hang out. The channel is on the Freenode network (irc.freenode.net); the channel name is #doctrine.
- User mailing list: http://groups.google.com/group/doctrine-user
- Development mailing http://groups.google.com/group/doctrine-dev
- Commit log mailing http://groups.google.com/group/doctrine-svn
Features
A praised feature of Doctrine is the low level of configuration that is needed to start a project. Doctrine can generate object classes from an existing database, and the programmer can then specify relations and add custom functionality to the generated classes. There is no need to generate or maintain complex XML database schemas, as seen in many other frameworks.
Another key feature of Doctrine is the ability to optionally write database queries in an OO (object oriented) SQL dialect called DQL (Doctrine Query Language) inspired by Hibernate's HQL. Alternatively, the Doctrine_Query class allows one to construct queries through a fluent interface. These interfaces provide developers with powerful alternatives to SQL which maintain flexibility and still allow for switching of database back-ends, without requiring any code duplication.
Writing queries explicitly however is not always necessary, as Doctrine performs joins and fetches related objects automatically. Small projects can be easily constructed without writing queries.
Other notable features of Doctrine are:
- support for hierarchical (tree-structured) data;
- support for hooks (methods which can validate or modify database input and output) and event listeners to structure business-related logic;
- column aggregation inheritance (similar objects can be stored in one database table, with one type-column specifying the subtype of the particular object - the correct subclass is always returned when a query is done);
- a caching framework, making use of several backends such as memcached, SQLite or APC;
- ACID transactions;
- model behaviors (sluggable, timestampable, nested set, internationalization, audit log, search index);
- database migrations;
- a "compile" function to combine many PHP files of the framework into one, to avoid the performance hit usually incurred by including the many PHP files of a framework.