ORM

Note

if you want to automatically generate the models, consult the generating models part.

A model class is just a plain old php object without inheritance.
Models are located by default in the app\models folder.
Object Relational Mapping (ORM) relies on member annotations or attributes (since PHP8) in the model class.

Models definition

A basic model

  • A model must define its primary key using the @id annotation on the members concerned
  • Serialized members must have getters and setters
  • Without any other annotation, a class corresponds to a table with the same name in the database, each member corresponds to a field of this table
app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
namespace models;

use Ubiquity\attributes\items\Id;

class User{

   #[Id]
   private $id;

   private $firstname;

   public function getFirstname(){
      return $this->firstname;
   }
   public function setFirstname($firstname){
      $this->firstname=$firstname;
   }
}
app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 namespace models;

 class User{
   /**
    * @id
    */
   private $id;

   private $firstname;

   public function getFirstname(){
      return $this->firstname;
   }
   public function setFirstname($firstname){
      $this->firstname=$firstname;
   }
 }

Mapping

Table->Class

If the name of the table is different from the name of the class, the annotation @table allows to specify the name of the table.

app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
namespace models;

use Ubiquity\attributes\items\Table;
use Ubiquity\attributes\items\Id;

#[Table('user')]
class User{

   #[Id]
   private $id;

   private $firstname;

   public function getFirstname(){
      return $this->firstname;
   }
   public function setFirstname($firstname){
      $this->firstname=$firstname;
   }
}
app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
namespace models;

/**
 * @table("name"=>"user")
 */
class User{
   /**
    * @id
    */
   private $id;

   private $firstname;

   public function getFirstname(){
      return $this->firstname;
   }
   public function setFirstname($firstname){
      $this->firstname=$firstname;
   }
}

Field->Member

If the name of a field is different from the name of a member in the class, the annotation @column allows to specify a different field name.

app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace models;

use Ubiquity\attributes\items\Table;
use Ubiquity\attributes\items\Id;
use Ubiquity\attributes\items\Column;

#[Table('user')
class User{

   #[Id]
   private $id;

   #[Column('column_name')]
   private $firstname;

   public function getFirstname(){
      return $this->firstname;
   }
   public function setFirstname($firstname){
      $this->firstname=$firstname;
   }
}
app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace models;

/**
 * @table("user")
 */
class User{
   /**
    * @id
    */
   private $id;

   /**
    * column("user_name")
    */
   private $firstname;

   public function getFirstname(){
      return $this->firstname;
   }
   public function setFirstname($firstname){
      $this->firstname=$firstname;
   }
}

Associations

Note

Naming convention
Foreign key field names consist of the primary key name of the referenced table followed by the name of the referenced table whose first letter is capitalized.
Example
idUser for the table user whose primary key is id

ManyToOne

A user belongs to an organization:

../_images/manyToOne.png
app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 namespace models;

use Ubiquity\attributes\items\ManyToOne;
use Ubiquity\attributes\items\Id;
use Ubiquity\attributes\items\JoinColumn;

 class User{

   #[Id]
   private $id;

   private $firstname;

   #[ManyToOne]
   #[JoinColumn(className: \models\Organization::class, name: 'idOrganization', nullable: false)]
   private $organization;

   public function getOrganization(){
      return $this->organization;
   }

   public function setOrganization($organization){
      $this->organization=$organization;
   }
}
app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 namespace models;

 class User{
   /**
    * @id
    */
   private $id;

   private $firstname;

   /**
    * @manyToOne
    * @joinColumn("className"=>"models\\Organization","name"=>"idOrganization","nullable"=>false)
    */
   private $organization;

   public function getOrganization(){
      return $this->organization;
   }

   public function setOrganization($organization){
      $this->organization=$organization;
   }
}

The @joinColumn annotation or the JoinColumn attribute specifies that:

  • The member $organization is an instance of modelsOrganization
  • The table user has a foreign key idOrganization refering to organization primary key
  • This foreign key is not null => a user will always have an organization

OneToMany

An organization has many users:

../_images/oneToMany.png
app/models/Organization.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace models;

use Ubiquity\attributes\items\OneToMany;
use Ubiquity\attributes\items\Id;

class Organization{

   #[Id]
   private $id;

   private $name;

   #[OneToMany(mappedBy: 'organization', className: \models\User::class)]
   private $users;
}
app/models/Organization.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace models;

class Organization{
   /**
    * @id
    */
   private $id;

   private $name;

   /**
    * @oneToMany("mappedBy"=>"organization","className"=>"models\\User")
    */
   private $users;
}

In this case, the association is bi-directional.
The @oneToMany annotation must just specify:

  • The class of each user in users array : modelsUser
  • the value of @mappedBy is the name of the association-mapping attribute on the owning side : $organization in User class

ManyToMany

  • A user can belong to groups.
  • A group consists of multiple users.
../_images/manyToMany.png
app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
namespace models;

use Ubiquity\attributes\items\ManyToMany;
use Ubiquity\attributes\items\Id;
use Ubiquity\attributes\items\JoinTable;

class User{

   #[Id]
   private $id;

   private $firstname;

   #[ManyToMany(targetEntity: \models\Group::class, inversedBy: 'users')]
   #[JoinTable(name: 'groupusers')]
   private $groups;

}
app/models/User.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
namespace models;

class User{
   /**
    * @id
    */
   private $id;

   private $firstname;

   /**
    * @manyToMany("targetEntity"=>"models\\Group","inversedBy"=>"users")
    * @joinTable("name"=>"groupusers")
    */
   private $groups;

}
app/models/Group.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
namespace models;

use Ubiquity\attributes\items\ManyToMany;
use Ubiquity\attributes\items\Id;
use Ubiquity\attributes\items\JoinTable;

class Group{

   #[Id]
   private $id;

   private $name;

   #[ManyToMany(targetEntity: \models\User::class, inversedBy: 'groups')]
   #[JoinTable(name: 'groupusers')]
   private $users;

}
app/models/Group.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
namespace models;

class Group{
   /**
    * @id
    */
   private $id;

   private $name;

   /**
    * @manyToMany("targetEntity"=>"models\\User","inversedBy"=>"groups")
    * @joinTable("name"=>"groupusers")
    */
   private $users;

}

If the naming conventions are not respected for foreign keys,
it is possible to specify the related fields.

app/models/Group.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
namespace models;

use Ubiquity\attributes\items\ManyToMany;
use Ubiquity\attributes\items\Id;
use Ubiquity\attributes\items\JoinTable;

class Group{

   #[Id]
   private $id;

   private $name;

   #[ManyToMany(targetEntity: \models\User::class, inversedBy: 'groupes')]
   #[JoinTable(name: 'groupeusers',
   joinColumns: ['name'=>'id_groupe','referencedColumnName'=>'id'],
   inverseJoinColumns: ['name'=>'id_user','referencedColumnName'=>'id'])]
   private $users;

}
app/models/Group.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
namespace models;

class Group{
   /**
    * @id
    */
   private $id;

   private $name;

   /**
    * @manyToMany("targetEntity"=>"models\\User","inversedBy"=>"groupes")
    * @joinTable("name"=>"groupeusers",
    * "joinColumns"=>["name"=>"id_groupe","referencedColumnName"=>"id"],
    * "inverseJoinColumns"=>["name"=>"id_user","referencedColumnName"=>"id"])
    */
   private $users;

}

ORM Annotations

Annotations for classes

@annotation role properties role
@database Defines the associated database offset (defined in config file)
@table Defines the associated table name.

Annotations for members

@annotation role properties role
@id Defines the primary key(s).
@column Specify the associated field characteristics. name Name of the associated field
nullable true if value can be null
dbType Type of the field in database
@transient Specify that the field is not persistent.

Associations

@annotation (extends) role properties [optional] role
@manyToOne Defines a single-valued association to another entity class.
@joinColumn (@column) Indicates the foreign key in manyToOne asso. className Class of the member
[referencedColumnName] Name of the associated column
@oneToMany Defines a multi-valued association to another entity class. className Class of the objects in member
[mappedBy] Name of the association-mapping attribute on the owning side
@manyToMany Defines a many-valued association with many-to-many multiplicity targetEntity Class of the objects in member
[inversedBy] Name of the association-member on the inverse-side
[mappedBy] Name of the association-member on the owning side
@joinTable Defines the association table for many-to-many multiplicity name The name of the association table
[joinColumns] @column => name and referencedColumnName for this side
[inverseJoinColumns] @column => name and referencedColumnName for the other side