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:  * XML handling for Cake.
   5:  *
   6:  * The methods in these classes enable the datasources that use XML to work.
   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 v .0.10.3.1400
  21:  * @version       $Revision$
  22:  * @modifiedby    $LastChangedBy$
  23:  * @lastmodified  $Date$
  24:  * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
  25:  */
  26: App::import('Core', 'Set');
  27: /**
  28:  * XML node.
  29:  *
  30:  * Single XML node in an XML tree.
  31:  *
  32:  * @package       cake
  33:  * @subpackage    cake.cake.libs
  34:  * @since         CakePHP v .0.10.3.1400
  35:  */
  36: class XmlNode extends Object {
  37: /**
  38:  * Name of node
  39:  *
  40:  * @var string
  41:  * @access public
  42:  */
  43:     var $name = null;
  44: /**
  45:  * Node namespace
  46:  *
  47:  * @var string
  48:  * @access public
  49:  */
  50:     var $namespace = null;
  51: /**
  52:  * Namespaces defined for this node and all child nodes
  53:  *
  54:  * @var array
  55:  * @access public
  56:  */
  57:     var $namespaces = array();
  58: /**
  59:  * Value of node
  60:  *
  61:  * @var string
  62:  * @access public
  63:  */
  64:     var $value;
  65: /**
  66:  * Attributes on this node
  67:  *
  68:  * @var array
  69:  * @access public
  70:  */
  71:     var $attributes = array();
  72: /**
  73:  * This node's children
  74:  *
  75:  * @var array
  76:  * @access public
  77:  */
  78:     var $children = array();
  79: /**
  80:  * Reference to parent node.
  81:  *
  82:  * @var XmlNode
  83:  * @access private
  84:  */
  85:     var $__parent = null;
  86: /**
  87:  * Constructor.
  88:  *
  89:  * @param string $name Node name
  90:  * @param array $attributes Node attributes
  91:  * @param mixed $value Node contents (text)
  92:  * @param array $children Node children
  93:  */
  94:     function __construct($name = null, $value = null, $namespace = null) {
  95:         if (strpos($name, ':') !== false) {
  96:             list($prefix, $name) = explode(':', $name);
  97:             if (!$namespace) {
  98:                 $namespace = $prefix;
  99:             }
 100:         }
 101:         $this->name = $name;
 102:         if ($namespace) {
 103:             $this->namespace = $namespace;
 104:         }
 105: 
 106:         if (is_array($value) || is_object($value)) {
 107:             $this->normalize($value);
 108:         } elseif (!empty($value) || $value === 0 || $value === '0') {
 109:             $this->createTextNode($value);
 110:         }
 111:     }
 112: /**
 113:  * Adds a namespace to the current node
 114:  *
 115:  * @param string $prefix The namespace prefix
 116:  * @param string $url The namespace DTD URL
 117:  * @return void
 118:  */
 119:     function addNamespace($prefix, $url) {
 120:         if ($ns = Xml::addGlobalNs($prefix, $url)) {
 121:             $this->namespaces = array_merge($this->namespaces, $ns);
 122:             return true;
 123:         }
 124:         return false;
 125:     }
 126: /**
 127:  * Adds a namespace to the current node
 128:  *
 129:  * @param string $prefix The namespace prefix
 130:  * @param string $url The namespace DTD URL
 131:  * @return void
 132:  */
 133:     function removeNamespace($prefix) {
 134:         if (Xml::removeGlobalNs($prefix)) {
 135:             return true;
 136:         }
 137:         return false;
 138:     }
 139: /**
 140:  * Creates an XmlNode object that can be appended to this document or a node in it
 141:  *
 142:  * @param string $name Node name
 143:  * @param string $value Node value
 144:  * @param string $namespace Node namespace
 145:  * @return object XmlNode
 146:  */
 147:     function &createNode($name = null, $value = null, $namespace = false) {
 148:         $node =& new XmlNode($name, $value, $namespace);
 149:         $node->setParent($this);
 150:         return $node;
 151:     }
 152: /**
 153:  * Creates an XmlElement object that can be appended to this document or a node in it
 154:  *
 155:  * @param string $name Element name
 156:  * @param string $value Element value
 157:  * @param array $attributes Element attributes
 158:  * @param string $namespace Node namespace
 159:  * @return object XmlElement
 160:  */
 161:     function &createElement($name = null, $value = null, $attributes = array(), $namespace = false) {
 162:         $element =& new XmlElement($name, $value, $attributes, $namespace);
 163:         $element->setParent($this);
 164:         return $element;
 165:     }
 166: /**
 167:  * Creates an XmlTextNode object that can be appended to this document or a node in it
 168:  *
 169:  * @param string $value Node value
 170:  * @return object XmlTextNode
 171:  */
 172:     function &createTextNode($value = null) {
 173:         $node = new XmlTextNode($value);
 174:         $node->setParent($this);
 175:         return $node;
 176:     }
 177: /**
 178:  * Gets the XML element properties from an object.
 179:  *
 180:  * @param object $object Object to get properties from
 181:  * @return array Properties from object
 182:  * @access public
 183:  */
 184:     function normalize($object, $keyName = null, $options = array()) {
 185:         if (is_a($object, 'XmlNode')) {
 186:             return $object;
 187:         }
 188:         $name = null;
 189:         $options += array('format' => 'attributes');
 190: 
 191:         if ($keyName !== null && !is_numeric($keyName)) {
 192:             $name = $keyName;
 193:         } elseif (!empty($object->_name_)) {
 194:             $name = $object->_name_;
 195:         } elseif (isset($object->name)) {
 196:             $name = $object->name;
 197:         } elseif ($options['format'] == 'attributes') {
 198:             $name = get_class($object);
 199:         }
 200: 
 201:         $tagOpts = $this->__tagOptions($name);
 202: 
 203:         if ($tagOpts === false) {
 204:             return;
 205:         }
 206: 
 207:         if (isset($tagOpts['name'])) {
 208:             $name = $tagOpts['name'];
 209:         } elseif ($name != strtolower($name)) {
 210:             $name = Inflector::slug(Inflector::underscore($name));
 211:         }
 212: 
 213:         if (!empty($name)) {
 214:             $node =& $this->createElement($name);
 215:         } else {
 216:             $node =& $this;
 217:         }
 218: 
 219:         $namespace = array();
 220:         $attributes = array();
 221:         $children = array();
 222:         $chldObjs = array();
 223: 
 224:         if (is_object($object)) {
 225:             $chldObjs = get_object_vars($object);
 226:         } elseif (is_array($object)) {
 227:             $chldObjs = $object;
 228:         } elseif (!empty($object) || $object === 0 || $object === '0') {
 229:             $node->createTextNode($object);
 230:         }
 231:         $attr = array();
 232: 
 233:         if (isset($tagOpts['attributes'])) {
 234:             $attr = $tagOpts['attributes'];
 235:         }
 236:         if (isset($tagOpts['value']) && isset($chldObjs[$tagOpts['value']])) {
 237:             $node->createTextNode($chldObjs[$tagOpts['value']]);
 238:             unset($chldObjs[$tagOpts['value']]);
 239:         }
 240: 
 241:         $n = $name;
 242:         if (isset($chldObjs['_name_'])) {
 243:             $n = null;
 244:             unset($chldObjs['_name_']);
 245:         }
 246:         $c = 0;
 247: 
 248:         foreach ($chldObjs as $key => $val) {
 249:             if (in_array($key, $attr) && !is_object($val) && !is_array($val)) {
 250:                 $attributes[$key] = $val;
 251:             } else {
 252:                 if (!isset($tagOpts['children']) || $tagOpts['children'] === array() || (is_array($tagOpts['children']) && in_array($key, $tagOpts['children']))) {
 253:                     if (!is_numeric($key)) {
 254:                         $n = $key;
 255:                     }
 256:                     if (is_array($val)) {
 257:                         foreach ($val as $n2 => $obj2) {
 258:                             if (is_numeric($n2)) {
 259:                                 $n2 = $n;
 260:                             }
 261:                             $node->normalize($obj2, $n2, $options);
 262:                         }
 263:                     } else {
 264:                         if (is_object($val)) {
 265: 
 266:                             $node->normalize($val, $n, $options);
 267:                         } elseif ($options['format'] == 'tags' && $this->__tagOptions($key) !== false) {
 268:                             $tmp =& $node->createElement($key);
 269:                             if (!empty($val) || $val === 0 || $val === '0') {
 270:                                 $tmp->createTextNode($val);
 271:                             }
 272:                         } elseif ($options['format'] == 'attributes') {
 273:                             $node->addAttribute($key, $val);
 274:                         }
 275:                     }
 276:                 }
 277:             }
 278:             $c++;
 279:         }
 280:         if (!empty($name)) {
 281:             return $node;
 282:         }
 283:         return $children;
 284:     }
 285: /**
 286:  * Gets the tag-specific options for the given node name
 287:  *
 288:  * @param string $name XML tag name
 289:  * @param string $option The specific option to query.  Omit for all options
 290:  * @return mixed A specific option value if $option is specified, otherwise an array of all options
 291:  * @access private
 292:  */
 293:     function __tagOptions($name, $option = null) {
 294:         if (isset($this->__tags[$name])) {
 295:             $tagOpts = $this->__tags[$name];
 296:         } elseif (isset($this->__tags[strtolower($name)])) {
 297:             $tagOpts = $this->__tags[strtolower($name)];
 298:         } else {
 299:             return null;
 300:         }
 301:         if ($tagOpts === false) {
 302:             return false;
 303:         }
 304:         if (empty($option)) {
 305:             return $tagOpts;
 306:         }
 307:         if (isset($tagOpts[$option])) {
 308:             return $tagOpts[$option];
 309:         }
 310:         return null;
 311:     }
 312: /**
 313:  * Returns the fully-qualified XML node name, with namespace
 314:  *
 315:  * @access public
 316:  */
 317:     function name() {
 318:         if (!empty($this->namespace)) {
 319:             $_this =& XmlManager::getInstance();
 320:             if (!isset($_this->options['verifyNs']) || !$_this->options['verifyNs'] || in_array($this->namespace, array_keys($_this->namespaces))) {
 321:                 return $this->namespace . ':' . $this->name;
 322:             }
 323:         }
 324:         return $this->name;
 325:     }
 326: /**
 327:  * Sets the parent node of this XmlNode.
 328:  *
 329:  * @access public
 330:  */
 331:     function setParent(&$parent) {
 332:         if (strtolower(get_class($this)) == 'xml') {
 333:             return;
 334:         }
 335:         if (isset($this->__parent) && is_object($this->__parent)) {
 336:             if ($this->__parent->compare($parent)) {
 337:                 return;
 338:             }
 339:             foreach ($this->__parent->children as $i => $child) {
 340:                 if ($this->compare($child)) {
 341:                     array_splice($this->__parent->children, $i, 1);
 342:                     break;
 343:                 }
 344:             }
 345:         }
 346:         if ($parent == null) {
 347:             unset($this->__parent);
 348:         } else {
 349:             $parent->children[] =& $this;
 350:             $this->__parent =& $parent;
 351:         }
 352:     }
 353: /**
 354:  * Returns a copy of self.
 355:  *
 356:  * @return object Cloned instance
 357:  * @access public
 358:  */
 359:     function cloneNode() {
 360:         return clone($this);
 361:     }
 362: /**
 363:  * Compares $node to this XmlNode object
 364:  *
 365:  * @param object An XmlNode or subclass instance
 366:  * @return boolean True if the nodes match, false otherwise
 367:  * @access public
 368:  */
 369:     function compare($node) {
 370:         $keys = array(get_object_vars($this), get_object_vars($node));
 371:         return ($keys[0] === $keys[1]);
 372:     }
 373: /**
 374:  * Append given node as a child.
 375:  *
 376:  * @param object $child XmlNode with appended child
 377:  * @param array $options XML generator options for objects and arrays
 378:  * @return object A reference to the appended child node
 379:  * @access public
 380:  */
 381:     function &append(&$child, $options = array()) {
 382:         if (empty($child)) {
 383:             $return = false;
 384:             return $return;
 385:         }
 386: 
 387:         if (is_object($child)) {
 388:             if ($this->compare($child)) {
 389:                 trigger_error('Cannot append a node to itself.');
 390:                 $return = false;
 391:                 return $return;
 392:             }
 393:         } else if (is_array($child)) {
 394:             $child = Set::map($child);
 395:             if (is_array($child)) {
 396:                 if (!is_a(current($child), 'XmlNode')) {
 397:                     foreach ($child as $i => $childNode) {
 398:                         $child[$i] = $this->normalize($childNode, null, $options);
 399:                     }
 400:                 } else {
 401:                     foreach ($child as $childNode) {
 402:                         $this->append($childNode, $options);
 403:                     }
 404:                 }
 405:                 return $child;
 406:             }
 407:         } else {
 408:             $attributes = array();
 409:             if (func_num_args() >= 2) {
 410:                 $attributes = func_get_arg(1);
 411:             }
 412:             $child =& $this->createNode($child, null, $attributes);
 413:         }
 414: 
 415:         $child = $this->normalize($child, null, $options);
 416: 
 417:         if (empty($child->namespace) && !empty($this->namespace)) {
 418:             $child->namespace = $this->namespace;
 419:         }
 420: 
 421:         if (is_a($child, 'XmlNode')) {
 422:             $child->setParent($this);
 423:         }
 424: 
 425:         return $child;
 426:     }
 427: /**
 428:  * Returns first child node, or null if empty.
 429:  *
 430:  * @return object First XmlNode
 431:  * @access public
 432:  */
 433:     function &first() {
 434:         if (isset($this->children[0])) {
 435:             return $this->children[0];
 436:         } else {
 437:             $return = null;
 438:             return $return;
 439:         }
 440:     }
 441: /**
 442:  * Returns last child node, or null if empty.
 443:  *
 444:  * @return object Last XmlNode
 445:  * @access public
 446:  */
 447:     function &last() {
 448:         if (count($this->children) > 0) {
 449:             return $this->children[count($this->children) - 1];
 450:         } else {
 451:             $return = null;
 452:             return $return;
 453:         }
 454:     }
 455: /**
 456:  * Returns child node with given ID.
 457:  *
 458:  * @param string $id Name of child node
 459:  * @return object Child XmlNode
 460:  * @access public
 461:  */
 462:     function &child($id) {
 463:         $null = null;
 464: 
 465:         if (is_int($id)) {
 466:             if (isset($this->children[$id])) {
 467:                 return $this->children[$id];
 468:             } else {
 469:                 return null;
 470:             }
 471:         } elseif (is_string($id)) {
 472:             for ($i = 0; $i < count($this->children); $i++) {
 473:                 if ($this->children[$i]->name == $id) {
 474:                     return $this->children[$i];
 475:                 }
 476:             }
 477:         }
 478:         return $null;
 479:     }
 480: /**
 481:  * Gets a list of childnodes with the given tag name.
 482:  *
 483:  * @param string $name Tag name of child nodes
 484:  * @return array An array of XmlNodes with the given tag name
 485:  * @access public
 486:  */
 487:     function children($name) {
 488:         $nodes = array();
 489:         $count = count($this->children);
 490:         for ($i = 0; $i < $count; $i++) {
 491:             if ($this->children[$i]->name == $name) {
 492:                 $nodes[] =& $this->children[$i];
 493:             }
 494:         }
 495:         return $nodes;
 496:     }
 497: /**
 498:  * Gets a reference to the next child node in the list of this node's parent.
 499:  *
 500:  * @return object A reference to the XmlNode object
 501:  * @access public
 502:  */
 503:     function &nextSibling() {
 504:         $null = null;
 505:         $count = count($this->__parent->children);
 506:         for ($i = 0; $i < $count; $i++) {
 507:             if ($this->__parent->children[$i] == $this) {
 508:                 if ($i >= $count - 1 || !isset($this->__parent->children[$i + 1])) {
 509:                     return $null;
 510:                 }
 511:                 return $this->__parent->children[$i + 1];
 512:             }
 513:         }
 514:         return $null;
 515:     }
 516: /**
 517:  * Gets a reference to the previous child node in the list of this node's parent.
 518:  *
 519:  * @return object A reference to the XmlNode object
 520:  * @access public
 521:  */
 522:     function &previousSibling() {
 523:         $null = null;
 524:         $count = count($this->__parent->children);
 525:         for ($i = 0; $i < $count; $i++) {
 526:             if ($this->__parent->children[$i] == $this) {
 527:                 if ($i == 0 || !isset($this->__parent->children[$i - 1])) {
 528:                     return $null;
 529:                 }
 530:                 return $this->__parent->children[$i - 1];
 531:             }
 532:         }
 533:         return $null;
 534:     }
 535: /**
 536:  * Returns parent node.
 537:  *
 538:  * @return object Parent XmlNode
 539:  * @access public
 540:  */
 541:     function &parent() {
 542:         return $this->__parent;
 543:     }
 544: /**
 545:  * Returns the XML document to which this node belongs
 546:  *
 547:  * @return object Parent XML object
 548:  * @access public
 549:  */
 550:     function &document() {
 551:         $document =& $this;
 552:         while (true) {
 553:             if (get_class($document) == 'Xml' || $document == null) {
 554:                 break;
 555:             }
 556:             $document =& $document->parent();
 557:         }
 558:         return $document;
 559:     }
 560: /**
 561:  * Returns true if this structure has child nodes.
 562:  *
 563:  * @return bool
 564:  * @access public
 565:  */
 566:     function hasChildren() {
 567:         if (is_array($this->children) && !empty($this->children)) {
 568:             return true;
 569:         }
 570:         return false;
 571:     }
 572: /**
 573:  * Returns this XML structure as a string.
 574:  *
 575:  * @return string String representation of the XML structure.
 576:  * @access public
 577:  */
 578:     function toString($options = array(), $depth = 0) {
 579:         if (is_int($options)) {
 580:             $depth = $options;
 581:             $options = array();
 582:         }
 583:         $defaults = array('cdata' => true, 'whitespace' => false, 'convertEntities' => false, 'showEmpty' => true, 'leaveOpen' => false);
 584:         $options = array_merge($defaults, Xml::options(), $options);
 585:         $tag = !(strpos($this->name, '#') === 0);
 586:         $d = '';
 587: 
 588:         if ($tag) {
 589:             if ($options['whitespace']) {
 590:                 $d .= str_repeat("\t", $depth);
 591:             }
 592: 
 593:             $d .= '<' . $this->name();
 594:             if (!empty($this->namespaces) > 0) {
 595:                 foreach ($this->namespaces as $key => $val) {
 596:                     $val = str_replace('"', '\"', $val);
 597:                     $d .= ' xmlns:' . $key . '="' . $val . '"';
 598:                 }
 599:             }
 600: 
 601:             $parent =& $this->parent();
 602:             if ($parent->name === '#document' && !empty($parent->namespaces)) {
 603:                 foreach ($parent->namespaces as $key => $val) {
 604:                     $val = str_replace('"', '\"', $val);
 605:                     $d .= ' xmlns:' . $key . '="' . $val . '"';
 606:                 }
 607:             }
 608: 
 609:             if (is_array($this->attributes) && !empty($this->attributes)) {
 610:                 foreach ($this->attributes as $key => $val) {
 611:                     if (is_bool($val) && $val === false) {
 612:                         $val = 0;
 613:                     }
 614:                     $d .= ' ' . $key . '="' . htmlspecialchars($val, ENT_QUOTES, Configure::read('App.encoding')) . '"';
 615:                 }
 616:             }
 617:         }
 618: 
 619:         if (!$this->hasChildren() && empty($this->value) && $this->value !== 0 && $tag) {
 620:             if (!$options['leaveOpen']) {
 621:                 $d .= ' />';
 622:             }
 623:             if ($options['whitespace']) {
 624:                 $d .= "\n";
 625:             }
 626:         } elseif ($tag || $this->hasChildren()) {
 627:             if ($tag) {
 628:                 $d .= '>';
 629:             }
 630:             if ($this->hasChildren()) {
 631:                 if ($options['whitespace']) {
 632:                     $d .= "\n";
 633:                 }
 634:                 $count = count($this->children);
 635:                 $cDepth = $depth + 1;
 636:                 for ($i = 0; $i < $count; $i++) {
 637:                     $d .= $this->children[$i]->toString($options, $cDepth);
 638:                 }
 639:                 if ($tag) {
 640:                     if ($options['whitespace'] && $tag) {
 641:                         $d .= str_repeat("\t", $depth);
 642:                     }
 643:                     if (!$options['leaveOpen']) {
 644:                         $d .= '</' . $this->name() . '>';
 645:                     }
 646:                     if ($options['whitespace']) {
 647:                         $d .= "\n";
 648:                     }
 649:                 }
 650:             }
 651:         }
 652:         return $d;
 653:     }
 654: /**
 655:  * Return array representation of current object.
 656:  *
 657:  * @param boolean $camelize true will camelize child nodes, false will not alter node names
 658:  * @return array Array representation
 659:  * @access public
 660:  */
 661:     function toArray($camelize = true) {
 662:         $out = $this->attributes;
 663: 
 664:         foreach ($this->children as $child) {
 665:             $key = $camelize ? Inflector::camelize($child->name) : $child->name;
 666: 
 667:             $leaf = false;
 668:             if (is_a($child, 'XmlTextNode')) {
 669:                 $out['value'] = $child->value;
 670:                 continue;
 671:             } elseif (isset($child->children[0]) && is_a($child->children[0], 'XmlTextNode')) {
 672:                 $value = $child->children[0]->value;
 673:                 if ($child->attributes) {
 674:                     $value = array_merge(array('value' => $value), $child->attributes);
 675:                 }
 676:                 if (count($child->children) == 1) {
 677:                     $leaf = true;
 678:                 }
 679:             } elseif (count($child->children) === 0 && $child->value == '') {
 680:                 $value = $child->attributes;
 681:                 if (empty($value)) {
 682:                     $leaf = true;
 683:                 }
 684:             } else {
 685:                 $value = $child->toArray($camelize);
 686:             }
 687: 
 688:             if (isset($out[$key])) {
 689:                 if(!isset($out[$key][0]) || !is_array($out[$key]) || !is_int(key($out[$key]))) {
 690:                     $out[$key] = array($out[$key]);
 691:                 } 
 692:                 $out[$key][] = $value;
 693:             } elseif (isset($out[$child->name])) {
 694:                 $t = $out[$child->name];
 695:                 unset($out[$child->name]);
 696:                 $out[$key] = array($t);
 697:                 $out[$key][] = $value;
 698:             } elseif ($leaf) {
 699:                 $out[$child->name] = $value;
 700:             } else {
 701:                 $out[$key] = $value;
 702:             }
 703:         }
 704:         return $out;
 705:     }
 706: /**
 707:  * Returns data from toString when this object is converted to a string.
 708:  *
 709:  * @return string String representation of this structure.
 710:  * @access private
 711:  */
 712:     function __toString() {
 713:         return $this->toString();
 714:     }
 715: /**
 716:  * Debug method. Deletes the parent. Also deletes this node's children,
 717:  * if given the $recursive parameter.
 718:  *
 719:  * @param boolean $recursive Recursively delete elements.
 720:  * @access protected
 721:  */
 722:     function _killParent($recursive = true) {
 723:         unset($this->__parent, $this->_log);
 724:         if ($recursive && $this->hasChildren()) {
 725:             for ($i = 0; $i < count($this->children); $i++) {
 726:                 $this->children[$i]->_killParent(true);
 727:             }
 728:         }
 729:     }
 730: }
 731: 
 732: /**
 733:  * Main XML class.
 734:  *
 735:  * Parses and stores XML data, representing the root of an XML document
 736:  *
 737:  * @package       cake
 738:  * @subpackage    cake.cake.libs
 739:  * @since         CakePHP v .0.10.3.1400
 740:  */
 741: class Xml extends XmlNode {
 742: 
 743: /**
 744:  * Resource handle to XML parser.
 745:  *
 746:  * @var resource
 747:  * @access private
 748:  */
 749:     var $__parser;
 750: /**
 751:  * File handle to XML indata file.
 752:  *
 753:  * @var resource
 754:  * @access private
 755:  */
 756:     var $__file;
 757: /**
 758:  * Raw XML string data (for loading purposes)
 759:  *
 760:  * @var string
 761:  * @access private
 762:  */
 763:     var $__rawData = null;
 764: 
 765: /**
 766:  * XML document header
 767:  *
 768:  * @var string
 769:  * @access private
 770:  */
 771:     var $__header = null;
 772: 
 773: /**
 774:  * Default array keys/object properties to use as tag names when converting objects or array
 775:  * structures to XML. Set by passing $options['tags'] to this object's constructor.
 776:  *
 777:  * @var array
 778:  * @access private
 779:  */
 780:     var $__tags = array();
 781: 
 782: /**
 783:  * XML document version
 784:  *
 785:  * @var string
 786:  * @access private
 787:  */
 788:     var $version = '1.0';
 789: 
 790: /**
 791:  * XML document encoding
 792:  *
 793:  * @var string
 794:  * @access private
 795:  */
 796:     var $encoding = 'UTF-8';
 797: 
 798: /**
 799:  * Constructor.  Sets up the XML parser with options, gives it this object as
 800:  * its XML object, and sets some variables.
 801:  *
 802:  * ### Options
 803:  * - 'root': The name of the root element, defaults to '#document'
 804:  * - 'version': The XML version, defaults to '1.0'
 805:  * - 'encoding': Document encoding, defaults to 'UTF-8'
 806:  * - 'namespaces': An array of namespaces (as strings) used in this document
 807:  * - 'format': Specifies the format this document converts to when parsed or
 808:  *    rendered out as text, either 'attributes' or 'tags', defaults to 'attributes'
 809:  * - 'tags': An array specifying any tag-specific formatting options, indexed
 810:  *    by tag name.  See XmlNode::normalize().
 811:  * @param mixed $input The content with which this XML document should be initialized.  Can be a
 812:  *    string, array or object.  If a string is specified, it may be a literal XML
 813:  *    document, or a URL or file path to read from.
 814:  * @param array $options Options to set up with, for valid options see above:
 815:  * @see XmlNode::normalize()
 816:  */
 817:     function __construct($input = null, $options = array()) {
 818:         $defaults = array(
 819:             'root' => '#document', 'tags' => array(), 'namespaces' => array(),
 820:             'version' => '1.0', 'encoding' => 'UTF-8', 'format' => 'attributes'
 821:         );
 822:         $options = array_merge($defaults, Xml::options(), $options);
 823: 
 824:         foreach (array('version', 'encoding', 'namespaces') as $key) {
 825:             $this->{$key} = $options[$key];
 826:         }
 827:         $this->__tags = $options['tags'];
 828:         parent::__construct('#document');
 829: 
 830:         if ($options['root'] !== '#document') {
 831:             $Root =& $this->createNode($options['root']);
 832:         } else {
 833:             $Root =& $this;
 834:         }
 835: 
 836:         if (!empty($input)) {
 837:             if (is_string($input)) {
 838:                 $Root->load($input);
 839:             } elseif (is_array($input) || is_object($input)) {
 840:                 $Root->append($input, $options);
 841:             }
 842:         }
 843:     }
 844: /**
 845:  * Initialize XML object from a given XML string. Returns false on error.
 846:  *
 847:  * @param string $input XML string, a path to a file, or an HTTP resource to load
 848:  * @return boolean Success
 849:  * @access public
 850:  */
 851:     function load($input) {
 852:         if (!is_string($input)) {
 853:             return false;
 854:         }
 855:         $this->__rawData = null;
 856:         $this->__header = null;
 857: 
 858:         if (strstr($input, "<")) {
 859:             $this->__rawData = $input;
 860:         } elseif (strpos($input, 'http://') === 0 || strpos($input, 'https://') === 0) {
 861:             App::import('Core', 'HttpSocket');
 862:             $socket = new HttpSocket();
 863:             $this->__rawData = $socket->get($input);
 864:         } elseif (file_exists($input)) {
 865:             $this->__rawData = file_get_contents($input);
 866:         } else {
 867:             trigger_error('XML cannot be read');
 868:             return false;
 869:         }
 870:         return $this->parse();
 871:     }
 872: /**
 873:  * Parses and creates XML nodes from the __rawData property.
 874:  *
 875:  * @return boolean Success
 876:  * @access public
 877:  * @see Xml::load()
 878:  * @todo figure out how to link attributes and namespaces
 879:  */
 880:     function parse() {
 881:         $this->__initParser();
 882:         $this->__rawData = trim($this->__rawData);
 883:         $this->__header = trim(str_replace(
 884:             array('<' . '?', '?' . '>'),
 885:             array('', ''),
 886:             substr($this->__rawData, 0, strpos($this->__rawData, '?' . '>'))
 887:         ));
 888: 
 889:         xml_parse_into_struct($this->__parser, $this->__rawData, $vals);
 890:         $xml =& $this;
 891:         $count = count($vals);
 892: 
 893:         for ($i = 0; $i < $count; $i++) {
 894:             $data = $vals[$i];
 895:             $data += array('tag' => null, 'value' => null, 'attributes' => array());
 896:             switch ($data['type']) {
 897:                 case "open" :
 898:                     $xml =& $xml->createElement($data['tag'], $data['value'], $data['attributes']);
 899:                 break;
 900:                 case "close" :
 901:                     $xml =& $xml->parent();
 902:                 break;
 903:                 case "complete" :
 904:                     $xml->createElement($data['tag'], $data['value'], $data['attributes']);
 905:                 break;
 906:                 case 'cdata':
 907:                     $xml->createTextNode($data['value']);
 908:                 break;
 909:             }
 910:         }
 911:         xml_parser_free($this->__parser);
 912:         $this->__parser = null;
 913:         return true;
 914:     }
 915: /**
 916:  * Initializes the XML parser resource
 917:  *
 918:  * @return void
 919:  * @access private
 920:  */
 921:     function __initParser() {
 922:         if (empty($this->__parser)) {
 923:             $this->__parser = xml_parser_create();
 924:             xml_set_object($this->__parser, $this);
 925:             xml_parser_set_option($this->__parser, XML_OPTION_CASE_FOLDING, 0);
 926:             xml_parser_set_option($this->__parser, XML_OPTION_SKIP_WHITE, 1);
 927:         }
 928:     }
 929: /**
 930:  * Returns a string representation of the XML object
 931:  *
 932:  * @param mixed $options If boolean: whether to include the XML header with the document
 933:  *        (defaults to true); if an array, overrides the default XML generation options
 934:  * @return string XML data
 935:  * @access public
 936:  * @deprecated
 937:  * @see Xml::toString()
 938:  */
 939:     function compose($options = array()) {
 940:         return $this->toString($options);
 941:     }
 942: /**
 943:  * If debug mode is on, this method echoes an error message.
 944:  *
 945:  * @param string $msg Error message
 946:  * @param integer $code Error code
 947:  * @param integer $line Line in file
 948:  * @access public
 949:  */
 950:     function error($msg, $code = 0, $line = 0) {
 951:         if (Configure::read('debug')) {
 952:             echo $msg . " " . $code . " " . $line;
 953:         }
 954:     }
 955: /**
 956:  * Returns a string with a textual description of the error code, or FALSE if no description was found.
 957:  *
 958:  * @param integer $code Error code
 959:  * @return string Error message
 960:  * @access public
 961:  */
 962:     function getError($code) {
 963:         $r = @xml_error_string($code);
 964:         return $r;
 965:     }
 966: 
 967: // Overridden functions from superclass
 968: 
 969: /**
 970:  * Get next element. NOT implemented.
 971:  *
 972:  * @return object
 973:  * @access public
 974:  */
 975:     function &next() {
 976:         $return = null;
 977:         return $return;
 978:     }
 979: /**
 980:  * Get previous element. NOT implemented.
 981:  *
 982:  * @return object
 983:  * @access public
 984:  */
 985:     function &previous() {
 986:         $return = null;
 987:         return $return;
 988:     }
 989: /**
 990:  * Get parent element. NOT implemented.
 991:  *
 992:  * @return object
 993:  * @access public
 994:  */
 995:     function &parent() {
 996:         $return = null;
 997:         return $return;
 998:     }
 999: /**
1000:  * Adds a namespace to the current document
1001:  *
1002:  * @param string $prefix The namespace prefix
1003:  * @param string $url The namespace DTD URL
1004:  * @return void
1005:  */
1006:     function addNamespace($prefix, $url) {
1007:         if ($count = count($this->children)) {
1008:             for ($i = 0; $i < $count; $i++) {
1009:                 $this->children[$i]->addNamespace($prefix, $url);
1010:             }
1011:             return true;
1012:         }
1013:         return parent::addNamespace($prefix, $url);
1014:     }
1015: /**
1016:  * Removes a namespace to the current document
1017:  *
1018:  * @param string $prefix The namespace prefix
1019:  * @return void
1020:  */
1021:     function removeNamespace($prefix) {
1022:         if ($count = count($this->children)) {
1023:             for ($i = 0; $i < $count; $i++) {
1024:                 $this->children[$i]->removeNamespace($prefix);
1025:             }
1026:             return true;
1027:         }
1028:         return parent::removeNamespace($prefix);
1029:     }
1030: /**
1031:  * Return string representation of current object.
1032:  *
1033:  * @return string String representation
1034:  * @access public
1035:  */
1036:     function toString($options = array()) {
1037:         if (is_bool($options)) {
1038:             $options = array('header' => $options);
1039:         }
1040: 
1041:         $defaults = array('header' => false, 'encoding' => $this->encoding);
1042:         $options = array_merge($defaults, Xml::options(), $options);
1043:         $data = parent::toString($options, 0);
1044: 
1045:         if ($options['header']) {
1046:             if (!empty($this->__header)) {
1047:                 return $this->header($this->__header)  . "\n" . $data;
1048:             }
1049:             return $this->header()  . "\n" . $data;
1050:         }
1051: 
1052:         return $data;
1053:     }
1054: /**
1055:  * Return a header used on the first line of the xml file
1056:  *
1057:  * @param  mixed  $attrib attributes of the header element
1058:  * @return string formated header
1059:  */
1060:     function header($attrib = array()) {
1061:         $header = 'xml';
1062:         if (is_string($attrib)) {
1063:             $header = $attrib;
1064:         } else {
1065: 
1066:             $attrib = array_merge(array('version' => $this->version, 'encoding' => $this->encoding), $attrib);
1067:             foreach ($attrib as $key=>$val) {
1068:                 $header .= ' ' . $key . '="' . $val . '"';
1069:             }
1070:         }
1071:         return '<' . '?' . $header . ' ?' . '>';
1072:     }
1073: 
1074: /**
1075:  * Destructor, used to free resources.
1076:  *
1077:  * @access private
1078:  */
1079:     function __destruct() {
1080:         $this->_killParent(true);
1081:     }
1082: /**
1083:  * Adds a namespace to any XML documents generated or parsed
1084:  *
1085:  * @param  string  $name The namespace name
1086:  * @param  string  $url  The namespace URI; can be empty if in the default namespace map
1087:  * @return boolean False if no URL is specified, and the namespace does not exist
1088:  *                 default namespace map, otherwise true
1089:  * @access public
1090:  * @static
1091:  */
1092:     function addGlobalNs($name, $url = null) {
1093:         $_this =& XmlManager::getInstance();
1094:         if ($ns = Xml::resolveNamespace($name, $url)) {
1095:             $_this->namespaces = array_merge($_this->namespaces, $ns);
1096:             return $ns;
1097:         }
1098:         return false;
1099:     }
1100: /**
1101:  * Resolves current namespace
1102:  *
1103:  * @param  string  $name
1104:  * @param  string  $url
1105:  * @return array
1106:  */
1107:     function resolveNamespace($name, $url) {
1108:         $_this =& XmlManager::getInstance();
1109:         if ($url == null && isset($_this->defaultNamespaceMap[$name])) {
1110:             $url = $_this->defaultNamespaceMap[$name];
1111:         } elseif ($url == null) {
1112:             return false;
1113:         }
1114: 
1115:         if (!strpos($url, '://') && isset($_this->defaultNamespaceMap[$name])) {
1116:             $_url = $_this->defaultNamespaceMap[$name];
1117:             $name = $url;
1118:             $url = $_url;
1119:         }
1120:         return array($name => $url);
1121:     }
1122: /**
1123:  * Alias to Xml::addNs
1124:  *
1125:  * @access public
1126:  * @static
1127:  */
1128:     function addGlobalNamespace($name, $url = null) {
1129:         return Xml::addGlobalNs($name, $url);
1130:     }
1131: /**
1132:  * Removes a namespace added in addNs()
1133:  *
1134:  * @param  string  $name The namespace name or URI
1135:  * @access public
1136:  * @static
1137:  */
1138:     function removeGlobalNs($name) {
1139:         $_this =& XmlManager::getInstance();
1140:         if (isset($_this->namespaces[$name])) {
1141:             unset($_this->namespaces[$name]);
1142:             unset($this->namespaces[$name]);
1143:             return true;
1144:         } elseif (in_array($name, $_this->namespaces)) {
1145:             $keys = array_keys($_this->namespaces);
1146:             $count = count($keys);
1147:             for ($i = 0; $i < $count; $i++) {
1148:                 if ($_this->namespaces[$keys[$i]] == $name) {
1149:                     unset($_this->namespaces[$keys[$i]]);
1150:                     unset($this->namespaces[$keys[$i]]);
1151:                     return true;
1152:                 }
1153:             }
1154:         }
1155:         return false;
1156:     }
1157: /**
1158:  * Alias to Xml::removeNs
1159:  *
1160:  * @access public
1161:  * @static
1162:  */
1163:     function removeGlobalNamespace($name) {
1164:         return Xml::removeGlobalNs($name);
1165:     }
1166: /**
1167:  * Sets/gets global XML options
1168:  *
1169:  * @param array $options
1170:  * @return array
1171:  * @access public
1172:  * @static
1173:  */
1174:     function options($options = array()) {
1175:         $_this =& XmlManager::getInstance();
1176:         $_this->options = array_merge($_this->options, $options);
1177:         return $_this->options;
1178:     }
1179: }
1180: /**
1181:  * The XML Element
1182:  *
1183:  */
1184: class XmlElement extends XmlNode {
1185: /**
1186:  * Construct an Xml element
1187:  *
1188:  * @param  string  $name name of the node
1189:  * @param  string  $value value of the node
1190:  * @param  array  $attributes
1191:  * @param  string  $namespace
1192:  * @return string A copy of $data in XML format
1193:  */
1194:     function __construct($name = null, $value = null, $attributes = array(), $namespace = false) {
1195:         parent::__construct($name, $value, $namespace);
1196:         $this->addAttribute($attributes);
1197:     }
1198: /**
1199:  * Get all the attributes for this element
1200:  *
1201:  * @return array
1202:  */
1203:     function attributes() {
1204:         return $this->attributes;
1205:     }
1206: /**
1207:  * Add attributes to this element
1208:  *
1209:  * @param  string  $name name of the node
1210:  * @param  string  $value value of the node
1211:  * @return boolean
1212:  */
1213:     function addAttribute($name, $val = null) {
1214:         if (is_object($name)) {
1215:             $name = get_object_vars($name);
1216:         }
1217:         if (is_array($name)) {
1218:             foreach ($name as $key => $val) {
1219:                 $this->addAttribute($key, $val);
1220:             }
1221:             return true;
1222:         }
1223:         if (is_numeric($name)) {
1224:             $name = $val;
1225:             $val = null;
1226:         }
1227:         if (!empty($name)) {
1228:             if (strpos($name, 'xmlns') === 0) {
1229:                 if ($name == 'xmlns') {
1230:                     $this->namespace = $val;
1231:                 } else {
1232:                     list($pre, $prefix) = explode(':', $name);
1233:                     $this->addNamespace($prefix, $val);
1234:                     return true;
1235:                 }
1236:             }
1237:             $this->attributes[$name] = $val;
1238:             return true;
1239:         }
1240:         return false;
1241:     }
1242: /**
1243:  * Remove attributes to this element
1244:  *
1245:  * @param  string  $name name of the node
1246:  * @return boolean
1247:  */
1248:     function removeAttribute($attr) {
1249:         if (array_key_exists($attr, $this->attributes)) {
1250:             unset($this->attributes[$attr]);
1251:             return true;
1252:         }
1253:         return false;
1254:     }
1255: }
1256: 
1257: /**
1258:  * XML text or CDATA node
1259:  *
1260:  * Stores XML text data according to the encoding of the parent document
1261:  *
1262:  * @package       cake
1263:  * @subpackage    cake.cake.libs
1264:  * @since         CakePHP v .1.2.6000
1265:  */
1266: class XmlTextNode extends XmlNode {
1267: /**
1268:  * Harcoded XML node name, represents this object as a text node
1269:  *
1270:  * @var string
1271:  */
1272:     var $name = '#text';
1273: /**
1274:  * The text/data value which this node contains
1275:  *
1276:  * @var string
1277:  */
1278:     var $value = null;
1279: /**
1280:  * Construct text node with the given parent object and data
1281:  *
1282:  * @param object $parent Parent XmlNode/XmlElement object
1283:  * @param mixed $value Node value
1284:  */
1285:     function __construct($value = null) {
1286:         $this->value = $value;
1287:     }
1288: /**
1289:  * Looks for child nodes in this element
1290:  *
1291:  * @return boolean False - not supported
1292:  */
1293:     function hasChildren() {
1294:         return false;
1295:     }
1296: /**
1297:  * Append an XML node: XmlTextNode does not support this operation
1298:  *
1299:  * @return boolean False - not supported
1300:  * @todo make convertEntities work without mb support, convert entities to number entities
1301:  */
1302:     function append() {
1303:         return false;
1304:     }
1305: /**
1306:  * Return string representation of current text node object.
1307:  *
1308:  * @return string String representation
1309:  * @access public
1310:  */
1311:     function toString($options = array(), $depth = 0) {
1312:         if (is_int($options)) {
1313:             $depth = $options;
1314:             $options = array();
1315:         }
1316: 
1317:         $defaults = array('cdata' => true, 'whitespace' => false, 'convertEntities' => false);
1318:         $options = array_merge($defaults, Xml::options(), $options);
1319:         $val = $this->value;
1320: 
1321:         if ($options['convertEntities'] && function_exists('mb_convert_encoding')) {
1322:             $val = mb_convert_encoding($val,'UTF-8', 'HTML-ENTITIES');
1323:         }
1324: 
1325:         if ($options['cdata'] === true && !is_numeric($val)) {
1326:             $val = '<![CDATA[' . $val . ']]>';
1327:         }
1328: 
1329:         if ($options['whitespace']) {
1330:             return str_repeat("\t", $depth) . $val . "\n";
1331:         }
1332:         return $val;
1333:     }
1334: }
1335: /**
1336:  * Manages application-wide namespaces and XML parsing/generation settings.
1337:  * Private class, used exclusively within scope of XML class.
1338:  *
1339:  * @access private
1340:  */
1341: class XmlManager {
1342: 
1343: /**
1344:  * Global XML namespaces.  Used in all XML documents processed by this application
1345:  *
1346:  * @var array
1347:  * @access public
1348:  */
1349:     var $namespaces = array();
1350: /**
1351:  * Global XML document parsing/generation settings.
1352:  *
1353:  * @var array
1354:  * @access public
1355:  */
1356:     var $options = array();
1357: /**
1358:  * Map of common namespace URIs
1359:  *
1360:  * @access private
1361:  * @var array
1362:  */
1363:     var $defaultNamespaceMap = array(
1364:         'dc'     => 'http://purl.org/dc/elements/1.1/',                 // Dublin Core
1365:         'dct'    => 'http://purl.org/dc/terms/',                        // Dublin Core Terms
1366:         'g'         => 'http://base.google.com/ns/1.0',                 // Google Base
1367:         'rc'        => 'http://purl.org/rss/1.0/modules/content/',      // RSS 1.0 Content Module
1368:         'wf'        => 'http://wellformedweb.org/CommentAPI/',          // Well-Formed Web Comment API
1369:         'fb'        => 'http://rssnamespace.org/feedburner/ext/1.0',    // FeedBurner extensions
1370:         'lj'        => 'http://www.livejournal.org/rss/lj/1.0/',        // Live Journal
1371:         'itunes'    => 'http://www.itunes.com/dtds/podcast-1.0.dtd',    // iTunes
1372:         'xhtml'     => 'http://www.w3.org/1999/xhtml',                  // XHTML,
1373:         'atom'      => 'http://www.w3.org/2005/Atom'                    // Atom
1374:     );
1375: /**
1376:  * Returns a reference to the global XML object that manages app-wide XML settings
1377:  *
1378:  * @return object
1379:  * @access public
1380:  */
1381:     function &getInstance() {
1382:         static $instance = array();
1383: 
1384:         if (!$instance) {
1385:             $instance[0] =& new XmlManager();
1386:         }
1387:         return $instance[0];
1388:     }
1389: }
1390: ?>
1391: 
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