Doctrine2 (PHP Doctrine 2)

Doctrine 2 est de sortie dans vos codes sources PHP !

Certains savez peut-être que nous avions initialement prévu de la version 2.0 stable, mais aujourd'hui nous sommes tout simplement pas encore là. Toutefois, les choses vont très bien et nous sommes confiants que les versions finales des versions 2.0 sont proches. L'ORM et DBAL entrent maintenant en phase finale de la correction de bogues pour résoudre tous les problèmes que nous trouvons essentiel pour les versions finales et suivra ensuite le projet commun en RC (release candidate) du statut.

Doctrine

Les projets Doctrine2

Introduction sur Doctrine 2

Traduction de Working with Doctrine 2, Flex, Zend AMF, and Flash Builder :

Vous travaillez déjà avec Doctrine 1 et vous vous demandez ce qu'il faudrait pour passer à la version 2 ?

Avant d'entrer dans les détails je dirai ceci: si vous n'utilisez pas déjà un cadre ORM pour PHP, vous devriez. Pour la plupart des projets il peut vous aider en vous libérant des tâches fastidieuses d'écriture de code CRUD et des requêtes SQL. Il permet de vous concentrer sur la logique métier de votre application. Et tous ces avantages sont multipliées lorsque l'on travaille sur les applications Internet riches, car sur ce type de projet une grande partie du travail est effectué sur le client et non sur le serveur.

Si vous ne connaissez pas grand-chose ORM en général, avant de poursuivre, vous pouvez d'abord lire mon premier article : Working with Doctrine 1.x, Zend Framework, and Flex.

Les différences entre Doctrine 2 et 1.x

Avant d'expliquer comment j'ai construit l'application, parlons un peu des principales différences entre 2 et Doctrine Doctrine 1.x (au moment où j'écris cet article Doctrine 2 est encore en Beta, donc les choses peuvent changer).

Le plus grand changement est de loin celle qui est liée au modèle principal utilisé par l'ORM Doctrine 2. Dans les versions 1.x il utilise le modèle Active Record (Ruby on Rails utilise aussi Active Record), maintenant vous pouvez dire au revoir à Active Record et bienvenue Data Mapper (Hibernate utilise le même schéma).Quelles sont les différences entre ces deux modèles?

Avec Active Record les entités savent comment se persister jusqu'à la base de données; essentiellement chaque entité s'étend une sorte de classe du framework de l'ORM et met en œuvre des méthodes comme read(), find(), delete(), et update(). Bien qu'il ne soit pas obligatoire, les entités ressemblent beaucoup à la structure de base de données.

Avec Data Mapper les entités ne sais rien de la couche de persistance et rien au sujet de la structure de base de données. L'ORM fournit les moyens de conserver les entités et lire les données en entités (à partir de la base de données).

Du point de vue Rich Client cela se traduit par moins de travail du côté de PHP lors de la préparation des données pour l'envoi à travers le fil tout en utilisant Doctrine 2. Avec Doctrine 1, le modèle de données était lourd à cause du modèle Active Record.

La seconde différence est la taille de cette Doctrine 2 nécessite PHP 5.3 ou plus récent. Ainsi, si votre installation nécessite les anciennes versions de PHP, alors vous devez vous en tenir à Doctrine 1.x.

Bien sûr, les ondulations agitées par ces deux changements sont assez grands et je pense qu'il est juste de dire que lors du passage de Doctrine 1.x à 2 vous ne réutiliser pas une grande partie de votre expérience antérieure avec Doctrine 1.x ou le code que vous avez écrit .

Cela dit, je dois dire que, pour ma part, je suis content de l'évolution de Doctrine, parce que je suis en faveur Data Mapper sur Active Record.

Installation de Doctrine 2 et création du projet PHP

L'étape suivante consiste à créer un fichier de bootstrap qui configure Doctrine 2 pour être utilisable avec mon projet. Cela signifie pour charger les classes du framework, mis en place des informations d'accès à la de base de données, préciser la localisation des entités et la méthode d'annotation, et de configurer les différents caches qui sera utilisé par l'application.

Vous trouverez un bootstrap dans le bac à sable sandbox inclus sur Downloads for doctrine/doctrine2

Dans le fichier de bootstrap même, j'ai créé une instance de la classe EntityManager. C'est le point d'entrée pour la Doctrine 2.

Si vous téléchargez le code source du projet (voir les liens de la deuxième à la dernière section), vous trouverez le fichier bootstrap.php l'intérieur du dossier doctrine2_students.

Introduction à Doctrine 2 avec son bac à sable : Sandbox Quickstart

Génération des tables depuis la déclaration des entités

Après avoir modifier cli-config.php

//$connectionOptions = array(
//    'driver' => 'pdo_sqlite',
//    'path' => 'database.sqlite'
//);
$connectionOptions = array(
    'driver' => 'pdo_mysql',
    'host' => 'mysql.placeoweb.com',
    'dbname' => 'rbas_test',
    'user' => 'rbas',
    'password' => 'rbas'
);

On exécute la génération des tables :

C:\doctrine-doctrine2-e3a7b25\tools\sandbox>"c:\wamp\bin\php\php5.3.3\php" doctrine orm:schema-tool:create
Creating database schema...
Database schema created successfully!

Si on le relance, les tables existent déjà en base :

C:\doctrine-doctrine2-e3a7b25\tools\sandbox>"c:\wamp\bin\php\php5.3.3\php" doctrine orm:schema-tool:create
Creating database schema...

 [PDOException]
 SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'addresses' already exists

orm:schema-tool:create [--dump-sql] [-h|--help] [-q|--quiet] [-v|--verbose] [-V|--version] [-c|--color] [-n|--no-interaction] command

Pour l'opération inverse : reverse ingenering

$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory($em);
$metadata = $cmf->getAllMetadata();
 
$cme = new \Doctrine\ORM\Tools\Export\ClassMetadataExporter();
$exporter = $cme->getExporter('annotation', 'Infofab');
$exporter->setMetadata($metadata);
$etg = new \Doctrine\ORM\Tools\EntityGenerator;
$exporter->setEntityGenerator($etg);
$exporter->export();
Création des entités PHP

Avec Doctrine 2 (et tous ORM qui utilise le modèle Data Mapper) vous devez spécifier comment une entité est conservé par le framework et quelles sont les relations qu'il entretient avec d'autres entités (le cas échéant). Dans Doctrine 2, vous pouvez choisir entre quatre méthodes différentes: annotations, YAML, XML, et PHP. J'ai d'abord privilégié la première parce que toutes les informations sont stockées dans les classes entités en tant que commentaires PHPDoc. Ainsi, si vous souhaitez modifier une entité, vous n'avez qu'un seul endroit où chercher. Toutefois, après l'utilisation de cette approche, je pense que l'approche XML est la meilleure parce que vous obtenez des conseils de code (auto complétion). Voici la liste pour l'entité de cours (rappelez-vous que j'ai quatre tables dans ma base de données et j'ai besoin de quatre entités pour mon application):

namespace entities;
 
/** @Entity 
 * @Table(name="courses") 
 */
 
class Course {
    /**
     * @Id @Column(type="integer")
     * @GeneratedValue(strategy="AUTO")
     */
    private $id;
 
    /** 
     * @Column(type="string", length=255) 
     */
    private $name;
 
    public function getId() {
        return $this->id;
 
    }
 
    public function getName() {
        return $this->name;
    }
 
    public function setName($val) {
        $this->name = $val;
    }
 
}

En utilisant les annotations vous spécifiez quel table est utilisé pour l'entité (rappelez-vous une ligne de cette table sera enveloppé dans une instance de l'entité). Vous pouvez définir des noms différents pour les propriétés si vous voulez (dans SQL vous n'utilisez pas la notation camelCase, mais en PHP ou ActionScript vous utilisez généralement cette convention).

Les entités j'ai créé suivent de près la structure de la base de données. La seule différence est dans la façon dont les clés étrangères sont représentées.

Par exemple, l'entité Etudiant, qui a un many-to-one relation avec l'entité pays, n'a pas une propriété country_id de type int. Au lieu de cela, j'ai ajouté une propriété appelée pays qui est de type Pays. De même, j'ai créé une propriété appelée marque qui contient un tableau de Mark entités - si un étudiant suit trois cours, puis sa propriété marques tiendra un tableau d'objets avec Mark trois cas.

Voici quelques notes sur la création d'entités avec Doctrine 2:

  • Avec une Doctrine 1 j'ai utilisé le outils inclus pour créer le modèle de domaine depuis la structure de base de données
  • Doctrine 2 a un support pour créer le YAML du schéma de base de données, puis générer les entités, mais je ne suis pas sûr c'est une bonne idée de le faire. Si vous avez des schémas complexes le code généré peut pas fonctionné comme prévu, et vous aurez besoin de modifier manuellement de toute façon
  • Vous devez vous rappeler pour définir les propriétés que private/protected et non public, et ajouter getters/setters. Si vous ne le faites pas, vous pouvez obtenir les bugs (Doctrine aura des problèmes injecter le code pour gérer les relations).
Créer des services PHP

Comme je l'ai déjà dit, le point d'entrée à la doctrine 2 est sa classe EntityManager. Vous pouvez utiliser cette classe pour rechercher des objets persistants en utilisant des méthodes différentes. La méthode la plus puissante est Doctrine Query Language (DQL) qui ressemble à SQL, mais fonctionne sur les entités que vous avez définis dans votre modèle de domaine plutôt que sur les tables sous-jacentes.

Si vous voulez créer un nouveau pays, vous devez écrire le code :

$countryEntity = new entities\Country();
$countryEntity->setName('Mihai\'s country');
//set the entity to be managed by Doctrine
$entityManager->persist($countryEntity);
//persist the changes to database
$entityManager->flush();

Avec DQL lorsque vous écrivez une jointure, on faire jointure filtrée (similaire à la notion de jointure dans SQL utilisée pour limiter ou l'agrégation des résultats) ou un fetch join (utilisé pour récupérer les documents connexes et les inclure dans le résultat de la requête principale ). Lorsque vous incluez les champs de l'entité jointe dans la clause SELECT vous obtenez un fetch join. Voici le code de la getStudents StudentsService-> () méthode:

$dql = "SELECT s, c, m, e FROM entities\Student s
            JOIN s.country c JOIN s.marks m
            JOIN m.course e ORDER BY s.lastName, s.firstName";
$q = $this->entityManager->createQuery($dql);
return $q->getArrayResult();

Chaque étudiant est trouvé avec le pays auquel il appartient et à tous ses cours de la table plusieurs-vers-plusieurs - le tout avec une seule requête DQL.

Conclusion

Une caractéristique je suis resté loin d'instinct (les deux avec Doctrine 1 et 2) a été la capacité de générer le schéma de base de données en utilisant les entités et le mappage entre eux. En d'autres termes, vous pourriez commencer votre premier projet d'écriture du modèle de données PHP, et ensuite utiliser la doctrine de générer la base de données pour vous. Je suis vieille école, et toute mon expérience m'a appris que bases de données relationnelles vous traitent bien si vous les traitez bien. Ainsi, je préfère de beaucoup à créer la base de données avec mes "propres" mains et assurez-vous j'ai mis tous les indexes/constraints dont j'ai besoin. Cela dit, je ne dis pas que la fonction de la doctrine pour générer un schéma de base de données est bogué ou sans valeur. Je voulais simplement expliquer pourquoi je n'ai pas essayé. Votre kilométrage peut varier sur ce point.

Lexique

Database Abstraction Layer

Powerful database abstraction layer with many features for database schema introspection, schema management and PDO abstraction.

Puissante couche d'abstraction de base de données avec de nombreuses fonctionnalités pour l'introspection du schéma de base de données, gestion du schéma et de l'abstraction PDO.

Object Relational Mapper

Object relational mapper (ORM) for PHP that sits on top of a powerful database abstraction layer (DBAL). One of its key features is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL), inspired by Hibernates HQL. This provides developers with a powerful alternative to SQL that maintains flexibility without requiring unnecessary code duplication.

Objet mappeur relationnel (ORM) de PHP qui se trouve au sommet d'une couche d'abstraction de base de données puissante (DBAL). Une de ses caractéristiques principales est la possibilité d'écrire des requêtes de base de données dans un objet de propriété orientée dialecte SQL appelée Doctrine Query Language (DQL), inspiré par hiberne HQL. Cette offre aux développeurs une alternative puissante à SQL qui maintient la flexibilité sans nécessiter de duplication de code inutile.

Ressources