Doctrine offers both database and application level cascading operations. This section will explain in detail how to setup both application and database level cascades.
Since it can be quite cumbersome to save and delete individual objects, especially if you deal with an object graph, Doctrine provides application-level cascading of operations.
You may already have noticed that save() operations are already cascaded to associated objects by default.
Doctrine provides a second application-level cascade style: delete. Unlike the save() cascade, the delete cascade needs to be turned on explicitly as can be seen in the following code snippet:
// models/User.php
class User extends BaseUser
{
// ...
public function setUp()
{
parent::setup();
// ...
$this->hasMany('Address as Addresses', array(
'local' => 'id',
'foreign' => 'user_id',
'cascade' => array('delete')
)
);
}
}
Here is the same example in YAML format. You can read more about YAML in the YAML Schema Files chapter:
---
# schema.yml
# ...
User:
# ...
relations:
# ...
Addresses:
class: Address
local: id
foreign: user_id
cascade: [delete]
The cascade option is used to specify the operations that are cascaded to the related objects on the application-level.
Please note that the only currently supported value is delete, more options will be added in future releases of Doctrine.
In the example above, Doctrine would cascade the deletion of a User to it's associated Addresses. The following describes the generic procedure when you delete a record through $record->delete():
1. Doctrine looks at the relations to see if there are any deletion cascades it needs to apply. If there are no deletion cascades, go to 3).
2. For each relation that has a delete cascade specified, Doctrine verifies that the objects that are the target of the cascade are loaded. That usually means that Doctrine fetches the related objects from the database if they're not yet loaded.(Exception: many-valued associations are always re-fetched from the database, to make sure all objects are loaded). For each associated object, proceed with step 1).
3. Doctrine orders all deletions and executes them in the most efficient way, maintaining referential integrity.
From this description one thing should be instantly clear: Application-level cascades happen on the object-level, meaning operations are cascaded from one object to another and in order to do that the participating objects need to be available.
This has some important implications:
Some cascading operations can be done much more efficiently at the database level. The best example is the delete cascade.
Database-level delete cascades are generally preferrable over application-level delete cascades except:
Database-level delete cascades are applied on the foreign key constraint. Therefore they're specified on that side of the relation that owns the foreign key. Picking up the example from above, the definition of a database-level cascade would look as follows:
// models/Address.php
class Address extends Doctrine_Record
{
public function setTableDefinition()
{
$this->hasColumn('user_id', 'integer');
$this->hasColumn('address', 'string', 255);
$this->hasColumn('country', 'string', 255);
$this->hasColumn('city', 'string', 255);
$this->hasColumn('state', 'string', 2);
$this->hasColumn('postal_code', 'string', 25);
}
public function setUp()
{
$this->hasOne('User', array(
'local' => 'user_id',
'foreign' => 'id',
'onDelete' => 'CASCADE'
)
);
}
}
Here is the same example in YAML format. You can read more about YAML in the YAML Schema Files chapter:
---
# schema.yml
# ...
Address:
columns:
user_id: integer
address: string(255)
country: string(255)
city: string(255)
state: string(2)
postal_code: string(25)
relations:
User:
local: user_id
foreign: id
onDelete: CASCADE
The onDelete option is translated to proper DDL/DML statements when Doctrine creates your tables.
Note that 'onDelete' => 'CASCADE' is specified on the Address class, since the Address owns the foreign key (user_id) and database-level cascades are applied on the foreign key.
Currently, the only two supported database-level cascade styles are for onDelete and onUpdate. Both are specified on the side that owns the foreign key and applied to your database schema when Doctrine creates your tables.