Aller au menu - Aller au contenu

Icône Configuration de la base de données

Avatar
Mise à jour : 04/09/2010
Difficulté : Intermédiaire Intermédiaire Creative Commons BY-NC-SA
487 visites depuis 7 jours, dont 36 sur ce chapitre classé 233/786
Nous allons maintenant voir comment nous connecter avec la base de données, puis configurer nos tables.
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Connexion

La classe Doctrine_Manager



Toutes les connexions à la base de données sont gérées par un objet Doctrine_Manager.
Doctrine_Manager est un singleton, cela signifie qu'il ne peut y en avoir qu'une seule instance à la fois dans votre projet. Si vous êtes allés farfouiller dans ~/lib/vendor/doctrine/Doctrine/Manager.php (ce que je vous encourage toujours à faire ;) ), vous avez pu vous apercevoir que la méthode __construct() est privée : on ne pourra donc pas faire de <?php new Doctrine_Manager(); ?>.

Mais alors, pourquoi tu nous parles de cette classe si elle ne sert à rien ? o_O

Je m'attarde un peu là-dessus, parce que c'est le principe du singleton : on ne peut pas instancier des objets comme on veut. On va donc utiliser une méthode statique : Doctrine_Manager::getInstance(). C'est elle qui va nous retourner un nouvel objet ; et l'intérêt est qu'elle nous retournera toujours le même, au lieu d'en créer un à chaque fois. Nous n'avons en effet pas besoin d'utiliser plusieurs objets Doctrine_Manager.

Doctrine_Manager nous permet de configurer de nombreuses options, mais nous reviendrons dessus au fur et à mesure du tutoriel. Il y a aussi une partie en annexe qui récapitule tout ça.


Connexion à la base de données



Doctrine_Manager possède une méthode statique connection(). Cette méthode prend en paramètre un DSN, du même format que PDO (par exemple, mysql://root:@localhost/db_doctrine_test) et nous retourne un objet connexion. Un DSN doit être de la forme SGBD://utilisateur:motdepasse@serveur/nomdelabasededonnées.

Modifions le fichier ~/config/global.php :

Code : PHP - ~/config/global.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php 
// Adaptez bien sûr le DSN à votre cas.
define('CFG_DB_DSN', 'mysql://root@localhost/db_doctrine_test');

define('LIB_DIR',  dirname(__FILE__).'/../lib/');
define('CFG_DIR',  dirname(__FILE__).'/');
define('WEB_DIR',  dirname(__FILE__).'/../web/');
define('HTML_DIR', dirname(__FILE__).'/../html/');

require_once(LIB_DIR.'vendor/doctrine/Doctrine.php');
spl_autoload_register(array('Doctrine_Core', 'autoload'));

$conn = Doctrine_Manager::connection(CFG_DB_DSN);


Note : Doctrine_Manager peut prendre en charge plusieurs connexions à différentes bases de données. Il est conseillé pour cela d'affecter explicitement un label aux connexions créées : Doctrine_Manager::connection('dsn', 'label');. Il est possible ensuite de les récupérer avec Doctrine_Manager::getConnection('label');.

Schéma de données (Yaml)

Petite surprise : on va apprendre un nouveau langage. :) Mais pas de panique, c'est un langage très simple, utilisé pour définir le schéma de données de Doctrine.

Le langage Yaml



Ce langage est un langage de description, un peu comme le XML, mais moins lourd. Pour info, YAML est un acronyme récursif, tout comme PHP, et signifie YAML Ain't Markup Language.

Comme vous allez le voir, la syntaxe du Yaml repose presque uniquement sur l'indentation du code. Attention, quelque chose de très important : l'indentation doit se faire UNIQUEMENT AVEC DES ESPACES, jamais avec des tabulations.

Le langage repose sur ces règles principales :
  • Les nombres (entiers, flottants, etc.) sont écrits naturellement.
  • La valeur Null peut être indiquée avec null ou ~.
  • Les booléens sont exprimés par true ou false.
  • Les dates sont écrites au format ISO-8601, c'est-à-dire, par exemple, 2010-06-03 23:30:53.
  • Les chaînes de caractères peuvent être écrites sans délimiteurs, délimitées par des simple quotes ('), ou par des doubles quotes ("). Lorsque la chaîne s'étend sur plusieurs lignes, il faut utiliser le symbole pipe | pour l'indiquer.
  • Les paires clé/valeur sont séparées par ':'.
  • Plutôt que l'indentation, on peut utiliser les symboles [] et {} pour indiquer explicitement un tableau, par exemple, tableau: { cle: valeur, cle2: valeur2 }. Les accolades indiquent des paires clé/valeur, les crochets indiquent simplement des valeurs. Par exemple : tableau: [valeur1, valeur2, valeur3].
  • Les commentaires sont indiqués par #. Toute ligne contenant un # devient commentaire sur le reste de la ligne.


Ces règles sont très intuitives, voyez par vous-mêmes.

Le schéma



Voyons tout de suite le schéma que j'utiliserai dans la suite de ce tutoriel. Nous placerons tout ceci dans le fichier ~/config/schema.yml :

Code : Autre - ~/config/schema.yml
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
26
27
28
29
30
# Cela représentera nos articles :
Article:
  columns:
    title:
      type: string(255)
      notnull: true
    content:
      type: string
      notnull: true
    user_id:
      type: integer
  relations:
    User:
      class: User
      local: user_id
      foreign: id
      alias: User # Inutile, puisque l'alias par défaut est le nom de la classe.
      foreignAlias: Articles

# Et là les utilisateurs :
User:
  tableName: member
  columns:
    login:
      type: string(255)
      unique: true
      notnull: true
    password:
      type: string(255)
      notnull: true


Détaillons maintenant le schéma ci-dessus. Les clés de premier niveau représentent nos classes (Article et User). Chaque classe sera représentée par une table dans la base de données. Doctrine déduit automatiquement le nom de la table, si on ne spécifie pas l'option tableName.
À l'intérieur, on retrouve les clés columns (qui contient la définition des colonnes de la table) et relations (qui définit les relations entre les tables).

Les colonnes



Chaque colonne accepte plusieurs options, dont :
  • type : un des types suivants : boolean, integer, float, decimal, string, blob, clob, timestamp, time, date, enum, gzip, array, object. Doctrine adapte ensuite le type utilisé dans la base de données selon ce que le SGBD supporte ;
  • notnull : indique si le champ peut être vide ou s'il doit toujours contenir une valeur (true ou false) ;
  • unique : indique si le champ doit être unique ou non (true ou false).

Vous avez dû remarquer que l'on peut indiquer comme type array ou object ; or, ces types n'existent pas dans un SGBD classique. En fait, Doctrine va s'occuper de sérialiser/désérialiser automatiquement la valeur de ces champs. Ils sont utiles lorsque l'on veut éviter de créer une table supplémentaire avec des relations, parfois un peu lourdes à gérer pour pas grand-chose.


Les relations



Il y a plusieurs manières de définir les relations. Ici, nous sommes partis de l'objet Article et avons indiqué qu'ils ont un auteur. Nous aurions aussi pu indiquer cette relation à partir de l'objet User et indiquer que chacun peut posséder plusieurs articles.

Nous commençons par donner un nom à notre relation ('User'). La classe étrangère est indiquée par class. L'identifiant local est spécifié par local, et l'identifiant étranger par foreign. Doctrine nous donne la possibilité de donner des alias avec alias et foreignAlias. Ceci nous permettra d'utiliser ensuite : <?php $article->AliasPourUser->login.

Schéma de données (PHP)

Le langage Yaml n'est en fait qu'une manière alternative de définir notre modèle. Doctrine le traduit ensuite en PHP ; mais nous pouvons bien entendu écrire directement tout cela en PHP.

Les classes de modèle



Voyons l'équivalent du schéma précédent :

Code : PHP - ~/lib/models/generated/BaseArticle.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php
class BaseArticle extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->hasColumn('title',   'string',  255,  array('notnull' => true));
        $this->hasColumn('content', 'string',  null, array('notnull' => true));
        $this->hasColumn('user_id', 'integer', null, array());
    }

    public function setUp()
    {
        $this->hasOne('User as User', array('local' => 'user_id', 'foreign' => 'id'));
        // Même remarque que pour l'alias ici : il s'agit par défaut du nom de la classe, donc il est inutile
        // de préciser 'as User'.
    }
}

Code : PHP - ~/lib/models/generated/BaseUser.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php
class BaseUser extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->setTableName('member');
        $this->hasColumn('login', 'string', 255, array('unique' => true, 'notnull' => true));
        $this->hasColumn('password', 'string', 255, array('notnull' => true));
    }

    public function setUp()
    {
        $this->hasMany('Article as Articles', array('local' => 'id', 'foreign' => 'user_id'));
    }
}


La méthode hasColumn() permet de définir les colonnes ; elle prend en argument le nom, le type, la longueur, et les options supplémentaires. Les méthodes hasOne() / hasMany() permettent de définir les relations ; avec en argument le nom du modèle et éventuellement un alias, et les options.

L'héritage des classes de base



Lisez bien ceci, c'est important.
Vous avez vu que nous avons appelé nos classes BaseArticle et BaseUser et que nous les avons placées dans le dossier generated/. Ceci est peu important si vous écrivez le PHP à la main, et vous pouvez directement nommer vos classes Article et User. Je le fais pour que dans la suite du tuto, la configuration du projet soit la même, peu importe la méthode que vous avez choisie.

Je ne comprends toujours pas l'utilité de ces classes « BaseMachin » moi...

Lorsque nous demanderons à Doctrine de les générer automatiquement à partir du Yaml, Doctrine aura besoin de recréer ces fichiers. Pour ne pas effacer ceux qui nous servent (et que l'on modifiera ensuite), Doctrine génère une classe « intermédiaire », que nous NE MODIFIERONS PAS. Nous modifierons seulement les classes Article et User (qui héritent donc de BaseArticle et BaseUser :-° ).

Si vous ne comprenez pas tout de suite, ne vous inquiétez pas, je récapitulerai juste après.

Les classes représentant les tables



Si vous décidez d'utiliser le PHP, il vous faudra aussi créer une classe pour chaque table. Elles nous serviront plus tard pour effectuer certaines tâches.

Code : PHP - ~/lib/models/ArticleTable.php et ~/lib/models/UserTable.php
1
2
3
4
5
6
7
8
<?php
// Fichier ~/lib/models/ArticleTable.php
class ArticleTable extends Doctrine_Table
{ }

// Fichier ~/lib/models/UserTable.php
class UserTable extends Doctrine_Table
{ }


Vous noterez que nos modèles héritent de Doctrine_Record et que nos tables héritent de Doctrine_Table. Ceci est OBLIGATOIRE ! Les méthodes setTableName(), hasColumn(), hasMany() etc... sont héritées de Doctrine_Record. Allez donc jeter un coup d'oeil au fichier ~/lib/vendor/doctrine/Doctrine/Record.php. ;)

Génération des tables et modèles

Voyons maintenant comment générer automatiquement notre base de données à partir du schéma que nous venons de créer.

Modifions le fichier ~/config/global.php pour correspondre à nos besoins :

Code : PHP - ~/config/global.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
// Adaptez bien sûr le DSN à votre cas.
define('CFG_DB_DSN', 'mysql://root@localhost/db_doctrine_test');

define('LIB_DIR',  dirname(__FILE__).'/../lib/');
define('CFG_DIR',  dirname(__FILE__).'/');
define('WEB_DIR',  dirname(__FILE__).'/../web/');
define('HTML_DIR', dirname(__FILE__).'/../html/');

require_once(LIB_DIR.'vendor/doctrine/Doctrine.php');
spl_autoload_register(array('Doctrine_Core', 'autoload'));
spl_autoload_register(array('Doctrine_Core', 'modelsAutoload'));

$manager = Doctrine_Manager::getInstance();
$conn    = Doctrine_Manager::connection(CFG_DB_DSN);

$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE,               Doctrine_Core::VALIDATE_ALL);
$manager->setAttribute(Doctrine_Core::ATTR_AUTO_ACCESSOR_OVERRIDE, true);
$manager->setAttribute(Doctrine_Core::ATTR_AUTOLOAD_TABLE_CLASSES, true);
$manager->setAttribute(Doctrine_Core::ATTR_MODEL_LOADING,          Doctrine_Core::MODEL_LOADING_CONSERVATIVE);

Doctrine_Core::loadModels(LIB_DIR.'models/');


IMPORTANT
Nous ajoutons un autre autoloader (Doctrine_Core::modelsAutoload). Celui-ci se chargera d'inclure les classes de modèles. En effet, l'autoloader basique ne trouve les fichiers que par leur nom (souvenez-vous, je l'ai expliqué en première partie du tuto). Or, les fichiers contenant les modèles ne respectent pas cette règle : souvenez-vous lorsque nous avons défini le schéma. Je vous avais parlé des classes BaseXXX : elles sont placées par Doctrine dans un dossier generated/.


Nous utilisons la méthode setAttribute() de Doctrine_Manager pour personnaliser plusieurs attributs. Je vous invite à vous reporter à la partie Annexes pour une explication détaillée de ces attributs. Sachez simplement que nous définissions le nécessaire pour une utilisation classique, et pour le chargement automatique de tous les fichiers.

La dernière instruction <?php Doctrine_Core::loadModels(LIB_DIR.'models/') demande d'inclure les modèles se situant dans le dossier indiqué.

Pour le code des modèles, je vous laisse vous reporter aux chapitres précédents.
Voici les commandes à exécuter pour que Doctrine génère les fichiers de modèle et construise notre base de données :

ATTENTION :
Si vous n'avez pas dédié une base de données entière à Doctrine comme je vous l'ai conseillé lors de l'installation, n'exécutez pas Doctrine_Core::dropDatabases() ! Cela efface la base de données avant de la reconstruire. Attention donc aux autres projets partageant la même base de données ! Si vous partagez la base de données avec d'autres applications, vous pouvez simplement supprimer les tables utilisées par Doctrine à la main, ce qui peut vite devenir fastidieux, je vous l'accorde... :-°


Code : PHP - ~/web/builder.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php
require(dirname(__FILE__).'/../config/global.php');

// Si elle existe, supprimez la base existante.
// Attention, cela vide totalement la base de données !
Doctrine_Core::dropDatabases();

// Création de la base (uniquement si elle n'EXISTE PAS)
Doctrine_Core::createDatabases();

// Création des fichiers de modèle à partir du schema.yml
// Si vous n'utilisez pas le Yaml, n'exécutez pas cette ligne !
Doctrine_Core::generateModelsFromYaml(CFG_DIR.'schema.yml', LIB_DIR.'models', array('generateTableClasses' => true));

// Création des tables
Doctrine_Core::createTablesFromModels(LIB_DIR.'models');



Lorsque vous appellerez le fichier builder.php, votre base de données et les fichiers des classes BaseXXX seront reconstruits (les autres seront créés s'ils n'existent pas ; s'ils existent déjà, ils ne seront pas modifiés).

Tout ce fonctionnement automatique peut vous paraître un peu obscur. Exécutez donc le fichier ~/web/builder.php. Je vous laisse maintenant aller jeter un coup d'oeil dans votre base de données et dans le répertoire ~/lib/models/. Un dossier generated/ y a été créé, ainsi que les classes BaseXXX. Notez que les classes « normales » (c'est-à-dire Article, User, ArticleTable et UserTable) ont été créées parce qu'elles n'existaient pas. Par la suite, si vous régénérez à nouveau tout cela, elles ne seront plus modifiées. C'est donc dans celles-ci que nous travaillerons.
Pour finir, notez que j'ai indiqué ici (en Yaml et en PHP) les options les plus utilisées, mais il en existe d'autres et je vous les montrerai au cours du tutoriel.

Rappelez-moi comment vous faisiez jusqu'ici ? Vous construisiez vos bases de données à la main ? Eh bien maintenant vous pouvez oublier tout ça ! :p
(Oui enfin, ne prenez pas non plus à la lettre tout ce que je peux raconter... ^^ )
Chapitre précédent Sommaire Chapitre suivant

Partager

32 commentaires pour "Configuration de la base de données"
Note moyenne : 3.54 / 4 (35 votes)
Pseudo Commentaire
Hors ligne iglou # Posté le 30/08/2011 à 12:57:22
Avatar

et je me demande aussi,sur la connexion vers la BDD!
dans le fichier global.php
il y a ca :
define('CFG_DB_DSN', 'mysql://root@localhost/db_doctrine_test');
et si jamais j'utilise une session avec mot de passe
genre host="165.26.520.12", user='iglou' , password='okok' ou est ce que je configure tous ca ?
Hors ligne Cybermanu # Posté le 31/08/2011 à 01:00:28
Avatar

Avis : Très bon

Ville : Hostun
Pays : France métropolitaine

1. Pour ton schéma, pose ta question sur le forum. Ou envoie moi ton schéma, sinon j'pourrais pas faire grand chose. ;)

Citation : Toi !
j'ai tout recopié à l'identique sauf sur UserTable et ArticleTable

C'est pas ce qui est identique, qui m'intéresse, mais ce qui ne l'est pas ! :)


2. Pour ta deuxième question, tu as bien lu le tuto ?

Citation : Chapitre 'Connexion > Connexion à la base de données'
SGBD://utilisateur:motdepasse@serveur/nomdelabasededonnées

D'après ce que tu me dis :
SGBD = mysql
utilisateur = iglou
motdepasse = okok
serveur = 165.26.520.12
nomdelabasededonnées = jepeuxpasledevineràtaplace

Il ne faut pas lire que les codes que je donne, mais aussi le "blabla" qu'il y a autour. Comme quoi, c'est pas toujours inutile !! Merci :)

Programmeur : c'est celui qui résout pour toi, de façon incompréhensible, un problème que tu ne savais pas que tu avait... :p
Image utilisateur

Apprenez à utiliser un ORM pour PHP : Doctrine !
 
Hors ligne iglou # Posté le 07/10/2011 à 13:03:48
Avatar

J'ai relu le tuto + les blabla.

J'ai tjr un erreur : SQLSTATE[28000] [1045] et je me suis renseigner sur google donc je suis tombé sur un truc qui dit que l'acces de l'utilisateur à la base est refusé, et jme demande prkwa?
j'ai vérifier les utilisateurs, d'ailleur j'en ai creer d'autre sous phpmyadmin ms ca me donne tjr la même erreur.

Fatal error: Uncaught exception 'Doctrine_Connection_Exception' with message 'PDO Connection Error: SQLSTATE[28000] [1045] Access denied for user 'mpfrigany'@'localhost' (using password: YES)' in C:\wamp\www\doctrine2\lib\vendor\doctrine\Doctrine\Connection.php on line 474

j'ai utiliser le root, ms cela ne marche pas non plus.
aider mwa svp!
Hors ligne iglou # Posté le 07/10/2011 à 13:17:25
Avatar

ca y est ca a marché, en fait il y avait une erreur sans doute dans mon schema.yml puique quand j'aivait l'accès à la bdd, il y avait une autre erreur soit disant qu'il y a une erreur SQL quelque part du coup j'ai recopié le schema.yml du tuto
Hors ligne Wize # Posté le 27/10/2011 à 16:50:51
...
Avatar

Études : IUP MIAGE Paris Sorbonne

Edit : merci trouvé

Wize
 

Voir tous les commentaires
Ce tutoriel a été corrigé par les zCorrecteurs.