Mercurial > hg > Members > shoshi > webvirt
comparison cake/console/libs/tasks/fixture.php @ 0:261e66bd5a0c
hg init
author | Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 24 Jul 2011 21:08:31 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:261e66bd5a0c |
---|---|
1 <?php | |
2 /** | |
3 * The FixtureTask handles creating and updating fixture files. | |
4 * | |
5 * PHP versions 4 and 5 | |
6 * | |
7 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) | |
8 * Copyright 2005-2010, Cake Software Foundation, Inc. | |
9 * | |
10 * Licensed under The MIT License | |
11 * Redistributions of files must retain the above copyright notice. | |
12 * | |
13 * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
14 * @link http://cakephp.org CakePHP(tm) Project | |
15 * @package cake | |
16 * @subpackage cake.cake.console.libs.tasks | |
17 * @since CakePHP(tm) v 1.3 | |
18 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) | |
19 */ | |
20 include_once dirname(__FILE__) . DS . 'bake.php'; | |
21 /** | |
22 * Task class for creating and updating fixtures files. | |
23 * | |
24 * @package cake | |
25 * @subpackage cake.cake.console.libs.tasks | |
26 */ | |
27 class FixtureTask extends BakeTask { | |
28 | |
29 /** | |
30 * Tasks to be loaded by this Task | |
31 * | |
32 * @var array | |
33 * @access public | |
34 */ | |
35 var $tasks = array('DbConfig', 'Model', 'Template'); | |
36 | |
37 /** | |
38 * path to fixtures directory | |
39 * | |
40 * @var string | |
41 * @access public | |
42 */ | |
43 var $path = null; | |
44 | |
45 /** | |
46 * Schema instance | |
47 * | |
48 * @var object | |
49 * @access protected | |
50 */ | |
51 var $_Schema = null; | |
52 | |
53 /** | |
54 * Override initialize | |
55 * | |
56 * @access public | |
57 */ | |
58 function __construct(&$dispatch) { | |
59 parent::__construct($dispatch); | |
60 $this->path = $this->params['working'] . DS . 'tests' . DS . 'fixtures' . DS; | |
61 } | |
62 | |
63 /** | |
64 * Execution method always used for tasks | |
65 * Handles dispatching to interactive, named, or all processess. | |
66 * | |
67 * @access public | |
68 */ | |
69 function execute() { | |
70 if (empty($this->args)) { | |
71 $this->__interactive(); | |
72 } | |
73 | |
74 if (isset($this->args[0])) { | |
75 $this->interactive = false; | |
76 if (!isset($this->connection)) { | |
77 $this->connection = 'default'; | |
78 } | |
79 if (strtolower($this->args[0]) == 'all') { | |
80 return $this->all(); | |
81 } | |
82 $model = $this->_modelName($this->args[0]); | |
83 $this->bake($model); | |
84 } | |
85 } | |
86 | |
87 /** | |
88 * Bake All the Fixtures at once. Will only bake fixtures for models that exist. | |
89 * | |
90 * @access public | |
91 * @return void | |
92 */ | |
93 function all() { | |
94 $this->interactive = false; | |
95 $this->Model->interactive = false; | |
96 $tables = $this->Model->listAll($this->connection, false); | |
97 foreach ($tables as $table) { | |
98 $model = $this->_modelName($table); | |
99 $this->bake($model); | |
100 } | |
101 } | |
102 | |
103 /** | |
104 * Interactive baking function | |
105 * | |
106 * @access private | |
107 */ | |
108 function __interactive() { | |
109 $this->DbConfig->interactive = $this->Model->interactive = $this->interactive = true; | |
110 $this->hr(); | |
111 $this->out(sprintf("Bake Fixture\nPath: %s", $this->path)); | |
112 $this->hr(); | |
113 | |
114 $useDbConfig = $this->connection; | |
115 if (!isset($this->connection)) { | |
116 $this->connection = $this->DbConfig->getConfig(); | |
117 } | |
118 $modelName = $this->Model->getName($this->connection); | |
119 $useTable = $this->Model->getTable($modelName, $this->connection); | |
120 $importOptions = $this->importOptions($modelName); | |
121 $this->bake($modelName, $useTable, $importOptions); | |
122 } | |
123 | |
124 /** | |
125 * Interacts with the User to setup an array of import options. For a fixture. | |
126 * | |
127 * @param string $modelName Name of model you are dealing with. | |
128 * @return array Array of import options. | |
129 * @access public | |
130 */ | |
131 function importOptions($modelName) { | |
132 $options = array(); | |
133 $doSchema = $this->in(__('Would you like to import schema for this fixture?', true), array('y', 'n'), 'n'); | |
134 if ($doSchema == 'y') { | |
135 $options['schema'] = $modelName; | |
136 } | |
137 $doRecords = $this->in(__('Would you like to use record importing for this fixture?', true), array('y', 'n'), 'n'); | |
138 if ($doRecords == 'y') { | |
139 $options['records'] = true; | |
140 } | |
141 if ($doRecords == 'n') { | |
142 $prompt = sprintf(__("Would you like to build this fixture with data from %s's table?", true), $modelName); | |
143 $fromTable = $this->in($prompt, array('y', 'n'), 'n'); | |
144 if (strtolower($fromTable) == 'y') { | |
145 $options['fromTable'] = true; | |
146 } | |
147 } | |
148 return $options; | |
149 } | |
150 | |
151 /** | |
152 * Assembles and writes a Fixture file | |
153 * | |
154 * @param string $model Name of model to bake. | |
155 * @param string $useTable Name of table to use. | |
156 * @param array $importOptions Options for var $import | |
157 * @return string Baked fixture content | |
158 * @access public | |
159 */ | |
160 function bake($model, $useTable = false, $importOptions = array()) { | |
161 if (!class_exists('CakeSchema')) { | |
162 App::import('Model', 'CakeSchema', false); | |
163 } | |
164 $table = $schema = $records = $import = $modelImport = null; | |
165 $importBits = array(); | |
166 | |
167 if (!$useTable) { | |
168 $useTable = Inflector::tableize($model); | |
169 } elseif ($useTable != Inflector::tableize($model)) { | |
170 $table = $useTable; | |
171 } | |
172 | |
173 if (!empty($importOptions)) { | |
174 if (isset($importOptions['schema'])) { | |
175 $modelImport = true; | |
176 $importBits[] = "'model' => '{$importOptions['schema']}'"; | |
177 } | |
178 if (isset($importOptions['records'])) { | |
179 $importBits[] = "'records' => true"; | |
180 } | |
181 if ($this->connection != 'default') { | |
182 $importBits[] .= "'connection' => '{$this->connection}'"; | |
183 } | |
184 if (!empty($importBits)) { | |
185 $import = sprintf("array(%s)", implode(', ', $importBits)); | |
186 } | |
187 } | |
188 | |
189 $this->_Schema = new CakeSchema(); | |
190 $data = $this->_Schema->read(array('models' => false, 'connection' => $this->connection)); | |
191 | |
192 if (!isset($data['tables'][$useTable])) { | |
193 $this->err('Could not find your selected table ' . $useTable); | |
194 return false; | |
195 } | |
196 | |
197 $tableInfo = $data['tables'][$useTable]; | |
198 if (is_null($modelImport)) { | |
199 $schema = $this->_generateSchema($tableInfo); | |
200 } | |
201 | |
202 if (!isset($importOptions['records']) && !isset($importOptions['fromTable'])) { | |
203 $recordCount = 1; | |
204 if (isset($this->params['count'])) { | |
205 $recordCount = $this->params['count']; | |
206 } | |
207 $records = $this->_makeRecordString($this->_generateRecords($tableInfo, $recordCount)); | |
208 } | |
209 if (isset($this->params['records']) || isset($importOptions['fromTable'])) { | |
210 $records = $this->_makeRecordString($this->_getRecordsFromTable($model, $useTable)); | |
211 } | |
212 $out = $this->generateFixtureFile($model, compact('records', 'table', 'schema', 'import', 'fields')); | |
213 return $out; | |
214 } | |
215 | |
216 /** | |
217 * Generate the fixture file, and write to disk | |
218 * | |
219 * @param string $model name of the model being generated | |
220 * @param string $fixture Contents of the fixture file. | |
221 * @return string Content saved into fixture file. | |
222 * @access public | |
223 */ | |
224 function generateFixtureFile($model, $otherVars) { | |
225 $defaults = array('table' => null, 'schema' => null, 'records' => null, 'import' => null, 'fields' => null); | |
226 $vars = array_merge($defaults, $otherVars); | |
227 | |
228 $path = $this->getPath(); | |
229 $filename = Inflector::underscore($model) . '_fixture.php'; | |
230 | |
231 $this->Template->set('model', $model); | |
232 $this->Template->set($vars); | |
233 $content = $this->Template->generate('classes', 'fixture'); | |
234 | |
235 $this->out("\nBaking test fixture for $model..."); | |
236 $this->createFile($path . $filename, $content); | |
237 return $content; | |
238 } | |
239 | |
240 /** | |
241 * Get the path to the fixtures. | |
242 * | |
243 * @return void | |
244 */ | |
245 function getPath() { | |
246 $path = $this->path; | |
247 if (isset($this->plugin)) { | |
248 $path = $this->_pluginPath($this->plugin) . 'tests' . DS . 'fixtures' . DS; | |
249 } | |
250 return $path; | |
251 } | |
252 | |
253 /** | |
254 * Generates a string representation of a schema. | |
255 * | |
256 * @param array $table Table schema array | |
257 * @return string fields definitions | |
258 * @access protected | |
259 */ | |
260 function _generateSchema($tableInfo) { | |
261 $schema = $this->_Schema->generateTable('f', $tableInfo); | |
262 return substr($schema, 10, -2); | |
263 } | |
264 | |
265 /** | |
266 * Generate String representation of Records | |
267 * | |
268 * @param array $table Table schema array | |
269 * @return array Array of records to use in the fixture. | |
270 * @access protected | |
271 */ | |
272 function _generateRecords($tableInfo, $recordCount = 1) { | |
273 $records = array(); | |
274 for ($i = 0; $i < $recordCount; $i++) { | |
275 $record = array(); | |
276 foreach ($tableInfo as $field => $fieldInfo) { | |
277 if (empty($fieldInfo['type'])) { | |
278 continue; | |
279 } | |
280 switch ($fieldInfo['type']) { | |
281 case 'integer': | |
282 case 'float': | |
283 $insert = $i + 1; | |
284 break; | |
285 case 'string': | |
286 case 'binary': | |
287 $isPrimaryUuid = ( | |
288 isset($fieldInfo['key']) && strtolower($fieldInfo['key']) == 'primary' && | |
289 isset($fieldInfo['length']) && $fieldInfo['length'] == 36 | |
290 ); | |
291 if ($isPrimaryUuid) { | |
292 $insert = String::uuid(); | |
293 } else { | |
294 $insert = "Lorem ipsum dolor sit amet"; | |
295 if (!empty($fieldInfo['length'])) { | |
296 $insert = substr($insert, 0, (int)$fieldInfo['length'] - 2); | |
297 } | |
298 } | |
299 $insert = "'$insert'"; | |
300 break; | |
301 case 'timestamp': | |
302 $ts = time(); | |
303 $insert = "'$ts'"; | |
304 break; | |
305 case 'datetime': | |
306 $ts = date('Y-m-d H:i:s'); | |
307 $insert = "'$ts'"; | |
308 break; | |
309 case 'date': | |
310 $ts = date('Y-m-d'); | |
311 $insert = "'$ts'"; | |
312 break; | |
313 case 'time': | |
314 $ts = date('H:i:s'); | |
315 $insert = "'$ts'"; | |
316 break; | |
317 case 'boolean': | |
318 $insert = 1; | |
319 break; | |
320 case 'text': | |
321 $insert = "'Lorem ipsum dolor sit amet, aliquet feugiat."; | |
322 $insert .= " Convallis morbi fringilla gravida,"; | |
323 $insert .= " phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin"; | |
324 $insert .= " venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla"; | |
325 $insert .= " vestibulum massa neque ut et, id hendrerit sit,"; | |
326 $insert .= " feugiat in taciti enim proin nibh, tempor dignissim, rhoncus"; | |
327 $insert .= " duis vestibulum nunc mattis convallis.'"; | |
328 break; | |
329 } | |
330 $record[$field] = $insert; | |
331 } | |
332 $records[] = $record; | |
333 } | |
334 return $records; | |
335 } | |
336 | |
337 /** | |
338 * Convert a $records array into a a string. | |
339 * | |
340 * @param array $records Array of records to be converted to string | |
341 * @return string A string value of the $records array. | |
342 * @access protected | |
343 */ | |
344 function _makeRecordString($records) { | |
345 $out = "array(\n"; | |
346 foreach ($records as $record) { | |
347 $values = array(); | |
348 foreach ($record as $field => $value) { | |
349 $values[] = "\t\t\t'$field' => $value"; | |
350 } | |
351 $out .= "\t\tarray(\n"; | |
352 $out .= implode(",\n", $values); | |
353 $out .= "\n\t\t),\n"; | |
354 } | |
355 $out .= "\t)"; | |
356 return $out; | |
357 } | |
358 | |
359 /** | |
360 * Interact with the user to get a custom SQL condition and use that to extract data | |
361 * to build a fixture. | |
362 * | |
363 * @param string $modelName name of the model to take records from. | |
364 * @param string $useTable Name of table to use. | |
365 * @return array Array of records. | |
366 * @access protected | |
367 */ | |
368 function _getRecordsFromTable($modelName, $useTable = null) { | |
369 if ($this->interactive) { | |
370 $condition = null; | |
371 $prompt = __("Please provide a SQL fragment to use as conditions\nExample: WHERE 1=1 LIMIT 10", true); | |
372 while (!$condition) { | |
373 $condition = $this->in($prompt, null, 'WHERE 1=1 LIMIT 10'); | |
374 } | |
375 } else { | |
376 $condition = 'WHERE 1=1 LIMIT ' . (isset($this->params['count']) ? $this->params['count'] : 10); | |
377 } | |
378 App::import('Model', 'Model', false); | |
379 $modelObject =& new Model(array('name' => $modelName, 'table' => $useTable, 'ds' => $this->connection)); | |
380 $records = $modelObject->find('all', array( | |
381 'conditions' => $condition, | |
382 'recursive' => -1 | |
383 )); | |
384 $db =& ConnectionManager::getDataSource($modelObject->useDbConfig); | |
385 $schema = $modelObject->schema(true); | |
386 $out = array(); | |
387 foreach ($records as $record) { | |
388 $row = array(); | |
389 foreach ($record[$modelObject->alias] as $field => $value) { | |
390 $row[$field] = $db->value($value, $schema[$field]['type']); | |
391 } | |
392 $out[] = $row; | |
393 } | |
394 return $out; | |
395 } | |
396 | |
397 /** | |
398 * Displays help contents | |
399 * | |
400 * @access public | |
401 */ | |
402 function help() { | |
403 $this->hr(); | |
404 $this->out("Usage: cake bake fixture <arg1> <params>"); | |
405 $this->hr(); | |
406 $this->out('Arguments:'); | |
407 $this->out(); | |
408 $this->out("<name>"); | |
409 $this->out("\tName of the fixture to bake. Can use Plugin.name"); | |
410 $this->out("\tas a shortcut for plugin baking."); | |
411 $this->out(); | |
412 $this->out('Commands:'); | |
413 $this->out("\nfixture <name>\n\tbakes fixture with specified name."); | |
414 $this->out("\nfixture all\n\tbakes all fixtures."); | |
415 $this->out(); | |
416 $this->out('Parameters:'); | |
417 $this->out("\t-count When using generated data, the number of records to include in the fixture(s)."); | |
418 $this->out("\t-connection Which database configuration to use for baking."); | |
419 $this->out("\t-plugin CamelCased name of plugin to bake fixtures for."); | |
420 $this->out("\t-records Used with -count and <name>/all commands to pull [n] records from the live tables"); | |
421 $this->out("\t Where [n] is either -count or the default of 10."); | |
422 $this->out(); | |
423 $this->_stop(); | |
424 } | |
425 } |