CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 1.2 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 1.2
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Classes

  • AclBase
  • AclBehavior
  • AclComponent
  • AclNode
  • AclShell
  • Aco
  • AcoAction
  • AjaxHelper
  • ApcEngine
  • ApiShell
  • App
  • AppController
  • AppHelper
  • AppModel
  • Aro
  • AuthComponent
  • BakeShell
  • BehaviorCollection
  • Cache
  • CacheEngine
  • CacheHelper
  • CakeErrorController
  • CakeLog
  • CakeSchema
  • CakeSession
  • CakeSocket
  • ClassRegistry
  • Component
  • Configure
  • ConnectionManager
  • ConsoleShell
  • ContainableBehavior
  • Controller
  • ControllerTask
  • CookieComponent
  • DataSource
  • DbAcl
  • DbAclSchema
  • DbConfigTask
  • DboAdodb
  • DboDb2
  • DboFirebird
  • DboMssql
  • DboMysql
  • DboMysqlBase
  • DboMysqli
  • DboOdbc
  • DboOracle
  • DboPostgres
  • DboSource
  • DboSqlite
  • DboSybase
  • Debugger
  • EmailComponent
  • ErrorHandler
  • ExtractTask
  • File
  • FileEngine
  • Flay
  • Folder
  • FormHelper
  • Helper
  • HtmlHelper
  • HttpSocket
  • I18n
  • I18nModel
  • i18nSchema
  • I18nShell
  • Inflector
  • IniAcl
  • JavascriptHelper
  • JsHelper
  • JsHelperObject
  • L10n
  • MagicDb
  • MagicFileResource
  • MediaView
  • MemcacheEngine
  • Model
  • ModelBehavior
  • ModelTask
  • Multibyte
  • NumberHelper
  • Object
  • Overloadable
  • Overloadable2
  • PagesController
  • PaginatorHelper
  • Permission
  • PluginTask
  • ProjectTask
  • RequestHandlerComponent
  • Router
  • RssHelper
  • Sanitize
  • Scaffold
  • ScaffoldView
  • SchemaShell
  • Security
  • SecurityComponent
  • SessionComponent
  • SessionHelper
  • SessionsSchema
  • Set
  • Shell
  • String
  • TestSuiteShell
  • TestTask
  • TextHelper
  • ThemeView
  • TimeHelper
  • TranslateBehavior
  • TreeBehavior
  • Validation
  • View
  • ViewTask
  • XcacheEngine
  • Xml
  • XmlElement
  • XmlHelper
  • XmlManager
  • XmlNode
  • XmlTextNode

Functions

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

Generated using CakePHP API Docs