Coverage for Doctrine_Data_Import

Back to coverage report

1 <?php
2 /*
3  *  $Id: Import.php 2552 2007-09-19 19:33:00Z 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_Data_Import
24  *
25  * @package     Doctrine
26  * @package     Data
27  * @author      Jonathan H. Wage <jwage@mac.com>
28  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
29  * @link        www.phpdoctrine.org
30  * @since       1.0
31  * @version     $Revision: 2552 $
32  */
33 class Doctrine_Data_Import extends Doctrine_Data
34 {
35     /**
36      * Array of imported objects for processing and saving
37      *
38      * @var array
39      */
40     protected $_importedObjects = array();
41
42     /**
43      * Array of the raw data parsed from yaml
44      *
45      * @var array
46      */
47     protected $_rows = array();
48
49     /**
50      * constructor
51      *
52      * @param string $directory 
53      * @return void
54      */
55     public function __construct($directory = null)
56     {
57         if ($directory !== null) {
58             $this->setDirectory($directory);
59         }
60     }
61
62     /**
63      * doImport
64      *
65      * @return void
66      */
67     public function doImport()
68     {
69         $directory = $this->getDirectory();
70
71         $array = array();
72
73         if ($directory !== null) {
74             foreach ((array) $directory as $dir) {
75                 $e = explode('.', $dir);
76
77                 // If they specified a specific yml file
78                 if (end($e) == 'yml') {
79                     $array = array_merge($array, Doctrine_Parser::load($dir, $this->getFormat()));
80                 // If they specified a directory
81                 } else if(is_dir($dir)) {
82                     $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir),
83                                                             RecursiveIteratorIterator::LEAVES_ONLY);
84
85                     foreach ($it as $file) {
86                         $e = explode('.', $file->getFileName());
87                         if (in_array(end($e), $this->getFormats())) {
88                             $array = array_merge($array, Doctrine_Parser::load($file->getPathName(), $this->getFormat()));
89                         }
90                     }
91                 }
92             }
93         }
94
95         $this->_loadData($array);
96     }
97
98     /**
99      * _buildRows
100      *
101      * @return void
102      */
103     protected function _buildRows($className, $data)
104     {
105         foreach ($data as $rowKey => $row) {
106             // do the same for the row information
107             $this->_rows[$className][$rowKey] = $row;
108
109             foreach ($row as $key => $value) {
110                 if (Doctrine::getTable($className)->hasRelation($key) && is_array($value)) {
111                     $keys = array_keys($value);
112
113                     // Skip associative arrays defining keys to relationships
114                     if ( ! isset($keys[0])) {
115                         $this->_buildRows(Doctrine::getTable($className)->getRelation($key)->getTable()->getOption('name'), $value);
116                     }
117                 }
118             }
119         }
120     }
121
122     /**
123      * _buildNestedSetRows
124      *
125      * @return void
126      */
127     protected function _buildNestedSetRows($className, $data)
128     {
129         foreach ($data as $rowKey => $row) {
130             $children = isset($row['children']) ? $row['children']:array();
131             unset($row['children']);
132             $this->_rows[$className][$rowKey] = $row;
133
134             $this->_buildNestedSetRows($className, $children);
135         }
136     }
137
138     /**
139      * _getImportedObject
140      *
141      * @param string $rowKey 
142      * @return Doctrine_Record
143      * @throws Doctrine_Data_Exception
144      */
145     protected function _getImportedObject($rowKey)
146     {
147         if (isset($this->_importedObjects[$rowKey])) {
148             return $this->_importedObjects[$rowKey];
149         } else {
150             throw new Doctrine_Data_Exception('Invalid row key specified: ' . $rowKey);
151         }
152     }
153
154     /**
155      * _processRow
156      *
157      * @param string $rowKey 
158      * @param string $row 
159      * @return void
160      */    
161     protected function _processRow($rowKey, $row)
162     {
163         $obj = $this->_importedObjects[$rowKey];
164
165         foreach ($row as $key => $value) {
166             if ($obj->getTable()->hasField($key)) {
167                 $obj->set($key, $value);
168             } else if (method_exists($obj, 'set' . Doctrine::classify($key))) {
169                     $func = 'set' . Doctrine::classify($key);
170                     $obj->$func($value);
171             } else if ($obj->getTable()->hasRelation($key)) {
172                 if (is_array($value)) {
173                     if (isset($value[0])) {
174                         foreach ($value as $link) {
175                             if ($obj->getTable()->getRelation($key)->getType() === Doctrine_Relation::ONE) {
176                                 $obj->set($key, $this->_getImportedObject($link));
177                             } else if ($obj->getTable()->getRelation($key)->getType() === Doctrine_Relation::MANY) {
178                                 $relation = $obj->$key;
179
180                                 $relation[] = $this->_getImportedObject($link);
181                             }
182                         }
183                     } else {
184                         $obj->$key->fromArray($value);
185                     }
186                 } else {
187                     $obj->set($key, $this->_getImportedObject($value));
188                 }
189             }
190         }
191     }
192
193     /**
194      * _loadData
195      *
196      * @param string $array 
197      * @return void
198      */
199     protected function _loadData(array $array)
200     {
201         $nestedSets = array();
202
203         $specifiedModels = $this->getModels();
204         $rows = array();
205
206         foreach ($array as $className => $data) {
207             if ( ! empty($specifiedModels) && !in_array($className, $specifiedModels)) {
208                 continue;
209             }
210
211             $templates = array_keys(Doctrine::getTable($className)->getTemplates());
212
213             if (in_array('Doctrine_Template_NestedSet', $templates)) {
214                 $nestedSets[$className][] = $data;
215                 $this->_buildNestedSetRows($className, $data);
216             } else {
217                 $this->_buildRows($className, $data);
218             }
219         }
220
221         $buildRows = array();
222         foreach ($this->_rows as $className => $classRows) {
223             foreach ($classRows as $rowKey => $row) {
224                 $buildRows[$rowKey] = $row;
225                 $this->_importedObjects[$rowKey] = new $className();
226                 $this->_importedObjects[$rowKey]->state('TDIRTY');
227             }
228         }
229
230         foreach($buildRows as $rowKey => $row) {
231             $this->_processRow($rowKey, $row);
232         }
233
234         $objects = array();
235         foreach ($this->_importedObjects as $object) {
236             $className = get_class($object);
237             $objects[$className] = $className;
238         }
239
240         $manager = Doctrine_Manager::getInstance();
241         foreach ($manager as $connection) {            
242             $tree = $connection->unitOfWork->buildFlushTree($objects);
243
244             foreach ($tree as $model) {
245                 foreach ($this->_importedObjects as $obj) {
246                     $templates = array_keys($obj->getTable()->getTemplates());
247                     
248                     if ($obj instanceof $model && ! in_array('Doctrine_Template_NestedSet', $templates)) {
249                         $obj->save();
250                     }
251                 }
252             }
253         }
254
255         foreach ($nestedSets as $className => $sets) {
256             foreach ($sets as $data) {
257                 $this->_loadNestedSetData($className, $data);
258             }
259         }
260     }
261
262     /**
263      * _loadNestedSetData
264      *
265      * @param string $model 
266      * @param string $nestedSetData 
267      * @param string $parent 
268      * @return void
269      */
270     protected function _loadNestedSetData($model, $nestedSetData, $parent = null)
271     {
272         $manager = Doctrine_Manager::getInstance();
273
274         foreach($nestedSetData AS $rowKey => $nestedSet) {
275             $children = array();
276             $data  = array();
277
278             if (array_key_exists('children', $nestedSet)) {
279                 $children = $nestedSet['children'];
280                 $children = array_reverse($children, true);
281                 unset($nestedSet['children']);
282             }
283
284             $record = $this->_importedObjects[$rowKey];
285
286             if( ! $parent) {
287                 $manager->getTable($model)->getTree()->createRoot($record);
288             } else {
289                 $parent->getNode()->addChild($record);
290             }
291
292             if (is_array($children) AND !empty($children)) {
293                 $this->_loadNestedSetData($model, $children, $record);
294             }
295         }
296     }
297
298     /**
299      * doImportDummyData
300      *
301      * @param string $num 
302      * @return void
303      */
304     public function doImportDummyData($num = 3)
305     {
306         $models = Doctrine::getLoadedModels();
307         $specifiedModels = $this->getModels();
308
309         foreach ($models as $name) {
310             if ( ! empty($specifiedModels) && !in_array($name, $specifiedModels)) {
311                 continue;
312             }
313
314             for ($i = 0; $i < $num; $i++) {
315                 $obj = new $name();
316
317                 $this->populateDummyRecord($obj);
318
319                 $obj->save();
320
321                 $ids[get_class($obj)][] = $obj->identifier();
322             }
323         }
324     }
325
326     /**
327      * populateDummyRecord
328      *
329      * @param Doctrine_Record $record 
330      * @return Doctrine_Record $record
331      */
332     public function populateDummyRecord(Doctrine_Record $record)
333     {
334         $lorem = explode(' ', "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem 
335                                Ipsum has been the industry's standard dummy text ever since the 1500s, when an 
336                                unknown printer took a galley of type and scrambled it to make a type specimen book. 
337                                It has survived not only five centuries, but also the leap into electronic 
338                                typesetting, remaining essentially unchanged. It was popularised in the 1960s with 
339                                the release of Letraset sheets containing Lorem Ipsum passages, and more recently 
340                                with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.");
341
342         $columns = array_keys($record->toArray());
343         $pks = $record->getTable()->getIdentifier();
344
345         if ( ! is_array($pks)) {
346           $pks = array($pks);
347         }
348
349         foreach ($columns as $column) {
350             if ( ! in_array($column, $pks)) {
351                 if ($relation = $this->isRelation($record, $column)) {
352                     $alias = $relation['alias'];
353                     $relationObj = $record->$alias;
354
355                     $this->populateDummyRecord($relationObj);
356                 } else {
357                     $definition = $record->getTable()->getDefinitionOf($column);
358
359                     switch($definition['type'])
360                     {
361                         case 'string';     
362                             shuffle($lorem);
363
364                             $record->$column = substr(implode(' ', $lorem), 0, $definition['length']);
365                         break;
366
367                         case 'integer':
368                             $record->$column = rand();
369                         break;
370
371                         case 'boolean':
372                             $record->$column = true;
373                         break;
374
375                         case 'float':
376                             $record->$column = number_format(rand($definition['length'], $definition['length']), 2, '.', null);
377                         break;
378
379                         case 'array':
380                             $record->$column = array('test' => 'test');
381                         break;
382
383                         case 'object':
384                             $record->$column = new stdObject();
385                         break;
386
387                         case 'blob':
388                             $record->$column = '';
389                         break;
390
391                         case 'clob':
392                             $record->$column = '';
393                         break;
394
395                         case 'timestamp':
396                             $record->$column = date('Y-m-d h:i:s', time());
397                         break;
398
399                         case 'time':
400                             $record->$column = date('h:i:s', time());
401                         break;
402
403                         case 'date':
404                             $record->$column = date('Y-m-d', time());
405                         break;
406
407                         case 'enum':
408                             $record->$column = 'test';
409                         break;
410
411                         case 'gzip':
412                             $record->$column = 'test';
413                         break;
414                     }
415                 }
416             }
417         }
418
419         return $record;
420     }
421 }