Coverage for Doctrine_Import_Builder

Back to coverage report

1 <?php
2 /*
3  *  $Id: Builder.php 4078 2008-03-22 01:04:27Z jwage $
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_Import_Builder
24  *
25  * Import builder is responsible of building Doctrine_Record classes
26  * based on a database schema.
27  *
28  * @package     Doctrine
29  * @subpackage  Import
30  * @link        www.phpdoctrine.org
31  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
32  * @since       1.0
33  * @version     $Revision: 4078 $
34  * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
35  * @author      Jukka Hassinen <Jukka.Hassinen@BrainAlliance.com>
36  * @author      Nicolas BĂ©rard-Nault <nicobn@php.net>
37  * @author      Jonathan H. Wage <jwage@mac.com>
38  */
39 class Doctrine_Import_Builder
40 {
41     /**
42      * _path
43      * 
44      * the path where imported files are being generated
45      *
46      * @var string $_path
47      */
48     protected $_path = '';
49     
50     /**
51      * _packagesPrefix
52      *
53      * @var string
54      */
55     protected $_packagesPrefix = 'Package';
56
57     /**
58      * _packagesPath
59      *
60      * @var string
61      */
62     protected $_packagesPath = '';
63
64     /**
65      * _packagesFolderName
66      *
67      * @var string
68      */
69     protected $_packagesFolderName = 'packages';
70
71     /**
72      * _suffix
73      * 
74      * File suffix to use when writing class definitions
75      *
76      * @var string $suffix
77      */
78     protected $_suffix = '.php';
79
80     /**
81      * _generateBaseClasses
82      * 
83      * Bool true/false for whether or not to generate base classes
84      *
85      * @var string $suffix
86      */
87     protected $_generateBaseClasses = true;
88
89     /**
90      * _base
91      *
92      * Prefix to use for generated base classes
93      *
94      * @var string
95      */
96     protected $_baseClassPrefix = 'Base';
97
98     /**
99      * _baseClassesDirectory
100      * 
101      * Directory to put the generate base classes in
102      *
103      * @var string $suffix
104      */
105     protected $_baseClassesDirectory = 'generated';
106     
107     /**
108      * _baseClassName
109      *
110      * @var string
111      */
112     protected $_baseClassName = 'Doctrine_Record';
113
114     /**
115      * _tpl
116      *
117      * Class template used for writing classes
118      *
119      * @var $_tpl
120      */
121     protected static $_tpl;
122
123     /**
124      * __construct
125      *
126      * @return void
127      */
128     public function __construct()
129     {
130         $this->loadTemplate();
131     }
132
133     /**
134      * setTargetPath
135      *
136      * @param string path   the path where imported files are being generated
137      * @return
138      */
139     public function setTargetPath($path)
140     {
141         if ($path) {
142             if ( ! $this->_packagesPath) {
143                 $this->setPackagesPath($path . DIRECTORY_SEPARATOR . $this->_packagesFolderName);
144             }
145
146             $this->_path = $path;
147         }
148     }
149     
150     /**
151      * setPackagePath
152      *
153      * @param string $packagesPrefix 
154      * @return void
155      */
156     public function setPackagesPrefix($packagesPrefix)
157     {
158         $this->_packagesPrefix = $packagesPrefix;
159     }
160
161     /**
162      * setPackagesPath
163      *
164      * @param string $packagesPath 
165      * @return void
166      */
167     public function setPackagesPath($packagesPath)
168     {
169         if ($packagesPath) {
170             $this->_packagesPath = $packagesPath;
171         }
172     }
173     
174     /**
175      * generateBaseClasses
176      *
177      * Specify whether or not to generate classes which extend from generated base classes
178      *
179      * @param string $bool
180      * @return void
181      */
182     public function generateBaseClasses($bool = null)
183     {
184         if ($bool !== null) {
185             $this->_generateBaseClasses = $bool;
186         }
187
188         return $this->_generateBaseClasses;
189     }
190     
191     /**
192      * setBaseClassPrefix
193      *
194      * @param string $prefix 
195      * @return void
196      */
197     public function setBaseClassPrefix($prefix)
198     {
199         $this->_baseClassPrefix = $prefix;
200     }
201     
202     /**
203      * getBaseClassPrefix
204      *
205      * @return void
206      */
207     public function getBaseClassPrefix()
208     {
209         return $this->_baseClassPrefix;
210     }
211     
212     /**
213      * setBaseClassesDirectory
214      *
215      * @return void
216      */
217     public function setBaseClassesDirectory($baseClassesDirectory)
218     {
219         $this->_baseClassesDirectory = $baseClassesDirectory;
220     }
221     
222     /**
223      * setBaseClassName
224      *
225      * @package default
226      */
227     public function setBaseClassName($className)
228     {
229         $this->_baseClassName = $className;
230     }
231     
232     /**
233      * setSuffix
234      *
235      * @param string $suffix 
236      * @return void
237      */
238     public function setSuffix($suffix)
239     {
240         $this->_suffix = $suffix;
241     }
242
243     /**
244      * getTargetPath
245      *
246      * @return string       the path where imported files are being generated
247      */
248     public function getTargetPath()
249     {
250         return $this->_path;
251     }
252
253     /**
254      * setOptions
255      *
256      * @param string $options 
257      * @return void
258      */
259     public function setOptions($options)
260     {
261         if ( ! empty($options)) {
262             foreach ($options as $key => $value) {
263                 $this->setOption($key, $value);
264             }
265         }
266     }
267
268     /**
269      * setOption
270      *
271      * @param string $key 
272      * @param string $value 
273      * @return void
274      */
275     public function setOption($key, $value)
276     {
277         $name = 'set' . Doctrine::classify($key);
278         
279         if (method_exists($this, $name)) {
280             $this->$name($value);
281         } else {
282             $key = '_' . $key;
283             $this->$key = $value;
284         }
285     }
286
287     /**
288      * loadTemplate
289      * 
290      * Loads the class template used for generating classes
291      *
292      * @return void
293      */
294     public function loadTemplate() 
295     {
296         if (isset(self::$_tpl)) {
297             return;
298         }
299
300         self::$_tpl =<<<END
301 /**
302  * This class has been auto-generated by the Doctrine ORM Framework
303  */
304 %sclass %s extends %s
305 {
306 %s
307 %s
308 %s
309 }
310 END;
311     }
312
313     /*
314      * Build the table definition of a Doctrine_Record object
315      *
316      * @param  string $table
317      * @param  array  $tableColumns
318      */
319     public function buildTableDefinition(array $definition)
320     {
321         if (isset($definition['inheritance']['type']) && ($definition['inheritance']['type'] == 'simple' || $definition['inheritance']['type'] == 'column_aggregation')) {
322             return;
323         }
324         
325         $ret = array();
326         
327         $i = 0;
328         
329         if (isset($definition['inheritance']['type']) && $definition['inheritance']['type'] == 'concrete') {
330             $ret[$i] = "    parent::setTableDefinition();";
331             $i++;
332         }
333         
334         if (isset($definition['tableName']) && !empty($definition['tableName'])) {
335             $ret[$i] = "    ".'$this->setTableName(\''. $definition['tableName'].'\');';
336             $i++;
337         }
338         
339         if (isset($definition['columns']) && is_array($definition['columns']) && !empty($definition['columns'])) {
340             $ret[$i] = $this->buildColumns($definition['columns']);
341             $i++;
342         }
343         
344         if (isset($definition['indexes']) && is_array($definition['indexes']) && !empty($definition['indexes'])) {
345             $ret[$i] = $this->buildIndexes($definition['indexes']);
346             $i++;
347         }
348         
349         if (isset($definition['attributes']) && is_array($definition['attributes']) && !empty($definition['attributes'])) {
350             $ret[$i] = $this->buildAttributes($definition['attributes']);
351             $i++;
352         }
353         
354         if (isset($definition['options']) && is_array($definition['options']) && !empty($definition['options'])) {
355             $ret[$i] = $this->buildOptions($definition['options']);
356             $i++;
357         }
358         
359         if (isset($definition['inheritance']['subclasses']) && ! empty($definition['inheritance']['subclasses'])) {
360             $ret[$i] = "    ".'$this->setSubClasses('. $this->varExport($definition['inheritance']['subclasses']).');';
361             $i++;
362         }
363         
364         $code = implode("\n", $ret);
365         $code = trim($code);
366         
367         return "\n  public function setTableDefinition()"."\n  {\n    ".$code."\n  }";
368     }
369
370     /**
371      * buildSetUp
372      *
373      * @param  array $options 
374      * @param  array $columns 
375      * @param  array $relations 
376      * @return string
377      */
378     public function buildSetUp(array $definition)
379     {
380         if (isset($definition['inheritance']['type']) && ($definition['inheritance']['type'] == 'simple')) {
381             return;
382         }
383
384         $ret = array();
385         $i = 0;
386
387         $ret[$i] = "    parent::setUp();";
388         $i++;
389
390         if (isset($definition['relations']) && is_array($definition['relations']) && ! empty($definition['relations'])) {
391             foreach ($definition['relations'] as $name => $relation) {
392                 $class = isset($relation['class']) ? $relation['class']:$name;
393                 $alias = (isset($relation['alias']) && $relation['alias'] !== $relation['class']) ? ' as ' . $relation['alias'] : '';
394
395                 if ( ! isset($relation['type'])) {
396                     $relation['type'] = Doctrine_Relation::ONE;
397                 }
398
399                 if ($relation['type'] === Doctrine_Relation::ONE || 
400                     $relation['type'] === Doctrine_Relation::ONE_COMPOSITE) {
401                     $ret[$i] = "    ".'$this->hasOne(\'' . $class . $alias . '\'';
402                 } else {
403                     $ret[$i] = "    ".'$this->hasMany(\'' . $class . $alias . '\'';
404                 }
405             
406                 $a = array();
407
408                 if (isset($relation['refClass'])) {
409                     $a[] = '\'refClass\' => ' . $this->varExport($relation['refClass']);
410                 }
411             
412                 if (isset($relation['deferred']) && $relation['deferred']) {
413                     $a[] = '\'default\' => ' . $this->varExport($relation['deferred']);
414                 }
415             
416                 if (isset($relation['local']) && $relation['local']) {
417                     $a[] = '\'local\' => ' . $this->varExport($relation['local']);
418                 }
419             
420                 if (isset($relation['foreign']) && $relation['foreign']) {
421                     $a[] = '\'foreign\' => ' . $this->varExport($relation['foreign']);
422                 }
423             
424                 if (isset($relation['onDelete']) && $relation['onDelete']) {
425                     $a[] = '\'onDelete\' => ' . $this->varExport($relation['onDelete']);
426                 }
427             
428                 if (isset($relation['onUpdate']) && $relation['onUpdate']) {
429                     $a[] = '\'onUpdate\' => ' . $this->varExport($relation['onUpdate']);
430                 }
431             
432                 if (isset($relation['equal']) && $relation['equal']) { 
433                     $a[] = '\'equal\' => ' . $this->varExport($relation['equal']); 
434                 }
435             
436                 if ( ! empty($a)) {
437                     $ret[$i] .= ', ' . 'array(';
438                     $length = strlen($ret[$i]);
439                     $ret[$i] .= implode(',' . PHP_EOL . str_repeat(' ', $length), $a) . ')';
440                 }
441             
442                 $ret[$i] .= ');'."\n";
443                 $i++;
444             }
445         }
446
447         if (isset($definition['templates']) && is_array($definition['templates']) && !empty($definition['templates'])) {
448             $ret[$i] = $this->buildTemplates($definition['templates']);
449             $i++;
450         }
451
452         if (isset($definition['actAs']) && is_array($definition['actAs']) && !empty($definition['actAs'])) {
453             $ret[$i] = $this->buildActAs($definition['actAs']);
454             $i++;
455         }
456
457         $code = implode("\n", $ret);
458         $code = trim($code);
459         
460         return "\n  public function setUp()\n  {\n    ".$code."\n  }";
461     }
462
463     /**
464      * buildColumns
465      *
466      * @param string $array 
467      * @return void
468      */
469     public function buildColumns(array $columns)
470     {
471         $build = null;
472         foreach ($columns as $name => $column) {
473             $build .= "    ".'$this->hasColumn(\'' . $name . '\', \'' . $column['type'] . '\'';
474     
475             if ($column['length']) {
476                 $build .= ', ' . $column['length'];
477             } else {
478                 $build .= ', null';
479             }
480
481             // The column definition is one array, everthing but name, type and length are an array of
482             // possible options. This removes the name, type and length and creates the options array for
483             // the column definition
484             $options = $column;
485             $unset = array('name', 'type', 'length');
486             foreach ($options as $key => $value) {
487                 // Remove column elements which are specified above or are null
488                 if (in_array($key, $unset) || is_null($value)) {
489                     unset($options[$key]);
490                 }
491             }
492
493             if (is_array($options) && !empty($options)) {
494                 $build .= ', ' . $this->varExport($options);
495             }
496     
497             $build .= ");\n";
498         }
499         
500         return $build;
501     }
502
503     /**
504      * varExport
505      *
506      * Special function for var_export()
507      * The normal code which is returned is malformed and does not follow Doctrine standards
508      * So we do some string replacing to clean it up
509      *
510      * @param string $var 
511      * @return void
512      */
513     public function varExport($var)
514     {
515         $export = var_export($var, true);
516         $export = str_replace("\n ", '', $export);
517         $export = str_replace('array ( ', 'array(', $export);
518         $export = str_replace(",\n", "", $export);
519         
520         return $export;
521     }
522
523     /*
524      * Build the accessors
525      *
526      * @param  string $table
527      * @param  array  $columns
528      */
529     public function buildAccessors(array $definition)
530     {
531         $accessors = array();
532         foreach (array_keys($definition['columns']) as $name) {
533             $accessors[] = $name;
534         }
535         
536         foreach ($definition['relations'] as $relation) {
537             $accessors[] = $relation['alias'];
538         }
539         
540         $ret = '';
541         foreach ($accessors as $name) {
542             // getters
543             $ret .= "\n  public function get" . Doctrine_Inflector::classify(Doctrine_Inflector::tableize($name)) . "(\$load = true)\n";
544             $ret .= "  {\n";
545             $ret .= "    return \$this->get('{$name}', \$load);\n";
546             $ret .= "  }\n";
547
548             // setters
549             $ret .= "\n  public function set" . Doctrine_Inflector::classify(Doctrine_Inflector::tableize($name)) . "(\${$name}, \$load = true)\n";
550             $ret .= "  {\n";
551             $ret .= "    return \$this->set('{$name}', \${$name}, \$load);\n";
552             $ret .= "  }\n";
553         }
554
555         return $ret;
556     }
557
558     /**
559      * buildTemplates
560      *
561      * @param string $array 
562      * @return void
563      */
564     public function buildTemplates(array $templates)
565     {
566         $build = '';
567         foreach ($templates as $name => $options) {
568             
569             if (is_array($options) && !empty($options)) {
570                 $optionsPhp = $this->varExport($options);
571             
572                 $build .= "    \$this->loadTemplate('" . $name . "', " . $optionsPhp . ");\n";
573             } else {
574                 if (isset($templates[0])) {
575                     $build .= "    \$this->loadTemplate('" . $options . "');\n";
576                 } else {
577                     $build .= "    \$this->loadTemplate('" . $name . "');\n";
578                 }
579             }
580         }
581         
582         return $build;
583     }
584
585     /**
586      * buildActAs
587      *
588      * @param string $array 
589      * @return void
590      */
591     public function buildActAs(array $actAs)
592     {
593         $build = '';
594         foreach ($actAs as $name => $options) {
595             if (is_array($options) && !empty($options)) {
596                 $optionsPhp = $this->varExport($options);
597                 
598                 $build .= "    \$this->actAs('" . $name . "', " . $optionsPhp . ");\n";
599             } else {
600                 if (isset($actAs[0])) {
601                     $build .= "    \$this->actAs('" . $options . "');\n";
602                 } else {
603                     $build .= "    \$this->actAs('" . $name . "');\n";
604                 }
605             }
606         }
607         
608         return $build;
609     }
610
611     /**
612      * buildAttributes
613      *
614      * @param string $array 
615      * @return void
616      */
617     public function buildAttributes(array $attributes)
618     {
619         $build = "\n";
620         foreach ($attributes as $key => $value) {
621           
622             if (is_bool($value))
623             {
624               $values = $value ? 'true':'false';
625             } else {
626                 if ( ! is_array($value)) {
627                     $value = array($value);
628                 }
629             
630                 $values = '';
631                 foreach ($value as $attr) {
632                     $values .= "Doctrine::" . strtoupper($key) . "_" . strtoupper($attr) . ' ^ ';
633                 }
634                 
635                 // Trim last ^
636                 $values = substr($values, 0, strlen($values) - 3);
637             }
638             
639             $build .= "    \$this->setAttribute(Doctrine::ATTR_" . strtoupper($key) . ", " . $values . ");\n";
640         }
641         
642         return $build;
643     }
644     
645     /**
646      * buildTableOptions
647      *
648      * @param string $array 
649      * @return void
650      */
651     public function buildOptions(array $options)
652     {
653         $build = '';
654         foreach ($options as $name => $value) {
655             $build .= "    \$this->option('$name', " . $this->varExport($value) . ");\n";
656         }
657         
658         return $build;
659     }
660
661     /**
662      * buildIndexes
663      *
664      * @param string $array 
665      * @return void
666      */
667     public function buildIndexes(array $indexes)
668     {
669       $build = '';
670
671       foreach ($indexes as $indexName => $definitions) {
672           $build .= "\n    \$this->index('" . $indexName . "'";
673           $build .= ', ' . $this->varExport($definitions);
674           $build .= ');';
675       }
676
677       return $build;
678     }
679
680     /**
681      * buildDefinition
682      *
683      * @param array $definition
684      * @return string
685      */
686     public function buildDefinition(array $definition)
687     {
688         if ( ! isset($definition['className'])) {
689             throw new Doctrine_Import_Builder_Exception('Missing class name.');
690         }
691
692         $abstract = isset($definition['abstract']) && $definition['abstract'] === true ? 'abstract ':null;
693         $className = $definition['className'];
694         $extends = isset($definition['inheritance']['extends']) ? $definition['inheritance']['extends']:$this->_baseClassName;
695
696         if ( ! (isset($definition['no_definition']) && $definition['no_definition'] === true)) {
697             $tableDefinitionCode = $this->buildTableDefinition($definition);
698             $setUpCode = $this->buildSetUp($definition);
699         } else {
700             $tableDefinitionCode = null;
701             $setUpCode = null;
702         }
703         
704         $accessorsCode = (isset($definition['generate_accessors']) && $definition['generate_accessors'] === true) ? $this->buildAccessors($definition):null;
705         
706         $content = sprintf(self::$_tpl, $abstract,
707                                        $className,
708                                        $extends,
709                                        $tableDefinitionCode,
710                                        $setUpCode,
711                                        $accessorsCode);
712         
713         return $content;
714     }
715
716     /**
717      * buildRecord
718      *
719      * @param array $options 
720      * @param array $columns 
721      * @param array $relations 
722      * @param array $indexes 
723      * @param array $attributes 
724      * @param array $templates 
725      * @param array $actAs 
726      * @return void=
727      */
728     public function buildRecord(array $definition)
729     {
730         if ( ! isset($definition['className'])) {
731             throw new Doctrine_Import_Builder_Exception('Missing class name.');
732         }
733         
734         $definition['topLevelClassName'] = $definition['className'];
735         
736         if ($this->generateBaseClasses()) {
737             $definition['is_package'] = (isset($definition['package']) && $definition['package']) ? true:false;
738             
739             if ($definition['is_package']) {
740                 $e = explode('.', $definition['package']);
741                 $definition['package_name'] = $e[0];
742                 
743                 $definition['package_path'] = ! empty($e) ? implode(DIRECTORY_SEPARATOR, $e):$definition['package_name'];
744             }
745             
746             // Top level definition that extends from all the others
747             $topLevel = $definition;
748             unset($topLevel['tableName']);
749             
750             // If we have a package then we need to make this extend the package definition and not the base definition
751             // The package definition will then extends the base definition
752             $topLevel['inheritance']['extends'] = (isset($topLevel['package']) && $topLevel['package']) ? $this->_packagesPrefix . $topLevel['className']:'Base' . $topLevel['className'];
753             $topLevel['no_definition'] = true;
754             $topLevel['generate_once'] = true;
755             $topLevel['is_main_class'] = true;
756             unset($topLevel['connection']);
757
758             // Package level definition that extends from the base definition
759             if (isset($definition['package'])) {
760                 
761                 $packageLevel = $definition;
762                 $packageLevel['className'] = $topLevel['inheritance']['extends'];
763                 $packageLevel['inheritance']['extends'] = 'Base' . $topLevel['className'];
764                 $packageLevel['no_definition'] = true;
765                 $packageLevel['abstract'] = true;
766                 $packageLevel['override_parent'] = true;
767                 $packageLevel['generate_once'] = true;
768                 $packageLevel['is_package_class'] = true;
769                 unset($packageLevel['connection']);
770                 
771                 $packageLevel['tableClassName'] = $packageLevel['className'] . 'Table';
772                 $packageLevel['inheritance']['tableExtends'] = isset($definition['inheritance']['extends']) ? $definition['inheritance']['extends'] . 'Table':'Doctrine_Table';
773                 
774                 $topLevel['tableClassName'] = $topLevel['topLevelClassName'] . 'Table';
775                 $topLevel['inheritance']['tableExtends'] = $packageLevel['className'] . 'Table';
776             } else {
777                 $topLevel['tableClassName'] = $topLevel['className'] . 'Table';
778                 $topLevel['inheritance']['tableExtends'] = isset($definition['inheritance']['extends']) ? $definition['inheritance']['extends'] . 'Table':'Doctrine_Table';
779             }
780
781             $baseClass = $definition;
782             $baseClass['className'] = 'Base' . $baseClass['className'];
783             $baseClass['abstract'] = true;
784             $baseClass['override_parent'] = false;
785             $baseClass['is_base_class'] = true;
786
787             $this->writeDefinition($baseClass);
788             
789             if ( ! empty($packageLevel)) {
790                 $this->writeDefinition($packageLevel);
791             }
792             
793             $this->writeDefinition($topLevel);
794         } else {
795             $this->writeDefinition($definition);
796         }
797     }
798
799     /**
800      * writeTableDefinition
801      *
802      * @return void
803      */
804     public function writeTableDefinition($className, $path, $options = array())
805     {
806         $content  = '<?php' . PHP_EOL;
807         $content .= sprintf(self::$_tpl, false,
808                                        $className,
809                                        isset($options['extends']) ? $options['extends']:'Doctrine_Table',
810                                        null,
811                                        null,
812                                        null
813                                        );
814
815         Doctrine_Lib::makeDirectories($path);
816
817         $writePath = $path . DIRECTORY_SEPARATOR . $className . $this->_suffix;
818
819         Doctrine::loadModel($className, $writePath);
820
821         if ( ! file_exists($writePath)) {
822             file_put_contents($writePath, $content);
823         }
824     }
825
826     /**
827      * writeDefinition
828      *
829      * @param array $options 
830      * @param array $columns 
831      * @param array $relations 
832      * @param array $indexes 
833      * @param array $attributes 
834      * @param array $templates 
835      * @param array $actAs 
836      * @return void
837      */
838     public function writeDefinition(array $definition)
839     {
840         $definitionCode = $this->buildDefinition($definition);
841
842         $fileName = $definition['className'] . $this->_suffix;
843
844         $packagesPath = $this->_packagesPath ? $this->_packagesPath:$this->_path;
845
846         // If this is a main class that either extends from Base or Package class
847         if (isset($definition['is_main_class']) && $definition['is_main_class']) {
848             // If is package then we need to put it in a package subfolder
849             if (isset($definition['is_package']) && $definition['is_package']) {
850                 $writePath = $this->_path . DIRECTORY_SEPARATOR . $definition['package_name'];
851             // Otherwise lets just put it in the root of the path
852             } else {
853                 $writePath = $this->_path;
854             }
855
856             $this->writeTableDefinition($definition['tableClassName'], $writePath, array('extends' => $definition['inheritance']['tableExtends']));
857         }
858         // If is the package class then we need to make the path to the complete package
859         else if (isset($definition['is_package_class']) && $definition['is_package_class']) {
860             $writePath = $packagesPath . DIRECTORY_SEPARATOR . $definition['package_path'];
861
862             $this->writeTableDefinition($definition['tableClassName'], $writePath, array('extends' => $definition['inheritance']['tableExtends']));
863         }
864         // If it is the base class of the doctrine record definition
865         else if (isset($definition['is_base_class']) && $definition['is_base_class']) {
866             // If it is a part of a package then we need to put it in a package subfolder
867             if (isset($definition['is_package']) && $definition['is_package']) {
868                 $basePath = $this->_path . DIRECTORY_SEPARATOR . $definition['package_name'];
869                 $writePath = $basePath . DIRECTORY_SEPARATOR . $this->_baseClassesDirectory;
870             // Otherwise lets just put it in the root generated folder
871             } else {
872                 $writePath = $this->_path . DIRECTORY_SEPARATOR . $this->_baseClassesDirectory;
873             }
874         }
875
876         // If we have a writePath from the if else conditionals above then use it
877         if (isset($writePath)) {
878             Doctrine_Lib::makeDirectories($writePath);
879
880             $writePath .= DIRECTORY_SEPARATOR . $fileName;
881         // Otherwise none of the conditions were met and we aren't generating base classes
882         } else {
883             Doctrine_Lib::makeDirectories($this->_path);
884
885             $writePath = $this->_path . DIRECTORY_SEPARATOR . $fileName;
886         }
887
888         $code = "<?php" . PHP_EOL;
889
890         if (isset($definition['connection']) && $definition['connection']) {
891             $code .= "// Connection Component Binding\n";
892             $code .= "Doctrine_Manager::getInstance()->bindComponent('" . $definition['connectionClassName'] . "', '" . $definition['connection'] . "');\n";
893         }
894
895         $code .= PHP_EOL . $definitionCode;
896
897         if (isset($definition['generate_once']) && $definition['generate_once'] === true) {
898             if ( ! file_exists($writePath)) {
899                 $bytes = file_put_contents($writePath, $code);
900             }
901         } else {
902             $bytes = file_put_contents($writePath, $code);
903         }
904
905         if (isset($bytes) && $bytes === false) {
906             throw new Doctrine_Import_Builder_Exception("Couldn't write file " . $writePath);
907         }
908
909         Doctrine::loadModel($definition['className'], $writePath);
910     }
911 }