Symfony and Doctrine 2
Doctrine 2 requires PHP 5.3 so you must have this version in order to follow and test this article.
Today I am happy to tell you that this version of sfDoctrinePlugin
is now available
and ready for you to use. This article will give you a little information about
how you can get started using it today!
Installing
First we need to install the plugin from SVN with the following command from the root of your project:
$ svn co http://svn.symfony-project.org/plugins/sfDoctrinePlugin/branches/1.3-2.0/ plugins/sfDoctrine2Plugin
Now you just need to enable the plugin:
class ProjectConfiguration extends sfProjectConfiguration { public function setup() { $this->enablePlugins('sfDoctrine2Plugin'); } }
Configuring Database Connections
Open your config/databases.yml
and configure it for your database connection:
all: doctrine: class: sfDoctrineDatabase param: options: driver: pdo_mysql user: root password: dbname: doctrine
The DSN(data source name) no longer exists in Doctrine 2. Connection information is much simpler and just supplied as an array of information. You are required to at least specify a
driver
and the remaining options that are available and required are determined by the driver.
Configuring Your Schema
You can configure your schema much in the same way you always have in config/doctrine
.
The syntax of the schema files are much different now though. Below is an example
of a simple User
entity:
# config/doctrine/schema.yml Models\User: type: entity table: user id: id: type: integer generator: strategy: AUTO fields: username: type: string length: 255 password: type: string length: 255
Writing Data Fixtures
The times of using YAML for data fixtures is no longer. Instead, you are only required to use plain PHP for loading your data fixtures.
// data/fixtures/fixtures.php $em = $this->getEntityManager(); $admin = new \Models\User(); $admin->username = 'admin'; $admin->password = 'changeme';
Building Doctrine
Now you're ready to build everything. The following command will build models, forms, filters, database and load data fixtures.
$ php symfony doctrine:build --all --and-load
Updating Schema
If you change your schema mapping information and want to update the database you can easily do so by running the following command after changing your mapping information.
$ php symfony doctrine:build --all-classes --and-update-schema
Doctrine 2 In Action
So now that you have everything setup and running lets explore some of the way Doctrine 2 works and how it is integrated with Symfony.
Custom Repository Class
The EntityRepository
class is basically what Doctrine_Table
is in Doctrine 1.
Instead of it being magical and automatic, you simply need to configure your entity
mapping information to use a repository class.
Models\User: type: entity table: user repositoryClass: UserRepository # ...
Now define a UserRepository
class somewhere that Symfony can autoload it.
class UserRepository extends EntityRepository { public function getActiveUsers() { $qb = $this->createQueryBuilder('u'); $q = $qb->getQuery(); return $q->execute(); } }
Now you can use this method like the following:
public function executeIndex() { // ... $repository = $em->getRepository('Models\User'); $users = $repository->getActiveUsers(); }
When using Doctrine 2 with Symfony, our entities extend a base class so we have some additional possibilities. You can access the repository methods via static calls, similar to how it is done in Ruby on Rails Active Record.
$users = \Models\User::getActiveUsers();
You also have the same type of built in finders as you do in Doctrine 1.
$user = \Models\User::find(1); $user = \Models\User::findOneByUsername('jwage');
Entity Manager from Actions
When you are in a Symfony action you can retrieve an entity manager instance by
using the getEntityManager()
method.
public function executeIndex() { $em = $this->getEntityManager(); $user = new \Models\User(); $user->username = 'jwage'; $user->password = 'changeme'; $user->save(); $em->flush(); }
By default the method returns the entity manager for the last configured database
inside databases.yml
. You can optionally give an argument for which entity manager
to get.
public function executeIndex() { $em = $this->getEntityManager('conn_name'); // ... }
That is all for now!
This article can't possibly explain everything new about Doctrine 2 so it is recommended that you start reading the documentation on Doctrine 2 from the Doctrine website.
Help the Symfony project!
As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.
Comments
Comments are closed.
To ensure that comments stay relevant, they are closed for old posts.
Thanks a lot:-D
Excellent jobs guys!
Using php objects means more chars to type or worse copy and paste.
$admin = new \Models\User();
$admin->username = 'admin';
$admin->password = 'changeme';
$admin->email = 'foo@bar.com';
$user = new \Models\User();
$user->username = 'user';
$user->password = 'pass';
$user->email = 'foo@bared.com';
Models\User:
admin:
username: admin
password: changeme
email: foo@bar.com
user:
username: user
password: pass
email: foo@bared.com
Took me about 2 seconds to write the YAML and much longer to copy and paste and make the changes to the PHP.
One thing I notice when I have tried using Python and Django is the power of writing less. Means you get to the important stuff quicker.
Please please please don't get rid of YML for fixtures...
$users = \Models\User::getActiveUsers();
I doubt it because the methods are in the UserRepository class, am I right?
@Jonathan: To find out whats better (or different), please look through the doctrine 2 documentation. This is not an article about doctrine 2 but about the new sfDoctrinePlugin for doctrine 2 (you can of course use doctrine 2 with symfony without sfDoctrinePlugin).
@Chris: Agreed ;) but its not so bad once you start to make use of the flexible "use" statements. No need to write the full namespaces everywhere.
@Massimiliano: Doctrine (2) is geared towards less magic because it makes code more robust and reliable. We focus much more on less features that are much more stable, rather than the other way around. But nevertheless, doctrine 2 has a lot of features doctrine 1 can only dream of, like class table inheritance, integrated support for optimistic locking and more. Just check the docs. I cant speak for the yml fixtures, that falls under "utilities" and is not really a part of the core functionality. I'm sure Jon will answer that.
I am pretty sure in other frameworks, like rails they still allow use of yaml data fixtures but discourage it and are slowly moving away from it.
In this stage of development I need stuff to get out of my way and stop making me type so much.
YAML is brilliant for this.
But if you guys don't provide a YAML parser I'm sure me and Rich will put one together when the time comes!
Any reason you guys decided not to go with the interop naming standard that all other major 5.3 frameworks will be relying on?
https://gist.github.com/9a677147c42e5fed7d05
Creating loaders this way will do fine for most development environments. In production you'll want to use a sql drop anyway.
- Marijn
If there are any technical interoperability issues with our standard, please let me know, if its just about lower/uppercase or other cosmetical issues, sorry but no.
Don't get me wrong, the initiative is great, but it should focus on technical interoperability. The most important thing in that sense in my eyes is class loading and the requirement that the namespace+class name reflects the position of the class file in the directory structure. So that anyones autoloader can load anyone else's class files. I am so tired of each library requiring its own autoloader (symfony + symfony components included). Thats what I understand under important standards for technical interoperability.
When i use "php symfony doctrine:build-model"
I get this:
PHP Fatal error: Call to undefined method sfDoctrineConvertMappingTask::setConfiguration() in /home/tferreira/tproject/plugins/sfDoctrine2Plugin/lib/task/sfDoctrineBuildModelTask.class.php on line 79
Fatal error: Call to undefined method sfDoctrineConvertMappingTask::setConfiguration() in /home/tferreira/tproject/plugins/sfDoctrine2Plugin/lib/task/sfDoctrineBuildModelTask.class.php on line 79
Can anyone help me please? Thanks
LL\lib\plugins\sfDoctrine2Plugin\lib\task\sfDoctrineBaseTask.class.php on line 9
1
Me too.
console return:
Fatal error: Cannot redeclare class sfDoctrineBaseTask in D:\workspace\SFFULL\li
b\plugins\sfDoctrine2Plugin\lib\task\sfDoctrineBaseTask.class.php on line 91