KeyNested.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <?php
  2. /*
  3. * Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
  4. * SPDX-License-Identifier: MIT
  5. */
  6. declare(strict_types=1);
  7. namespace Respect\Validation\Rules;
  8. use ArrayAccess;
  9. use Respect\Validation\Exceptions\ComponentException;
  10. use function array_key_exists;
  11. use function array_shift;
  12. use function explode;
  13. use function is_array;
  14. use function is_null;
  15. use function is_object;
  16. use function is_scalar;
  17. use function property_exists;
  18. use function rtrim;
  19. use function sprintf;
  20. /**
  21. * @author Alexandre Gomes Gaigalas <alganet@gmail.com>
  22. * @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
  23. * @author Henrique Moody <henriquemoody@gmail.com>
  24. * @author Ivan Zinovyev <vanyazin@gmail.com>
  25. */
  26. final class KeyNested extends AbstractRelated
  27. {
  28. /**
  29. * {@inheritDoc}
  30. */
  31. public function hasReference($input): bool
  32. {
  33. try {
  34. $this->getReferenceValue($input);
  35. } catch (ComponentException $cex) {
  36. return false;
  37. }
  38. return true;
  39. }
  40. /**
  41. * {@inheritDoc}
  42. */
  43. public function getReferenceValue($input)
  44. {
  45. if (is_scalar($input)) {
  46. $message = sprintf('Cannot select the %s in the given data', $this->getReference());
  47. throw new ComponentException($message);
  48. }
  49. $keys = $this->getReferencePieces();
  50. $value = $input;
  51. while (!is_null($key = array_shift($keys))) {
  52. $value = $this->getValue($value, $key);
  53. }
  54. return $value;
  55. }
  56. /**
  57. * @return string[]
  58. */
  59. private function getReferencePieces(): array
  60. {
  61. return explode('.', rtrim((string) $this->getReference(), '.'));
  62. }
  63. /**
  64. * @param mixed[] $array
  65. * @param mixed $key
  66. *
  67. * @return mixed
  68. */
  69. private function getValueFromArray(array $array, $key)
  70. {
  71. if (!array_key_exists($key, $array)) {
  72. $message = sprintf('Cannot select the key %s from the given array', $this->getReference());
  73. throw new ComponentException($message);
  74. }
  75. return $array[$key];
  76. }
  77. /**
  78. * @param ArrayAccess<mixed, mixed> $array
  79. * @param mixed $key
  80. *
  81. * @return mixed
  82. */
  83. private function getValueFromArrayAccess(ArrayAccess $array, $key)
  84. {
  85. if (!$array->offsetExists($key)) {
  86. $message = sprintf('Cannot select the key %s from the given array', $this->getReference());
  87. throw new ComponentException($message);
  88. }
  89. return $array->offsetGet($key);
  90. }
  91. /**
  92. * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint
  93. *
  94. *
  95. * @return mixed
  96. */
  97. private function getValueFromObject(object $object, string $property)
  98. {
  99. if (empty($property) || !property_exists($object, $property)) {
  100. $message = sprintf('Cannot select the property %s from the given object', $this->getReference());
  101. throw new ComponentException($message);
  102. }
  103. return $object->{$property};
  104. }
  105. /**
  106. * @param mixed $value
  107. * @param mixed $key
  108. *
  109. * @return mixed
  110. */
  111. private function getValue($value, $key)
  112. {
  113. if (is_array($value)) {
  114. return $this->getValueFromArray($value, $key);
  115. }
  116. if ($value instanceof ArrayAccess) {
  117. return $this->getValueFromArrayAccess($value, $key);
  118. }
  119. if (is_object($value)) {
  120. return $this->getValueFromObject($value, $key);
  121. }
  122. $message = sprintf('Cannot select the property %s from the given data', $this->getReference());
  123. throw new ComponentException($message);
  124. }
  125. }