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.7 Red Velvet API

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