Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/vendor/yoomoney/yookassa-sdk-php/lib/Common/ |
Upload File : |
<?php /* * The MIT License * * Copyright (c) 2025 "YooMoney", NBСO LLC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ namespace YooKassa\Common; use ArrayAccess; use DateTime; use JsonSerializable; use ReturnTypeWillChange; use Traversable; use YooKassa\Helpers\TypeCast; use YooKassa\Validator\Constraints as Assert; use YooKassa\Validator\Validator; if (!defined('YOOKASSA_DATE')) { define('YOOKASSA_DATE', 'Y-m-d\\TH:i:s.v\\Z'); } /** * Класс, представляющий модель AbstractObject. * * Базовый класс генерируемых объектов. * * @category Class * @package YooKassa * @author cms@yoomoney.ru * @link https://yookassa.ru/developers/api */ abstract class AbstractObject implements ArrayAccess, JsonSerializable { /** * @var Validator Валидатор данных */ private Validator $validator; /** * @var array Свойства установленные пользователем */ private array $unknownProperties = []; /** * AbstractObject constructor. * @param array|null $data */ public function __construct(?array $data = []) { $this->validator = new Validator($this); if (!empty($data) && is_array($data)) { $this->fromArray($data); } } /** * Возвращает значение свойства. * * @param string $propertyName Имя свойства * * @return mixed Значение свойства */ public function __get(string $propertyName): mixed { return $this->offsetGet($propertyName); } /** * Устанавливает значение свойства. * * @param string $propertyName Имя свойства * @param mixed $value Значение свойства */ public function __set(string $propertyName, mixed $value): void { $this->offsetSet($propertyName, $value); } /** * Проверяет наличие свойства. * * @param string $propertyName Имя проверяемого свойства * * @return bool True если свойство имеется, false если нет */ public function __isset(string $propertyName): bool { return $this->offsetExists($propertyName); } /** * Удаляет свойство. * * @param string $propertyName Имя удаляемого свойства */ public function __unset(string $propertyName): void { $this->offsetUnset($propertyName); } #[ReturnTypeWillChange] /** * Проверяет наличие свойства. * * @param string $offset Имя проверяемого свойства * * @return bool True если свойство имеется, false если нет */ public function offsetExists(mixed $offset): bool { $method = 'get' . ucfirst($offset); if (method_exists($this, $method)) { return true; } $method = 'get' . self::matchPropertyName($offset); if (method_exists($this, $method)) { return true; } return array_key_exists($offset, $this->unknownProperties); } #[ReturnTypeWillChange] /** * Возвращает значение свойства. * * @param string $offset Имя свойства * * @return mixed Значение свойства */ public function offsetGet(mixed $offset): mixed { if ($offset === 'validator') { return null; } $method = 'get' . ucfirst($offset); if (method_exists($this, $method)) { return $this->{$method}(); } $method = 'get' . self::matchPropertyName($offset); if (method_exists($this, $method)) { return $this->{$method}(); } return $this->unknownProperties[$offset] ?? null; } #[ReturnTypeWillChange] /** * Устанавливает значение свойства. * * @param string $offset Имя свойства * @param mixed $value Значение свойства */ public function offsetSet(mixed $offset, mixed $value): void { if ($offset === 'validator') { return; } $method = 'set' . ucfirst($offset); if (method_exists($this, $method)) { $this->{$method}($value); } else { $method = 'set' . self::matchPropertyName($offset); if (method_exists($this, $method)) { $this->{$method}($value); } else { $this->unknownProperties[$offset] = $value; } } } #[ReturnTypeWillChange] /** * Удаляет свойство. * * @param string $offset Имя удаляемого свойства */ public function offsetUnset(mixed $offset): void { if ($offset === 'validator') { return; } $method = 'set' . ucfirst($offset); if (method_exists($this, $method)) { $this->{$method}(null); } else { $method = 'set' . self::matchPropertyName($offset); if (method_exists($this, $method)) { $this->{$method}(null); } else { unset($this->unknownProperties[$offset]); } } } /** * Устанавливает значения свойств текущего объекта из массива. * * @param array|Traversable $sourceArray Ассоциативный массив с настройками */ public function fromArray(iterable $sourceArray): void { foreach ($sourceArray as $key => $value) { $this->offsetSet($key, $value); } } /** * Возвращает ассоциативный массив со свойствами текущего объекта для его дальнейшей JSON сериализации * Является алиасом метода AbstractObject::jsonSerialize(). * * @return array Ассоциативный массив со свойствами текущего объекта */ public function toArray(): array { return $this->jsonSerialize(); } #[ReturnTypeWillChange] /** * Возвращает ассоциативный массив со свойствами текущего объекта для его дальнейшей JSON сериализации. * * @return array Ассоциативный массив со свойствами текущего объекта */ public function jsonSerialize(): array { $excludedMethods = ['getUnknownProperties', 'getIterator', 'getValidator']; $result = []; foreach (get_class_methods($this) as $method) { if (0 === strncmp('get', $method, 3)) { if (in_array($method, $excludedMethods)) { continue; } $property = strtolower(preg_replace('/[A-Z]/', '_\0', lcfirst(substr($method, 3)))); $value = $this->serializeValueToJson($this->{$method}()); if (null !== $value) { $result[$property] = $value; } } } if (!empty($this->unknownProperties)) { foreach ($this->unknownProperties as $property => $value) { if (!array_key_exists($property, $result)) { $result[$property] = $this->serializeValueToJson($value); } } } return $result; } /** * Возвращает массив свойств которые не существуют, но были заданы у объекта. * * @return array Ассоциативный массив с не существующими у текущего объекта свойствами */ protected function getUnknownProperties(): array { return $this->unknownProperties; } private function serializeValueToJson($value) { if (null === $value || is_scalar($value)) { return $value; } if (is_array($value)) { $array = []; foreach ($value as $key => $item) { if ('validator' === $key) { continue; } $array[$key] = $this->serializeValueToJson($item); } return $array; } if ($value instanceof JsonSerializable) { if ($value instanceof ListObjectInterface && $value->isEmpty()) { return null; } return $value->jsonSerialize(); } if ($value instanceof DateTime) { return $value->format(YOOKASSA_DATE); } return $value; } /** * Преобразует имя свойства из snake_case в camelCase. * * @param string $property Преобразуемое значение * * @return string Значение в камэл кейсе */ private static function matchPropertyName(string $property): string { return preg_replace('/_(\w)/', '\1', $property); } /** * @return Validator */ public function getValidator(): Validator { return $this->validator; } /** * @param string $propertyName * @param mixed $propertyValue * @return mixed */ protected function validatePropertyValue(string $propertyName, mixed $propertyValue): mixed { $propertyValue = $this->prepareTypeValue($propertyName, $propertyValue); $this->getValidator()->validatePropertyValue($propertyName, $propertyValue); return $propertyValue; } /** * @param string $propertyName * @param mixed $propertyValue * @return mixed */ private function prepareTypeValue(string $propertyName, mixed $propertyValue): mixed { $finalType = null; $allType = null; foreach ($this->getValidator()->getRulesByPropName($propertyName) ?? [] as $rule) { switch (true) { case $rule instanceof Assert\Type: $finalType = $rule->getType(); break; case $rule instanceof Assert\AllType: $allType = $rule->getType(); break; } } if ($finalType === 'DateTime' && is_string($propertyValue) && TypeCast::canCastToDateTime($propertyValue)) { $this->getValidator()->validatePropertyValue($propertyName, $propertyValue, [Assert\Type::class]); return TypeCast::castToDateTime($propertyValue) ?: $propertyValue; } if ((is_string($propertyValue) || is_array($propertyValue)) && empty($propertyValue) && $propertyValue !== '0') { return null; } if (!is_null($allType) && is_array($propertyValue) && $finalType === ListObject::class && class_exists($allType)) { return new ListObject($allType, $propertyValue); } if (is_array($propertyValue) && class_exists($finalType) && new $finalType instanceof self) { return new $finalType($propertyValue); } return $propertyValue; } }