uawdijnntqw1x1x1
IP : 216.73.216.8
Hostname : toronto-dev2
Kernel : Linux toronto-dev2 4.15.0-213-generic #224-Ubuntu SMP Mon Jun 19 13:30:12 UTC 2023 x86_64
Disable Function : None :)
OS : Linux
PATH:
/
srv
/
users
/
craft4
/
apps
/
craft4-newsite-space
/
.
/
vendor
/
elvanto
/
..
/
voku
/
arrayy
/
src
/
Mapper
/
Json.php
/
/
<?php namespace Arrayy\Mapper; /** * @category Netresearch * * @license OSL-3.0 http://opensource.org/licenses/osl-3.0 * * @see http://cweiske.de/ * * INFO: this json-mapper is mostly a copy of https://github.com/cweiske/jsonmapper/ * * @internal */ final class Json { /** * Override class names that JsonMapper uses to create objects. * Useful when your setter methods accept abstract classes or interfaces. * * @var array */ public $classMap = []; /** * Callback used when an undefined property is found. * * Works only when $bExceptionOnUndefinedProperty is disabled. * * Parameters to this function are: * 1. Object that is being filled * 2. Name of the unknown JSON property * 3. JSON value of the property * * @var callable */ public $undefinedPropertyHandler; /** * Runtime cache for inspected classes. This is particularly effective if * mapArray() is called with a large number of objects * * @var array property inspection result cache */ private $arInspectedClasses = []; /** * Map data all data in $json into the given $object instance. * * @param object|iterable $json * <p>JSON object structure from json_decode()</p> * @param object|string $object * <p>Object to map $json data into</p> * * @return mixed * <p>mapped object is returned</p> * * @see mapArray() * * @template TObject * @phpstan-param TObject|class-string<TObject> $object * <p>Object to map $json data into.</p> * @phpstan-return TObject * */ public function map($json, $object) { if (\is_string($object) && \class_exists($object)) { $object = self::createInstance($object); } if (!\is_object($object)) { throw new \InvalidArgumentException( 'JsonMapper::map() requires second argument to be an object, ' . \gettype($object) . ' given.' ); } $strClassName = \get_class($object); $rc = new \ReflectionClass($object); $strNs = $rc->getNamespaceName(); foreach ($json as $key => $jsonValue) { $key = $this->getSafeName($key); // Store the property inspection results, so we don't have to do it // again for subsequent objects of the same type. if (!isset($this->arInspectedClasses[$strClassName][$key])) { $this->arInspectedClasses[$strClassName][$key] = $this->inspectProperty($rc, $key); } list( $hasProperty, $accessor, $type ) = $this->arInspectedClasses[$strClassName][$key]; if (!$hasProperty) { if (\is_callable($this->undefinedPropertyHandler)) { \call_user_func( $this->undefinedPropertyHandler, $object, $key, $jsonValue ); } continue; } if ($accessor === null) { continue; } if ($this->isNullable($type)) { if ($jsonValue === null) { $this->setProperty($object, $accessor, null); continue; } $type = $this->removeNullable($type); } elseif ($jsonValue === null) { throw new \InvalidArgumentException( 'JSON property "' . $key . '" in class "' . $strClassName . '" must not be NULL' ); } $type = $this->getFullNamespace($type, $strNs); $type = $this->getMappedType($type, $jsonValue); if ( $type === null || $type === 'mixed' ) { // no given type - simply set the json data $this->setProperty($object, $accessor, $jsonValue); continue; } if ($this->isObjectOfSameType($type, $jsonValue)) { $this->setProperty($object, $accessor, $jsonValue); continue; } if ($this->isSimpleType($type)) { if ($type === 'string' && \is_object($jsonValue)) { throw new \InvalidArgumentException( 'JSON property "' . $key . '" in class "' . $strClassName . '" is an object and cannot be converted to a string' ); } if (\strpos($type, '|') !== false) { foreach (\explode('|', $type) as $tmpType) { if (\gettype($jsonValue) === $tmpType) { \settype($jsonValue, $tmpType); } } } else { \settype($jsonValue, $type); } $this->setProperty($object, $accessor, $jsonValue); continue; } if ($type === '') { throw new \InvalidArgumentException( 'Empty type at property "' . $strClassName . '::$' . $key . '"' ); } $array = null; $subtype = null; if ($this->isArrayOfType($type)) { $array = []; $subtype = \substr($type, 0, -2); } elseif (\substr($type, -1) == ']') { list($proptype, $subtype) = \explode('[', \substr($type, 0, -1)); if ($proptype == 'array') { $array = []; } else { /** @noinspection PhpSillyAssignmentInspection - phpstan helper */ /** @phpstan-var class-string $proptype */ $proptype = $proptype; $array = self::createInstance($proptype, false, $jsonValue); } } elseif (\is_a($type, \ArrayObject::class, true)) { /** @noinspection PhpSillyAssignmentInspection - phpstan helper */ /** @phpstan-var \ArrayObject<array-key, mixed> $type */ $type = $type; $array = self::createInstance($type, false, $jsonValue); } if ($array !== null) { /** @noinspection NotOptimalIfConditionsInspection */ if ( !\is_array($jsonValue) && $this->isScalarType(\gettype($jsonValue)) ) { throw new \InvalidArgumentException( 'JSON property "' . $key . '" must be an array, ' . \gettype($jsonValue) . ' given' ); } $cleanSubtype = $this->removeNullable($subtype); $subtype = $this->getFullNamespace($cleanSubtype, $strNs); $child = $this->mapArray($jsonValue, $array, $subtype, $key); } elseif ($this->isScalarType(\gettype($jsonValue))) { // use constructor parameter if we have a class, but only a flat type (i.e. string, int) /** @noinspection PhpSillyAssignmentInspection - phpstan helper */ /** @phpstan-var object $type */ $type = $type; $child = self::createInstance($type, true, $jsonValue); } else { /** @noinspection PhpSillyAssignmentInspection - phpstan helper */ /** @phpstan-var object $type */ $type = $type; $child = self::createInstance($type, false, $jsonValue); $this->map($jsonValue, $child); } $this->setProperty($object, $accessor, $child); } /** @noinspection PhpSillyAssignmentInspection */ /** @phpstan-var TObject $object */ $object = $object; return $object; } /** * Map an array * * @param array $json JSON array structure from json_decode() * @param mixed $array Array or ArrayObject that gets filled with * data from $json * @param string|null $class Class name for children objects. * All children will get mapped onto this type. * Supports class names and simple types * like "string" and nullability "string|null". * Pass "null" to not convert any values * @param string $parent_key defines the key this array belongs to * in order to aid debugging * * @pslam-param null|class-string $class * * @return mixed Mapped $array is returned */ public function mapArray($json, $array, $class = null, $parent_key = '') { $originalClass = $class; foreach ($json as $key => $jsonValue) { $class = $this->getMappedType($originalClass, $jsonValue); if ($class === null) { $foundArrayy = false; if ($array instanceof \Arrayy\Arrayy && $jsonValue instanceof \stdClass) { foreach ($array->getPhpDocPropertiesFromClass() as $typesKey => $typesTmp) { if ( ( $typesKey === $key || $typesKey === \Arrayy\Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES ) && \count($typesTmp->getTypes()) === 1 && \is_subclass_of($typesTmp->getTypes()[0], \Arrayy\Arrayy::class) ) { $array[$key] = $typesTmp->getTypes()[0]::createFromObjectVars($jsonValue); $foundArrayy = true; break; } } } if ($foundArrayy === false) { if ($array instanceof \Arrayy\Arrayy && $jsonValue instanceof \stdClass) { foreach ($array->getPhpDocPropertiesFromClass() as $typesKey => $typesTmp) { if ( ( $typesKey === $key || $typesKey === \Arrayy\Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES ) && \count($typesTmp->getTypes()) === 1 ) { $array[$key] = $this->map($jsonValue, $typesTmp->getTypes()[0]); $foundArrayy = true; break; } } } if ($foundArrayy === false) { $array[$key] = $jsonValue; } } } elseif ($this->isArrayOfType($class)) { $array[$key] = $this->mapArray( $jsonValue, [], \substr($class, 0, -2) ); } elseif ($this->isScalarType(\gettype($jsonValue))) { // Use constructor parameter if we have a class, but only a flat type (i.e. string, int). if ($jsonValue === null) { $array[$key] = null; } elseif ($this->isSimpleType($class)) { \settype($jsonValue, $class); $array[$key] = $jsonValue; } else { /** @noinspection PhpSillyAssignmentInspection - phpstan helper */ /** @phpstan-var class-string $class */ $class = $class; $array[$key] = self::createInstance( $class, true, $jsonValue ); } } elseif ($this->isScalarType($class)) { throw new \InvalidArgumentException( 'JSON property "' . ($parent_key ?: '?') . '" is an array of type "' . $class . '" but contained a value of type "' . \gettype($jsonValue) . '"' ); } elseif (\is_a($class, \ArrayObject::class, true)) { /** @noinspection PhpSillyAssignmentInspection - phpstan helper */ /** @phpstan-var \ArrayObject<array-key, mixed> $class */ $class = $class; $array[$key] = $this->mapArray( $jsonValue, self::createInstance($class) ); } else { /** @noinspection PhpSillyAssignmentInspection - phpstan helper */ /** @phpstan-var class-string $class */ $class = $class; $array[$key] = $this->map( $jsonValue, self::createInstance($class, false, $jsonValue) ); } } return $array; } /** * Convert a type name to a fully namespaced type name. * * @param string|null $type Type name (simple type or class name) * @param string $strNs Base namespace that gets prepended to the type name * * @return string|null Fully-qualified type name with namespace */ private function getFullNamespace($type, $strNs) { if ( $type === null || $type === '' || $type[0] == '\\' || $strNs == '' ) { return $type; } list($first) = \explode('[', $type, 2); if ( $first === 'mixed' || $this->isSimpleType($first) ) { return $type; } //create a full qualified namespace return '\\' . $strNs . '\\' . $type; } /** * Try to find out if a property exists in a given class. * Checks property first, falls back to setter method. * * @param \ReflectionClass<object> $rc Reflection class to check * @param string $name Property name * * @return array First value: if the property exists * Second value: the accessor to use ( * Array-Key-String or ReflectionMethod or ReflectionProperty, or null) * Third value: type of the property */ private function inspectProperty(\ReflectionClass $rc, $name): array { // now try to set the property directly, we have to look it up in the class hierarchy $class = $rc; $accessor = null; /** @var \Arrayy\Arrayy[] $ARRAYY_CACHE */ /** @phpstan-var array<string, \Arrayy\Arrayy<array-key, mixed>> $ARRAYY_CACHE */ static $ARRAYY_CACHE = []; if (\is_subclass_of($class->name, \Arrayy\Arrayy::class)) { if (!isset($ARRAYY_CACHE[$class->name])) { $ARRAYY_CACHE[$class->name] = new $class->name(); } $tmpProps = $ARRAYY_CACHE[$class->name]->getPhpDocPropertiesFromClass(); if ($tmpProps === []) { return [true, $name, 'mixed']; } foreach ($tmpProps as $tmpName => $tmpProp) { if ($tmpName === $name) { return [true, $name, \implode('|', $tmpProp->getTypes())]; } } } do { if ($class->hasProperty($name)) { $accessor = $class->getProperty($name); } } while ($accessor === null && $class = $class->getParentClass()); if ($accessor === null) { // case-insensitive property matching foreach ($rc->getProperties() as $p) { if ((\strcasecmp($p->name, $name) === 0)) { $accessor = $p; break; } } } if ($accessor !== null) { if ($accessor->isPublic()) { $docblock = $accessor->getDocComment(); if ($docblock === false) { return [true, null, null]; } $annotations = self::parseAnnotations($docblock); if (!isset($annotations['var'][0])) { return [true, $accessor, null]; } // support "@var type description" list($type) = \explode(' ', $annotations['var'][0]); return [true, $accessor, $type]; } // no private property return [true, null, null]; } // no setter, no property return [false, null, null]; } /** * Copied from PHPUnit 3.7.29, Util/Test.php * * @param string $docblock Full method docblock * * @return array */ private static function parseAnnotations($docblock): array { // init $annotations = []; // Strip away the docblock header and footer // to ease parsing of one line annotations $docblock = \substr($docblock, 3, -2); $re = '/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m'; if (\preg_match_all($re, $docblock, $matches)) { $numMatches = \count($matches[0]); for ($i = 0; $i < $numMatches; ++$i) { $annotations[$matches['name'][$i]][] = $matches['value'][$i]; } } return $annotations; } /** * Removes - and _ and makes the next letter uppercase * * @param string $name Property name * * @return string CamelCasedVariableName */ private function getCamelCaseName($name): string { return \str_replace( ' ', '', \ucwords(\str_replace(['_', '-'], ' ', $name)) ); } /** * Since hyphens cannot be used in variables we have to uppercase them. * * Technically you may use them, but they are awkward to access. * * @param string $name Property name * * @return string Name without hyphen */ private function getSafeName($name): string { $convertHyphens = \strpos($name, '-') !== false; $convertSnake = \strpos($name, '_') !== false; if ($convertHyphens || $convertSnake) { $name = $this->getCamelCaseName($name); } return $name; } /** * Set a property on a given object to a given value. * * Checks if the setter or the property are public are made before * calling this method. * * @param \Arrayy\Arrayy|object $object Object to set property on * @param \ReflectionMethod|\ReflectionProperty|string $accessor Array-Key-String or ReflectionMethod or ReflectionProperty * @param mixed $value Value of property * * @return void */ private function setProperty( $object, $accessor, $value ) { if (\is_string($accessor) && $object instanceof \Arrayy\Arrayy) { $object[$accessor] = $value; } elseif ($accessor instanceof \ReflectionProperty) { $accessor->setValue($object, $value); } elseif ($accessor instanceof \ReflectionMethod) { // setter method $accessor->invoke($object, $value); } } /** * Get the mapped class/type name for this class. * Returns the incoming classname if not mapped. * * @param string|null $type Type name to map * @param mixed $jsonValue Constructor parameter (the json value) * * @return string|null The mapped type/class name * * @phpstan-return class-string|string|null */ private function getMappedType($type, $jsonValue = null) { if (isset($this->classMap[$type])) { $target = $this->classMap[$type]; } elseif ( \is_string($type) && $type !== '' && $type[0] == '\\' && isset($this->classMap[\substr($type, 1)]) ) { $target = $this->classMap[\substr($type, 1)]; } else { $target = null; } if ($target) { if (\is_callable($target)) { $type = $target($type, $jsonValue); } else { $type = $target; } } return $type; } /** * Checks if the given type is a "simple type" * * @param string $type type name from gettype() * * @return bool True if it is a simple PHP type * * @see isScalarType() */ private function isSimpleType($type): bool { if (\strpos($type, '|') !== false) { foreach (\explode('|', $type) as $tmpType) { if ($this->isSimpleType($tmpType)) { return true; } } } /** @noinspection InArrayCanBeUsedInspection */ return $type == 'string' || $type == 'boolean' || $type == 'bool' || $type == 'integer' || $type == 'int' || $type == 'int' || $type == 'double' || $type == 'float' || $type == 'array' || $type == 'object'; } /** * Checks if the object is of this type or has this type as one of its parents * * @param string $type class name of type being required * @param mixed $value Some PHP value to be tested * * @return bool True if $object has type of $type */ private function isObjectOfSameType($type, $value): bool { if (\is_object($value) === false) { return false; } return \is_a($value, $type); } /** * Checks if the given type is a type that is not nested * (simple type except array and object) * * @param string $type type name from gettype() * * @return bool True if it is a non-nested PHP type * * @see isSimpleType() */ private function isScalarType($type): bool { /** @noinspection InArrayCanBeUsedInspection */ return $type == 'NULL' || $type == 'string' || $type == 'boolean' || $type == 'bool' || $type == 'integer' || $type == 'int' || $type == 'double' || $type == 'float'; } /** * Returns true if type is an array of elements * (bracket notation) * * @param string $strType type to be matched * * @return bool */ private function isArrayOfType($strType): bool { return \substr($strType, -2) === '[]'; } /** * Checks if the given type is nullable * * @param string $type type name from the phpdoc param * * @return bool True if it is nullable */ private function isNullable($type): bool { return \stripos('|' . $type . '|', '|null|') !== false; } /** * Remove the 'null' section of a type * * @param false|string|null $type type name from the phpdoc param * * @return string|null The new type value */ private function removeNullable($type) { if ($type === null || $type === false) { return null; } return \substr( \str_ireplace('|null|', '|', '|' . $type . '|'), 1, -1 ); } /** * Create a new object of the given type. * * This method exists to be overwritten in child classes, * so you can do dependency injection or so. * * @param object|string $class * <p>Class name to instantiate</p> * @param bool $useParameter * <p>Pass $parameter to the constructor or not</p> * @param mixed $jsonValue * <p>Constructor parameter (the json value)</p> * * @return object * <p>Freshly created object</p> * * @internal * * @template TClass * @phpstan-param TClass|class-string<TClass> $class * @phpstan-return TClass */ private static function createInstance( $class, bool $useParameter = false, $jsonValue = null ) { if ($useParameter) { /** @phpstan-var TClass $return */ $return = new $class($jsonValue); return $return; } $reflectClass = new \ReflectionClass($class); $constructor = $reflectClass->getConstructor(); if ( $constructor === null || $constructor->getNumberOfRequiredParameters() > 0 ) { /** @phpstan-var TClass $return */ $return = $reflectClass->newInstanceWithoutConstructor(); } else { /** @phpstan-var TClass $return */ $return = $reflectClass->newInstance(); } return $return; } }
/srv/users/craft4/apps/craft4-newsite-space/./vendor/elvanto/../voku/arrayy/src/Mapper/Json.php