{"id":373,"date":"2013-04-22T21:56:48","date_gmt":"2013-04-22T19:56:48","guid":{"rendered":"http:\/\/www.lafabriquedecode.com\/blog\/?p=373"},"modified":"2013-04-22T21:56:48","modified_gmt":"2013-04-22T19:56:48","slug":"doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin","status":"publish","type":"post","link":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/","title":{"rendered":"Doctrine : les migrations avec le bundle DoctrineMigrationsBundle (3\/3)"},"content":{"rendered":"<p>Voici la derni\u00e8re partie de mon billet concernant les migrations Doctrine et le <em>bundle<\/em> associ\u00e9.<\/p>\n<h1>Les relations des entit\u00e9s Doctrine<\/h1>\n<p>Nos \u00e9l\u00e8ves ont une relation avec leur fili\u00e8re. Nous en avons parl\u00e9 au tout d\u00e9but lorsque nous d\u00e9finissions les cardinalit\u00e9s :<\/p>\n<ul>\n<li><span style=\"line-height: 1.714285714; font-size: 1rem;\">un \u00e9l\u00e8ve a une seule fili\u00e8re<\/span><\/li>\n<li><span style=\"line-height: 1.714285714; font-size: 1rem;\">une fili\u00e8re a 0 ou plusieurs \u00e9l\u00e8ves<\/span><\/li>\n<\/ul>\n<p><img loading=\"lazy\" class=\"alignnone size-full wp-image-382\" alt=\"doctrine\" src=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/04\/doctrine.gif\" width=\"191\" height=\"53\" \/><br \/>\nIl va nous falloir d\u00e9finir ceci au niveau de nos entit\u00e9s Doctrine. Nous allons donc \u00ab\u00a0tirer un fil\u00a0\u00bb entre nos entit\u00e9s Eleve et Filiere. Doctrine a des moyens de mettre \u00e7a en place et nous allons voir comment ceci se mat\u00e9rialise avec les annotations, que nous avons choisi de privil\u00e9gier lorsque nous avons g\u00e9n\u00e9r\u00e9 nos entit\u00e9s.<\/p>\n<p>Entre Eleve et Filiere, il y a une relation de un \u00e0 plusieurs (<em>one to many<\/em> en anglais). Nous la voulons bi-directionnelle dans le sens o\u00f9 nous souhaitons pouvoir \u00e0 partir d&rsquo;un \u00e9l\u00e8ve r\u00e9cup\u00e9rer sa fili\u00e8re et, \u00e0 partir d&rsquo;une fili\u00e8re, r\u00e9cup\u00e9rer ses \u00e9l\u00e8ves.\u00a0Dans l&rsquo;entit\u00e9 Eleve, nous sommes du c\u00f4t\u00e9 <em>plusieurs<\/em> de la relation (car plusieurs \u00e9l\u00e8ves correspondent \u00e0 une fili\u00e8re). Voici comment nous allons nous servir des annotations Doctrine :<\/p>\n<pre>   \/**\r\n     * @ORM\\ManyToOne(targetEntity=\"Filiere\", inversedBy=\"eleves\")\r\n     * @ORM\\JoinColumn(name=\"filiere_id\", referencedColumnName=\"id\", nullable=false)\r\n     **\/\r\n    <strong>private $filiere;<\/strong><\/pre>\n<p>Nous d\u00e9finissons une variable d&rsquo;instance priv\u00e9e <em>filiere<\/em> qui va aider Doctrine \u00e0 stocker la fili\u00e8re d&rsquo;un \u00e9l\u00e8ve (il n&rsquo;y en a qu&rsquo;une possible, souvenez-vous). La cible de la relation que nous sommes en train de d\u00e9crire dans l&rsquo;entit\u00e9 Eleve est l&rsquo;entit\u00e9 Filiere, c&rsquo;est ce que nous dit <em>targetEntity<\/em>. Le <em>inversedBy<\/em> qui suit signifie que de l&rsquo;autre c\u00f4t\u00e9 de la relation (dans l&rsquo;entit\u00e9 Filiere) nous trouverons l&rsquo;attribut charg\u00e9 de g\u00e9rer cette relation sous le nom d&rsquo;eleves (notez bien le pluriel car de l&rsquo;autre c\u00f4t\u00e9 de la relation nous aurons plusieurs \u00e9l\u00e8ves pour notre fili\u00e8re). <em>JoinColumn<\/em> d\u00e9crit la mani\u00e8re physique dont cette relation va exister. En lisant, vous devinez que dans notre table nous allons avoir un champ rajout\u00e9 suite \u00e0 l&rsquo;\u00e9criture de cette relation qui va identifier une fili\u00e8re pour un \u00e9l\u00e8ve, que ce champ s&rsquo;appellera <em>filiere_id<\/em> et qu&rsquo;il r\u00e9f\u00e9rencera une colonne appel\u00e9e id&#8230;Vous voyez d\u00e9j\u00e0 venir gros comme une maison la contrainte d&rsquo;int\u00e9grit\u00e9 r\u00e9f\u00e9rentielle. Le <strong>nullable=false<\/strong> signifie qu&rsquo;il faut obligatoirement une fili\u00e8re \u00e0 un \u00e9l\u00e8ve\u00a0; l\u00e0 aussi vous devez imaginer que cette clause entra\u00eenera la pr\u00e9sence d&rsquo;un NOT NULL dans le sch\u00e9ma relationnel.<\/p>\n<p>Du c\u00f4t\u00e9 de l&rsquo;entit\u00e9 Filiere, nous avons l&rsquo;annotation Doctrine suivante pour la variable d&rsquo;instance eleves dont nous avons d\u00e9j\u00e0 parl\u00e9 :<\/p>\n<pre>     \/**\r\n     * @ORM\\OneToMany(targetEntity=\"Eleve\", mappedBy=\"filiere\")\r\n     **\/\r\n    <strong>private $eleves;<\/strong>\r\n\r\n    public function __construct()\r\n    {\r\n        $this-&gt;eleves = new ArrayCollection;\r\n    }<\/pre>\n<p>Nous prenons la relation dans l&rsquo;autre sens &#8211; \u00ab\u00a0un vers plusieurs\u00a0\u00bb &#8211; parce qu&rsquo;une fili\u00e8re a plusieurs \u00e9l\u00e8ves. Voil\u00e0 pourquoi cette fois c&rsquo;est one to many en lieu et place du many to one qu&rsquo;on trouvait dans Eleve. La cible, c&rsquo;est bien Eleve et l&rsquo;attribut qui va servir c&rsquo;est bien filiere (private $filiere). Dans Eleve nous avions <em>inversedBy<\/em>, dans Filiere nous avons <em>mappedBy<\/em>.\u00a0Doctrine d\u00e9termine le c\u00f4t\u00e9 \u00ab\u00a0possesseur\u00a0\u00bb de la relation par <em>inversedBy<\/em> et l&rsquo;autre c\u00f4t\u00e9 (\u00ab\u00a0inverseur\u00a0\u00bb) par <em>mappedBy<\/em>.<\/p>\n<p>Comme nous avons potentiellement plusieurs \u00e9l\u00e8ves pour une fili\u00e8re, nous allons avoir \u00e0 g\u00e9rer plusieurs objets. Pour ce faire, Doctrine nous propose son type <em>ArrayCollection<\/em>, que vous allez pouvoir utiliser en faisant :<\/p>\n<pre>use Doctrine\\Common\\Collections\\ArrayCollection;<\/pre>\n<p>Notre variable d&rsquo;instance priv\u00e9e eleves sera de ce type et nous l&rsquo;initialiserons dans le constructeur de notre classe.<\/p>\n<p>Nous avons construit notre premi\u00e8re relation au niveau objet ! L&rsquo;heure est venue de mettre notre sch\u00e9ma de bases de donn\u00e9es \u00e0 jour avec tout cela ! Allons-y !<\/p>\n<pre>app\/console doctrine:migrations:diff<\/pre>\n<p>Ouvrons le fichier ainsi g\u00e9n\u00e9r\u00e9 pour v\u00e9rifier que notre relation est bien en place :<\/p>\n<pre>$this-&gt;addSql(\"ALTER TABLE eleve ADD filiere_id INT NOT NULL\");\r\n$this-&gt;addSql(\"ALTER TABLE eleve ADD CONSTRAINT FK_ECA105F7180AA129 FOREIGN KEY (filiere_id) REFERENCES filiere (id)\");\r\n$this-&gt;addSql(\"CREATE INDEX IDX_ECA105F7180AA129 ON eleve (filiere_id)\");<\/pre>\n<p>Ce que nous envisagions est effectivement arriv\u00e9, nous avons bel et bien une contrainte d&rsquo;int\u00e9grit\u00e9 r\u00e9f\u00e9rentielle pos\u00e9e entre la table eleve et la table filiere !<\/p>\n<p>Lan\u00e7ons maintenant la migration\u00a0:<\/p>\n<pre>app\/console doctrine:migrations:migrate<\/pre>\n<p>Notre table eleve a bien un champ en plus\u00a0: filiere_id !<\/p>\n<pre>sebastien.ferrandez@sebastien:~\/migrations$ mysql -u root -p -e 'use exercice; desc eleve'\r\nEnter password: \r\n+------------+-------------+------+-----+---------+----------------+\r\n| Field      | Type        | Null | Key | Default | Extra          |\r\n+------------+-------------+------+-----+---------+----------------+\r\n| id         | int(11)     | NO   | PRI | NULL    | auto_increment |\r\n| nom        | varchar(40) | NO   |     | NULL    |                |\r\n| prenom     | varchar(40) | NO   |     | NULL    |                |\r\n| age        | int(11)     | NO   |     | NULL    |                |\r\n|<strong> filiere_id | int(11)     | NO   | MUL | NULL    | <\/strong>               |\r\n+------------+-------------+------+-----+---------+----------------+<\/pre>\n<p>Occupons-nous ensuite des cours: un cours a des relations avec salle, enseignant et fili\u00e8re, en fait cours est au centre de tout&#8230;Quelles sont-elles exactement ? Reprenons ce que nous avions \u00e9tabli :<\/p>\n<ul>\n<li><span style=\"line-height: 1.714285714; font-size: 1rem;\">une <strong>fili\u00e8re<\/strong> est compos\u00e9e d&rsquo;un ou plusieurs <em>cours<\/em><\/span><\/li>\n<li><span style=\"line-height: 1.714285714; font-size: 1rem;\">un <strong>cours<\/strong> n&rsquo;a qu&rsquo;un seul et unique <strong>enseignant<\/strong> mais un enseignant a un ou plusieurs cours<\/span><\/li>\n<li><span style=\"line-height: 1.714285714; font-size: 1rem;\">un <strong>cours<\/strong> se tient dans une seule <strong>salle<\/strong> \u00e0 un moment donn\u00e9 et une salle peut abriter plusieurs cours. On peut tr\u00e8s bien cr\u00e9er un cours sans salle car il arrive qu&rsquo;on ne puisse d\u00e9cider de suite dans quelle salle il se tiendra. Elle sera rajout\u00e9e plus tard.<\/span><\/li>\n<\/ul>\n<p>Les relations nous apparaissent \u00e9videntes. Un lien de type \u00ab\u00a0un \u00e0 plusieurs\u00a0\u00bb existe entre cours et enseignant (\u00ab\u00a0un \u00e0 plusieurs\u00a0\u00bb dans le sens enseignant \u2192 cours et \u00ab\u00a0plusieurs \u00e0 un\u00a0\u00bb dans le sens inverse). Il en va de m\u00eame pour les salles ou les fili\u00e8res. La seule diff\u00e9rence r\u00e9side en le fait qu&rsquo;un cours a forc\u00e9ment un enseignant ou une fili\u00e8re alors qu&rsquo;il n&rsquo;a pas forc\u00e9ment de salle (on peut le cr\u00e9er sans salle pour lui en affecter une quand on a consult\u00e9 le planning des salles et qu&rsquo;on en a trouv\u00e9 une de disponible). Nous allons donc nous retrouver \u00e0 ajouter des annotations de type <em>ManyToOne<\/em> dans notre entit\u00e9 Cours.<\/p>\n<pre>    \/**\r\n     * @ORM\\ManyToOne(targetEntity=\"Filiere\", inversedBy=\"cours\")\r\n     * @ORM\\JoinColumn(name=\"filiere_id\", referencedColumnName=\"id\", nullable=false)\r\n     **\/\r\n    <strong>private $filiere;<\/strong>\r\n\r\n    \/**\r\n     * @ORM\\ManyToOne(targetEntity=\"Salle\", inversedBy=\"cours\")\r\n     * @ORM\\JoinColumn(name=\"salle_id\", referencedColumnName=\"id\")\r\n     **\/\r\n    <strong>private $salle;<\/strong>\r\n\r\n    \/**\r\n     * @ORM\\ManyToOne(targetEntity=\"Enseignant\", inversedBy=\"cours\")\r\n     * @ORM\\JoinColumn(name=\"enseignant_id\", referencedColumnName=\"id\", nullable=false)\r\n     **\/\r\n    <strong>private $enseignant;<\/strong><\/pre>\n<p>Vous noterez que salle est le seul endroit o\u00f9 nullable est \u00e0 sa valeur par d\u00e9faut, c&rsquo;est \u00e0 dire true et qu&rsquo;il sera donc possible d&rsquo;enregistrer un cours sans salle. Dans la mesure o\u00f9 nous avons pour un cours soit 0 (pour une salle) soit un (enseignant, fili\u00e8re) inutile ici d&rsquo;utiliser les <em>ArrayCollection<\/em> comme c&rsquo;\u00e9tait le cas pour mat\u00e9rialiser la relation fili\u00e8re\/\u00e9l\u00e8ve.<br \/>\nDans chacune de ces entit\u00e9s cibles nous auront une variable d&rsquo;instance nomm\u00e9e cours, c&rsquo;est aussi ce que nous disent ces annotations.<\/p>\n<p>Dans l&rsquo;entit\u00e9 Salle\u00a0:<\/p>\n<pre>    \/**\r\n     * @ORM\\OneToMany(targetEntity=\"Cours\", mappedBy=\"salle\")\r\n     **\/\r\n    private $cours;\r\n\r\n    public function __construct()\r\n    {\r\n        $this-&gt;cours = new ArrayCollection;\r\n    }<\/pre>\n<p>Ici par contre une salle est susceptible d&rsquo;accueillir plusieurs cours (NFA057 le jeudi soir, NFA053 le mardi), la notion de collection a ici du sens. Idem pour les enseignants\u00a0:<\/p>\n<pre>    \/**\r\n     * @ORM\\OneToMany(targetEntity=\"Cours\", mappedBy=\"enseignant\")\r\n     **\/\r\n    private $cours;\r\n\r\n    public function __construct()\r\n    {\r\n        $this-&gt;cours = new ArrayCollection;\r\n    }<\/pre>\n<p>Ou encore Filiere :<\/p>\n<pre>    \/**\r\n     * @ORM\\OneToMany(targetEntity=\"Cours\", mappedBy=\"filiere\")\r\n     **\/\r\n    private $cours;<\/pre>\n<p>Vous avez remarqu\u00e9 que le champ <em>mappedBy<\/em> de l&rsquo;annotation pointe vers la variable d&rsquo;instance correspondante dans l&rsquo;entit\u00e9 Cours. Dans le cas de Filiere, l&rsquo;entit\u00e9 avait d\u00e9j\u00e0 une instanciation de la classe <em>ArrayCollection<\/em> dans son constructeur, nous devons en rajouter une autre pour les cours, comme fait dans les autres entit\u00e9s, plus haut, ce qui donnera\u00a0:<\/p>\n<pre>public function __construct()\r\n    {\r\n        $this-&gt;cours = new ArrayCollection;\r\n        $this-&gt;eleves = new ArrayCollection;\r\n    }<\/pre>\n<p>Une fois que nous avons mis nos relations dans nos 4 entit\u00e9s, il nous reste \u00e0 ex\u00e9cuter une migration\u00a0!<\/p>\n<pre>app\/console doctrine:migrations:diff\r\napp\/console doctrine:migrations:migrate<\/pre>\n<p>feront appara\u00eetre les contraintes d&rsquo;int\u00e9grit\u00e9 r\u00e9f\u00e9rentielle entre la table cours et enseignant, salle et filiere.<\/p>\n<p>Maintenant que nous avons \u00e9tabli notre architecture objet avec nos entit\u00e9s, regardons avec <a href=\"http:\/\/www.mysql.com\/downloads\/workbench\/\" target=\"_blank\">MySQL Workbench<\/a> \u00e0 quoi ressemble notre sch\u00e9ma et surtout s&rsquo;il satisfait \u00e0 toutes les contraintes que nous avons \u00e9nonc\u00e9es au d\u00e9but du pr\u00e9sent document\u00a0:<\/p>\n<p><a href=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/04\/snapshot26.png\"><img loading=\"lazy\" class=\"alignnone size-full wp-image-379\" alt=\"snapshot2\" src=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/04\/snapshot26.png\" width=\"425\" height=\"587\" srcset=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/04\/snapshot26.png 425w, http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/04\/snapshot26-217x300.png 217w\" sizes=\"(max-width: 425px) 100vw, 425px\" \/><\/a><\/p>\n<p>En naviguant \u00e0 travers les relations, nous sommes s\u00fbrs que nous avons effectu\u00e9 du bon travail car elles correspondent en tous points \u00e0 ce que nous souhaitions.<\/p>\n<p>Au sujet des types de donn\u00e9es utilis\u00e9s par Doctrine, nous voyons qu&rsquo;ils ne correspondent pas forc\u00e9ment \u00e0 ce que nous recherchons en terme de plage de valeurs (des INTEGER pour g\u00e9rer des \u00e2ges &#8211; pas sign\u00e9s qui plus est -, des DATETIME alors que des TIMESTAMP, deux fois moins gourmands en espace disque, suffiraient). Il y a beaucoup \u00e0 redire de ce c\u00f4t\u00e9 l\u00e0 sur ce sch\u00e9ma mais sachez qu&rsquo;il est toujours possible de forcer Doctrine \u00e0 utiliser des types choisis par nos soins avant de passer une migration\u00a0! Il suffit d&rsquo;en faire \u00e9tat dans les annotations de nos entit\u00e9s. Attention cependant, changer le type des donn\u00e9es choisies par Doctrine peut faire que les changements d&rsquo;\u00e9tat de votre sch\u00e9ma (de la colonne modifi\u00e9e, pour \u00eatre plus exact) ne sont pas pris en compte comme ils devraient l&rsquo;\u00eatre par Doctrine, qui ne retrouve plus ses types \u00ab\u00a0natifs\u00a0\u00bb, puisque vous les avez modifi\u00e9s.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Voici la derni\u00e8re partie de mon billet concernant les migrations Doctrine et le bundle associ\u00e9. Les relations des entit\u00e9s Doctrine Nos \u00e9l\u00e8ves ont une relation avec leur fili\u00e8re. Nous en avons parl\u00e9 au tout d\u00e9but lorsque nous d\u00e9finissions les cardinalit\u00e9s : un \u00e9l\u00e8ve a une seule fili\u00e8re une fili\u00e8re a 0 ou plusieurs \u00e9l\u00e8ves Il [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[38,33,2],"tags":[34,45,44],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.6.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Doctrine : les migrations avec le bundle DoctrineMigrationsBundle (3\/3) - La Fabrique de code - Tech blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Doctrine : les migrations avec le bundle DoctrineMigrationsBundle (3\/3) - La Fabrique de code - Tech blog\" \/>\n<meta property=\"og:description\" content=\"Voici la derni\u00e8re partie de mon billet concernant les migrations Doctrine et le bundle associ\u00e9. Les relations des entit\u00e9s Doctrine Nos \u00e9l\u00e8ves ont une relation avec leur fili\u00e8re. Nous en avons parl\u00e9 au tout d\u00e9but lorsque nous d\u00e9finissions les cardinalit\u00e9s : un \u00e9l\u00e8ve a une seule fili\u00e8re une fili\u00e8re a 0 ou plusieurs \u00e9l\u00e8ves Il [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/\" \/>\n<meta property=\"og:site_name\" content=\"La Fabrique de code - Tech blog\" \/>\n<meta property=\"article:published_time\" content=\"2013-04-22T19:56:48+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/04\/doctrine.gif\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary\" \/>\n<meta name=\"twitter:creator\" content=\"@LaFabrique2Code\" \/>\n<meta name=\"twitter:site\" content=\"@LaFabrique2Code\" \/>\n<meta name=\"twitter:label1\" content=\"\u00c9crit par\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/\",\"url\":\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/\",\"name\":\"Doctrine : les migrations avec le bundle DoctrineMigrationsBundle (3\/3) - La Fabrique de code - Tech blog\",\"isPartOf\":{\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#website\"},\"datePublished\":\"2013-04-22T19:56:48+00:00\",\"dateModified\":\"2013-04-22T19:56:48+00:00\",\"author\":{\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162\"},\"breadcrumb\":{\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/#breadcrumb\"},\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"http:\/\/www.lafabriquedecode.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Doctrine : les migrations avec le bundle DoctrineMigrationsBundle (3\/3)\"}]},{\"@type\":\"WebSite\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#website\",\"url\":\"http:\/\/www.lafabriquedecode.com\/blog\/\",\"name\":\"La Fabrique de code - Tech blog\",\"description\":\"PHP objet, MySQL, Design Patterns, OOP...et plus !\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"http:\/\/www.lafabriquedecode.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Person\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g\",\"contentUrl\":\"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g\",\"caption\":\"admin\"},\"url\":\"http:\/\/www.lafabriquedecode.com\/blog\/author\/admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Doctrine : les migrations avec le bundle DoctrineMigrationsBundle (3\/3) - La Fabrique de code - Tech blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/","og_locale":"fr_FR","og_type":"article","og_title":"Doctrine : les migrations avec le bundle DoctrineMigrationsBundle (3\/3) - La Fabrique de code - Tech blog","og_description":"Voici la derni\u00e8re partie de mon billet concernant les migrations Doctrine et le bundle associ\u00e9. Les relations des entit\u00e9s Doctrine Nos \u00e9l\u00e8ves ont une relation avec leur fili\u00e8re. Nous en avons parl\u00e9 au tout d\u00e9but lorsque nous d\u00e9finissions les cardinalit\u00e9s : un \u00e9l\u00e8ve a une seule fili\u00e8re une fili\u00e8re a 0 ou plusieurs \u00e9l\u00e8ves Il [&hellip;]","og_url":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/","og_site_name":"La Fabrique de code - Tech blog","article_published_time":"2013-04-22T19:56:48+00:00","og_image":[{"url":"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2013\/04\/doctrine.gif"}],"author":"admin","twitter_card":"summary","twitter_creator":"@LaFabrique2Code","twitter_site":"@LaFabrique2Code","twitter_misc":{"\u00c9crit par":"admin","Dur\u00e9e de lecture estim\u00e9e":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/","url":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/","name":"Doctrine : les migrations avec le bundle DoctrineMigrationsBundle (3\/3) - La Fabrique de code - Tech blog","isPartOf":{"@id":"http:\/\/www.lafabriquedecode.com\/blog\/#website"},"datePublished":"2013-04-22T19:56:48+00:00","dateModified":"2013-04-22T19:56:48+00:00","author":{"@id":"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162"},"breadcrumb":{"@id":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/#breadcrumb"},"inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/"]}]},{"@type":"BreadcrumbList","@id":"http:\/\/www.lafabriquedecode.com\/blog\/2013\/04\/doctrine-les-migrations-avec-le-bundle-doctrinemigrationsbundle-suite-et-fin\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"http:\/\/www.lafabriquedecode.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Doctrine : les migrations avec le bundle DoctrineMigrationsBundle (3\/3)"}]},{"@type":"WebSite","@id":"http:\/\/www.lafabriquedecode.com\/blog\/#website","url":"http:\/\/www.lafabriquedecode.com\/blog\/","name":"La Fabrique de code - Tech blog","description":"PHP objet, MySQL, Design Patterns, OOP...et plus !","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"http:\/\/www.lafabriquedecode.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"fr-FR"},{"@type":"Person","@id":"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162","name":"admin","image":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/image\/","url":"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g","contentUrl":"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g","caption":"admin"},"url":"http:\/\/www.lafabriquedecode.com\/blog\/author\/admin\/"}]}},"_links":{"self":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts\/373"}],"collection":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/comments?post=373"}],"version-history":[{"count":9,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts\/373\/revisions"}],"predecessor-version":[{"id":384,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts\/373\/revisions\/384"}],"wp:attachment":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/media?parent=373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/categories?post=373"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/tags?post=373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}