File manager - Edit - /home/watersyst/public_html/wp-includes/blocks/comment-content/Common.zip
Back
PK E/�\���1^ ^ % Contracts/WithJsonSchemaInterface.phpnu �[��� <?php declare (strict_types=1); namespace WordPress\AiClient\Common\Contracts; /** * Interface for objects that can provide their JSON schema representation. * * This interface is implemented by DTOs to provide a consistent way to retrieve * their JSON schema for validation and serialization purposes. * * @since 0.1.0 */ interface WithJsonSchemaInterface { /** * Gets the JSON schema representation of the object. * * @since 0.1.0 * * @return array<string, mixed> The JSON schema as an associative array. */ public static function getJsonSchema(): array; } PK E/�\=�5�W W ( Contracts/AiClientExceptionInterface.phpnu �[��� <?php declare (strict_types=1); namespace WordPress\AiClient\Common\Contracts; use Throwable; /** * Base interface for all AI Client exceptions. * * This interface allows callers to catch all AI Client specific exceptions * with a single catch statement. * * @since 0.2.0 */ interface AiClientExceptionInterface extends Throwable { } PK E/�\�ED�b b ! Contracts/CachesDataInterface.phpnu �[��� <?php declare (strict_types=1); namespace WordPress\AiClient\Common\Contracts; /** * Interface for objects that cache data. * * @since 0.4.0 */ interface CachesDataInterface { /** * Invalidates all caches managed by this object. * * @since 0.4.0 * * @return void */ public function invalidateCaches(): void; } PK E/�\ꬖD . Contracts/WithArrayTransformationInterface.phpnu �[��� <?php declare (strict_types=1); namespace WordPress\AiClient\Common\Contracts; /** * Interface for objects that support array transformation. * * @since 0.1.0 * * @template TArrayShape of array<string, mixed> */ interface WithArrayTransformationInterface { /** * Converts the object to an array representation. * * @since 0.1.0 * * @return TArrayShape The array representation. */ public function toArray(): array; /** * Creates an instance from array data. * * @since 0.1.0 * * @param TArrayShape $array The array data. * @return self<TArrayShape> The created instance. */ public static function fromArray(array $array): self; /** * Checks if the array is a valid shape for this object. * * @since 0.1.0 * * @param array<mixed> $array The array to check. * @return bool True if the array is a valid shape. * @phpstan-assert-if-true TArrayShape $array */ public static function isArrayShape(array $array): bool; } PK E/�\ �µ} } AbstractDataTransferObject.phpnu �[��� <?php declare (strict_types=1); namespace WordPress\AiClient\Common; use JsonSerializable; use stdClass; use WordPress\AiClient\Common\Contracts\WithArrayTransformationInterface; use WordPress\AiClient\Common\Contracts\WithJsonSchemaInterface; use WordPress\AiClient\Common\Exception\InvalidArgumentException; /** * Abstract base class for all Data Value Objects in the AI Client. * * This abstract class consolidates the common functionality needed by all * data transfer objects: * - Array transformation for data manipulation * - JSON schema support for validation and documentation * - JSON serialization with proper empty object handling * * All DTOs in the AI Client should extend this class to ensure * consistent behavior across the codebase. * * @since 0.1.0 * * @template TArrayShape of array<string, mixed> * @implements WithArrayTransformationInterface<TArrayShape> */ abstract class AbstractDataTransferObject implements WithArrayTransformationInterface, WithJsonSchemaInterface, JsonSerializable { /** * Validates that required keys exist in the array data. * * @since 0.1.0 * * @param array<mixed> $data The array data to validate. * @param string[] $requiredKeys The keys that must be present. * @throws InvalidArgumentException If any required key is missing. */ protected static function validateFromArrayData(array $data, array $requiredKeys): void { $missingKeys = []; foreach ($requiredKeys as $key) { if (!array_key_exists($key, $data)) { $missingKeys[] = $key; } } if (!empty($missingKeys)) { throw new InvalidArgumentException(sprintf('%s::fromArray() missing required keys: %s', static::class, implode(', ', $missingKeys))); } } /** * {@inheritDoc} * * @since 0.1.0 */ public static function isArrayShape(array $array): bool { try { /** @var TArrayShape $array */ static::fromArray($array); return \true; } catch (InvalidArgumentException $e) { return \false; } } /** * Converts the object to a JSON-serializable format. * * This method uses the toArray() method and then processes the result * based on the JSON schema to ensure proper object representation for * empty arrays. * * @since 0.1.0 * * @return mixed The JSON-serializable representation. */ #[\ReturnTypeWillChange] public function jsonSerialize() { $data = $this->toArray(); $schema = static::getJsonSchema(); return $this->convertEmptyArraysToObjects($data, $schema); } /** * Recursively converts empty arrays to stdClass objects where the schema expects objects. * * @since 0.1.0 * * @param mixed $data The data to process. * @param array<mixed, mixed> $schema The JSON schema for the data. * @return mixed The processed data. */ private function convertEmptyArraysToObjects($data, array $schema) { // If data is an empty array and schema expects object, convert to stdClass if (is_array($data) && empty($data) && isset($schema['type']) && $schema['type'] === 'object') { return new stdClass(); } // If data is an array with content, recursively process nested structures if (is_array($data)) { // Handle object properties if (isset($schema['properties']) && is_array($schema['properties'])) { foreach ($data as $key => $value) { if (isset($schema['properties'][$key]) && is_array($schema['properties'][$key])) { $data[$key] = $this->convertEmptyArraysToObjects($value, $schema['properties'][$key]); } } } // Handle array items if (isset($schema['items']) && is_array($schema['items'])) { foreach ($data as $index => $item) { $data[$index] = $this->convertEmptyArraysToObjects($item, $schema['items']); } } // Handle oneOf/anyOf schemas - just use the first one foreach (['oneOf', 'anyOf'] as $keyword) { if (isset($schema[$keyword]) && is_array($schema[$keyword])) { foreach ($schema[$keyword] as $possibleSchema) { if (is_array($possibleSchema)) { return $this->convertEmptyArraysToObjects($data, $possibleSchema); } } } } } return $data; } } PK E/�\�`]� � Traits/WithDataCachingTrait.phpnu �[��� <?php declare (strict_types=1); namespace WordPress\AiClient\Common\Traits; use WordPress\AiClient\AiClient; /** * Trait for objects that cache data using PSR-16 cache with in-memory fallback. * * When a PSR-16 cache is configured via AiClient::setCache(), data is stored persistently. * Otherwise, data is cached in-memory for the duration of the request. * * @since 0.4.0 */ trait WithDataCachingTrait { /** * In-memory cache used when no PSR-16 cache is configured. * * @since 0.4.0 * * @var array<string, mixed> */ private array $localCache = []; /** * Gets the cache key suffixes managed by this object. * * @since 0.4.0 * * @return list<string> The cache key suffixes. */ abstract protected function getCachedKeys(): array; /** * Gets the base cache key for this object. * * The base cache key is used as a prefix for all cache keys managed by this object. * It should be unique to the implementing class to avoid cache key collisions. * * @since 0.4.0 * * @return string The base cache key. */ abstract protected function getBaseCacheKey(): string; /** * Checks if a value exists in the cache. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @return bool True if the value exists in cache, false otherwise. */ protected function hasCache(string $key): bool { $fullKey = $this->buildCacheKey($key); $cache = AiClient::getCache(); if ($cache !== null) { return $cache->has($fullKey); } return array_key_exists($fullKey, $this->localCache); } /** * Gets a value from the cache, or computes and caches it if not present. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @param callable $callback The callback to compute the value if not cached. * @param int|\DateInterval|null $ttl The TTL for the cache entry, or null for default. * Ignored for local cache. * @return mixed The cached or computed value. */ protected function cached(string $key, callable $callback, $ttl = null) { if ($this->hasCache($key)) { return $this->getCache($key); } $value = $callback(); $this->setCache($key, $value, $ttl); return $value; } /** * Gets a value from the cache. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @param mixed $default The default value to return if the key does not exist. * @return mixed The cached value or the default value if not found. */ protected function getCache(string $key, $default = null) { $fullKey = $this->buildCacheKey($key); $cache = AiClient::getCache(); if ($cache !== null) { return $cache->get($fullKey, $default); } return $this->localCache[$fullKey] ?? $default; } /** * Sets a value in the cache. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @param mixed $value The value to cache. * @param int|\DateInterval|null $ttl The TTL for the cache entry, or null for default. Ignored for local cache. * @return bool True on success, false on failure. */ protected function setCache(string $key, $value, $ttl = null): bool { $fullKey = $this->buildCacheKey($key); $cache = AiClient::getCache(); if ($cache !== null) { return $cache->set($fullKey, $value, $ttl); } $this->localCache[$fullKey] = $value; return \true; } /** * Invalidates all caches managed by this object. * * @since 0.4.0 * * @return void */ public function invalidateCaches(): void { foreach ($this->getCachedKeys() as $key) { $this->clearCache($key); } } /** * Clears a value from the cache. * * @since 0.4.0 * * @param string $key The cache key suffix (will be appended to the base key). * @return bool True on success, false on failure. */ protected function clearCache(string $key): bool { $fullKey = $this->buildCacheKey($key); $cache = AiClient::getCache(); if ($cache !== null) { return $cache->delete($fullKey); } unset($this->localCache[$fullKey]); return \true; } /** * Builds the full cache key by combining the base key with the suffix. * * @since 0.4.0 * * @param string $key The cache key suffix. * @return string The full cache key. */ private function buildCacheKey(string $key): string { return $this->getBaseCacheKey() . '_' . $key; } } PK E/�\�M3Vp, p, AbstractEnum.phpnu �[��� <?php declare (strict_types=1); namespace WordPress\AiClient\Common; use BadMethodCallException; use JsonSerializable; use ReflectionClass; use WordPress\AiClient\Common\Exception\InvalidArgumentException; use WordPress\AiClient\Common\Exception\RuntimeException; /** * Abstract base class for enum-like behavior in PHP 7.4. * * This class provides enum-like functionality for PHP versions that don't support native enums. * Child classes should define uppercase snake_case constants for enum values. * * @example * class PersonEnum extends AbstractEnum { * public const FIRST_NAME = 'first'; * public const LAST_NAME = 'last'; * } * * // Usage: * $enum = PersonEnum::from('first'); // Creates instance with value 'first' * $enum = PersonEnum::tryFrom('invalid'); // Returns null * $enum = PersonEnum::firstName(); // Creates instance with value 'first' * $enum->name; // 'FIRST_NAME' * $enum->value; // 'first' * $enum->equals('first'); // Returns true * $enum->is(PersonEnum::firstName()); // Returns true * PersonEnum::cases(); // Returns array of all enum instances * * @property-read string $value The value of the enum instance. * @property-read string $name The name of the enum constant. * * @since 0.1.0 */ abstract class AbstractEnum implements JsonSerializable { /** * @var string The value of the enum instance. */ private string $value; /** * @var string The name of the enum constant. */ private string $name; /** * @var array<string, array<string, string>> Cache for reflection data. */ private static array $cache = []; /** * @var array<string, array<string, self>> Cache for enum instances. */ private static array $instances = []; /** * Constructor is private to ensure instances are created through static methods. * * @since 0.1.0 * * @param string $value The enum value. * @param string $name The constant name. */ final private function __construct(string $value, string $name) { $this->value = $value; $this->name = $name; } /** * Provides read-only access to properties. * * @since 0.1.0 * * @param string $property The property name. * @return mixed The property value. * @throws BadMethodCallException If property doesn't exist. */ final public function __get(string $property) { if ($property === 'value' || $property === 'name') { return $this->{$property}; } throw new BadMethodCallException(sprintf('Property %s::%s does not exist', static::class, $property)); } /** * Prevents property modification. * * @since 0.1.0 * * @param string $property The property name. * @param mixed $value The value to set. * @throws BadMethodCallException Always, as enum properties are read-only. */ final public function __set(string $property, $value): void { throw new BadMethodCallException(sprintf('Cannot modify property %s::%s - enum properties are read-only', static::class, $property)); } /** * Creates an enum instance from a value, throws exception if invalid. * * @since 0.1.0 * * @param string $value The enum value. * @return static The enum instance. * @throws InvalidArgumentException If the value is not valid. */ final public static function from(string $value): self { $instance = self::tryFrom($value); if ($instance === null) { throw new InvalidArgumentException(sprintf('%s is not a valid backing value for enum %s', $value, static::class)); } return $instance; } /** * Tries to create an enum instance from a value, returns null if invalid. * * @since 0.1.0 * * @param string $value The enum value. * @return static|null The enum instance or null. */ final public static function tryFrom(string $value): ?self { $constants = static::getConstants(); foreach ($constants as $name => $constantValue) { if ($constantValue === $value) { return self::getInstance($constantValue, $name); } } return null; } /** * Gets all enum cases. * * @since 0.1.0 * * @return static[] Array of all enum instances. */ final public static function cases(): array { $cases = []; $constants = static::getConstants(); foreach ($constants as $name => $value) { $cases[] = self::getInstance($value, $name); } return $cases; } /** * Checks if this enum has the same value as the given value. * * @since 0.1.0 * * @param string|self $other The value or enum to compare. * @return bool True if values are equal. */ final public function equals($other): bool { if ($other instanceof self) { return $this->is($other); } return $this->value === $other; } /** * Checks if this enum is the same instance type and value as another enum. * * @since 0.1.0 * * @param self $other The other enum to compare. * @return bool True if enums are identical. */ final public function is(self $other): bool { return $this === $other; // Since we're using singletons, we can use identity comparison } /** * Gets all valid values for this enum. * * @since 0.1.0 * * @return string[] List of all enum values. */ final public static function getValues(): array { return array_values(static::getConstants()); } /** * Checks if a value is valid for this enum. * * @since 0.1.0 * * @param string $value The value to check. * @return bool True if value is valid. */ final public static function isValidValue(string $value): bool { return in_array($value, self::getValues(), \true); } /** * Gets or creates a singleton instance for the given value and name. * * @since 0.1.0 * * @param string $value The enum value. * @param string $name The constant name. * @return static The enum instance. */ private static function getInstance(string $value, string $name): self { $className = static::class; if (!isset(self::$instances[$className])) { self::$instances[$className] = []; } if (!isset(self::$instances[$className][$name])) { $instance = new $className($value, $name); self::$instances[$className][$name] = $instance; } /** @var static */ return self::$instances[$className][$name]; } /** * Gets all constants for this enum class. * * @since 0.1.0 * * @return array<string, string> Map of constant names to values. * @throws RuntimeException If invalid constant found. */ final protected static function getConstants(): array { $className = static::class; if (!isset(self::$cache[$className])) { self::$cache[$className] = static::determineClassEnumerations($className); } return self::$cache[$className]; } /** * Determines the class enumerations by reflecting on class constants. * * This method can be overridden by subclasses to customize how * enumerations are determined (e.g., to add dynamic constants). * * @since 0.1.0 * * @param class-string $className The fully qualified class name. * @return array<string, string> Map of constant names to values. * @throws RuntimeException If invalid constant found. */ protected static function determineClassEnumerations(string $className): array { $reflection = new ReflectionClass($className); $constants = $reflection->getConstants(); // Validate all constants $enumConstants = []; foreach ($constants as $name => $value) { // Check if constant name follows uppercase snake_case pattern if (!preg_match('/^[A-Z][A-Z0-9_]*$/', $name)) { throw new RuntimeException(sprintf('Invalid enum constant name "%s" in %s. Constants must be UPPER_SNAKE_CASE.', $name, $className)); } // Check if value is valid type if (!is_string($value)) { throw new RuntimeException(sprintf('Invalid enum value type for constant %s::%s. ' . 'Only string values are allowed, %s given.', $className, $name, gettype($value))); } $enumConstants[$name] = $value; } return $enumConstants; } /** * Handles dynamic method calls for enum checking. * * @since 0.1.0 * * @param string $name The method name. * @param array<mixed> $arguments The method arguments. * @return bool True if the enum value matches. * @throws BadMethodCallException If the method doesn't exist. */ final public function __call(string $name, array $arguments): bool { // Handle is* methods if (str_starts_with($name, 'is')) { $constantName = self::camelCaseToConstant(substr($name, 2)); $constants = static::getConstants(); if (isset($constants[$constantName])) { return $this->value === $constants[$constantName]; } } throw new BadMethodCallException(sprintf('Method %s::%s does not exist', static::class, $name)); } /** * Handles static method calls for enum creation. * * @since 0.1.0 * * @param string $name The method name. * @param array<mixed> $arguments The method arguments. * @return static The enum instance. * @throws BadMethodCallException If the method doesn't exist. */ final public static function __callStatic(string $name, array $arguments): self { $constantName = self::camelCaseToConstant($name); $constants = static::getConstants(); if (isset($constants[$constantName])) { return self::getInstance($constants[$constantName], $constantName); } throw new BadMethodCallException(sprintf('Method %s::%s does not exist', static::class, $name)); } /** * Converts camelCase to CONSTANT_CASE. * * @since 0.1.0 * * @param string $camelCase The camelCase string. * @return string The CONSTANT_CASE version. */ private static function camelCaseToConstant(string $camelCase): string { $snakeCase = preg_replace('/([a-z])([A-Z])/', '$1_$2', $camelCase); if ($snakeCase === null) { return strtoupper($camelCase); } return strtoupper($snakeCase); } /** * Returns string representation of the enum. * * @since 0.1.0 * * @return string The enum value. */ final public function __toString(): string { return $this->value; } /** * Converts the enum to a JSON-serializable format. * * @since 0.1.0 * * @return string The enum value. */ #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->value; } } PK E/�\PX�c� � &