MergeVariablesTrait.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. * @link http://cakephp.org CakePHP(tm) Project
  11. * @since CakePHP(tm) v 3.0.0
  12. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  13. */
  14. namespace Cake\Utility;
  15. use Cake\Utility\Hash;
  16. /**
  17. * Provides features for merging object properties recursively with
  18. * parent classes.
  19. *
  20. */
  21. trait MergeVariablesTrait {
  22. /**
  23. * Merge the list of $properties with all parent classes of the current class.
  24. *
  25. * ### Options:
  26. *
  27. * - `associative` - A list of properties that should be treated as associative arrays.
  28. * Properties in this list will be passed through Hash::normalize() before merging.
  29. * - `reverse` - A list of properties that should be merged in reverse. Reverse merging
  30. * allows the parent properties to follow the child classes. Generally this option is only
  31. * useful when merging list properties that need to maintain the child property values
  32. * as the first elements in the merged list.
  33. *
  34. * @param array $properties An array of properties and the merge strategy for them.
  35. * @param array $options The options to use when merging properties.
  36. * @return void
  37. */
  38. protected function _mergeVars($properties, $options = []) {
  39. $class = get_class($this);
  40. $parents = [];
  41. while (true) {
  42. $parent = get_parent_class($class);
  43. if (!$parent) {
  44. break;
  45. }
  46. $parents[] = $parent;
  47. $class = $parent;
  48. }
  49. foreach ($properties as $property) {
  50. if (!property_exists($this, $property)) {
  51. continue;
  52. }
  53. $thisValue = $this->{$property};
  54. if ($thisValue === null || $thisValue === false) {
  55. continue;
  56. }
  57. $this->_mergeProperty($property, $parents, $options);
  58. }
  59. }
  60. /**
  61. * Merge a single property with the values declared in all parent classes.
  62. *
  63. * @param string $property The name of the property being merged.
  64. * @param array $parentClasses An array of classes you want to merge with.
  65. * @param array $options Options for merging the property, see _mergeVars()
  66. * @return void
  67. */
  68. protected function _mergeProperty($property, $parentClasses, $options) {
  69. $thisValue = $this->{$property};
  70. $isAssoc = $isReversed = false;
  71. if (
  72. isset($options['associative']) &&
  73. in_array($property, (array)$options['associative'])
  74. ) {
  75. $isAssoc = true;
  76. }
  77. if (
  78. isset($options['reverse']) &&
  79. in_array($property, (array)$options['reverse'])
  80. ) {
  81. $isReversed = true;
  82. }
  83. if ($isAssoc) {
  84. $thisValue = Hash::normalize($thisValue);
  85. }
  86. foreach ($parentClasses as $class) {
  87. $parentProperties = get_class_vars($class);
  88. if (!isset($parentProperties[$property])) {
  89. continue;
  90. }
  91. $parentProperty = $parentProperties[$property];
  92. if (empty($parentProperty) || $parentProperty === true) {
  93. continue;
  94. }
  95. if ($isAssoc) {
  96. $parentProperty = Hash::normalize($parentProperty);
  97. }
  98. if ($isReversed) {
  99. $thisValue = Hash::merge($thisValue, $parentProperty);
  100. } else {
  101. $thisValue = Hash::merge($parentProperty, $thisValue);
  102. }
  103. }
  104. $this->{$property} = $thisValue;
  105. }
  106. }