Mercurial > hg > Members > shoshi > webvirt
comparison cake/libs/controller/scaffold.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 * Scaffold. | |
4 * | |
5 * Automatic forms and actions generation for rapid web application development. | |
6 * | |
7 * PHP versions 4 and 5 | |
8 * | |
9 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) | |
10 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
11 * | |
12 * Licensed under The MIT License | |
13 * Redistributions of files must retain the above copyright notice. | |
14 * | |
15 * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
16 * @link http://cakephp.org CakePHP(tm) Project | |
17 * @package cake | |
18 * @subpackage cake.cake.libs.controller | |
19 * @since Cake v 0.10.0.1076 | |
20 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) | |
21 */ | |
22 | |
23 /** | |
24 * Scaffolding is a set of automatic actions for starting web development work faster. | |
25 * | |
26 * Scaffold inspects your database tables, and making educated guesses, sets up a | |
27 * number of pages for each of your Models. These pages have data forms that work, | |
28 * and afford the web developer an early look at the data, and the possibility to over-ride | |
29 * scaffolded actions with custom-made ones. | |
30 * | |
31 * @package cake | |
32 * @subpackage cake.cake.libs.controller | |
33 */ | |
34 class Scaffold extends Object { | |
35 | |
36 /** | |
37 * Controller object | |
38 * | |
39 * @var Controller | |
40 * @access public | |
41 */ | |
42 var $controller = null; | |
43 | |
44 /** | |
45 * Name of the controller to scaffold | |
46 * | |
47 * @var string | |
48 * @access public | |
49 */ | |
50 var $name = null; | |
51 | |
52 /** | |
53 * Action to be performed. | |
54 * | |
55 * @var string | |
56 * @access public | |
57 */ | |
58 var $action = null; | |
59 | |
60 /** | |
61 * Name of current model this view context is attached to | |
62 * | |
63 * @var string | |
64 * @access public | |
65 */ | |
66 var $model = null; | |
67 | |
68 /** | |
69 * Path to View. | |
70 * | |
71 * @var string | |
72 * @access public | |
73 */ | |
74 var $viewPath; | |
75 | |
76 /** | |
77 * Path parts for creating links in views. | |
78 * | |
79 * @var string Base URL | |
80 * @access public | |
81 */ | |
82 var $base = null; | |
83 | |
84 /** | |
85 * Name of layout to use with this View. | |
86 * | |
87 * @var string | |
88 * @access public | |
89 */ | |
90 var $layout = 'default'; | |
91 | |
92 /** | |
93 * Array of parameter data | |
94 * | |
95 * @var array | |
96 * @access public | |
97 */ | |
98 var $params; | |
99 | |
100 /** | |
101 * File extension. Defaults to Cake's template ".ctp". | |
102 * | |
103 * @var array | |
104 * @access public | |
105 */ | |
106 var $ext = '.ctp'; | |
107 | |
108 /** | |
109 * Sub-directory for this view file. | |
110 * | |
111 * @var string | |
112 * @access public | |
113 */ | |
114 var $subDir = null; | |
115 | |
116 /** | |
117 * Plugin name. | |
118 * | |
119 * @var string | |
120 * @access public | |
121 */ | |
122 var $plugin = null; | |
123 | |
124 /** | |
125 * valid session. | |
126 * | |
127 * @var boolean | |
128 * @access public | |
129 */ | |
130 var $_validSession = null; | |
131 | |
132 /** | |
133 * List of variables to collect from the associated controller | |
134 * | |
135 * @var array | |
136 * @access private | |
137 */ | |
138 var $__passedVars = array( | |
139 'action', 'base', 'webroot', 'layout', 'name', | |
140 'viewPath', 'ext', 'params', 'data', 'plugin', 'cacheAction' | |
141 ); | |
142 | |
143 /** | |
144 * Title HTML element for current scaffolded view | |
145 * | |
146 * @var string | |
147 * @access public | |
148 */ | |
149 var $scaffoldTitle = null; | |
150 | |
151 /** | |
152 * Construct and set up given controller with given parameters. | |
153 * | |
154 * @param string $controller_class Name of controller | |
155 * @param array $params Parameters for scaffolding | |
156 */ | |
157 function __construct(&$controller, $params) { | |
158 $this->controller =& $controller; | |
159 | |
160 $count = count($this->__passedVars); | |
161 for ($j = 0; $j < $count; $j++) { | |
162 $var = $this->__passedVars[$j]; | |
163 $this->{$var} = $controller->{$var}; | |
164 } | |
165 | |
166 $this->redirect = array('action' => 'index'); | |
167 | |
168 $this->modelClass = $controller->modelClass; | |
169 $this->modelKey = $controller->modelKey; | |
170 | |
171 if (!is_object($this->controller->{$this->modelClass})) { | |
172 return $this->cakeError('missingModel', array(array( | |
173 'className' => $this->modelClass, 'webroot' => '', 'base' => $controller->base | |
174 ))); | |
175 } | |
176 | |
177 $this->ScaffoldModel =& $this->controller->{$this->modelClass}; | |
178 $this->scaffoldTitle = Inflector::humanize($this->viewPath); | |
179 $this->scaffoldActions = $controller->scaffold; | |
180 $title_for_layout = __('Scaffold :: ', true) . Inflector::humanize($this->action) . ' :: ' . $this->scaffoldTitle; | |
181 $modelClass = $this->controller->modelClass; | |
182 $primaryKey = $this->ScaffoldModel->primaryKey; | |
183 $displayField = $this->ScaffoldModel->displayField; | |
184 $singularVar = Inflector::variable($modelClass); | |
185 $pluralVar = Inflector::variable($this->controller->name); | |
186 $singularHumanName = Inflector::humanize(Inflector::underscore($modelClass)); | |
187 $pluralHumanName = Inflector::humanize(Inflector::underscore($this->controller->name)); | |
188 $scaffoldFields = array_keys($this->ScaffoldModel->schema()); | |
189 $associations = $this->__associations(); | |
190 | |
191 $this->controller->set(compact( | |
192 'title_for_layout', 'modelClass', 'primaryKey', 'displayField', 'singularVar', 'pluralVar', | |
193 'singularHumanName', 'pluralHumanName', 'scaffoldFields', 'associations' | |
194 )); | |
195 | |
196 if ($this->controller->view) { | |
197 $this->controller->view = 'Scaffold'; | |
198 } | |
199 $this->_validSession = ( | |
200 isset($this->controller->Session) && $this->controller->Session->valid() != false | |
201 ); | |
202 $this->__scaffold($params); | |
203 } | |
204 | |
205 /** | |
206 * Outputs the content of a scaffold method passing it through the Controller::afterFilter() | |
207 * | |
208 * @return void | |
209 * @access protected | |
210 */ | |
211 function _output() { | |
212 $this->controller->afterFilter(); | |
213 echo($this->controller->output); | |
214 } | |
215 | |
216 /** | |
217 * Renders a view action of scaffolded model. | |
218 * | |
219 * @param array $params Parameters for scaffolding | |
220 * @return mixed A rendered view of a row from Models database table | |
221 * @access private | |
222 */ | |
223 function __scaffoldView($params) { | |
224 if ($this->controller->_beforeScaffold('view')) { | |
225 | |
226 $message = sprintf(__("No id set for %s::view()", true), Inflector::humanize($this->modelKey)); | |
227 if (isset($params['pass'][0])) { | |
228 $this->ScaffoldModel->id = $params['pass'][0]; | |
229 } elseif ($this->_validSession) { | |
230 $this->controller->Session->setFlash($message); | |
231 $this->controller->redirect($this->redirect); | |
232 } else { | |
233 return $this->controller->flash($message, '/' . Inflector::underscore($this->controller->viewPath)); | |
234 } | |
235 $this->ScaffoldModel->recursive = 1; | |
236 $this->controller->data = $this->ScaffoldModel->read(); | |
237 $this->controller->set( | |
238 Inflector::variable($this->controller->modelClass), $this->controller->data | |
239 ); | |
240 $this->controller->render($this->action, $this->layout); | |
241 $this->_output(); | |
242 } elseif ($this->controller->_scaffoldError('view') === false) { | |
243 return $this->__scaffoldError(); | |
244 } | |
245 } | |
246 | |
247 /** | |
248 * Renders index action of scaffolded model. | |
249 * | |
250 * @param array $params Parameters for scaffolding | |
251 * @return mixed A rendered view listing rows from Models database table | |
252 * @access private | |
253 */ | |
254 function __scaffoldIndex($params) { | |
255 if ($this->controller->_beforeScaffold('index')) { | |
256 $this->ScaffoldModel->recursive = 0; | |
257 $this->controller->set( | |
258 Inflector::variable($this->controller->name), $this->controller->paginate() | |
259 ); | |
260 $this->controller->render($this->action, $this->layout); | |
261 $this->_output(); | |
262 } elseif ($this->controller->_scaffoldError('index') === false) { | |
263 return $this->__scaffoldError(); | |
264 } | |
265 } | |
266 | |
267 /** | |
268 * Renders an add or edit action for scaffolded model. | |
269 * | |
270 * @param string $action Action (add or edit) | |
271 * @return mixed A rendered view with a form to edit or add a record in the Models database table | |
272 * @access private | |
273 */ | |
274 function __scaffoldForm($action = 'edit') { | |
275 $this->controller->viewVars['scaffoldFields'] = array_merge( | |
276 $this->controller->viewVars['scaffoldFields'], | |
277 array_keys($this->ScaffoldModel->hasAndBelongsToMany) | |
278 ); | |
279 $this->controller->render($action, $this->layout); | |
280 $this->_output(); | |
281 } | |
282 | |
283 /** | |
284 * Saves or updates the scaffolded model. | |
285 * | |
286 * @param array $params Parameters for scaffolding | |
287 * @param string $action add or edt | |
288 * @return mixed Success on save/update, add/edit form if data is empty or error if save or update fails | |
289 * @access private | |
290 */ | |
291 function __scaffoldSave($params = array(), $action = 'edit') { | |
292 $formAction = 'edit'; | |
293 $success = __('updated', true); | |
294 if ($action === 'add') { | |
295 $formAction = 'add'; | |
296 $success = __('saved', true); | |
297 } | |
298 | |
299 if ($this->controller->_beforeScaffold($action)) { | |
300 if ($action == 'edit') { | |
301 if (isset($params['pass'][0])) { | |
302 $this->ScaffoldModel->id = $params['pass'][0]; | |
303 } | |
304 | |
305 if (!$this->ScaffoldModel->exists()) { | |
306 $message = sprintf(__("Invalid id for %s::edit()", true), Inflector::humanize($this->modelKey)); | |
307 if ($this->_validSession) { | |
308 $this->controller->Session->setFlash($message); | |
309 $this->controller->redirect($this->redirect); | |
310 } else { | |
311 $this->controller->flash($message, $this->redirect); | |
312 $this->_output(); | |
313 } | |
314 } | |
315 } | |
316 | |
317 if (!empty($this->controller->data)) { | |
318 if ($action == 'create') { | |
319 $this->ScaffoldModel->create(); | |
320 } | |
321 | |
322 if ($this->ScaffoldModel->save($this->controller->data)) { | |
323 if ($this->controller->_afterScaffoldSave($action)) { | |
324 $message = sprintf( | |
325 __('The %1$s has been %2$s', true), | |
326 Inflector::humanize($this->modelKey), | |
327 $success | |
328 ); | |
329 if ($this->_validSession) { | |
330 $this->controller->Session->setFlash($message); | |
331 $this->controller->redirect($this->redirect); | |
332 } else { | |
333 $this->controller->flash($message, $this->redirect); | |
334 return $this->_output(); | |
335 } | |
336 } else { | |
337 return $this->controller->_afterScaffoldSaveError($action); | |
338 } | |
339 } else { | |
340 if ($this->_validSession) { | |
341 $this->controller->Session->setFlash(__('Please correct errors below.', true)); | |
342 } | |
343 } | |
344 } | |
345 | |
346 if (empty($this->controller->data)) { | |
347 if ($this->ScaffoldModel->id) { | |
348 $this->controller->data = $this->ScaffoldModel->read(); | |
349 } else { | |
350 $this->controller->data = $this->ScaffoldModel->create(); | |
351 } | |
352 } | |
353 | |
354 foreach ($this->ScaffoldModel->belongsTo as $assocName => $assocData) { | |
355 $varName = Inflector::variable(Inflector::pluralize( | |
356 preg_replace('/(?:_id)$/', '', $assocData['foreignKey']) | |
357 )); | |
358 $this->controller->set($varName, $this->ScaffoldModel->{$assocName}->find('list')); | |
359 } | |
360 foreach ($this->ScaffoldModel->hasAndBelongsToMany as $assocName => $assocData) { | |
361 $varName = Inflector::variable(Inflector::pluralize($assocName)); | |
362 $this->controller->set($varName, $this->ScaffoldModel->{$assocName}->find('list')); | |
363 } | |
364 | |
365 return $this->__scaffoldForm($formAction); | |
366 } elseif ($this->controller->_scaffoldError($action) === false) { | |
367 return $this->__scaffoldError(); | |
368 } | |
369 } | |
370 | |
371 /** | |
372 * Performs a delete on given scaffolded Model. | |
373 * | |
374 * @param array $params Parameters for scaffolding | |
375 * @return mixed Success on delete, error if delete fails | |
376 * @access private | |
377 */ | |
378 function __scaffoldDelete($params = array()) { | |
379 if ($this->controller->_beforeScaffold('delete')) { | |
380 $message = sprintf( | |
381 __("No id set for %s::delete()", true), | |
382 Inflector::humanize($this->modelKey) | |
383 ); | |
384 if (isset($params['pass'][0])) { | |
385 $id = $params['pass'][0]; | |
386 } elseif ($this->_validSession) { | |
387 $this->controller->Session->setFlash($message); | |
388 $this->controller->redirect($this->redirect); | |
389 } else { | |
390 $this->controller->flash($message, $this->redirect); | |
391 return $this->_output(); | |
392 } | |
393 | |
394 if ($this->ScaffoldModel->delete($id)) { | |
395 $message = sprintf( | |
396 __('The %1$s with id: %2$d has been deleted.', true), | |
397 Inflector::humanize($this->modelClass), $id | |
398 ); | |
399 if ($this->_validSession) { | |
400 $this->controller->Session->setFlash($message); | |
401 $this->controller->redirect($this->redirect); | |
402 } else { | |
403 $this->controller->flash($message, $this->redirect); | |
404 return $this->_output(); | |
405 } | |
406 } else { | |
407 $message = sprintf( | |
408 __('There was an error deleting the %1$s with id: %2$d', true), | |
409 Inflector::humanize($this->modelClass), $id | |
410 ); | |
411 if ($this->_validSession) { | |
412 $this->controller->Session->setFlash($message); | |
413 $this->controller->redirect($this->redirect); | |
414 } else { | |
415 $this->controller->flash($message, $this->redirect); | |
416 return $this->_output(); | |
417 } | |
418 } | |
419 } elseif ($this->controller->_scaffoldError('delete') === false) { | |
420 return $this->__scaffoldError(); | |
421 } | |
422 } | |
423 | |
424 /** | |
425 * Show a scaffold error | |
426 * | |
427 * @return mixed A rendered view showing the error | |
428 * @access private | |
429 */ | |
430 function __scaffoldError() { | |
431 return $this->controller->render('error', $this->layout); | |
432 $this->_output(); | |
433 } | |
434 | |
435 /** | |
436 * When methods are now present in a controller | |
437 * scaffoldView is used to call default Scaffold methods if: | |
438 * `var $scaffold;` is placed in the controller's class definition. | |
439 * | |
440 * @param array $params Parameters for scaffolding | |
441 * @return mixed A rendered view of scaffold action, or showing the error | |
442 * @access private | |
443 */ | |
444 function __scaffold($params) { | |
445 $db = &ConnectionManager::getDataSource($this->ScaffoldModel->useDbConfig); | |
446 $prefixes = Configure::read('Routing.prefixes'); | |
447 $scaffoldPrefix = $this->scaffoldActions; | |
448 | |
449 if (isset($db)) { | |
450 if (empty($this->scaffoldActions)) { | |
451 $this->scaffoldActions = array( | |
452 'index', 'list', 'view', 'add', 'create', 'edit', 'update', 'delete' | |
453 ); | |
454 } elseif (!empty($prefixes) && in_array($scaffoldPrefix, $prefixes)) { | |
455 $this->scaffoldActions = array( | |
456 $scaffoldPrefix . '_index', | |
457 $scaffoldPrefix . '_list', | |
458 $scaffoldPrefix . '_view', | |
459 $scaffoldPrefix . '_add', | |
460 $scaffoldPrefix . '_create', | |
461 $scaffoldPrefix . '_edit', | |
462 $scaffoldPrefix . '_update', | |
463 $scaffoldPrefix . '_delete' | |
464 ); | |
465 } | |
466 | |
467 if (in_array($params['action'], $this->scaffoldActions)) { | |
468 if (!empty($prefixes)) { | |
469 $params['action'] = str_replace($scaffoldPrefix . '_', '', $params['action']); | |
470 } | |
471 switch ($params['action']) { | |
472 case 'index': | |
473 case 'list': | |
474 $this->__scaffoldIndex($params); | |
475 break; | |
476 case 'view': | |
477 $this->__scaffoldView($params); | |
478 break; | |
479 case 'add': | |
480 case 'create': | |
481 $this->__scaffoldSave($params, 'add'); | |
482 break; | |
483 case 'edit': | |
484 case 'update': | |
485 $this->__scaffoldSave($params, 'edit'); | |
486 break; | |
487 case 'delete': | |
488 $this->__scaffoldDelete($params); | |
489 break; | |
490 } | |
491 } else { | |
492 return $this->cakeError('missingAction', array(array( | |
493 'className' => $this->controller->name . "Controller", | |
494 'base' => $this->controller->base, | |
495 'action' => $this->action, | |
496 'webroot' => $this->controller->webroot | |
497 ))); | |
498 } | |
499 } else { | |
500 return $this->cakeError('missingDatabase', array(array( | |
501 'webroot' => $this->controller->webroot | |
502 ))); | |
503 } | |
504 } | |
505 | |
506 /** | |
507 * Returns associations for controllers models. | |
508 * | |
509 * @return array Associations for model | |
510 * @access private | |
511 */ | |
512 function __associations() { | |
513 $keys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'); | |
514 $associations = array(); | |
515 | |
516 foreach ($keys as $key => $type) { | |
517 foreach ($this->ScaffoldModel->{$type} as $assocKey => $assocData) { | |
518 $associations[$type][$assocKey]['primaryKey'] = | |
519 $this->ScaffoldModel->{$assocKey}->primaryKey; | |
520 | |
521 $associations[$type][$assocKey]['displayField'] = | |
522 $this->ScaffoldModel->{$assocKey}->displayField; | |
523 | |
524 $associations[$type][$assocKey]['foreignKey'] = | |
525 $assocData['foreignKey']; | |
526 | |
527 $associations[$type][$assocKey]['controller'] = | |
528 Inflector::pluralize(Inflector::underscore($assocData['className'])); | |
529 | |
530 if ($type == 'hasAndBelongsToMany') { | |
531 $associations[$type][$assocKey]['with'] = $assocData['with']; | |
532 } | |
533 } | |
534 } | |
535 return $associations; | |
536 } | |
537 } | |
538 | |
539 /** | |
540 * Scaffold View. | |
541 * | |
542 * @package cake | |
543 * @subpackage cake.cake.libs.controller | |
544 */ | |
545 if (!class_exists('ThemeView')) { | |
546 App::import('View', 'Theme'); | |
547 } | |
548 | |
549 /** | |
550 * ScaffoldView provides specific view file loading features for scaffolded views. | |
551 * | |
552 * @package cake.libs.view | |
553 */ | |
554 class ScaffoldView extends ThemeView { | |
555 | |
556 /** | |
557 * Override _getViewFileName Appends special scaffolding views in. | |
558 * | |
559 * @param string $name name of the view file to get. | |
560 * @return string action | |
561 * @access protected | |
562 */ | |
563 function _getViewFileName($name = null) { | |
564 if ($name === null) { | |
565 $name = $this->action; | |
566 } | |
567 $name = Inflector::underscore($name); | |
568 $prefixes = Configure::read('Routing.prefixes'); | |
569 | |
570 if (!empty($prefixes)) { | |
571 foreach ($prefixes as $prefix) { | |
572 if (strpos($name, $prefix . '_') !== false) { | |
573 $name = substr($name, strlen($prefix) + 1); | |
574 break; | |
575 } | |
576 } | |
577 } | |
578 | |
579 if ($name === 'add') { | |
580 $name = 'edit'; | |
581 } | |
582 | |
583 $scaffoldAction = 'scaffold.' . $name; | |
584 | |
585 if (!is_null($this->subDir)) { | |
586 $subDir = strtolower($this->subDir) . DS; | |
587 } else { | |
588 $subDir = null; | |
589 } | |
590 | |
591 $names[] = $this->viewPath . DS . $subDir . $scaffoldAction; | |
592 $names[] = 'scaffolds' . DS . $subDir . $name; | |
593 | |
594 $paths = $this->_paths($this->plugin); | |
595 $exts = array($this->ext); | |
596 if ($this->ext !== '.ctp') { | |
597 array_push($exts, '.ctp'); | |
598 } | |
599 foreach ($exts as $ext) { | |
600 foreach ($paths as $path) { | |
601 foreach ($names as $name) { | |
602 if (file_exists($path . $name . $ext)) { | |
603 return $path . $name . $ext; | |
604 } | |
605 } | |
606 } | |
607 } | |
608 | |
609 if ($name === 'scaffolds' . DS . $subDir . 'error') { | |
610 return LIBS . 'view' . DS . 'errors' . DS . 'scaffold_error.ctp'; | |
611 } | |
612 | |
613 return $this->_missingView($paths[0] . $name . $this->ext, 'missingView'); | |
614 } | |
615 } |