CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.8 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.8
      • 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

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • ConnectionManager
  • ConnectionRegistry
  • FactoryLocator
  • Paginator
  • QueryCacher
  • ResultSetDecorator
  • RulesChecker

Interfaces

  • ConnectionInterface
  • EntityInterface
  • FixtureInterface
  • InvalidPropertyInterface
  • PaginatorInterface
  • QueryInterface
  • RepositoryInterface
  • ResultSetInterface
  • SchemaInterface
  • TableSchemaInterface

Traits

  • EntityTrait
  • ModelAwareTrait
  • QueryTrait
  • RulesAwareTrait
   1: <?php
   2: /**
   3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
   4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
   5:  *
   6:  * Licensed under The MIT License
   7:  * For full copyright and license information, please see the LICENSE.txt
   8:  * Redistributions of files must retain the above copyright notice.
   9:  *
  10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11:  * @link          https://cakephp.org CakePHP(tm) Project
  12:  * @since         3.0.0
  13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
  14:  */
  15: namespace Cake\Datasource;
  16: 
  17: use Cake\Collection\Collection;
  18: use Cake\Utility\Hash;
  19: use Cake\Utility\Inflector;
  20: use InvalidArgumentException;
  21: use Traversable;
  22: 
  23: /**
  24:  * An entity represents a single result row from a repository. It exposes the
  25:  * methods for retrieving and storing properties associated in this row.
  26:  */
  27: trait EntityTrait
  28: {
  29:     /**
  30:      * Holds all properties and their values for this entity
  31:      *
  32:      * @var array
  33:      */
  34:     protected $_properties = [];
  35: 
  36:     /**
  37:      * Holds all properties that have been changed and their original values for this entity
  38:      *
  39:      * @var array
  40:      */
  41:     protected $_original = [];
  42: 
  43:     /**
  44:      * List of property names that should **not** be included in JSON or Array
  45:      * representations of this Entity.
  46:      *
  47:      * @var array
  48:      */
  49:     protected $_hidden = [];
  50: 
  51:     /**
  52:      * List of computed or virtual fields that **should** be included in JSON or array
  53:      * representations of this Entity. If a field is present in both _hidden and _virtual
  54:      * the field will **not** be in the array/json versions of the entity.
  55:      *
  56:      * @var array
  57:      */
  58:     protected $_virtual = [];
  59: 
  60:     /**
  61:      * Holds the name of the class for the instance object
  62:      *
  63:      * @var string
  64:      *
  65:      * @deprecated 3.2 This field is no longer being used
  66:      */
  67:     protected $_className;
  68: 
  69:     /**
  70:      * Holds a list of the properties that were modified or added after this object
  71:      * was originally created.
  72:      *
  73:      * @var array
  74:      */
  75:     protected $_dirty = [];
  76: 
  77:     /**
  78:      * Holds a cached list of getters/setters per class
  79:      *
  80:      * @var array
  81:      */
  82:     protected static $_accessors = [];
  83: 
  84:     /**
  85:      * Indicates whether or not this entity is yet to be persisted.
  86:      * Entities default to assuming they are new. You can use Table::persisted()
  87:      * to set the new flag on an entity based on records in the database.
  88:      *
  89:      * @var bool
  90:      */
  91:     protected $_new = true;
  92: 
  93:     /**
  94:      * List of errors per field as stored in this object
  95:      *
  96:      * @var array
  97:      */
  98:     protected $_errors = [];
  99: 
 100:     /**
 101:      * List of invalid fields and their data for errors upon validation/patching
 102:      *
 103:      * @var array
 104:      */
 105:     protected $_invalid = [];
 106: 
 107:     /**
 108:      * Map of properties in this entity that can be safely assigned, each
 109:      * property name points to a boolean indicating its status. An empty array
 110:      * means no properties are accessible
 111:      *
 112:      * The special property '\*' can also be mapped, meaning that any other property
 113:      * not defined in the map will take its value. For example, `'\*' => true`
 114:      * means that any property not defined in the map will be accessible by default
 115:      *
 116:      * @var array
 117:      */
 118:     protected $_accessible = ['*' => true];
 119: 
 120:     /**
 121:      * The alias of the repository this entity came from
 122:      *
 123:      * @var string
 124:      */
 125:     protected $_registryAlias;
 126: 
 127:     /**
 128:      * Magic getter to access properties that have been set in this entity
 129:      *
 130:      * @param string $property Name of the property to access
 131:      * @return mixed
 132:      */
 133:     public function &__get($property)
 134:     {
 135:         return $this->get($property);
 136:     }
 137: 
 138:     /**
 139:      * Magic setter to add or edit a property in this entity
 140:      *
 141:      * @param string $property The name of the property to set
 142:      * @param mixed $value The value to set to the property
 143:      * @return void
 144:      */
 145:     public function __set($property, $value)
 146:     {
 147:         $this->set($property, $value);
 148:     }
 149: 
 150:     /**
 151:      * Returns whether this entity contains a property named $property
 152:      * regardless of if it is empty.
 153:      *
 154:      * @param string $property The property to check.
 155:      * @return bool
 156:      * @see \Cake\ORM\Entity::has()
 157:      */
 158:     public function __isset($property)
 159:     {
 160:         return $this->has($property);
 161:     }
 162: 
 163:     /**
 164:      * Removes a property from this entity
 165:      *
 166:      * @param string $property The property to unset
 167:      * @return void
 168:      */
 169:     public function __unset($property)
 170:     {
 171:         $this->unsetProperty($property);
 172:     }
 173: 
 174:     /**
 175:      * Sets a single property inside this entity.
 176:      *
 177:      * ### Example:
 178:      *
 179:      * ```
 180:      * $entity->set('name', 'Andrew');
 181:      * ```
 182:      *
 183:      * It is also possible to mass-assign multiple properties to this entity
 184:      * with one call by passing a hashed array as properties in the form of
 185:      * property => value pairs
 186:      *
 187:      * ### Example:
 188:      *
 189:      * ```
 190:      * $entity->set(['name' => 'andrew', 'id' => 1]);
 191:      * echo $entity->name // prints andrew
 192:      * echo $entity->id // prints 1
 193:      * ```
 194:      *
 195:      * Some times it is handy to bypass setter functions in this entity when assigning
 196:      * properties. You can achieve this by disabling the `setter` option using the
 197:      * `$options` parameter:
 198:      *
 199:      * ```
 200:      * $entity->set('name', 'Andrew', ['setter' => false]);
 201:      * $entity->set(['name' => 'Andrew', 'id' => 1], ['setter' => false]);
 202:      * ```
 203:      *
 204:      * Mass assignment should be treated carefully when accepting user input, by default
 205:      * entities will guard all fields when properties are assigned in bulk. You can disable
 206:      * the guarding for a single set call with the `guard` option:
 207:      *
 208:      * ```
 209:      * $entity->set(['name' => 'Andrew', 'id' => 1], ['guard' => true]);
 210:      * ```
 211:      *
 212:      * You do not need to use the guard option when assigning properties individually:
 213:      *
 214:      * ```
 215:      * // No need to use the guard option.
 216:      * $entity->set('name', 'Andrew');
 217:      * ```
 218:      *
 219:      * @param string|array $property the name of property to set or a list of
 220:      * properties with their respective values
 221:      * @param mixed $value The value to set to the property or an array if the
 222:      * first argument is also an array, in which case will be treated as $options
 223:      * @param array $options options to be used for setting the property. Allowed option
 224:      * keys are `setter` and `guard`
 225:      * @return $this
 226:      * @throws \InvalidArgumentException
 227:      */
 228:     public function set($property, $value = null, array $options = [])
 229:     {
 230:         if (is_string($property) && $property !== '') {
 231:             $guard = false;
 232:             $property = [$property => $value];
 233:         } else {
 234:             $guard = true;
 235:             $options = (array)$value;
 236:         }
 237: 
 238:         if (!is_array($property)) {
 239:             throw new InvalidArgumentException('Cannot set an empty property');
 240:         }
 241:         $options += ['setter' => true, 'guard' => $guard];
 242: 
 243:         foreach ($property as $p => $value) {
 244:             if ($options['guard'] === true && !$this->isAccessible($p)) {
 245:                 continue;
 246:             }
 247: 
 248:             $this->setDirty($p, true);
 249: 
 250:             if (!array_key_exists($p, $this->_original) &&
 251:                 array_key_exists($p, $this->_properties) &&
 252:                 $this->_properties[$p] !== $value
 253:             ) {
 254:                 $this->_original[$p] = $this->_properties[$p];
 255:             }
 256: 
 257:             if (!$options['setter']) {
 258:                 $this->_properties[$p] = $value;
 259:                 continue;
 260:             }
 261: 
 262:             $setter = static::_accessor($p, 'set');
 263:             if ($setter) {
 264:                 $value = $this->{$setter}($value);
 265:             }
 266:             $this->_properties[$p] = $value;
 267:         }
 268: 
 269:         return $this;
 270:     }
 271: 
 272:     /**
 273:      * Returns the value of a property by name
 274:      *
 275:      * @param string $property the name of the property to retrieve
 276:      * @return mixed
 277:      * @throws \InvalidArgumentException if an empty property name is passed
 278:      */
 279:     public function &get($property)
 280:     {
 281:         if (!strlen((string)$property)) {
 282:             throw new InvalidArgumentException('Cannot get an empty property');
 283:         }
 284: 
 285:         $value = null;
 286:         $method = static::_accessor($property, 'get');
 287: 
 288:         if (isset($this->_properties[$property])) {
 289:             $value =& $this->_properties[$property];
 290:         }
 291: 
 292:         if ($method) {
 293:             $result = $this->{$method}($value);
 294: 
 295:             return $result;
 296:         }
 297: 
 298:         return $value;
 299:     }
 300: 
 301:     /**
 302:      * Returns the value of an original property by name
 303:      *
 304:      * @param string $property the name of the property for which original value is retrieved.
 305:      * @return mixed
 306:      * @throws \InvalidArgumentException if an empty property name is passed.
 307:      */
 308:     public function getOriginal($property)
 309:     {
 310:         if (!strlen((string)$property)) {
 311:             throw new InvalidArgumentException('Cannot get an empty property');
 312:         }
 313:         if (array_key_exists($property, $this->_original)) {
 314:             return $this->_original[$property];
 315:         }
 316: 
 317:         return $this->get($property);
 318:     }
 319: 
 320:     /**
 321:      * Gets all original values of the entity.
 322:      *
 323:      * @return array
 324:      */
 325:     public function getOriginalValues()
 326:     {
 327:         $originals = $this->_original;
 328:         $originalKeys = array_keys($originals);
 329:         foreach ($this->_properties as $key => $value) {
 330:             if (!in_array($key, $originalKeys)) {
 331:                 $originals[$key] = $value;
 332:             }
 333:         }
 334: 
 335:         return $originals;
 336:     }
 337: 
 338:     /**
 339:      * Returns whether this entity contains a property named $property
 340:      * that contains a non-null value.
 341:      *
 342:      * ### Example:
 343:      *
 344:      * ```
 345:      * $entity = new Entity(['id' => 1, 'name' => null]);
 346:      * $entity->has('id'); // true
 347:      * $entity->has('name'); // false
 348:      * $entity->has('last_name'); // false
 349:      * ```
 350:      *
 351:      * You can check multiple properties by passing an array:
 352:      *
 353:      * ```
 354:      * $entity->has(['name', 'last_name']);
 355:      * ```
 356:      *
 357:      * All properties must not be null to get a truthy result.
 358:      *
 359:      * When checking multiple properties. All properties must not be null
 360:      * in order for true to be returned.
 361:      *
 362:      * @param string|array $property The property or properties to check.
 363:      * @return bool
 364:      */
 365:     public function has($property)
 366:     {
 367:         foreach ((array)$property as $prop) {
 368:             if ($this->get($prop) === null) {
 369:                 return false;
 370:             }
 371:         }
 372: 
 373:         return true;
 374:     }
 375: 
 376:     /**
 377:      * Checks that a property is empty
 378:      *
 379:      * This is not working like the PHP `empty()` function. The method will
 380:      * return true for:
 381:      *
 382:      * - `''` (empty string)
 383:      * - `null`
 384:      * - `[]`
 385:      *
 386:      * and false in all other cases.
 387:      *
 388:      * @param string $property The property to check.
 389:      * @return bool
 390:      */
 391:     public function isEmpty($property)
 392:     {
 393:         $value = $this->get($property);
 394:         if ($value === null
 395:             || (is_array($value) && empty($value)
 396:             || (is_string($value) && empty($value)))
 397:         ) {
 398:             return true;
 399:         }
 400: 
 401:         return false;
 402:     }
 403: 
 404:     /**
 405:      * Checks tha a property has a value.
 406:      *
 407:      * This method will return true for
 408:      *
 409:      * - Non-empty strings
 410:      * - Non-empty arrays
 411:      * - Any object
 412:      * - Integer, even `0`
 413:      * - Float, even 0.0
 414:      *
 415:      * and false in all other cases.
 416:      *
 417:      * @param string $property The property to check.
 418:      * @return bool
 419:      */
 420:     public function hasValue($property)
 421:     {
 422:         return !$this->isEmpty($property);
 423:     }
 424: 
 425:     /**
 426:      * Removes a property or list of properties from this entity
 427:      *
 428:      * ### Examples:
 429:      *
 430:      * ```
 431:      * $entity->unsetProperty('name');
 432:      * $entity->unsetProperty(['name', 'last_name']);
 433:      * ```
 434:      *
 435:      * @param string|array $property The property to unset.
 436:      * @return $this
 437:      */
 438:     public function unsetProperty($property)
 439:     {
 440:         $property = (array)$property;
 441:         foreach ($property as $p) {
 442:             unset($this->_properties[$p], $this->_dirty[$p]);
 443:         }
 444: 
 445:         return $this;
 446:     }
 447: 
 448:     /**
 449:      * Get/Set the hidden properties on this entity.
 450:      *
 451:      * If the properties argument is null, the currently hidden properties
 452:      * will be returned. Otherwise the hidden properties will be set.
 453:      *
 454:      * @deprecated 3.4.0 Use EntityTrait::setHidden() and EntityTrait::getHidden()
 455:      * @param array|null $properties Either an array of properties to hide or null to get properties
 456:      * @return array|$this
 457:      */
 458:     public function hiddenProperties($properties = null)
 459:     {
 460:         deprecationWarning(
 461:             get_called_class() . '::hiddenProperties() is deprecated. ' .
 462:             'Use setHidden()/getHidden() instead.'
 463:         );
 464:         if ($properties === null) {
 465:             return $this->_hidden;
 466:         }
 467:         $this->_hidden = $properties;
 468: 
 469:         return $this;
 470:     }
 471: 
 472:     /**
 473:      * Sets hidden properties.
 474:      *
 475:      * @param array $properties An array of properties to hide from array exports.
 476:      * @param bool $merge Merge the new properties with the existing. By default false.
 477:      * @return $this
 478:      */
 479:     public function setHidden(array $properties, $merge = false)
 480:     {
 481:         if ($merge === false) {
 482:             $this->_hidden = $properties;
 483: 
 484:             return $this;
 485:         }
 486: 
 487:         $properties = array_merge($this->_hidden, $properties);
 488:         $this->_hidden = array_unique($properties);
 489: 
 490:         return $this;
 491:     }
 492: 
 493:     /**
 494:      * Gets the hidden properties.
 495:      *
 496:      * @return array
 497:      */
 498:     public function getHidden()
 499:     {
 500:         return $this->_hidden;
 501:     }
 502: 
 503:     /**
 504:      * Get/Set the virtual properties on this entity.
 505:      *
 506:      * If the properties argument is null, the currently virtual properties
 507:      * will be returned. Otherwise the virtual properties will be set.
 508:      *
 509:      * @deprecated 3.4.0 Use EntityTrait::getVirtual() and EntityTrait::setVirtual()
 510:      * @param array|null $properties Either an array of properties to treat as virtual or null to get properties
 511:      * @return array|$this
 512:      */
 513:     public function virtualProperties($properties = null)
 514:     {
 515:         deprecationWarning(
 516:             get_called_class() . '::virtualProperties() is deprecated. ' .
 517:             'Use setVirtual()/getVirtual() instead.'
 518:         );
 519:         if ($properties === null) {
 520:             return $this->getVirtual();
 521:         }
 522: 
 523:         return $this->setVirtual($properties);
 524:     }
 525: 
 526:     /**
 527:      * Sets the virtual properties on this entity.
 528:      *
 529:      * @param array $properties An array of properties to treat as virtual.
 530:      * @param bool $merge Merge the new properties with the existing. By default false.
 531:      * @return $this
 532:      */
 533:     public function setVirtual(array $properties, $merge = false)
 534:     {
 535:         if ($merge === false) {
 536:             $this->_virtual = $properties;
 537: 
 538:             return $this;
 539:         }
 540: 
 541:         $properties = array_merge($this->_virtual, $properties);
 542:         $this->_virtual = array_unique($properties);
 543: 
 544:         return $this;
 545:     }
 546: 
 547:     /**
 548:      * Gets the virtual properties on this entity.
 549:      *
 550:      * @return array
 551:      */
 552:     public function getVirtual()
 553:     {
 554:         return $this->_virtual;
 555:     }
 556: 
 557:     /**
 558:      * Gets the list of visible properties.
 559:      *
 560:      * The list of visible properties is all standard properties
 561:      * plus virtual properties minus hidden properties.
 562:      *
 563:      * @return array A list of properties that are 'visible' in all
 564:      *     representations.
 565:      */
 566:     public function getVisible()
 567:     {
 568:         $properties = array_keys($this->_properties);
 569:         $properties = array_merge($properties, $this->_virtual);
 570: 
 571:         return array_diff($properties, $this->_hidden);
 572:     }
 573: 
 574:     /**
 575:      * Gets the list of visible properties.
 576:      *
 577:      * The list of visible properties is all standard properties
 578:      * plus virtual properties minus hidden properties.
 579:      *
 580:      * @return array A list of properties that are 'visible' in all
 581:      *     representations.
 582:      * @deprecated 3.8.0 Use getVisible() instead.
 583:      */
 584:     public function visibleProperties()
 585:     {
 586:         deprecationWarning(
 587:             get_called_class() . '::visibleProperties() is deprecated. ' .
 588:             'Use getVisible() instead.'
 589:         );
 590: 
 591:         return $this->getVisible();
 592:     }
 593: 
 594:     /**
 595:      * Returns an array with all the properties that have been set
 596:      * to this entity
 597:      *
 598:      * This method will recursively transform entities assigned to properties
 599:      * into arrays as well.
 600:      *
 601:      * @return array
 602:      */
 603:     public function toArray()
 604:     {
 605:         $result = [];
 606:         foreach ($this->getVisible() as $property) {
 607:             $value = $this->get($property);
 608:             if (is_array($value)) {
 609:                 $result[$property] = [];
 610:                 foreach ($value as $k => $entity) {
 611:                     if ($entity instanceof EntityInterface) {
 612:                         $result[$property][$k] = $entity->toArray();
 613:                     } else {
 614:                         $result[$property][$k] = $entity;
 615:                     }
 616:                 }
 617:             } elseif ($value instanceof EntityInterface) {
 618:                 $result[$property] = $value->toArray();
 619:             } else {
 620:                 $result[$property] = $value;
 621:             }
 622:         }
 623: 
 624:         return $result;
 625:     }
 626: 
 627:     /**
 628:      * Returns the properties that will be serialized as JSON
 629:      *
 630:      * @return array
 631:      */
 632:     public function jsonSerialize()
 633:     {
 634:         return $this->extract($this->getVisible());
 635:     }
 636: 
 637:     /**
 638:      * Implements isset($entity);
 639:      *
 640:      * @param mixed $offset The offset to check.
 641:      * @return bool Success
 642:      */
 643:     public function offsetExists($offset)
 644:     {
 645:         return $this->has($offset);
 646:     }
 647: 
 648:     /**
 649:      * Implements $entity[$offset];
 650:      *
 651:      * @param mixed $offset The offset to get.
 652:      * @return mixed
 653:      */
 654:     public function &offsetGet($offset)
 655:     {
 656:         return $this->get($offset);
 657:     }
 658: 
 659:     /**
 660:      * Implements $entity[$offset] = $value;
 661:      *
 662:      * @param mixed $offset The offset to set.
 663:      * @param mixed $value The value to set.
 664:      * @return void
 665:      */
 666:     public function offsetSet($offset, $value)
 667:     {
 668:         $this->set($offset, $value);
 669:     }
 670: 
 671:     /**
 672:      * Implements unset($result[$offset]);
 673:      *
 674:      * @param mixed $offset The offset to remove.
 675:      * @return void
 676:      */
 677:     public function offsetUnset($offset)
 678:     {
 679:         $this->unsetProperty($offset);
 680:     }
 681: 
 682:     /**
 683:      * Fetch accessor method name
 684:      * Accessor methods (available or not) are cached in $_accessors
 685:      *
 686:      * @param string $property the field name to derive getter name from
 687:      * @param string $type the accessor type ('get' or 'set')
 688:      * @return string method name or empty string (no method available)
 689:      */
 690:     protected static function _accessor($property, $type)
 691:     {
 692:         $class = static::class;
 693: 
 694:         if (isset(static::$_accessors[$class][$type][$property])) {
 695:             return static::$_accessors[$class][$type][$property];
 696:         }
 697: 
 698:         if (!empty(static::$_accessors[$class])) {
 699:             return static::$_accessors[$class][$type][$property] = '';
 700:         }
 701: 
 702:         if ($class === 'Cake\ORM\Entity') {
 703:             return '';
 704:         }
 705: 
 706:         foreach (get_class_methods($class) as $method) {
 707:             $prefix = substr($method, 1, 3);
 708:             if ($method[0] !== '_' || ($prefix !== 'get' && $prefix !== 'set')) {
 709:                 continue;
 710:             }
 711:             $field = lcfirst(substr($method, 4));
 712:             $snakeField = Inflector::underscore($field);
 713:             $titleField = ucfirst($field);
 714:             static::$_accessors[$class][$prefix][$snakeField] = $method;
 715:             static::$_accessors[$class][$prefix][$field] = $method;
 716:             static::$_accessors[$class][$prefix][$titleField] = $method;
 717:         }
 718: 
 719:         if (!isset(static::$_accessors[$class][$type][$property])) {
 720:             static::$_accessors[$class][$type][$property] = '';
 721:         }
 722: 
 723:         return static::$_accessors[$class][$type][$property];
 724:     }
 725: 
 726:     /**
 727:      * Returns an array with the requested properties
 728:      * stored in this entity, indexed by property name
 729:      *
 730:      * @param array $properties list of properties to be returned
 731:      * @param bool $onlyDirty Return the requested property only if it is dirty
 732:      * @return array
 733:      */
 734:     public function extract(array $properties, $onlyDirty = false)
 735:     {
 736:         $result = [];
 737:         foreach ($properties as $property) {
 738:             if (!$onlyDirty || $this->isDirty($property)) {
 739:                 $result[$property] = $this->get($property);
 740:             }
 741:         }
 742: 
 743:         return $result;
 744:     }
 745: 
 746:     /**
 747:      * Returns an array with the requested original properties
 748:      * stored in this entity, indexed by property name.
 749:      *
 750:      * Properties that are unchanged from their original value will be included in the
 751:      * return of this method.
 752:      *
 753:      * @param array $properties List of properties to be returned
 754:      * @return array
 755:      */
 756:     public function extractOriginal(array $properties)
 757:     {
 758:         $result = [];
 759:         foreach ($properties as $property) {
 760:             $result[$property] = $this->getOriginal($property);
 761:         }
 762: 
 763:         return $result;
 764:     }
 765: 
 766:     /**
 767:      * Returns an array with only the original properties
 768:      * stored in this entity, indexed by property name.
 769:      *
 770:      * This method will only return properties that have been modified since
 771:      * the entity was built. Unchanged properties will be omitted.
 772:      *
 773:      * @param array $properties List of properties to be returned
 774:      * @return array
 775:      */
 776:     public function extractOriginalChanged(array $properties)
 777:     {
 778:         $result = [];
 779:         foreach ($properties as $property) {
 780:             $original = $this->getOriginal($property);
 781:             if ($original !== $this->get($property)) {
 782:                 $result[$property] = $original;
 783:             }
 784:         }
 785: 
 786:         return $result;
 787:     }
 788: 
 789:     /**
 790:      * Sets the dirty status of a single property. If called with no second
 791:      * argument, it will return whether the property was modified or not
 792:      * after the object creation.
 793:      *
 794:      * When called with no arguments it will return whether or not there are any
 795:      * dirty property in the entity
 796:      *
 797:      * @deprecated 3.4.0 Use EntityTrait::setDirty() and EntityTrait::isDirty()
 798:      * @param string|null $property the field to set or check status for
 799:      * @param bool|null $isDirty true means the property was changed, false means
 800:      * it was not changed and null will make the function return current state
 801:      * for that property
 802:      * @return bool Whether the property was changed or not
 803:      */
 804:     public function dirty($property = null, $isDirty = null)
 805:     {
 806:         deprecationWarning(
 807:             get_called_class() . '::dirty() is deprecated. ' .
 808:             'Use setDirty()/isDirty() instead.'
 809:         );
 810:         if ($property === null) {
 811:             return $this->isDirty();
 812:         }
 813: 
 814:         if ($isDirty === null) {
 815:             return $this->isDirty($property);
 816:         }
 817: 
 818:         $this->setDirty($property, $isDirty);
 819: 
 820:         return true;
 821:     }
 822: 
 823:     /**
 824:      * Sets the dirty status of a single property.
 825:      *
 826:      * @param string $property the field to set or check status for
 827:      * @param bool $isDirty true means the property was changed, false means
 828:      * it was not changed. Defaults to true.
 829:      * @return $this
 830:      */
 831:     public function setDirty($property, $isDirty = true)
 832:     {
 833:         if ($isDirty === false) {
 834:             unset($this->_dirty[$property]);
 835: 
 836:             return $this;
 837:         }
 838: 
 839:         $this->_dirty[$property] = true;
 840:         unset($this->_errors[$property], $this->_invalid[$property]);
 841: 
 842:         return $this;
 843:     }
 844: 
 845:     /**
 846:      * Checks if the entity is dirty or if a single property of it is dirty.
 847:      *
 848:      * @param string|null $property The field to check the status for. Null for the whole entity.
 849:      * @return bool Whether the property was changed or not
 850:      */
 851:     public function isDirty($property = null)
 852:     {
 853:         if ($property === null) {
 854:             return !empty($this->_dirty);
 855:         }
 856: 
 857:         return isset($this->_dirty[$property]);
 858:     }
 859: 
 860:     /**
 861:      * Gets the dirty properties.
 862:      *
 863:      * @return string[]
 864:      */
 865:     public function getDirty()
 866:     {
 867:         return array_keys($this->_dirty);
 868:     }
 869: 
 870:     /**
 871:      * Sets the entire entity as clean, which means that it will appear as
 872:      * no properties being modified or added at all. This is an useful call
 873:      * for an initial object hydration
 874:      *
 875:      * @return void
 876:      */
 877:     public function clean()
 878:     {
 879:         $this->_dirty = [];
 880:         $this->_errors = [];
 881:         $this->_invalid = [];
 882:         $this->_original = [];
 883:     }
 884: 
 885:     /**
 886:      * Returns whether or not this entity has already been persisted.
 887:      * This method can return null in the case there is no prior information on
 888:      * the status of this entity.
 889:      *
 890:      * If called with a boolean it will set the known status of this instance,
 891:      * true means that the instance is not yet persisted in the database, false
 892:      * that it already is.
 893:      *
 894:      * @param bool|null $new true if it is known this instance was not yet persisted
 895:      * @return bool Whether or not the entity has been persisted.
 896:      */
 897:     public function isNew($new = null)
 898:     {
 899:         if ($new === null) {
 900:             return $this->_new;
 901:         }
 902: 
 903:         $new = (bool)$new;
 904: 
 905:         if ($new) {
 906:             foreach ($this->_properties as $k => $p) {
 907:                 $this->_dirty[$k] = true;
 908:             }
 909:         }
 910: 
 911:         return $this->_new = $new;
 912:     }
 913: 
 914:     /**
 915:      * Returns whether this entity has errors.
 916:      *
 917:      * @param bool $includeNested true will check nested entities for hasErrors()
 918:      * @return bool
 919:      */
 920:     public function hasErrors($includeNested = true)
 921:     {
 922:         if (Hash::filter($this->_errors)) {
 923:             return true;
 924:         }
 925: 
 926:         if ($includeNested === false) {
 927:             return false;
 928:         }
 929: 
 930:         foreach ($this->_properties as $property) {
 931:             if ($this->_readHasErrors($property)) {
 932:                 return true;
 933:             }
 934:         }
 935: 
 936:         return false;
 937:     }
 938: 
 939:     /**
 940:      * Returns all validation errors.
 941:      *
 942:      * @return array
 943:      */
 944:     public function getErrors()
 945:     {
 946:         $diff = array_diff_key($this->_properties, $this->_errors);
 947: 
 948:         return $this->_errors + (new Collection($diff))
 949:             ->filter(function ($value) {
 950:                 return is_array($value) || $value instanceof EntityInterface;
 951:             })
 952:             ->map(function ($value) {
 953:                 return $this->_readError($value);
 954:             })
 955:             ->filter()
 956:             ->toArray();
 957:     }
 958: 
 959:     /**
 960:      * Returns validation errors of a field
 961:      *
 962:      * @param string $field Field name to get the errors from
 963:      * @return array
 964:      */
 965:     public function getError($field)
 966:     {
 967:         $errors = isset($this->_errors[$field]) ? $this->_errors[$field] : [];
 968:         if ($errors) {
 969:             return $errors;
 970:         }
 971: 
 972:         return $this->_nestedErrors($field);
 973:     }
 974: 
 975:     /**
 976:      * Sets error messages to the entity
 977:      *
 978:      * ## Example
 979:      *
 980:      * ```
 981:      * // Sets the error messages for multiple fields at once
 982:      * $entity->setErrors(['salary' => ['message'], 'name' => ['another message']]);
 983:      * ```
 984:      *
 985:      * @param array $errors The array of errors to set.
 986:      * @param bool $overwrite Whether or not to overwrite pre-existing errors for $fields
 987:      * @return $this
 988:      */
 989:     public function setErrors(array $errors, $overwrite = false)
 990:     {
 991:         if ($overwrite) {
 992:             foreach ($errors as $f => $error) {
 993:                 $this->_errors[$f] = (array)$error;
 994:             }
 995: 
 996:             return $this;
 997:         }
 998: 
 999:         foreach ($errors as $f => $error) {
1000:             $this->_errors += [$f => []];
1001: 
1002:             // String messages are appended to the list,
1003:             // while more complex error structures need their
1004:             // keys preserved for nested validator.
1005:             if (is_string($error)) {
1006:                 $this->_errors[$f][] = $error;
1007:             } else {
1008:                 foreach ($error as $k => $v) {
1009:                     $this->_errors[$f][$k] = $v;
1010:                 }
1011:             }
1012:         }
1013: 
1014:         return $this;
1015:     }
1016: 
1017:     /**
1018:      * Sets errors for a single field
1019:      *
1020:      * ### Example
1021:      *
1022:      * ```
1023:      * // Sets the error messages for a single field
1024:      * $entity->setError('salary', ['must be numeric', 'must be a positive number']);
1025:      * ```
1026:      *
1027:      * @param string $field The field to get errors for, or the array of errors to set.
1028:      * @param string|array $errors The errors to be set for $field
1029:      * @param bool $overwrite Whether or not to overwrite pre-existing errors for $field
1030:      * @return $this
1031:      */
1032:     public function setError($field, $errors, $overwrite = false)
1033:     {
1034:         if (is_string($errors)) {
1035:             $errors = [$errors];
1036:         }
1037: 
1038:         return $this->setErrors([$field => $errors], $overwrite);
1039:     }
1040: 
1041:     /**
1042:      * Sets the error messages for a field or a list of fields. When called
1043:      * without the second argument it returns the validation
1044:      * errors for the specified fields. If called with no arguments it returns
1045:      * all the validation error messages stored in this entity and any other nested
1046:      * entity.
1047:      *
1048:      * ### Example
1049:      *
1050:      * ```
1051:      * // Sets the error messages for a single field
1052:      * $entity->errors('salary', ['must be numeric', 'must be a positive number']);
1053:      *
1054:      * // Returns the error messages for a single field
1055:      * $entity->getErrors('salary');
1056:      *
1057:      * // Returns all error messages indexed by field name
1058:      * $entity->getErrors();
1059:      *
1060:      * // Sets the error messages for multiple fields at once
1061:      * $entity->getErrors(['salary' => ['message'], 'name' => ['another message']);
1062:      * ```
1063:      *
1064:      * When used as a setter, this method will return this entity instance for method
1065:      * chaining.
1066:      *
1067:      * @deprecated 3.4.0 Use EntityTrait::setError(), EntityTrait::setErrors(), EntityTrait::getError() and EntityTrait::getErrors()
1068:      * @param string|array|null $field The field to get errors for, or the array of errors to set.
1069:      * @param string|array|null $errors The errors to be set for $field
1070:      * @param bool $overwrite Whether or not to overwrite pre-existing errors for $field
1071:      * @return array|$this
1072:      */
1073:     public function errors($field = null, $errors = null, $overwrite = false)
1074:     {
1075:         deprecationWarning(
1076:             get_called_class() . '::errors() is deprecated. ' .
1077:             'Use setError()/getError() or setErrors()/getErrors() instead.'
1078:         );
1079:         if ($field === null) {
1080:             return $this->getErrors();
1081:         }
1082: 
1083:         if (is_string($field) && $errors === null) {
1084:             return $this->getError($field);
1085:         }
1086: 
1087:         if (!is_array($field)) {
1088:             $field = [$field => $errors];
1089:         }
1090: 
1091:         return $this->setErrors($field, $overwrite);
1092:     }
1093: 
1094:     /**
1095:      * Auxiliary method for getting errors in nested entities
1096:      *
1097:      * @param string $field the field in this entity to check for errors
1098:      * @return array errors in nested entity if any
1099:      */
1100:     protected function _nestedErrors($field)
1101:     {
1102:         // Only one path element, check for nested entity with error.
1103:         if (strpos($field, '.') === false) {
1104:             return $this->_readError($this->get($field));
1105:         }
1106:         // Try reading the errors data with field as a simple path
1107:         $error = Hash::get($this->_errors, $field);
1108:         if ($error !== null) {
1109:             return $error;
1110:         }
1111:         $path = explode('.', $field);
1112: 
1113:         // Traverse down the related entities/arrays for
1114:         // the relevant entity.
1115:         $entity = $this;
1116:         $len = count($path);
1117:         while ($len) {
1118:             $part = array_shift($path);
1119:             $len = count($path);
1120:             $val = null;
1121:             if ($entity instanceof EntityInterface) {
1122:                 $val = $entity->get($part);
1123:             } elseif (is_array($entity)) {
1124:                 $val = isset($entity[$part]) ? $entity[$part] : false;
1125:             }
1126: 
1127:             if (is_array($val) ||
1128:                 $val instanceof Traversable ||
1129:                 $val instanceof EntityInterface
1130:             ) {
1131:                 $entity = $val;
1132:             } else {
1133:                 $path[] = $part;
1134:                 break;
1135:             }
1136:         }
1137:         if (count($path) <= 1) {
1138:             return $this->_readError($entity, array_pop($path));
1139:         }
1140: 
1141:         return [];
1142:     }
1143: 
1144:     /**
1145:      * Reads if there are errors for one or many objects.
1146:      *
1147:      * @param mixed $object The object to read errors from.
1148:      * @return bool
1149:      */
1150:     protected function _readHasErrors($object)
1151:     {
1152:         if ($object instanceof EntityInterface && $object->hasErrors()) {
1153:             return true;
1154:         }
1155: 
1156:         if (is_array($object)) {
1157:             foreach ($object as $value) {
1158:                 if ($this->_readHasErrors($value)) {
1159:                     return true;
1160:                 }
1161:             }
1162:         }
1163: 
1164:         return false;
1165:     }
1166: 
1167:     /**
1168:      * Read the error(s) from one or many objects.
1169:      *
1170:      * @param array|\Cake\Datasource\EntityInterface $object The object to read errors from.
1171:      * @param string|null $path The field name for errors.
1172:      * @return array
1173:      */
1174:     protected function _readError($object, $path = null)
1175:     {
1176:         if ($path !== null && $object instanceof EntityInterface) {
1177:             return $object->getError($path);
1178:         }
1179:         if ($object instanceof EntityInterface) {
1180:             return $object->getErrors();
1181:         }
1182:         if (is_array($object)) {
1183:             $array = array_map(function ($val) {
1184:                 if ($val instanceof EntityInterface) {
1185:                     return $val->getErrors();
1186:                 }
1187:             }, $object);
1188: 
1189:             return array_filter($array);
1190:         }
1191: 
1192:         return [];
1193:     }
1194: 
1195:     /**
1196:      * Get a list of invalid fields and their data for errors upon validation/patching
1197:      *
1198:      * @return array
1199:      */
1200:     public function getInvalid()
1201:     {
1202:         return $this->_invalid;
1203:     }
1204: 
1205:     /**
1206:      * Get a single value of an invalid field. Returns null if not set.
1207:      *
1208:      * @param string $field The name of the field.
1209:      * @return mixed|null
1210:      */
1211:     public function getInvalidField($field)
1212:     {
1213:         $value = isset($this->_invalid[$field]) ? $this->_invalid[$field] : null;
1214: 
1215:         return $value;
1216:     }
1217: 
1218:     /**
1219:      * Set fields as invalid and not patchable into the entity.
1220:      *
1221:      * This is useful for batch operations when one needs to get the original value for an error message after patching.
1222:      * This value could not be patched into the entity and is simply copied into the _invalid property for debugging purposes
1223:      * or to be able to log it away.
1224:      *
1225:      * @param array $fields The values to set.
1226:      * @param bool $overwrite Whether or not to overwrite pre-existing values for $field.
1227:      * @return $this
1228:      */
1229:     public function setInvalid(array $fields, $overwrite = false)
1230:     {
1231:         foreach ($fields as $field => $value) {
1232:             if ($overwrite === true) {
1233:                 $this->_invalid[$field] = $value;
1234:                 continue;
1235:             }
1236:             $this->_invalid += [$field => $value];
1237:         }
1238: 
1239:         return $this;
1240:     }
1241: 
1242:     /**
1243:      * Sets a field as invalid and not patchable into the entity.
1244:      *
1245:      * @param string $field The value to set.
1246:      * @param mixed $value The invalid value to be set for $field.
1247:      * @return $this
1248:      */
1249:     public function setInvalidField($field, $value)
1250:     {
1251:         $this->_invalid[$field] = $value;
1252: 
1253:         return $this;
1254:     }
1255: 
1256:     /**
1257:      * Sets a field as invalid and not patchable into the entity.
1258:      *
1259:      * This is useful for batch operations when one needs to get the original value for an error message after patching.
1260:      * This value could not be patched into the entity and is simply copied into the _invalid property for debugging purposes
1261:      * or to be able to log it away.
1262:      *
1263:      * @deprecated 3.5 Use getInvalid()/getInvalidField()/setInvalid() instead.
1264:      * @param string|array|null $field The field to get invalid value for, or the value to set.
1265:      * @param mixed|null $value The invalid value to be set for $field.
1266:      * @param bool $overwrite Whether or not to overwrite pre-existing values for $field.
1267:      * @return $this|mixed
1268:      */
1269:     public function invalid($field = null, $value = null, $overwrite = false)
1270:     {
1271:         deprecationWarning(
1272:             get_called_class() . '::invalid() is deprecated. ' .
1273:             'Use setInvalid()/getInvalid()/getInvalidField() instead.'
1274:         );
1275:         if ($field === null) {
1276:             return $this->_invalid;
1277:         }
1278: 
1279:         if (is_string($field) && $value === null) {
1280:             $value = isset($this->_invalid[$field]) ? $this->_invalid[$field] : null;
1281: 
1282:             return $value;
1283:         }
1284: 
1285:         if (!is_array($field)) {
1286:             $field = [$field => $value];
1287:         }
1288: 
1289:         foreach ($field as $f => $value) {
1290:             if ($overwrite) {
1291:                 $this->_invalid[$f] = $value;
1292:                 continue;
1293:             }
1294:             $this->_invalid += [$f => $value];
1295:         }
1296: 
1297:         return $this;
1298:     }
1299: 
1300:     /**
1301:      * Stores whether or not a property value can be changed or set in this entity.
1302:      * The special property `*` can also be marked as accessible or protected, meaning
1303:      * that any other property specified before will take its value. For example
1304:      * `$entity->accessible('*', true)` means that any property not specified already
1305:      * will be accessible by default.
1306:      *
1307:      * You can also call this method with an array of properties, in which case they
1308:      * will each take the accessibility value specified in the second argument.
1309:      *
1310:      * ### Example:
1311:      *
1312:      * ```
1313:      * $entity->accessible('id', true); // Mark id as not protected
1314:      * $entity->accessible('author_id', false); // Mark author_id as protected
1315:      * $entity->accessible(['id', 'user_id'], true); // Mark both properties as accessible
1316:      * $entity->accessible('*', false); // Mark all properties as protected
1317:      * ```
1318:      *
1319:      * When called without the second param it will return whether or not the property
1320:      * can be set.
1321:      *
1322:      * ### Example:
1323:      *
1324:      * ```
1325:      * $entity->accessible('id'); // Returns whether it can be set or not
1326:      * ```
1327:      *
1328:      * @deprecated 3.4.0 Use EntityTrait::setAccess() and EntityTrait::isAccessible()
1329:      * @param string|array $property single or list of properties to change its accessibility
1330:      * @param bool|null $set true marks the property as accessible, false will
1331:      * mark it as protected.
1332:      * @return $this|bool
1333:      */
1334:     public function accessible($property, $set = null)
1335:     {
1336:         deprecationWarning(
1337:             get_called_class() . '::accessible() is deprecated. ' .
1338:             'Use setAccess()/isAccessible() instead.'
1339:         );
1340:         if ($set === null) {
1341:             return $this->isAccessible($property);
1342:         }
1343: 
1344:         return $this->setAccess($property, $set);
1345:     }
1346: 
1347:     /**
1348:      * Stores whether or not a property value can be changed or set in this entity.
1349:      * The special property `*` can also be marked as accessible or protected, meaning
1350:      * that any other property specified before will take its value. For example
1351:      * `$entity->setAccess('*', true)` means that any property not specified already
1352:      * will be accessible by default.
1353:      *
1354:      * You can also call this method with an array of properties, in which case they
1355:      * will each take the accessibility value specified in the second argument.
1356:      *
1357:      * ### Example:
1358:      *
1359:      * ```
1360:      * $entity->setAccess('id', true); // Mark id as not protected
1361:      * $entity->setAccess('author_id', false); // Mark author_id as protected
1362:      * $entity->setAccess(['id', 'user_id'], true); // Mark both properties as accessible
1363:      * $entity->setAccess('*', false); // Mark all properties as protected
1364:      * ```
1365:      *
1366:      * @param string|array $property single or list of properties to change its accessibility
1367:      * @param bool $set true marks the property as accessible, false will
1368:      * mark it as protected.
1369:      * @return $this
1370:      */
1371:     public function setAccess($property, $set)
1372:     {
1373:         if ($property === '*') {
1374:             $this->_accessible = array_map(function ($p) use ($set) {
1375:                 return (bool)$set;
1376:             }, $this->_accessible);
1377:             $this->_accessible['*'] = (bool)$set;
1378: 
1379:             return $this;
1380:         }
1381: 
1382:         foreach ((array)$property as $prop) {
1383:             $this->_accessible[$prop] = (bool)$set;
1384:         }
1385: 
1386:         return $this;
1387:     }
1388: 
1389:     /**
1390:      * Checks if a property is accessible
1391:      *
1392:      * ### Example:
1393:      *
1394:      * ```
1395:      * $entity->isAccessible('id'); // Returns whether it can be set or not
1396:      * ```
1397:      *
1398:      * @param string $property Property name to check
1399:      * @return bool
1400:      */
1401:     public function isAccessible($property)
1402:     {
1403:         $value = isset($this->_accessible[$property]) ?
1404:             $this->_accessible[$property] :
1405:             null;
1406: 
1407:         return ($value === null && !empty($this->_accessible['*'])) || $value;
1408:     }
1409: 
1410:     /**
1411:      * Returns the alias of the repository from which this entity came from.
1412:      *
1413:      * @return string
1414:      */
1415:     public function getSource()
1416:     {
1417:         return $this->_registryAlias;
1418:     }
1419: 
1420:     /**
1421:      * Sets the source alias
1422:      *
1423:      * @param string $alias the alias of the repository
1424:      * @return $this
1425:      */
1426:     public function setSource($alias)
1427:     {
1428:         $this->_registryAlias = $alias;
1429: 
1430:         return $this;
1431:     }
1432: 
1433:     /**
1434:      * Returns the alias of the repository from which this entity came from.
1435:      *
1436:      * If called with no arguments, it returns the alias of the repository
1437:      * this entity came from if it is known.
1438:      *
1439:      * @deprecated 3.4.0 Use EntityTrait::getSource() and EntityTrait::setSource()
1440:      * @param string|null $alias the alias of the repository
1441:      * @return string|$this
1442:      */
1443:     public function source($alias = null)
1444:     {
1445:         deprecationWarning(
1446:             get_called_class() . '::source() is deprecated. ' .
1447:             'Use setSource()/getSource() instead.'
1448:         );
1449:         if ($alias === null) {
1450:             return $this->getSource();
1451:         }
1452: 
1453:         $this->setSource($alias);
1454: 
1455:         return $this;
1456:     }
1457: 
1458:     /**
1459:      * Returns a string representation of this object in a human readable format.
1460:      *
1461:      * @return string
1462:      */
1463:     public function __toString()
1464:     {
1465:         return json_encode($this, JSON_PRETTY_PRINT);
1466:     }
1467: 
1468:     /**
1469:      * Returns an array that can be used to describe the internal state of this
1470:      * object.
1471:      *
1472:      * @return array
1473:      */
1474:     public function __debugInfo()
1475:     {
1476:         $properties = $this->_properties;
1477:         foreach ($this->_virtual as $field) {
1478:             $properties[$field] = $this->$field;
1479:         }
1480: 
1481:         return $properties + [
1482:             '[new]' => $this->isNew(),
1483:             '[accessible]' => $this->_accessible,
1484:             '[dirty]' => $this->_dirty,
1485:             '[original]' => $this->_original,
1486:             '[virtual]' => $this->_virtual,
1487:             '[hasErrors]' => $this->hasErrors(),
1488:             '[errors]' => $this->_errors,
1489:             '[invalid]' => $this->_invalid,
1490:             '[repository]' => $this->_registryAlias
1491:         ];
1492:     }
1493: }
1494: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs