EntityTrait.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://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. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Datasource;
  16. use Cake\Collection\Collection;
  17. use Cake\Utility\Inflector;
  18. use InvalidArgumentException;
  19. use Traversable;
  20. /**
  21. * An entity represents a single result row from a repository. It exposes the
  22. * methods for retrieving and storing properties associated in this row.
  23. */
  24. trait EntityTrait
  25. {
  26. /**
  27. * Holds all properties and their values for this entity
  28. *
  29. * @var array
  30. */
  31. protected $_properties = [];
  32. /**
  33. * Holds all properties that have been changed and their original values for this entity
  34. *
  35. * @var array
  36. */
  37. protected $_original = [];
  38. /**
  39. * List of property names that should **not** be included in JSON or Array
  40. * representations of this Entity.
  41. *
  42. * @var array
  43. */
  44. protected $_hidden = [];
  45. /**
  46. * List of computed or virtual fields that **should** be included in JSON or array
  47. * representations of this Entity. If a field is present in both _hidden and _virtual
  48. * the field will **not** be in the array/json versions of the entity.
  49. *
  50. * @var array
  51. */
  52. protected $_virtual = [];
  53. /**
  54. * Holds the name of the class for the instance object
  55. *
  56. * @var string
  57. */
  58. protected $_className;
  59. /**
  60. * Holds a list of the properties that were modified or added after this object
  61. * was originally created.
  62. *
  63. * @var array
  64. */
  65. protected $_dirty = [];
  66. /**
  67. * Holds a cached list of methods that exist in the instanced class
  68. *
  69. * @var array
  70. */
  71. protected static $_accessors = [];
  72. /**
  73. * Indicates whether or not this entity is yet to be persisted.
  74. * Entities default to assuming they are new. You can use Table::persisted()
  75. * to set the new flag on an entity based on records in the database.
  76. *
  77. * @var bool
  78. */
  79. protected $_new = true;
  80. /**
  81. * List of errors per field as stored in this object
  82. *
  83. * @var array
  84. */
  85. protected $_errors = [];
  86. /**
  87. * Map of properties in this entity that can be safely assigned, each
  88. * property name points to a boolean indicating its status. An empty array
  89. * means no properties are accessible
  90. *
  91. * The special property '\*' can also be mapped, meaning that any other property
  92. * not defined in the map will take its value. For example, `'\*' => true`
  93. * means that any property not defined in the map will be accessible by default
  94. *
  95. * @var array
  96. */
  97. protected $_accessible = ['*' => true];
  98. /**
  99. * The alias of the repository this entity came from
  100. *
  101. * @var string
  102. */
  103. protected $_registryAlias;
  104. /**
  105. * Magic getter to access properties that have been set in this entity
  106. *
  107. * @param string $property Name of the property to access
  108. * @return mixed
  109. */
  110. public function &__get($property)
  111. {
  112. return $this->get($property);
  113. }
  114. /**
  115. * Magic setter to add or edit a property in this entity
  116. *
  117. * @param string $property The name of the property to set
  118. * @param mixed $value The value to set to the property
  119. * @return void
  120. */
  121. public function __set($property, $value)
  122. {
  123. $this->set($property, $value);
  124. }
  125. /**
  126. * Returns whether this entity contains a property named $property
  127. * regardless of if it is empty.
  128. *
  129. * @param string $property The property to check.
  130. * @return bool
  131. * @see \Cake\ORM\Entity::has()
  132. */
  133. public function __isset($property)
  134. {
  135. return $this->has($property);
  136. }
  137. /**
  138. * Removes a property from this entity
  139. *
  140. * @param string $property The property to unset
  141. * @return void
  142. */
  143. public function __unset($property)
  144. {
  145. $this->unsetProperty($property);
  146. }
  147. /**
  148. * Sets a single property inside this entity.
  149. *
  150. * ### Example:
  151. *
  152. * ``$entity->set('name', 'Andrew');``
  153. *
  154. * It is also possible to mass-assign multiple properties to this entity
  155. * with one call by passing a hashed array as properties in the form of
  156. * property => value pairs
  157. *
  158. * ### Example:
  159. *
  160. * ```
  161. * $entity->set(['name' => 'andrew', 'id' => 1]);
  162. * echo $entity->name // prints andrew
  163. * echo $entity->id // prints 1
  164. * ```
  165. *
  166. * Some times it is handy to bypass setter functions in this entity when assigning
  167. * properties. You can achieve this by disabling the `setter` option using the
  168. * `$options` parameter:
  169. *
  170. * ```
  171. * $entity->set('name', 'Andrew', ['setter' => false]);
  172. * $entity->set(['name' => 'Andrew', 'id' => 1], ['setter' => false]);
  173. * ```
  174. *
  175. * Mass assignment should be treated carefully when accepting user input, by default
  176. * entities will guard all fields when properties are assigned in bulk. You can disable
  177. * the guarding for a single set call with the `guard` option:
  178. *
  179. * ```
  180. * $entity->set(['name' => 'Andrew', 'id' => 1], ['guard' => true]);
  181. * ```
  182. *
  183. * You do not need to use the guard option when assigning properties individually:
  184. *
  185. * ```
  186. * // No need to use the guard option.
  187. * $entity->set('name', 'Andrew');
  188. * ```
  189. *
  190. * @param string|array $property the name of property to set or a list of
  191. * properties with their respective values
  192. * @param mixed $value The value to set to the property or an array if the
  193. * first argument is also an array, in which case will be treated as $options
  194. * @param array $options options to be used for setting the property. Allowed option
  195. * keys are `setter` and `guard`
  196. * @return $this
  197. * @throws \InvalidArgumentException
  198. */
  199. public function set($property, $value = null, array $options = [])
  200. {
  201. $isString = is_string($property);
  202. if ($isString && $property !== '') {
  203. $guard = false;
  204. $property = [$property => $value];
  205. } else {
  206. $guard = true;
  207. $options = (array)$value;
  208. }
  209. if (!is_array($property)) {
  210. throw new InvalidArgumentException('Cannot set an empty property');
  211. }
  212. $options += ['setter' => true, 'guard' => $guard];
  213. foreach ($property as $p => $value) {
  214. if ($options['guard'] === true && !$this->accessible($p)) {
  215. continue;
  216. }
  217. $this->dirty($p, true);
  218. if (!isset($this->_original[$p]) &&
  219. isset($this->_properties[$p]) &&
  220. $this->_properties[$p] !== $value
  221. ) {
  222. $this->_original[$p] = $this->_properties[$p];
  223. }
  224. if (!$options['setter']) {
  225. $this->_properties[$p] = $value;
  226. continue;
  227. }
  228. $setter = '_set' . Inflector::camelize($p);
  229. if ($this->_methodExists($setter)) {
  230. $value = $this->{$setter}($value);
  231. }
  232. $this->_properties[$p] = $value;
  233. }
  234. return $this;
  235. }
  236. /**
  237. * Returns the value of a property by name
  238. *
  239. * @param string $property the name of the property to retrieve
  240. * @return mixed
  241. * @throws \InvalidArgumentException if an empty property name is passed
  242. */
  243. public function &get($property)
  244. {
  245. if (!strlen((string)$property)) {
  246. throw new InvalidArgumentException('Cannot get an empty property');
  247. }
  248. $value = null;
  249. $method = '_get' . Inflector::camelize($property);
  250. if (isset($this->_properties[$property])) {
  251. $value =& $this->_properties[$property];
  252. }
  253. if ($this->_methodExists($method)) {
  254. $result = $this->{$method}($value);
  255. return $result;
  256. }
  257. return $value;
  258. }
  259. /**
  260. * Returns the value of an original property by name
  261. *
  262. * @param string $property the name of the property for which original value is retrieved.
  263. * @return mixed
  264. * @throws \InvalidArgumentException if an empty property name is passed.
  265. */
  266. public function getOriginal($property)
  267. {
  268. if (!strlen((string)$property)) {
  269. throw new InvalidArgumentException('Cannot get an empty property');
  270. }
  271. if (isset($this->_original[$property])) {
  272. return $this->_original[$property];
  273. }
  274. return $this->get($property);
  275. }
  276. /**
  277. * Returns whether this entity contains a property named $property
  278. * regardless of if it is empty.
  279. *
  280. * ### Example:
  281. *
  282. * ```
  283. * $entity = new Entity(['id' => 1, 'name' => null]);
  284. * $entity->has('id'); // true
  285. * $entity->has('name'); // false
  286. * $entity->has('last_name'); // false
  287. * ```
  288. *
  289. * When checking multiple properties. All properties must not be null
  290. * in order for true to be returned.
  291. *
  292. * @param string|array $property The property or properties to check.
  293. * @return bool
  294. */
  295. public function has($property)
  296. {
  297. foreach ((array)$property as $prop) {
  298. if ($this->get($prop) === null) {
  299. return false;
  300. }
  301. }
  302. return true;
  303. }
  304. /**
  305. * Removes a property or list of properties from this entity
  306. *
  307. * ### Examples:
  308. *
  309. * ```
  310. * $entity->unsetProperty('name');
  311. * $entity->unsetProperty(['name', 'last_name']);
  312. * ```
  313. *
  314. * @param string|array $property The property to unset.
  315. * @return $this
  316. */
  317. public function unsetProperty($property)
  318. {
  319. $property = (array)$property;
  320. foreach ($property as $p) {
  321. unset($this->_properties[$p]);
  322. unset($this->_dirty[$p]);
  323. }
  324. return $this;
  325. }
  326. /**
  327. * Get/Set the hidden properties on this entity.
  328. *
  329. * If the properties argument is null, the currently hidden properties
  330. * will be returned. Otherwise the hidden properties will be set.
  331. *
  332. * @param null|array $properties Either an array of properties to hide or null to get properties
  333. * @return array|$this
  334. */
  335. public function hiddenProperties($properties = null)
  336. {
  337. if ($properties === null) {
  338. return $this->_hidden;
  339. }
  340. $this->_hidden = $properties;
  341. return $this;
  342. }
  343. /**
  344. * Get/Set the virtual properties on this entity.
  345. *
  346. * If the properties argument is null, the currently virtual properties
  347. * will be returned. Otherwise the virtual properties will be set.
  348. *
  349. * @param null|array $properties Either an array of properties to treat as virtual or null to get properties
  350. * @return array|$this
  351. */
  352. public function virtualProperties($properties = null)
  353. {
  354. if ($properties === null) {
  355. return $this->_virtual;
  356. }
  357. $this->_virtual = $properties;
  358. return $this;
  359. }
  360. /**
  361. * Get the list of visible properties.
  362. *
  363. * The list of visible properties is all standard properties
  364. * plus virtual properties minus hidden properties.
  365. *
  366. * @return array A list of properties that are 'visible' in all
  367. * representations.
  368. */
  369. public function visibleProperties()
  370. {
  371. $properties = array_keys($this->_properties);
  372. $properties = array_merge($properties, $this->_virtual);
  373. return array_diff($properties, $this->_hidden);
  374. }
  375. /**
  376. * Returns an array with all the properties that have been set
  377. * to this entity
  378. *
  379. * This method will recursively transform entities assigned to properties
  380. * into arrays as well.
  381. *
  382. * @return array
  383. */
  384. public function toArray()
  385. {
  386. $result = [];
  387. foreach ($this->visibleProperties() as $property) {
  388. $value = $this->get($property);
  389. if (is_array($value) && isset($value[0]) && $value[0] instanceof EntityInterface) {
  390. $result[$property] = [];
  391. foreach ($value as $k => $entity) {
  392. $result[$property][$k] = $entity->toArray();
  393. }
  394. } elseif ($value instanceof EntityInterface) {
  395. $result[$property] = $value->toArray();
  396. } else {
  397. $result[$property] = $value;
  398. }
  399. }
  400. return $result;
  401. }
  402. /**
  403. * Returns the properties that will be serialized as JSON
  404. *
  405. * @return array
  406. */
  407. public function jsonSerialize()
  408. {
  409. return $this->toArray();
  410. }
  411. /**
  412. * Implements isset($entity);
  413. *
  414. * @param mixed $offset The offset to check.
  415. * @return bool Success
  416. */
  417. public function offsetExists($offset)
  418. {
  419. return $this->has($offset);
  420. }
  421. /**
  422. * Implements $entity[$offset];
  423. *
  424. * @param mixed $offset The offset to get.
  425. * @return mixed
  426. */
  427. public function &offsetGet($offset)
  428. {
  429. return $this->get($offset);
  430. }
  431. /**
  432. * Implements $entity[$offset] = $value;
  433. *
  434. * @param mixed $offset The offset to set.
  435. * @param mixed $value The value to set.
  436. * @return void
  437. */
  438. public function offsetSet($offset, $value)
  439. {
  440. $this->set($offset, $value);
  441. }
  442. /**
  443. * Implements unset($result[$offset);
  444. *
  445. * @param mixed $offset The offset to remove.
  446. * @return void
  447. */
  448. public function offsetUnset($offset)
  449. {
  450. $this->unsetProperty($offset);
  451. }
  452. /**
  453. * Determines whether a method exists in this class
  454. *
  455. * @param string $method the method to check for existence
  456. * @return bool true if method exists
  457. */
  458. protected function _methodExists($method)
  459. {
  460. if (empty(static::$_accessors[$this->_className])) {
  461. static::$_accessors[$this->_className] = array_flip(get_class_methods($this));
  462. }
  463. return isset(static::$_accessors[$this->_className][$method]);
  464. }
  465. /**
  466. * Returns an array with the requested properties
  467. * stored in this entity, indexed by property name
  468. *
  469. * @param array $properties list of properties to be returned
  470. * @param bool $onlyDirty Return the requested property only if it is dirty
  471. * @return array
  472. */
  473. public function extract(array $properties, $onlyDirty = false)
  474. {
  475. $result = [];
  476. foreach ($properties as $property) {
  477. if (!$onlyDirty || $this->dirty($property)) {
  478. $result[$property] = $this->get($property);
  479. }
  480. }
  481. return $result;
  482. }
  483. /**
  484. * Returns an array with the requested original properties
  485. * stored in this entity, indexed by property name
  486. *
  487. * @param array $properties List of properties to be returned
  488. * @return array
  489. */
  490. public function extractOriginal(array $properties)
  491. {
  492. $result = [];
  493. foreach ($properties as $property) {
  494. $original = $this->getOriginal($property);
  495. if ($original !== null && $original !== $this->get($property)) {
  496. $result[$property] = $original;
  497. }
  498. }
  499. return $result;
  500. }
  501. /**
  502. * Sets the dirty status of a single property. If called with no second
  503. * argument, it will return whether the property was modified or not
  504. * after the object creation.
  505. *
  506. * When called with no arguments it will return whether or not there are any
  507. * dirty property in the entity
  508. *
  509. * @param string $property the field to set or check status for
  510. * @param null|bool $isDirty true means the property was changed, false means
  511. * it was not changed and null will make the function return current state
  512. * for that property
  513. * @return bool whether the property was changed or not
  514. */
  515. public function dirty($property = null, $isDirty = null)
  516. {
  517. if ($property === null) {
  518. return !empty($this->_dirty);
  519. }
  520. if ($isDirty === null) {
  521. return isset($this->_dirty[$property]);
  522. }
  523. if ($isDirty === false) {
  524. unset($this->_dirty[$property]);
  525. return false;
  526. }
  527. $this->_dirty[$property] = true;
  528. unset($this->_errors[$property]);
  529. return true;
  530. }
  531. /**
  532. * Sets the entire entity as clean, which means that it will appear as
  533. * no properties being modified or added at all. This is an useful call
  534. * for an initial object hydration
  535. *
  536. * @return void
  537. */
  538. public function clean()
  539. {
  540. $this->_dirty = [];
  541. $this->_errors = [];
  542. }
  543. /**
  544. * Returns whether or not this entity has already been persisted.
  545. * This method can return null in the case there is no prior information on
  546. * the status of this entity.
  547. *
  548. * If called with a boolean it will set the known status of this instance,
  549. * true means that the instance is not yet persisted in the database, false
  550. * that it already is.
  551. *
  552. * @param bool|null $new true if it is known this instance was persisted
  553. * @return bool Whether or not the entity has been persisted.
  554. */
  555. public function isNew($new = null)
  556. {
  557. if ($new === null) {
  558. return $this->_new;
  559. }
  560. $new = (bool)$new;
  561. if ($new) {
  562. foreach ($this->_properties as $k => $p) {
  563. $this->_dirty[$k] = true;
  564. }
  565. }
  566. return $this->_new = $new;
  567. }
  568. /**
  569. * Sets the error messages for a field or a list of fields. When called
  570. * without the second argument it returns the validation
  571. * errors for the specified fields. If called with no arguments it returns
  572. * all the validation error messages stored in this entity and any other nested
  573. * entity.
  574. *
  575. * ### Example
  576. *
  577. * ```
  578. * // Sets the error messages for a single field
  579. * $entity->errors('salary', ['must be numeric', 'must be a positive number']);
  580. *
  581. * // Returns the error messages for a single field
  582. * $entity->errors('salary');
  583. *
  584. * // Returns all error messages indexed by field name
  585. * $entity->errors();
  586. *
  587. * // Sets the error messages for multiple fields at once
  588. * $entity->errors(['salary' => ['message'], 'name' => ['another message']);
  589. * ```
  590. *
  591. * When used as a setter, this method will return this entity instance for method
  592. * chaining.
  593. *
  594. * @param string|array|null $field The field to get errors for, or the array of errors to set.
  595. * @param string|array|null $errors The errors to be set for $field
  596. * @param bool $overwrite Whether or not to overwrite pre-existing errors for $field
  597. * @return array|$this
  598. */
  599. public function errors($field = null, $errors = null, $overwrite = false)
  600. {
  601. if ($field === null) {
  602. $diff = array_diff_key($this->_properties, $this->_errors);
  603. return $this->_errors + (new Collection($diff))
  604. ->filter(function ($value) {
  605. return is_array($value) || $value instanceof EntityInterface;
  606. })
  607. ->map(function ($value) {
  608. return $this->_readError($value);
  609. })
  610. ->filter()
  611. ->toArray();
  612. }
  613. if (is_string($field) && $errors === null) {
  614. $errors = isset($this->_errors[$field]) ? $this->_errors[$field] : [];
  615. if ($errors) {
  616. return $errors;
  617. }
  618. return $this->_nestedErrors($field);
  619. }
  620. if (!is_array($field)) {
  621. $field = [$field => $errors];
  622. }
  623. foreach ($field as $f => $error) {
  624. $this->_errors += [$f => []];
  625. $this->_errors[$f] = $overwrite ?
  626. (array)$error :
  627. array_merge($this->_errors[$f], (array)$error);
  628. }
  629. return $this;
  630. }
  631. /**
  632. * Auxiliary method for getting errors in nested entities
  633. *
  634. * @param string $field the field in this entity to check for errors
  635. * @return array errors in nested entity if any
  636. */
  637. protected function _nestedErrors($field)
  638. {
  639. $path = explode('.', $field);
  640. // Only one path element, check for nested entity with error.
  641. if (count($path) === 1) {
  642. return $this->_readError($this->get($path[0]));
  643. }
  644. $entity = $this;
  645. $len = count($path);
  646. while ($len) {
  647. $part = array_shift($path);
  648. $len = count($path);
  649. if ($entity instanceof EntityInterface) {
  650. $val = $entity->get($part);
  651. } elseif (is_array($entity)) {
  652. $val = isset($entity[$part]) ? $entity[$part] : false;
  653. }
  654. if (is_array($val) ||
  655. $val instanceof Traversable ||
  656. $val instanceof EntityInterface
  657. ) {
  658. $entity = $val;
  659. } else {
  660. $path[] = $part;
  661. break;
  662. }
  663. }
  664. if (count($path) <= 1) {
  665. return $this->_readError($entity, array_pop($path));
  666. }
  667. return [];
  668. }
  669. /**
  670. * Read the error(s) from one or many objects.
  671. *
  672. * @param array|\Cake\Datasource\EntityTrait $object The object to read errors from.
  673. * @param string $path The field name for errors.
  674. * @return array
  675. */
  676. protected function _readError($object, $path = null)
  677. {
  678. if ($object instanceof EntityInterface) {
  679. return $object->errors($path);
  680. }
  681. if (is_array($object)) {
  682. $array = array_map(function ($val) {
  683. if ($val instanceof EntityInterface) {
  684. return $val->errors();
  685. }
  686. }, $object);
  687. return array_filter($array);
  688. }
  689. return [];
  690. }
  691. /**
  692. * Stores whether or not a property value can be changed or set in this entity.
  693. * The special property `*` can also be marked as accessible or protected, meaning
  694. * that any other property specified before will take its value. For example
  695. * `$entity->accessible('*', true)` means that any property not specified already
  696. * will be accessible by default.
  697. *
  698. * You can also call this method with an array of properties, in which case they
  699. * will each take the accessibility value specified in the second argument.
  700. *
  701. * ### Example:
  702. *
  703. * ```
  704. * $entity->accessible('id', true); // Mark id as not protected
  705. * $entity->accessible('author_id', false); // Mark author_id as protected
  706. * $entity->accessible(['id', 'user_id'], true); // Mark both properties as accessible
  707. * $entity->accessible('*', false); // Mark all properties as protected
  708. * ```
  709. *
  710. * When called without the second param it will return whether or not the property
  711. * can be set.
  712. *
  713. * ### Example:
  714. *
  715. * ```
  716. * $entity->accessible('id'); // Returns whether it can be set or not
  717. * ```
  718. *
  719. * @param string|array $property single or list of properties to change its accessibility
  720. * @param bool $set true marks the property as accessible, false will
  721. * mark it as protected.
  722. * @return $this|bool
  723. */
  724. public function accessible($property, $set = null)
  725. {
  726. if ($set === null) {
  727. $value = isset($this->_accessible[$property]) ?
  728. $this->_accessible[$property] :
  729. null;
  730. return ($value === null && !empty($this->_accessible['*'])) || $value;
  731. }
  732. if ($property === '*') {
  733. $this->_accessible = array_map(function ($p) use ($set) {
  734. return (bool)$set;
  735. }, $this->_accessible);
  736. $this->_accessible['*'] = (bool)$set;
  737. return $this;
  738. }
  739. foreach ((array)$property as $prop) {
  740. $this->_accessible[$prop] = (bool)$set;
  741. }
  742. return $this;
  743. }
  744. /**
  745. * Returns the alias of the repository from which this entity came from.
  746. *
  747. * If called with no arguments, it returns the alias of the repository
  748. * this entity came from if it is known.
  749. *
  750. * @param string $alias the alias of the repository
  751. * @return string
  752. */
  753. public function source($alias = null)
  754. {
  755. if ($alias === null) {
  756. return $this->_registryAlias;
  757. }
  758. $this->_registryAlias = $alias;
  759. }
  760. /**
  761. * Returns a string representation of this object in a human readable format.
  762. *
  763. * @return string
  764. */
  765. public function __toString()
  766. {
  767. return json_encode($this, JSON_PRETTY_PRINT);
  768. }
  769. /**
  770. * Returns an array that can be used to describe the internal state of this
  771. * object.
  772. *
  773. * @return array
  774. */
  775. public function __debugInfo()
  776. {
  777. return [
  778. 'new' => $this->isNew(),
  779. 'accessible' => array_filter($this->_accessible),
  780. 'properties' => $this->_properties,
  781. 'dirty' => $this->_dirty,
  782. 'original' => $this->_original,
  783. 'virtual' => $this->_virtual,
  784. 'errors' => $this->_errors,
  785. 'repository' => $this->_registryAlias
  786. ];
  787. }
  788. }