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:  * Framework debugging and PHP error-handling class
  5:  *
  6:  * Provides enhanced logging, stack traces, and rendering debug views
  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
 20:  * @since         CakePHP(tm) v 1.2.4560
 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:  * Included libraries.
 28:  *
 29:  */
 30:     if (!class_exists('Object')) {
 31:         uses('object');
 32:     }
 33:     if (!class_exists('CakeLog')) {
 34:         uses('cake_log');
 35:     }
 36: /**
 37:  * Provide custom logging and error handling.
 38:  *
 39:  * Debugger overrides PHP's default error handling to provide stack traces and enhanced logging
 40:  *
 41:  * @package       cake
 42:  * @subpackage    cake.cake.libs
 43:  * @link          http://book.cakephp.org/view/460/Using-the-Debugger-Class
 44:  */
 45: class Debugger extends Object {
 46: /**
 47:  * A list of errors generated by the application.
 48:  *
 49:  * @var array
 50:  * @access public
 51:  */
 52:     var $errors = array();
 53: /**
 54:  * Contains the base URL for error code documentation.
 55:  *
 56:  * @var string
 57:  * @access public
 58:  */
 59:     var $helpPath = null;
 60: /**
 61:  * The current output format.
 62:  *
 63:  * @var string
 64:  * @access protected
 65:  */
 66:     var $_outputFormat = 'js';
 67: /**
 68:  * Holds current output data when outputFormat is false.
 69:  *
 70:  * @var string
 71:  * @access private
 72:  */
 73:     var $__data = array();
 74: /**
 75:  * Constructor.
 76:  *
 77:  */
 78:     function __construct() {
 79:         $docRef = ini_get('docref_root');
 80:         if (empty($docRef)) {
 81:             ini_set('docref_root', 'http://php.net/');
 82:         }
 83:         if (!defined('E_RECOVERABLE_ERROR')) {
 84:             define('E_RECOVERABLE_ERROR', 4096);
 85:         }
 86:     }
 87: /**
 88:  * Returns a reference to the Debugger singleton object instance.
 89:  *
 90:  * @return object
 91:  * @access public
 92:  * @static
 93:  */
 94:     function &getInstance($class = null) {
 95:         static $instance = array();
 96:         if (!empty($class)) {
 97:             if (!$instance || strtolower($class) != strtolower(get_class($instance[0]))) {
 98:                 $instance[0] = & new $class();
 99:                 if (Configure::read() > 0) {
100:                     Configure::version(); // Make sure the core config is loaded
101:                     $instance[0]->helpPath = Configure::read('Cake.Debugger.HelpPath');
102:                 }
103:             }
104:         }
105: 
106:         if (!$instance) {
107:             $instance[0] =& new Debugger();
108:             if (Configure::read() > 0) {
109:                 Configure::version(); // Make sure the core config is loaded
110:                 $instance[0]->helpPath = Configure::read('Cake.Debugger.HelpPath');
111:             }
112:         }
113:         return $instance[0];
114:     }
115: /**
116:  * Formats and outputs the contents of the supplied variable.
117:  *
118:  * @param $var mixed the variable to dump
119:  * @return void
120:  * @see exportVar
121:  * @access public
122:  * @static
123:  * @link http://book.cakephp.org/view/460/Using-the-Debugger-Class
124: */
125:     function dump($var) {
126:         $_this = Debugger::getInstance();
127:         pr($_this->exportVar($var));
128:     }
129: /**
130:  * Creates a detailed stack trace log at the time of invocation, much like dump()
131:  * but to debug.log.
132:  *
133:  * @param $var mixed Variable or content to log
134:  * @param $level int type of log to use. Defaults to LOG_DEBUG
135:  * @return void
136:  * @static
137:  * @link http://book.cakephp.org/view/460/Using-the-Debugger-Class
138:  */
139:     function log($var, $level = LOG_DEBUG) {
140:         $_this = Debugger::getInstance();
141:         $source = $_this->trace(array('start' => 1)) . "\n";
142:         CakeLog::write($level, "\n" . $source . $_this->exportVar($var));
143:     }
144: 
145: /**
146:  * Overrides PHP's default error handling.
147:  *
148:  * @param integer $code Code of error
149:  * @param string $description Error description
150:  * @param string $file File on which error occurred
151:  * @param integer $line Line that triggered the error
152:  * @param array $context Context
153:  * @return boolean true if error was handled
154:  * @access public
155:  */
156:     function handleError($code, $description, $file = null, $line = null, $context = null) {
157:         if (error_reporting() == 0 || $code === 2048 || $code === 8192) {
158:             return;
159:         }
160: 
161:         $_this = Debugger::getInstance();
162: 
163:         if (empty($file)) {
164:             $file = '[internal]';
165:         }
166:         if (empty($line)) {
167:             $line = '??';
168:         }
169:         $file = $_this->trimPath($file);
170: 
171:         $info = compact('code', 'description', 'file', 'line');
172:         if (!in_array($info, $_this->errors)) {
173:             $_this->errors[] = $info;
174:         } else {
175:             return;
176:         }
177: 
178:         $level = LOG_DEBUG;
179:         switch ($code) {
180:             case E_PARSE:
181:             case E_ERROR:
182:             case E_CORE_ERROR:
183:             case E_COMPILE_ERROR:
184:             case E_USER_ERROR:
185:                 $error = 'Fatal Error';
186:                 $level = LOG_ERROR;
187:             break;
188:             case E_WARNING:
189:             case E_USER_WARNING:
190:             case E_COMPILE_WARNING:
191:             case E_RECOVERABLE_ERROR:
192:                 $error = 'Warning';
193:                 $level = LOG_WARNING;
194:             break;
195:             case E_NOTICE:
196:             case E_USER_NOTICE:
197:                 $error = 'Notice';
198:                 $level = LOG_NOTICE;
199:             break;
200:             default:
201:                 return false;
202:             break;
203:         }
204: 
205:         $helpCode = null;
206:         if (!empty($_this->helpPath) && preg_match('/.*\[([0-9]+)\]$/', $description, $codes)) {
207:             if (isset($codes[1])) {
208:                 $helpCode = $codes[1];
209:                 $description = trim(preg_replace('/\[[0-9]+\]$/', '', $description));
210:             }
211:         }
212: 
213:         echo $_this->_output($level, $error, $code, $helpCode, $description, $file, $line, $context);
214: 
215:         if (Configure::read('log')) {
216:             CakeLog::write($level, "{$error} ({$code}): {$description} in [{$file}, line {$line}]");
217:         }
218: 
219:         if ($error == 'Fatal Error') {
220:             exit();
221:         }
222:         return true;
223:     }
224: /**
225:  * Outputs a stack trace based on the supplied options.
226:  *
227:  * @param array $options Format for outputting stack trace
228:  * @return string Formatted stack trace
229:  * @access public
230:  * @static
231:  * @link http://book.cakephp.org/view/460/Using-the-Debugger-Class
232:  */
233:     function trace($options = array()) {
234:         $options = array_merge(array(
235:                 'depth'     => 999,
236:                 'format'    => '',
237:                 'args'      => false,
238:                 'start'     => 0,
239:                 'scope'     => null,
240:                 'exclude'   => null
241:             ),
242:             $options
243:         );
244: 
245:         $backtrace = debug_backtrace();
246:         $back = array();
247:         $count = count($backtrace);
248: 
249:         for ($i = $options['start']; $i < $count && $i < $options['depth']; $i++) {
250:             $trace = array_merge(
251:                 array(
252:                     'file' => '[internal]',
253:                     'line' => '??'
254:                 ),
255:                 $backtrace[$i]
256:             );
257: 
258:             if (isset($backtrace[$i + 1])) {
259:                 $next = array_merge(
260:                     array(
261:                         'line'      => '??',
262:                         'file'      => '[internal]',
263:                         'class'     => null,
264:                         'function'  => '[main]'
265:                     ),
266:                     $backtrace[$i + 1]
267:                 );
268:                 $function = $next['function'];
269: 
270:                 if (!empty($next['class'])) {
271:                     $function = $next['class'] . '::' . $function . '(';
272:                     if ($options['args'] && isset($next['args'])) {
273:                         $args = array();
274:                         foreach ($next['args'] as $arg) {
275:                             $args[] = Debugger::exportVar($arg);
276:                         }
277:                         $function .= implode(', ', $args);
278:                     }
279:                     $function .= ')';
280:                 }
281:             } else {
282:                 $function = '[main]';
283:             }
284:             if (in_array($function, array('call_user_func_array', 'trigger_error'))) {
285:                 continue;
286:             }
287:             if ($options['format'] == 'points' && $trace['file'] != '[internal]') {
288:                 $back[] = array('file' => $trace['file'], 'line' => $trace['line']);
289:             } elseif (empty($options['format'])) {
290:                 $back[] = $function . ' - ' . Debugger::trimPath($trace['file']) . ', line ' . $trace['line'];
291:             } else {
292:                 $back[] = $trace;
293:             }
294:         }
295: 
296:         if ($options['format'] == 'array' || $options['format'] == 'points') {
297:             return $back;
298:         }
299:         return implode("\n", $back);
300:     }
301: /**
302:  * Shortens file paths by replacing the application base path with 'APP', and the CakePHP core
303:  * path with 'CORE'.
304:  *
305:  * @param string $path Path to shorten
306:  * @return string Normalized path
307:  * @access public
308:  * @static
309:  */
310:     function trimPath($path) {
311:         if (!defined('CAKE_CORE_INCLUDE_PATH') || !defined('APP')) {
312:             return $path;
313:         }
314: 
315:         if (strpos($path, APP) === 0) {
316:             return str_replace(APP, 'APP' . DS, $path);
317:         } elseif (strpos($path, CAKE_CORE_INCLUDE_PATH) === 0) {
318:             return str_replace(CAKE_CORE_INCLUDE_PATH, 'CORE', $path);
319:         } elseif (strpos($path, ROOT) === 0) {
320:             return str_replace(ROOT, 'ROOT', $path);
321:         }
322:         $corePaths = Configure::corePaths('cake');
323:         foreach ($corePaths as $corePath) {
324:             if (strpos($path, $corePath) === 0) {
325:                 return str_replace($corePath, 'CORE' .DS . 'cake' .DS, $path);
326:             }
327:         }
328:         return $path;
329:     }
330: /**
331:  * Grabs an excerpt from a file and highlights a given line of code
332:  *
333:  * @param string $file Absolute path to a PHP file
334:  * @param integer $line Line number to highlight
335:  * @param integer $context Number of lines of context to extract above and below $line
336:  * @return array Set of lines highlighted
337:  * @access public
338:  * @static
339:  * @link http://book.cakephp.org/view/460/Using-the-Debugger-Class
340:  */
341:     function excerpt($file, $line, $context = 2) {
342:         $data = $lines = array();
343:         if (!file_exists($file)) {
344:             return array();
345:         }
346:         $data = @explode("\n", file_get_contents($file));
347: 
348:         if (empty($data) || !isset($data[$line])) {
349:             return;
350:         }
351:         for ($i = $line - ($context + 1); $i < $line + $context; $i++) {
352:             if (!isset($data[$i])) {
353:                 continue;
354:             }
355:             $string = str_replace(array("\r\n", "\n"), "", highlight_string($data[$i], true));
356:             if ($i == $line) {
357:                 $lines[] = '<span class="code-highlight">' . $string . '</span>';
358:             } else {
359:                 $lines[] = $string;
360:             }
361:         }
362:         return $lines;
363:     }
364: /**
365:  * Converts a variable to a string for debug output.
366:  *
367:  * @param string $var Variable to convert
368:  * @return string Variable as a formatted string
369:  * @access public
370:  * @static
371:  * @link http://book.cakephp.org/view/460/Using-the-Debugger-Class
372:  */
373:     function exportVar($var, $recursion = 0) {
374:         $_this =  Debugger::getInstance();
375:         switch (strtolower(gettype($var))) {
376:             case 'boolean':
377:                 return ($var) ? 'true' : 'false';
378:             break;
379:             case 'integer':
380:             case 'double':
381:                 return $var;
382:             break;
383:             case 'string':
384:                 if (trim($var) == "") {
385:                     return '""';
386:                 }
387:                 return '"' . h($var) . '"';
388:             break;
389:             case 'object':
390:                 return get_class($var) . "\n" . $_this->__object($var);
391:             case 'array':
392:                 $out = "array(";
393:                 $vars = array();
394:                 foreach ($var as $key => $val) {
395:                     if ($recursion >= 0) {
396:                         if (is_numeric($key)) {
397:                             $vars[] = "\n\t" . $_this->exportVar($val, $recursion - 1);
398:                         } else {
399:                             $vars[] = "\n\t" .$_this->exportVar($key, $recursion - 1)
400:                                         . ' => ' . $_this->exportVar($val, $recursion - 1);
401:                         }
402:                     }
403:                 }
404:                 $n = null;
405:                 if (!empty($vars)) {
406:                     $n = "\n";
407:                 }
408:                 return $out . implode(",", $vars) . "{$n})";
409:             break;
410:             case 'resource':
411:                 return strtolower(gettype($var));
412:             break;
413:             case 'null':
414:                 return 'null';
415:             break;
416:         }
417:     }
418: /**
419:  * Handles object to string conversion.
420:  *
421:  * @param string $var Object to convert
422:  * @return string
423:  * @access private
424:  * @see Debugger:exportVar()
425:  */
426:     function __object($var) {
427:         $out = array();
428: 
429:         if (is_object($var)) {
430:             $className = get_class($var);
431:             $objectVars = get_object_vars($var);
432: 
433:             foreach ($objectVars as $key => $value) {
434:                 if (is_object($value)) {
435:                     $value = get_class($value) . ' object';
436:                 } elseif (is_array($value)) {
437:                     $value = 'array';
438:                 } elseif ($value === null) {
439:                     $value = 'NULL';
440:                 } elseif (in_array(gettype($value), array('boolean', 'integer', 'double', 'string', 'array', 'resource'))) {
441:                     $value = Debugger::exportVar($value);
442:                 }
443:                 $out[] = "$className::$$key = " . $value;
444:             }
445:         }
446:         return implode("\n", $out);
447:     }
448: /**
449:  * Handles object conversion to debug string.
450:  *
451:  * @param string $var Object to convert
452:  * @access protected
453:  */
454:     function output($format = 'js') {
455:         $_this = Debugger::getInstance();
456:         $data = null;
457: 
458:         if ($format === true && !empty($_this->__data)) {
459:             $data = $_this->__data;
460:             $_this->__data = array();
461:             $format = false;
462:         }
463:         $_this->_outputFormat = $format;
464: 
465:         return $data;
466:     }
467: /**
468:  * Handles object conversion to debug string.
469:  *
470:  * @param string $var Object to convert
471:  * @access private
472:  */
473:     function _output($level, $error, $code, $helpCode, $description, $file, $line, $kontext) {
474:         $files = $this->trace(array('start' => 2, 'format' => 'points'));
475:         $listing = $this->excerpt($files[0]['file'], $files[0]['line'] - 1, 1);
476:         $trace = $this->trace(array('start' => 2, 'depth' => '20'));
477:         $context = array();
478: 
479:         foreach ((array)$kontext as $var => $value) {
480:             $context[] = "\${$var}\t=\t" . $this->exportVar($value, 1);
481:         }
482: 
483:         switch ($this->_outputFormat) {
484:             default:
485:             case 'js':
486:                 $link = "document.getElementById(\"CakeStackTrace" . count($this->errors) . "\").style.display = (document.getElementById(\"CakeStackTrace" . count($this->errors) . "\").style.display == \"none\" ? \"\" : \"none\")";
487:                 $out = "<a href='javascript:void(0);' onclick='{$link}'><b>{$error}</b> ({$code})</a>: {$description} [<b>{$file}</b>, line <b>{$line}</b>]";
488:                 if (Configure::read() > 0) {
489:                     debug($out, false, false);
490:                     echo '<div id="CakeStackTrace' . count($this->errors) . '" class="cake-stack-trace" style="display: none;">';
491:                         $link = "document.getElementById(\"CakeErrorCode" . count($this->errors) . "\").style.display = (document.getElementById(\"CakeErrorCode" . count($this->errors) . "\").style.display == \"none\" ? \"\" : \"none\")";
492:                         echo "<a href='javascript:void(0);' onclick='{$link}'>Code</a>";
493: 
494:                         if (!empty($context)) {
495:                             $link = "document.getElementById(\"CakeErrorContext" . count($this->errors) . "\").style.display = (document.getElementById(\"CakeErrorContext" . count($this->errors) . "\").style.display == \"none\" ? \"\" : \"none\")";
496:                             echo " | <a href='javascript:void(0);' onclick='{$link}'>Context</a>";
497: 
498:                             if (!empty($helpCode)) {
499:                                 echo " | <a href='{$this->helpPath}{$helpCode}' target='_blank'>Help</a>";
500:                             }
501: 
502:                             echo "<pre id=\"CakeErrorContext" . count($this->errors) . "\" class=\"cake-context\" style=\"display: none;\">";
503:                             echo implode("\n", $context);
504:                             echo "</pre>";
505:                         }
506: 
507:                         if (!empty($listing)) {
508:                             echo "<div id=\"CakeErrorCode" . count($this->errors) . "\" class=\"cake-code-dump\" style=\"display: none;\">";
509:                                 pr(implode("\n", $listing) . "\n", false);
510:                             echo '</div>';
511:                         }
512:                         pr($trace, false);
513:                     echo '</div>';
514:                 }
515:             break;
516:             case 'html':
517:                 echo "<pre class=\"cake-debug\"><b>{$error}</b> ({$code}) : {$description} [<b>{$file}</b>, line <b>{$line}]</b></pre>";
518:                 if (!empty($context)) {
519:                     echo "Context:\n" .implode("\n", $context) . "\n";
520:                 }
521:                 echo "<pre class=\"cake-debug context\"><b>Context</b> <p>" . implode("\n", $context) . "</p></pre>";
522:                 echo "<pre class=\"cake-debug trace\"><b>Trace</b> <p>" . $trace. "</p></pre>";
523:             break;
524:             case 'text':
525:             case 'txt':
526:                 echo "{$error}: {$code} :: {$description} on line {$line} of {$file}\n";
527:                 if (!empty($context)) {
528:                     echo "Context:\n" .implode("\n", $context) . "\n";
529:                 }
530:                 echo "Trace:\n" . $trace;
531:             break;
532:             case 'log':
533:                 $this->log(compact('error', 'code', 'description', 'line', 'file', 'context', 'trace'));
534:             break;
535:             case false:
536:                 $this->__data[] = compact('error', 'code', 'description', 'line', 'file', 'context', 'trace');
537:             break;
538:         }
539:     }
540: /**
541:  * Verifies that the application's salt value has been changed from the default value.
542:  *
543:  * @access public
544:  * @static
545:  */
546:     function checkSessionKey() {
547:         if (Configure::read('Security.salt') == 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi') {
548:             trigger_error(__('Please change the value of \'Security.salt\' in app/config/core.php to a salt value specific to your application', true), E_USER_NOTICE);
549:         }
550:     }
551: /**
552:  * Invokes the given debugger object as the current error handler, taking over control from the previous handler
553:  * in a stack-like hierarchy.
554:  *
555:  * @param object $debugger A reference to the Debugger object
556:  * @access public
557:  * @static
558:  * @link http://book.cakephp.org/view/460/Using-the-Debugger-Class
559:  */
560:     function invoke(&$debugger) {
561:         set_error_handler(array(&$debugger, 'handleError'));
562:     }
563: }
564: 
565: if (!defined('DISABLE_DEFAULT_ERROR_HANDLING')) {
566:     Debugger::invoke(Debugger::getInstance());
567: }
568: ?>
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