Coverage for Doctrine_Migration_Builder

Back to coverage report

1 <?php
2 /*
3  *  $Id: Builder.php 2939 2007-10-19 14:23:42Z Jonathan.Wage $
4  *
5  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16  *
17  * This software consists of voluntary contributions made by many individuals
18  * and is licensed under the LGPL. For more information, see
19  * <http://www.phpdoctrine.org>.
20  */
21
22 /**
23  * Doctrine_Migration_Builder
24  *
25  * @package     Doctrine
26  * @subpackage  Migration
27  * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
28  * @author      Jonathan H. Wage <jwage@mac.com>
29  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
30  * @link        www.phpdoctrine.org
31  * @since       1.0
32  * @version     $Revision: 2939 $
33  */
34 class Doctrine_Migration_Builder
35 {
36     /**
37      * migrationsPath
38      * 
39      * The path to your migration classes directory
40      *
41      * @var string
42      */
43     private $migrationsPath = '';
44
45     /**
46      * suffix
47      * 
48      * File suffix to use when writing class definitions
49      *
50      * @var string $suffix
51      */
52     private $suffix = '.class.php';
53
54     /**
55      * migration
56      *
57      * @var string
58      */
59     private $migration;
60
61     /**
62      * tpl
63      *
64      * Class template used for writing classes
65      *
66      * @var $tpl
67      */
68     private static $tpl;
69
70     /**
71      * __construct
72      *
73      * @return void
74      */
75     public function __construct($migrationsPath = null)
76     {
77         if ($migrationsPath) {
78             $this->setMigrationsPath($migrationsPath);
79             $this->migration = new Doctrine_Migration($migrationsPath);
80         }
81         
82         $this->loadTemplate();
83     }
84
85     /**
86      * setMigrationsPath
87      *
88      * @param string path   the path where migration classes are stored and being generated
89      * @return
90      */
91     public function setMigrationsPath($path)
92     {
93         Doctrine_Lib::makeDirectories($path);
94
95         $this->migrationsPath = $path;
96     }
97
98     /**
99      * getMigrationsPath
100      *
101      * @return string       the path where migration classes are stored and being generated
102      */
103     public function getMigrationsPath()
104     {
105         return $this->migrationsPath;
106     }
107
108     /**
109      * loadTemplate
110      * 
111      * Loads the class template used for generating classes
112      *
113      * @return void
114      */
115     protected function loadTemplate() 
116     {
117         if (isset(self::$tpl)) {
118             return;
119         }
120
121         self::$tpl =<<<END
122 /**
123  * This class has been auto-generated by the Doctrine ORM Framework
124  */
125 class %s extends %s
126 {
127 public function up()
128 {
129 %s
130 }
131
132 public function down()
133 {
134 %s
135 }
136 }
137 END;
138     }
139
140     /**
141      * generateMigrationsFromDb
142      *
143      * @return void
144      */
145     public function generateMigrationsFromDb()
146     {
147         $directory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'tmp_doctrine_models';
148
149         Doctrine::generateModelsFromDb($directory);
150         
151         $result = $this->generateMigrationsFromModels($directory, Doctrine::MODEL_LOADING_CONSERVATIVE);
152         
153         Doctrine_Lib::removeDirectories($directory);
154         
155         return $result;
156     }
157
158     /**
159      * generateMigrationsFromModels
160      *
161      * @param string $modelsPath 
162      * @return void
163      */
164     public function generateMigrationsFromModels($modelsPath = null, $modelLoading = null)
165     {
166         if ($modelsPath !== null) {
167             $models = Doctrine::filterInvalidModels(Doctrine::loadModels($modelsPath, $modelLoading));
168         } else {
169             $models = Doctrine::getLoadedModels();
170         }
171         
172         $foreignKeys = array();
173         
174         foreach ($models as $model) {
175             $export = Doctrine::getTable($model)->getExportableFormat();
176             
177             $foreignKeys[$export['tableName']] = $export['options']['foreignKeys'];
178             
179             $up = $this->buildCreateTable($export);
180             $down = $this->buildDropTable($export);
181             
182             $className = 'Add' . Doctrine::classify($export['tableName']);
183
184             $this->generateMigrationClass($className, array(), $up, $down);
185         }
186         
187         if ( ! empty($foreignKeys)) {
188             $className = 'ApplyForeignKeyConstraints';
189         
190             $up = '';
191             $down = '';
192             foreach ($foreignKeys as $tableName => $definitions)    {
193                 $tableForeignKeyNames[$tableName] = array();
194             
195                 foreach ($definitions as $definition) {
196                     $definition['name'] = $tableName . '_' . $definition['foreignTable'] . '_' . $definition['local'] . '_' . $definition['foreign'];
197                 
198                     $up .= $this->buildCreateForeignKey($tableName, $definition);
199                     $down .= $this->buildDropForeignKey($tableName, $definition);
200                 }
201             }
202         
203             $this->generateMigrationClass($className, array(), $up, $down);
204         }
205         
206         return true;
207     }
208
209     /**
210      * buildCreateForeignKey
211      *
212      * @param string $tableName 
213      * @param string $definition 
214      * @return void
215      */
216     public function buildCreateForeignKey($tableName, $definition)
217     {
218         return "\t\t\$this->createForeignKey('" . $tableName . "', " . var_export($definition, true) . ");";
219     }
220
221     /**
222      * buildDropForeignKey
223      *
224      * @param string $tableName 
225      * @param string $definition 
226      * @return void
227      */
228     public function buildDropForeignKey($tableName, $definition)
229     {
230         return "\t\t\$this->dropForeignKey('" . $tableName . "', '" . $definition['name'] . "');\n";
231     }
232
233     /**
234      * buildCreateTable
235      *
236      * @param string $tableData 
237      * @return void
238      */
239     public function buildCreateTable($tableData)
240     {
241         $code  = "\t\t\$this->createTable('" . $tableData['tableName'] . "', ";
242         
243         $code .= var_export($tableData['columns'], true) . ", ";
244         
245         $code .= var_export(array('indexes' => $tableData['options']['indexes'], 'primary' => $tableData['options']['primary']), true);
246         
247         $code .= ");";
248         
249         return $code;
250     }
251
252     /**
253      * buildDropTable
254      *
255      * @param string $tableData 
256      * @return string
257      */
258     public function buildDropTable($tableData)
259     {
260         return "\t\t\$this->dropTable('" . $tableData['tableName'] . "');";
261     }
262
263     /**
264      * generateMigrationClass
265      *
266      * @return void
267      */
268     public function generateMigrationClass($className, $options = array(), $up = null, $down = null, $return = false)
269     {
270         $className = Doctrine_Inflector::urlize($className);
271         $className = str_replace('-', '_', $className);
272         $className = Doctrine_Inflector::classify($className);
273
274         if ($return || ! $this->getMigrationsPath()) {
275             return $this->buildMigrationClass($className, null, $options, $up, $down);
276         } else {
277             if ( ! $this->getMigrationsPath()) {
278                 throw new Doctrine_Migration_Exception('You must specify the path to your migrations.');
279             }
280             
281             $next = (string) $this->migration->getNextVersion();
282             
283             $fileName = str_repeat('0', (3 - strlen($next))) . $next . '_' . Doctrine::tableize($className) . $this->suffix;
284             
285             $class = $this->buildMigrationClass($className, $fileName, $options, $up, $down);
286             
287             $path = $this->getMigrationsPath() . DIRECTORY_SEPARATOR . $fileName;
288             
289             if ( class_exists($className) || file_exists($path)) {
290                 return false;
291             }
292             
293             file_put_contents($path, $class);
294
295             return true;
296         }
297     }
298
299     /**
300      * buildMigrationClass
301      *
302      * @return string
303      */
304     public function buildMigrationClass($className, $fileName = null, $options = array(), $up = null, $down = null)
305     {
306         $extends = isset($options['extends']) ? $options['extends']:'Doctrine_Migration';
307         
308         $content  = '<?php' . PHP_EOL;
309         
310         $content .= sprintf(self::$tpl, $className,
311                                        $extends,
312                                        $up,
313                                        $down);
314         
315         
316         return $content;
317     }
318 }