vendor/spatie/data-transfer-object/src/DataTransferObject.php line 213

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Spatie\DataTransferObject;
  4. use ReflectionClass;
  5. use ReflectionProperty;
  6. abstract class DataTransferObject
  7. {
  8. protected bool $ignoreMissing = false;
  9. protected array $exceptKeys = [];
  10. protected array $onlyKeys = [];
  11. /**
  12. * @param array $parameters
  13. *
  14. * @return \Spatie\DataTransferObject\ImmutableDataTransferObject|static
  15. */
  16. public static function immutable(array $parameters = []): ImmutableDataTransferObject
  17. {
  18. return new ImmutableDataTransferObject(new static($parameters));
  19. }
  20. /**
  21. * @param array $arrayOfParameters
  22. *
  23. * @return \Spatie\DataTransferObject\ImmutableDataTransferObject[]|static[]
  24. */
  25. public static function arrayOf(array $arrayOfParameters): array
  26. {
  27. return array_map(
  28. function ($parameters) {
  29. return new static($parameters);
  30. },
  31. $arrayOfParameters
  32. );
  33. }
  34. public function __construct(array $parameters = [])
  35. {
  36. $validators = $this->getFieldValidators();
  37. $valueCaster = $this->getValueCaster();
  38. /** string[] */
  39. $invalidTypes = [];
  40. foreach ($validators as $field => $validator) {
  41. if (
  42. ! isset($parameters[$field])
  43. && ! $validator->hasDefaultValue
  44. && ! $validator->isNullable
  45. ) {
  46. throw DataTransferObjectError::uninitialized(
  47. static::class,
  48. $field
  49. );
  50. }
  51. $value = $parameters[$field] ?? $this->{$field} ?? null;
  52. $value = $this->castValue($valueCaster, $validator, $value);
  53. if (! $validator->isValidType($value)) {
  54. $invalidTypes[] = DataTransferObjectError::invalidTypeMessage(
  55. static::class,
  56. $field,
  57. $validator->allowedTypes,
  58. $value
  59. );
  60. continue;
  61. }
  62. $this->{$field} = $value;
  63. unset($parameters[$field]);
  64. }
  65. if ($invalidTypes) {
  66. DataTransferObjectError::invalidTypes($invalidTypes);
  67. }
  68. if (! $this->ignoreMissing && count($parameters)) {
  69. throw DataTransferObjectError::unknownProperties(array_keys($parameters), static::class);
  70. }
  71. }
  72. public function all(): array
  73. {
  74. $data = [];
  75. $class = new ReflectionClass(static::class);
  76. $properties = $class->getProperties(ReflectionProperty::IS_PUBLIC);
  77. foreach ($properties as $reflectionProperty) {
  78. // Skip static properties
  79. if ($reflectionProperty->isStatic()) {
  80. continue;
  81. }
  82. $data[$reflectionProperty->getName()] = $reflectionProperty->getValue($this);
  83. }
  84. return $data;
  85. }
  86. /**
  87. * @param string ...$keys
  88. *
  89. * @return static
  90. */
  91. public function only(string ...$keys): DataTransferObject
  92. {
  93. $dataTransferObject = clone $this;
  94. $dataTransferObject->onlyKeys = [...$this->onlyKeys, ...$keys];
  95. return $dataTransferObject;
  96. }
  97. /**
  98. * @param string ...$keys
  99. *
  100. * @return static
  101. */
  102. public function except(string ...$keys): DataTransferObject
  103. {
  104. $dataTransferObject = clone $this;
  105. $dataTransferObject->exceptKeys = [...$this->exceptKeys, ...$keys];
  106. return $dataTransferObject;
  107. }
  108. public function toArray(): array
  109. {
  110. if (count($this->onlyKeys)) {
  111. $array = Arr::only($this->all(), $this->onlyKeys);
  112. } else {
  113. $array = Arr::except($this->all(), $this->exceptKeys);
  114. }
  115. $array = $this->parseArray($array);
  116. return $array;
  117. }
  118. protected function parseArray(array $array): array
  119. {
  120. foreach ($array as $key => $value) {
  121. if (
  122. $value instanceof DataTransferObject
  123. || $value instanceof DataTransferObjectCollection
  124. ) {
  125. $array[$key] = $value->toArray();
  126. continue;
  127. }
  128. if (! is_array($value)) {
  129. continue;
  130. }
  131. $array[$key] = $this->parseArray($value);
  132. }
  133. return $array;
  134. }
  135. /**
  136. * @param \ReflectionClass $class
  137. *
  138. * @return \Spatie\DataTransferObject\FieldValidator[]
  139. */
  140. protected function getFieldValidators(): array
  141. {
  142. return DTOCache::resolve(static::class, function () {
  143. $class = new ReflectionClass(static::class);
  144. $properties = [];
  145. foreach ($class->getProperties(ReflectionProperty::IS_PUBLIC) as $reflectionProperty) {
  146. // Skip static properties
  147. if ($reflectionProperty->isStatic()) {
  148. continue;
  149. }
  150. $field = $reflectionProperty->getName();
  151. $properties[$field] = FieldValidator::fromReflection($reflectionProperty);
  152. }
  153. return $properties;
  154. });
  155. }
  156. /**
  157. * @param \Spatie\DataTransferObject\ValueCaster $valueCaster
  158. * @param \Spatie\DataTransferObject\FieldValidator $fieldValidator
  159. * @param mixed $value
  160. *
  161. * @return mixed
  162. */
  163. protected function castValue(ValueCaster $valueCaster, FieldValidator $fieldValidator, $value)
  164. {
  165. if (is_array($value)) {
  166. return $valueCaster->cast($value, $fieldValidator);
  167. }
  168. return $value;
  169. }
  170. protected function getValueCaster(): ValueCaster
  171. {
  172. return new ValueCaster();
  173. }
  174. }