<commit_before>++ Introduction

In Doctrine all record relations are being set with {{hasMany}}, {{hasOne}} methods. Doctrine supports almost all kinds of database relations from simple one-to-one foreign key relations to join table self-referencing relations.

Unlike the column definitions the {{hasMany}} and {{hasOne}} methods are placed within a method called setUp(). Both methods take two arguments: the first argument is a string containing the name of the class and optional alias, the second argument is an array consisting of relation options. The option array contains the following keys:

* **local**, the local field of the relation. Local field is the linked field or fields in the defining class.
* **foreign**, the foreign field of the relation. Foreign field is the linked field or fields in the linked class.
* **refClass**, the name of the reference / join class. This is needed for many-to-many associations.
* **onDelete**, the onDelete integrity action.
* **onUpdate**, the onUpdate integrity action.

So lets take our first example, say we have two classes Forum_Board and Forum_Thread. Here Forum_Board has many Forum_Threads, hence their relation is one-to-many. We don't want to write Forum_ when accessing relations, so we use relation aliases.

First lets take a look at the Forum_Board class. It has three columns: name, description and since we didn't specify any primary key, Doctrine auto-creates an id column for it.

We define the relation to the Forum_Thread class by using the hasMany() method. Here the local field is the primary key of the board class whereas the foreign field is the board_id field of the Forum_Thread class.

<code type="php">
class Forum_Board extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->hasColumn('name', 'string', 100);
        $this->hasColumn('description', 'string', 5000);
    }
    public function setUp()
    {
        // notice the 'as' keyword here
        $this->hasMany('Forum_Thread as Threads', array('local' => 'id',
                                                        'foreign' => 'board_id');
    }
}
</code>

Then lets have a peek at the Forum_Thread class. The columns here are irrelevant, but pay attention to how we define the relation. Since each Thread can have only one Board we are using the hasOne() method. Also notice how we once again use aliases and how the local column here is board_id while the foreign column is the id column.

<code type="php">
class Forum_Thread extends Doctrine_Record
{
    public function setTableDefinition() 
    {
        $this->hasColumn('board_id', 'integer', 10);
        $this->hasColumn('title', 'string', 200);
        $this->hasColumn('updated', 'integer', 10);
        $this->hasColumn('closed', 'integer', 1);
    }
    public function setUp() 
    {
        // notice the 'as' keyword here
        $this->hasOne('Forum_Board as Board', array('local' => 'board_id',
                                                    'foreign' => 'id');
    }
}
</code>

Now we can start using these classes. The same accessors that you've already used for properties are all availible for relations.

<code type="php">
// first create a board
$board = new Forum_Board();
$board->name = 'Some board';

// lets create a new thread
$board->Thread[0]->title = 'new thread';

// save the changes 
$board->save();
</code>

++ Foreign key associations
+++ One-To-One

One-to-one relations are propably the most basic relations. In the following example we have two classes, User and Email with their relation being one-to-one. 

First lets take a look at the Email class. Since we are binding a one-to-one relationship we are using the hasOne() method. Notice how we define the foreign key column (user_id) in the Email class. This is due to a fact that Email is owned by the User class and not the other way around. In fact you should always follow this convention - always place the foreign key in the owned class.

The recommended naming convention for foreign key columns is: [tableName]_[primaryKey]. As here the foreign table is 'user' and its primary key is 'id' we have named the foreign key column as 'user_id'.

<code type="php">
class Email extends Doctrine_Record 
{
    public function setTableDefinition() 
    {
        $this->hasColumn('user_id', 'integer');
        $this->hasColumn('address', 'string', 150);
    }
    public function setUp()
    {
        $this->hasOne('User', array('local' => 'user_id', 'foreign' => 'id'));
    }
}
</code>

The User class is very similar to the Email class. Notice how the local and foreign columns are switched in the hasOne() definition compared to the definition of the Email class.

<code type="php">
class User extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->hasColumn('name', 'string',50);
        $this->hasColumn('loginname', 'string',20);
        $this->hasColumn('password', 'string',16);
    }
    public function setUp()
    {
        $this->hasOne('Email', array('local' => 'id', 'foreign' => 'user_id'));
    }
}
</code>


+++ One-to-Many, Many-to-One

One-to-Many and Many-to-One relations are very similar to One-to-One relations. The recommended conventions you came in terms with in the previous chapter also apply to one-to-many and many-to-one relations.

In the following example we have two classes: User and Phonenumber. We define their relation as one-to-many (a user can have many phonenumbers). Here once again the Phonenumber is clearly owned by the User so we place the foreign key in the Phonenumber class.

<code type="php">
class User extends Doctrine_Record 
{
    public function setUp()
    {
        $this->hasMany('Phonenumber', array('local' => 'id', 'foreign' => 'user_id'));
    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 50);
        $this->hasColumn('loginname', 'string', 20);
        $this->hasColumn('password', 'string', 16);
    }
}
class Phonenumber extends Doctrine_Record 
{
    public function setTableDefinition() 
    {
        $this->hasColumn('phonenumber', 'string', 50);
        $this->hasColumn('user_id', 'integer');
    }
}
</code>


+++ Tree structure

A tree structure is a self-referencing foreign key relation. The following definition is also called Adjacency List implementation in terms of hierarchical data concepts. 

However this mainly just serves as an example how the self-referencing can be done. The definition above is rarely a good way of expressing hierarchical data, hence you should take a look at chapter [doc hierarchical-data :index :name] for how to set up efficient parent/child relations.

<code type="php">
class Task extends Doctrine_Record 
{
     public function setUp() 
     {
        $this->hasOne('Task as Parent', array('local' => 'parent_id', 'foreign' => 'id'));
        $this->hasMany('Task as Subtask', array('local' => 'id', 'foreign' => 'parent_id'));
    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 100);
        $this->hasColumn('parent_id', 'integer');
    }
}
</code>

++ Join table associations

+++ Many-to-Many

If you are coming from relational database background it may be familiar to you how many-to-many associations are handled: an additional association table is needed.

In many-to-many relations the relation between the two components is always an aggregate relation and the association table is owned by both ends. For example in the case of users and groups when user is being deleted the groups it belongs to are not being deleted and the associations between this user and the groups it belongs to are being deleted.

Sometimes you may not want that association table rows are being deleted when user / group is being deleted. You can override this behoviour by setting the relations to association component (in this case {{Groupuser}}) explicitly. 

In the following example we have Groups and Users of which relation is defined as many-to-many. In this case we also need to define an additional class called {{Groupuser}}.

<code type="php">
class User extends Doctrine_Record 
{
    public function setUp() 
    {
        $this->hasMany('Group', array('local' => 'user_id',    // <- these are the column names
                                      'foreign' => 'group_id', // <- in the association table
            // the following line is needed in many-to-many relations!
                                      'refClass' => 'GroupUser'));

    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 30);
    }
}

class Group extends Doctrine_Record
{
    public function setUp() {
        $this->hasMany('User', array('local' => 'group_id',  // <- these are the column names
                                     'foreign' => 'user_id', // <- in the association table
            // the following line is needed in many-to-many relations!
                                     'refClass' => 'GroupUser'));
    }
    public function setTableDefinition() {
        $this->hasColumn('name', 'string', 30);
    }
}

class GroupUser extends Doctrine_Record
{
    public function setTableDefinition() 
    {
        $this->hasColumn('user_id', 'integer', null, array('primary' => true));
        $this->hasColumn('group_id', 'integer', null, array('primary' => true));
    }
}


$user = new User();

// add two groups
$user->Group[0]->name = 'First Group';

$user->Group[1]->name = 'Second Group';

// save changes into database
$user->save();

// deleting the associations between user and groups it belongs to

$user->Groupuser->delete();

$groups = new Doctrine_Collection($conn->getTable('Group'));

$groups[0]->name = 'Third Group';

$groups[1]->name = 'Fourth Group';

$user->Group[2] = $groups[0];
// $user will now have 3 groups

$user->Group = $groups;
// $user will now have two groups 'Third Group' and 'Fourth Group'

</code>


+++ Self-referencing (Nest relations)
++++ Non-equal nest relations
<code type="php">
class User extends Doctrine_Record 
{
    public function setUp() 
    {
        $this->hasMany('User as Parents', array('local'    => 'parent_id',
                                                'foreign'  => 'child_id',
                                                'refClass' => 'UserReference'
                                                );

        $this->hasMany('User as Children', array('local'    => 'child_id',
                                                 'foreign'  => 'parent_id',
                                                 'refClass' => 'UserReference'
                                                 );

    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 30);
    }
}
class UserReference extends Doctrine_Record 
{
    public function setTableDefinition() {
        $this->hasColumn('parent_id', 'integer', null, array('primary' => true));
        $this->hasColumn('child_id', 'integer', null, array('primary' => true));
    }
}
</code>
++++ Equal nest relations

Equal nest relations are perfectly suitable for expressing relations where a class references to itself and the columns within the reference class are equal.

This means that when fetching related records it doesn't matter which column in the reference class has the primary key value of the main class.

The previous clause maybe hard to understand so lets take an example. We define a class called user which can have many friends. Notice here how we use the 'equal' option.

<code type="php">
class User extends Doctrine_Record 
{
    public function setUp() 
    {
        $this->hasMany('User as Friend', array('local'    => 'user1',
                                               'foreign'  => 'user2',
                                               'refClass' => 'UserReference'
                                               'equal'    => true,
                                                );
    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 30);
    }
}
class UserReference extends Doctrine_Record 
{
    public function setTableDefinition() {
        $this->hasColumn('user1', 'integer', null, array('primary' => true));
        $this->hasColumn('user2', 'integer', null, array('primary' => true));
    }
}
</code>

Now lets define 4 users: <NAME>, <NAME>, <NAME> and <NAME> with <NAME> and <NAME> being buddies and <NAME> being the friend of all of them.

<code type="php">
$daniels = new User();
$daniels->name = '<NAME>';<commit_msg>Fixed missing comma in code example<commit_after>++ Introduction

In Doctrine all record relations are being set with {{hasMany}}, {{hasOne}} methods. Doctrine supports almost all kinds of database relations from simple one-to-one foreign key relations to join table self-referencing relations.

Unlike the column definitions the {{hasMany}} and {{hasOne}} methods are placed within a method called setUp(). Both methods take two arguments: the first argument is a string containing the name of the class and optional alias, the second argument is an array consisting of relation options. The option array contains the following keys:

* **local**, the local field of the relation. Local field is the linked field or fields in the defining class.
* **foreign**, the foreign field of the relation. Foreign field is the linked field or fields in the linked class.
* **refClass**, the name of the reference / join class. This is needed for many-to-many associations.
* **onDelete**, the onDelete integrity action.
* **onUpdate**, the onUpdate integrity action.

So lets take our first example, say we have two classes Forum_Board and Forum_Thread. Here Forum_Board has many Forum_Threads, hence their relation is one-to-many. We don't want to write Forum_ when accessing relations, so we use relation aliases.

First lets take a look at the Forum_Board class. It has three columns: name, description and since we didn't specify any primary key, Doctrine auto-creates an id column for it.

We define the relation to the Forum_Thread class by using the hasMany() method. Here the local field is the primary key of the board class whereas the foreign field is the board_id field of the Forum_Thread class.

<code type="php">
class Forum_Board extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->hasColumn('name', 'string', 100);
        $this->hasColumn('description', 'string', 5000);
    }
    public function setUp()
    {
        // notice the 'as' keyword here
        $this->hasMany('Forum_Thread as Threads', array('local' => 'id',
                                                        'foreign' => 'board_id');
    }
}
</code>

Then lets have a peek at the Forum_Thread class. The columns here are irrelevant, but pay attention to how we define the relation. Since each Thread can have only one Board we are using the hasOne() method. Also notice how we once again use aliases and how the local column here is board_id while the foreign column is the id column.

<code type="php">
class Forum_Thread extends Doctrine_Record
{
    public function setTableDefinition() 
    {
        $this->hasColumn('board_id', 'integer', 10);
        $this->hasColumn('title', 'string', 200);
        $this->hasColumn('updated', 'integer', 10);
        $this->hasColumn('closed', 'integer', 1);
    }
    public function setUp() 
    {
        // notice the 'as' keyword here
        $this->hasOne('Forum_Board as Board', array('local' => 'board_id',
                                                    'foreign' => 'id');
    }
}
</code>

Now we can start using these classes. The same accessors that you've already used for properties are all availible for relations.

<code type="php">
// first create a board
$board = new Forum_Board();
$board->name = 'Some board';

// lets create a new thread
$board->Thread[0]->title = 'new thread';

// save the changes 
$board->save();
</code>

++ Foreign key associations
+++ One-To-One

One-to-one relations are propably the most basic relations. In the following example we have two classes, User and Email with their relation being one-to-one. 

First lets take a look at the Email class. Since we are binding a one-to-one relationship we are using the hasOne() method. Notice how we define the foreign key column (user_id) in the Email class. This is due to a fact that Email is owned by the User class and not the other way around. In fact you should always follow this convention - always place the foreign key in the owned class.

The recommended naming convention for foreign key columns is: [tableName]_[primaryKey]. As here the foreign table is 'user' and its primary key is 'id' we have named the foreign key column as 'user_id'.

<code type="php">
class Email extends Doctrine_Record 
{
    public function setTableDefinition() 
    {
        $this->hasColumn('user_id', 'integer');
        $this->hasColumn('address', 'string', 150);
    }
    public function setUp()
    {
        $this->hasOne('User', array('local' => 'user_id', 'foreign' => 'id'));
    }
}
</code>

The User class is very similar to the Email class. Notice how the local and foreign columns are switched in the hasOne() definition compared to the definition of the Email class.

<code type="php">
class User extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->hasColumn('name', 'string',50);
        $this->hasColumn('loginname', 'string',20);
        $this->hasColumn('password', 'string',16);
    }
    public function setUp()
    {
        $this->hasOne('Email', array('local' => 'id', 'foreign' => 'user_id'));
    }
}
</code>


+++ One-to-Many, Many-to-One

One-to-Many and Many-to-One relations are very similar to One-to-One relations. The recommended conventions you came in terms with in the previous chapter also apply to one-to-many and many-to-one relations.

In the following example we have two classes: User and Phonenumber. We define their relation as one-to-many (a user can have many phonenumbers). Here once again the Phonenumber is clearly owned by the User so we place the foreign key in the Phonenumber class.

<code type="php">
class User extends Doctrine_Record 
{
    public function setUp()
    {
        $this->hasMany('Phonenumber', array('local' => 'id', 'foreign' => 'user_id'));
    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 50);
        $this->hasColumn('loginname', 'string', 20);
        $this->hasColumn('password', 'string', 16);
    }
}
class Phonenumber extends Doctrine_Record 
{
    public function setTableDefinition() 
    {
        $this->hasColumn('phonenumber', 'string', 50);
        $this->hasColumn('user_id', 'integer');
    }
}
</code>


+++ Tree structure

A tree structure is a self-referencing foreign key relation. The following definition is also called Adjacency List implementation in terms of hierarchical data concepts. 

However this mainly just serves as an example how the self-referencing can be done. The definition above is rarely a good way of expressing hierarchical data, hence you should take a look at chapter [doc hierarchical-data :index :name] for how to set up efficient parent/child relations.

<code type="php">
class Task extends Doctrine_Record 
{
     public function setUp() 
     {
        $this->hasOne('Task as Parent', array('local' => 'parent_id', 'foreign' => 'id'));
        $this->hasMany('Task as Subtask', array('local' => 'id', 'foreign' => 'parent_id'));
    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 100);
        $this->hasColumn('parent_id', 'integer');
    }
}
</code>

++ Join table associations

+++ Many-to-Many

If you are coming from relational database background it may be familiar to you how many-to-many associations are handled: an additional association table is needed.

In many-to-many relations the relation between the two components is always an aggregate relation and the association table is owned by both ends. For example in the case of users and groups when user is being deleted the groups it belongs to are not being deleted and the associations between this user and the groups it belongs to are being deleted.

Sometimes you may not want that association table rows are being deleted when user / group is being deleted. You can override this behoviour by setting the relations to association component (in this case {{Groupuser}}) explicitly. 

In the following example we have Groups and Users of which relation is defined as many-to-many. In this case we also need to define an additional class called {{Groupuser}}.

<code type="php">
class User extends Doctrine_Record 
{
    public function setUp() 
    {
        $this->hasMany('Group', array('local' => 'user_id',    // <- these are the column names
                                      'foreign' => 'group_id', // <- in the association table
            // the following line is needed in many-to-many relations!
                                      'refClass' => 'GroupUser'));

    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 30);
    }
}

class Group extends Doctrine_Record
{
    public function setUp() {
        $this->hasMany('User', array('local' => 'group_id',  // <- these are the column names
                                     'foreign' => 'user_id', // <- in the association table
            // the following line is needed in many-to-many relations!
                                     'refClass' => 'GroupUser'));
    }
    public function setTableDefinition() {
        $this->hasColumn('name', 'string', 30);
    }
}

class GroupUser extends Doctrine_Record
{
    public function setTableDefinition() 
    {
        $this->hasColumn('user_id', 'integer', null, array('primary' => true));
        $this->hasColumn('group_id', 'integer', null, array('primary' => true));
    }
}


$user = new User();

// add two groups
$user->Group[0]->name = 'First Group';

$user->Group[1]->name = 'Second Group';

// save changes into database
$user->save();

// deleting the associations between user and groups it belongs to

$user->Groupuser->delete();

$groups = new Doctrine_Collection($conn->getTable('Group'));

$groups[0]->name = 'Third Group';

$groups[1]->name = 'Fourth Group';

$user->Group[2] = $groups[0];
// $user will now have 3 groups

$user->Group = $groups;
// $user will now have two groups 'Third Group' and 'Fourth Group'

</code>


+++ Self-referencing (Nest relations)
++++ Non-equal nest relations
<code type="php">
class User extends Doctrine_Record 
{
    public function setUp() 
    {
        $this->hasMany('User as Parents', array('local'    => 'parent_id',
                                                'foreign'  => 'child_id',
                                                'refClass' => 'UserReference'
                                                );

        $this->hasMany('User as Children', array('local'    => 'child_id',
                                                 'foreign'  => 'parent_id',
                                                 'refClass' => 'UserReference'
                                                 );

    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 30);
    }
}
class UserReference extends Doctrine_Record 
{
    public function setTableDefinition() {
        $this->hasColumn('parent_id', 'integer', null, array('primary' => true));
        $this->hasColumn('child_id', 'integer', null, array('primary' => true));
    }
}
</code>
++++ Equal nest relations

Equal nest relations are perfectly suitable for expressing relations where a class references to itself and the columns within the reference class are equal.

This means that when fetching related records it doesn't matter which column in the reference class has the primary key value of the main class.

The previous clause maybe hard to understand so lets take an example. We define a class called user which can have many friends. Notice here how we use the 'equal' option.

<code type="php">
class User extends Doctrine_Record 
{
    public function setUp() 
    {
        $this->hasMany('User as Friend', array('local'    => 'user1',
                                               'foreign'  => 'user2',
                                               'refClass' => 'UserReference',
                                               'equal'    => true,
                                                );
    }
    public function setTableDefinition() 
    {
        $this->hasColumn('name', 'string', 30);
    }
}
class UserReference extends Doctrine_Record 
{
    public function setTableDefinition() {
        $this->hasColumn('user1', 'integer', null, array('primary' => true));
        $this->hasColumn('user2', 'integer', null, array('primary' => true));
    }
}
</code>

Now lets define 4 users: <NAME>, <NAME>, <NAME> and <NAME> with <NAME> and <NAME> being buddies and Mikko Koskenkorva being the friend of all of them.

<code type="php">
$daniels = new User();
$daniels->name = '<NAME>';
{'fraction_non_alphanumeric': 0.1078493683959641, 'fraction_numerical': 0.004449034718360213, 'mean_word_length': 2.8844314149051073, 'pattern_counts': {'":': 0, '<': 68, '<?xml version=': 0, '>': 246, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 56, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '491511', 'n_tokens_mistral': 6650, 'n_tokens_neox': 6407, 'n_words': 2761}