Doctrine controls configuration of features and functionality using attributes. In this section we will discuss how to set and get attributes as well as an overview of what attributes exist for you to use to control Doctrine functionality.
Doctrine has a three-level configuration structure. You can set configuration attributes at a global, connection and table level. If the same attribute is set on both lower level and upper level, the uppermost attribute will always be used. So for example if a user first sets default fetchmode in global level to Doctrine_Core::FETCH_BATCH and then sets a table fetchmode to Doctrine_Core::FETCH_LAZY, the lazy fetching strategy will be used whenever the records of that table are being fetched.
In the following example we set an attribute at the global level:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL);
In the next example above we override the global attribute on given connection:
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_NONE);
In the last example we override once again the connection level attribute in the table level:
// bootstrap.php
// ...
$table = Doctrine_Core::getTable('User');
$table->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL);
We haven't introduced the above used Doctrine_Core::getTable() method. You will learn more about the table objects used in Doctrine in the Table section of the next chapter.
Doctrine has a few specific attributes available that allow you to specify the default values of things that in the past were hardcoded values. Such as default column length, default column type, etc.
It is possible to specify an array of default options to be used on every column in your model.
// bootstrap.php
// ...
$manager->setAttribute(Doctrine::ATTR_DEFAULT_COLUMN_OPTIONS,
array('type' => 'string', 'length' => 255, 'notnull' => true));
You can customize the properties of the automatically added primary key in Doctrine models.
$manager->setAttribute(Doctrine::ATTR_DEFAULT_IDENTIFIER_OPTIONS,
array('name' => '%s_id', 'type' => 'string', 'length' => 16));
The %s string in the name is replaced with the table name.
Each database management system (DBMS) has it's own behaviors. For example, some databases capitalize field names in their output, some lowercase them, while others leave them alone. These quirks make it difficult to port your applications over to another database type. Doctrine strives to overcome these differences so your applications can switch between DBMS's without any changes. For example switching from sqlite to mysql.
The portability modes are bitwised, so they can be combined using | and removed using ^. See the examples section below on how to do this.
You can read more about the bitwise operators on the PHP website.
Below is a list of all the available portability attributes and the description of what each one does:
| Name | Description |
|---|---|
| PORTABILITY_ALL | Turn on all portability features. This is the default setting. |
| PORTABILITY_DELETE_COUNT | Force reporting the number of rows deleted. Some DBMS's don't count the number of rows deleted when performingsimple DELETE FROM tablename queries. This mode tricks such DBMS's into telling the count by adding WHERE 1=1 to the end of DELETE queries. |
| PORTABILITY_EMPTY_TO_NULL | Convert empty strings values to null in data in and output. Needed because Oracle considers empty strings to be null, while most other DBMS's know the difference between empty and null. |
| PORTABILITY_ERRORS | Makes certain error messages in certain drivers compatible with those from other DBMS's |
| PORTABILITY_FIX_ASSOC_FIELD_NAMES | This removes any qualifiers from keys in associative fetches. Some RDBMS, like for example SQLite, will by default use the fully qualified name for a column in assoc fetches if it is qualified in a query. |
| PORTABILITY_FIX_CASE | Convert names of tables and fields to lower or upper case in all methods. The case depends on the field_case option that may be set to either CASE_LOWER (default) or CASE_UPPER |
| PORTABILITY_NONE | Turn off all portability features. |
| PORTABILITY_NUMROWS | Enable hack that makes numRows() work in Oracle. |
| PORTABILITY_EXPR | Makes DQL API throw exceptions when non-portable expressions are being used. |
| PORTABILITY_RTRIM | Right trim the data output for all data fetches. This does not applied in drivers for RDBMS that automatically right trim values of fixed length character values, even if they do not right trim value of variable length character values. |
Now we can use the setAttribute() method to enable portability for lowercasing and trimming with the following code:
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_PORTABILITY,
Doctrine_Core::PORTABILITY_FIX_CASE | Doctrine_Core::PORTABILITY_RTRIM);
Enable all portability options except trimming
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_PORTABILITY,
Doctrine_Core::PORTABILITY_ALL ^ Doctrine_Core::PORTABILITY_RTRIM);
You can quote the db identifiers (table and field names) with quoteIdentifier(). The delimiting style depends on which database driver is being used.
Just because you CAN use delimited identifiers, it doesn't mean you SHOULD use them. In general, they end up causing way more problems than they solve. Anyway, it may be necessary when you have a reserved word as a field name (in this case, we suggest you to change it, if you can).
Some of the internal Doctrine methods generate queries. Enabling the quote_identifier attribute of Doctrine you can tell Doctrine to quote the identifiers in these generated queries. For all user supplied queries this option is irrelevant.
Portability is broken by using the following characters inside delimited identifiers:
| Name | Character | Driver |
|---|---|---|
| backtick | ` | MySQL |
| double quote | " | Oracle |
| brackets | [ or ] | Access |
Delimited identifiers are known to generally work correctly under the following drivers: Mssql, Mysql, Oracle, Pgsql, Sqlite and Firebird.
When using the Doctrine_Core::ATTR_QUOTE_IDENTIFIER option, all of the field identifiers will be automatically quoted in the resulting SQL statements:
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_QUOTE_IDENTIFIER, true);
Will result in a SQL statement that all the field names are quoted with the backtick '`' operator (in MySQL).
SELECT
*
FROM sometable
WHERE `id` = '123'
As opposed to:
SELECT
*
FROM sometable
WHERE id = '123'
By default Doctrine is configured to overwrite any local changes you have on your objects if you were to query for some objects which have already been queried for and modified.
$user = Doctrine_Core::getTable('User')->find(1);
$user->username = 'newusername';
Now I have modified the above object and if I were to query for the same data again, my local changes would be overwritten.
$user = Doctrine_Core::getTable('User')->find(1);
echo $user->username; // would output original username in database
You can disable this behavior by using the ATTR_HYDRATE_OVERWRITE attribute:
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_HYDRATE_OVERWRITE, false);
Now if were to run the same test we ran above, the modified username would not be overwritten.
If you want to configure the class to be returned when using the Doctrine_Core::getTable()
method you can set the ATTR_TABLE_CLASS attribute. The only requirement is that
the class extends Doctrine_Table.
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_TABLE_CLASS, 'MyTableClass');
Now the MyTableClass would look like the following:
class MyTableClass extends Doctrine_Table
{
public function myMethod()
{
// run some query and return the results
}
}
Now when you do the following it will return an instance of MyTableClass:
$user = $conn->getTable('MyModel')->myMethod();
If you want to customize the table class even further you can customize it for each
model. Just create a class named MyModelTable and make sure it is able to be
autoloaded.
class MyModelTable extends MyTableClass
{
public function anotherMethod()
{
// run some query and return the results
}
}
Now when I execute the following code it will return an instance of MyModelTable:
echo get_class($conn->getTable('MyModel')); // MyModelTable
If you would like to configure the base query class returned when you create
new query instances, you can use the ATTR_QUERY_CLASS attribute. The only
requirement is that it extends the Doctrine_Query class.
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_QUERY_CLASS, 'MyQueryClass');
The MyQueryClass would look like the following:
class MyQueryClass extends Doctrine_Query
{
}
Now when you create a new query it will return an instance of MyQueryClass:
$q = Doctrine_Core::getTable('User')
->createQuery('u');
echo get_class($q); // MyQueryClass
Since you can configure the base query and table class, it would only make sense that you can also customize the collection class Doctrine should use. We just need to set the ATTR_COLLECTION_CLASS attribute.
// bootstrap.php
// ...
$conn->setAttribute(Doctrine_Core::ATTR_COLLECTION_CLASS, 'MyCollectionClass');
The only requirement of the MyCollectionClass is that it must extend Doctrine_Collection:
$phonenumbers = $user->Phonenumber;
echo get_class($phonenumbers); // MyCollectionClass
You can optionally disable the cascading save operations which are enabled by default for convenience with the ATTR_CASCADE_SAVES attribute. If you set this attribute to false it will only cascade and save if the record is dirty. This means that you can't cascade and save records who are dirty that are more than one level deep in the hierarchy, but you benefit with a significant performance
improvement.
$conn->setAttribute(Doctrine_Core::ATTR_CASCADE_SAVES, false);
The export attribute is used for telling Doctrine what it should export when exporting classes to your database for creating your tables.
If you don't want to export anything when exporting you can use:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT, Doctrine_Core::EXPORT_NONE);
For exporting tables only (but not constraints) you can use on of the following:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT, Doctrine_Core::EXPORT_TABLES);
You can also use the following syntax as it is the same as the above:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT,
Doctrine_Core::EXPORT_ALL ^ Doctrine_Core::EXPORT_CONSTRAINTS);
For exporting everything (tables and constraints) you can use:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT, Doctrine_Core::EXPORT_ALL);
Naming convention attributes affect the naming of different database related elements such as tables, indexes and sequences. Basically every naming convention attribute has affect in both ways. When importing schemas from the database to classes and when exporting classes into database tables.
So for example by default Doctrine naming convention for indexes is %s_idx. Not only do the indexes you set get a special suffix, also the imported classes get their indexes mapped to their non-suffixed equivalents. This applies to all naming convention attributes.
Doctrine_Core::ATTR_IDXNAME_FORMAT can be used for changing the naming convention of indexes. By default Doctrine uses the format [name]_idx. So defining an index called 'ageindex' will actually be converted into 'ageindex_idx'.
You can change the index naming convention with the following code:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_IDXNAME_FORMAT, '%s_index');
Similar to Doctrine_Core::ATTR_IDXNAME_FORMAT, Doctrine_Core::ATTR_SEQNAME_FORMAT can be used for changing the naming convention of sequences. By default Doctrine uses the format [name]_seq, hence creating a new sequence with the name of mysequence will lead into creation of sequence called mysequence_seq.
You can change the sequence naming convention with the following code:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_SEQNAME_FORMAT, '%s_sequence');
The table name format can be changed the same as the index and sequence name format with the following code:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_TBLNAME_FORMAT, '%s_table');
The database name format can be changed the same as the index, sequence and table name format with the following code:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_DBNAME_FORMAT, 'myframework_%s');
Doctrine provides complete control over what it validates. The validation procedure can be controlled with Doctrine_Core::ATTR_VALIDATE.
The validation modes are bitwised, so they can be combined using | and removed using ^. See the examples section below on how to do this.
| Name | Description |
|---|---|
| VALIDATE_NONE | Turns off the whole validation procedure. |
| VALIDATE_LENGTHS | Makes Doctrine validate all field lengths. |
| VALIDATE_TYPES | Makes Doctrine validate all field types. Doctrine does loose type validation. This means that for example string with value '13.3' will not pass as an integer but '13' will. |
| VALIDATE_CONSTRAINTS | Makes Doctrine validate all field constraints such as notnull, email etc. |
| VALIDATE_ALL | Turns on all validations. |
Validation by default is turned off so if you wish for your data to be validated you will need to enable it. Some examples of how to change this configuration are provided below.
You can turn on all validations by using the Doctrine_Core::VALIDATE_ALL attribute with the following code:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL);
You can also configure Doctrine to validate lengths and types, but not constraints with the following code:
// bootstrap.php
// ...
$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE,
Doctrine_Core::VALIDATE_LENGTHS | Doctrine_Core::VALIDATE_TYPES);
Now we have gone over some of the most common attributes used to configure Doctrine. Some of these attributes may not apply to you ever or you may not understand what you could use them for now. As you read the next chapters you will see which attributes you do and don't need to use and things will begin to make more sense.
If you saw some attributes you wanted to change the value above, then you should have added it to your bootstrap.php file and it should look something like the following now:
/**
* Bootstrap Doctrine.php, register autoloader and specify
* configuration attributes
*/
require_once('../doctrine/branches/1.2/lib/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));
$manager = Doctrine_Manager::getInstance();
$conn = Doctrine_Manager::connection('sqlite::memory:', 'doctrine');
$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL);
$manager->setAttribute(Doctrine_Core::ATTR_EXPORT, Doctrine_Core::EXPORT_ALL);
$manager->setAttribute(Doctrine_Core::ATTR_MODEL_LOADING, Doctrine_Core::MODEL_LOADING_CONSERVATIVE);
Now we are ready to move on to the next chapter where we will learn everything there is to know about Doctrine Connections.