The sfDoctrine FAQ
- The sfDoctrine FAQ
- FAQ
- Installation
- Troubleshooting
- Examples
- I really want to override the set and get methods. How do I do that?
- How to load data with sfDoctrine?
- When I load data, I see the same class being filled multiple times, what …
- How can I create a relation between a new object and an other ?
- How can I Implement a One-One relation in my model
- How can I set up a column aggregation inheritance with my YAML schema file …
- How can I use aggregate functions (max, min, avg, sum ...)
- How can I paginate results
- I'm getting "couldn't locate driver named mysql" when i run a doctrine …
- Why use Doctrine? What are the benefits it brings over Propel, both in …
- Using sfFeed2Plugin with Doctrine
- Snippets
sfDoctrine is a model layer replacement plugin for symfony. This plugin is an excellent alternative to Propel.
Why this FAQ ?
This FAQ is designed to help you to discover the sfDoctrine plugin more easily. If you encounter a problem during your developments with sfDoctrine, don't hesitate to check the FAQ.
Feel free to contribute
Share your experience of sfDoctrine with other symfony users ! It's nice to find a solution for a problem without destroying your brain :) ! Think about other users if you find a solution, contribute !
Requested questions
Please insert the questions you need an answer :
- How can I specify multi column unique key constraint in sfDoctrine? Please see this post for detailed description.
- Can I mix different inheritance concepts (Column Aggregation, One table per subclass, ...) in a schema ?
- Is there a way to make a deep copy of an data object ?
FAQ
Installation
How do I install the Doctrine plugin (sfDoctrinePlugin) in symfony 1.1?
See Getting Started with Doctrine (in the Symfony Cookbook).
Troubleshooting
What are the supported Doctrine types in sfDoctrine, and what are their YAML syntaxes ?
All the Doctrine types are supported by sfDoctrine. Here is the Doctrine type documentation. All types are defined with the following syntax:
values with no (or optional and omitted) length parameters
type: typename #examples: type: boolean type: string #note that omitted length params make the column default to the max db sizevalues with length parameters
type: typename(size) #examples: type: string(50) type: integer(5)enum has a special syntax:
type: enum values: [value1, value2, value3]
What is the difference between a relation name and a relation column?
In sfDoctrine there is a clear difference between the name of a relation and it's column. The column contains the id of the foreign record. The column only contains an integer (the key).
Consider the following simple example schema:
User:
table_name: user
columns:
name:
Post:
table_name: post
columns:
user_id: {foreignClass: User, foreignName: Author, localName: Articles}
There is a relation between Posts and Users. The column is user_id but the name is Author.
In the admin generator or when loading data, the difference between name and column is crucial. If you provide the user_id column in the generator.yml file it means that you want to edit the key itself, directly (not recommended). If you provide the Author name in the generator.yml file it means that you want to edit the relation itself (you get a pop-up menu).
When loading the data, this is equally important. The foreign relation is specified using the name of the relation, not the column. Here is an example:
User:
bob:
name: Bobby
Post:
goodOne:
Author: bob
In the Doctrine queries, it is not recommended either to use the relation column. Use the relation name instead, even if you need to restrict the search via ids only:
sfDoctrine::queryFrom('Post')->where('Post.Author.id = ?', bobsId)
A good rule of thumb is therefore: Never use the relation columns. Not in the generator.yml files, not in the fixture files, not in the Doctrine queries.
Why don't getState or getData don't fetch the records state or data??
This is because you cannot use the get* syntax for some reserved keywords in Doctrine. Those "keywords" are:
- up
- NullObect
- OID
- ErrorStack
- State
- Table
- Data
- Modified
- Prepared
- Iterator
- Incremented
- Last
- References
- Related
- Attribute
- TableName
- Inheritance
- EnumValues
- Listener
- Node
Why aren't my foreign keys appearing in the database?
Doctrine's foreign keys are a bit buggy at the moment, and the author has turned the default table output to just tables, with no foreign constraints (unique constraints work, however). If you wish to override this and create tables AND constraints, you can add to your sfDoctrinePlugin doctrine.yml:
export: all
other accepted values: none|constraints|tables (tables is the current doctrine default as described above: all without constraints)
Examples
I really want to override the set and get methods. How do I do that?
Ok, in some cases, it makes sense. Here is the solution:
1. /lib/model/doctrine/YourClass.class.php::
public function set($name, $value, $load = true)
{
$method = 'set'.sfInflector::camelize($name);
if(method_exists($this,$method)) {
return $this->$method($value);
}
return parent::set($name, $value, $load);
}
public function get($name, $invoke = true)
{
$method = 'get'.sfInflector::camelize($name);
if(method_exists($this,$method)) {
return $this->$method();
}
return parent::get($name, $invoke);
}
// BAD EXAMPLE (see previous section)
public function setName($v)
{
parent::set('stripped_title',myTools::stripText($v));
parent::set('name',$v);
}
Now, in that bad example, when we call set('name','example name'), we also setting stripped_title.
How to load data with sfDoctrine?
Easiest: Use symfony doctrine-load-data
symfony doctrine-load-data <<app>> <<environment>> symfony doctrine-load-data myapp prod
Note that this task doesnt create your tables. to do that, use doctrine-insert-sql (or doctrine-build-sql and insert yourself).
Alternative: Use a batch file
Such a php script is much more flexible than a command line since it allows you to choose the application, the environment, the data you want to load, which database connection to use, whether you want to delete the previous entries etc. Here is an example of such a batch script:
<?php define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/..')); define('SF_APP', 'main'); define('SF_ENVIRONMENT', 'dev'); define('SF_DEBUG', true); require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'); sfContext::getInstance(); //the below will export your doctrine tables to the db. not necessary if you've already used doctrine-insert-sql! Doctrine::export('path/to/your/app/lib/model/doctrine/generated'); $data = new sfDoctrineData(); $data->setDeleteCurrentData(true); $data->loadData(sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'fixtures', 'test');
(note: The 'test' parameter in loadData() is the name of the connection to use, not the name of the yaml file. All .yml files in your fixtures folder will be loaded sequentially.)
When I load data, I see the same class being filled multiple times, what gives ?
sfDoctrine will load data from any .yml file in the target directory. If you have test fixture that you don't want to load, rename the file to something other than .yml and it will be ignored.
How can I create a relation between a new object and an other ?
many solutions are available:
1. Working with object::
$a = new A();
$b = new B();
$a->set('RelationWithB', $b);
$a->save();
2. Working with primary keys::
// You have got B's id.
$idOfB = 256;
$a = new A();
$a->set('b_id', $idOfB);
$a->save();
How can I Implement a One-One relation in my model
It's really easy. You just have to use the 'unique' keyword in your relation option. (unique: true|false) Here's a YAML simple schema file to describe the concept.
A Person hasOne Address An Address hasOne Person
Person:
tableName: person
columns:
firstName: {columnName: first_name, type: string(60)}
lastName: {columnName: last_name, type: string(100)}
mail:
type: string(150)
unique: true
email: true
created_at: timestamp
update_at: timestamp
address_id:
type: integer(20) #without setting type you will have error "Unknown field type ''."
foreignClass: Address
foreignName: Address
localName: Person
cascadeDelete: true
unique: true
Address:
tableName: address
columns:
numberAndStreet: {columnName: number_and_street, type: string(100)}
city: {type: string(40)}
postalCode: {columnName: postal_code, type: string(10)}
created_at: timestamp
update_at: timestamp
How can I set up a column aggregation inheritance with my YAML schema file ?
It is really easy to set up a column aggregation inheritance with sfDoctrine using the power of the YAML schema file. The only thing you have to remember, is that one table will contains all the fields related to a parent class and all of its children.
You will understand with this simple example :
Person:
tableName: person
columns:
classKey: {columnName: class_key, type: integer(3)}
firstName: {columnName: first_name, type: string(100)}
lastName: {columnName: last_name, type: string(100)}
Member:
inheritance: {extends: Person, keyField: class_key, keyValue: 1}
columns:
login: {type: string(20)}
password: {type: string(32)}
Employee:
inheritance: {extends: Person, keyField: class_key, keyValue: 2}
columns:
employeeSince: {columnName: employee_since, type: timestamp}
Customer:
inheritance: {extends: Member, keyField: class_key, keyValue: 3}
columns:
company: {type: string(60)}
Notice that:
- You must only set the parent class's tableName, because all the children's fields will be placed in the person table.
- The keyField is not automatically generated for the parent class.
- The table used to implement this model in your RDBMS will contain the following fields
- class_key
- first_name
- last_name
- login
- password
- employee_since
- company
NOTE: the table creation is broken when you do column aggregation inheritance. Temporary fix it to add the child columns to the parent table definition. You can also put off the table creation and create you relational model on your own with your favorite RDBMS manager.
How can I use aggregate functions (max, min, avg, sum ...)
This is quite simple... but I can't find any documentation about it, I hope it'll be usefull for you.
Get the current connection and make a query in DQL syntax :
<?php sfDoctrine::connection()->query(" SELECT MAX(s.version), s.* FROM SomeClass s WHERE s.document_id = ? AND s.culture = ?", array($document_id, $culture));
This query return a Doctrine_Collection object, to get the max version of your collection, just add that :
<?php ->getFirst()->max
NOTE : this isn't a mistake, there is no brackets after max
How can I paginate results
A beginners-guide regarding sfDoctrinePager is available at sfDoctrinePager
I'm getting "couldn't locate driver named mysql" when i run a doctrine task or batch from the command line, but doctrine works in browser. What gives?
Odds are that your php.ini file for your CLI (often different from the apache php.ini) doesnt have pdo_mysql enabled. Enable it :)
Why use Doctrine? What are the benefits it brings over Propel, both in general and to symfony users?
The two ORM's are compared at ComparingPropelAndDoctrine.
Using sfFeed2Plugin with Doctrine
Make sure you set generate_accessors: true in your doctrine schema.yml so that autogenerating feed fields from object methods works.
Snippets
All snippets should be created in symfony snippets. Here are the current doctrine snippets.

