This commit is contained in:
2026-05-01 23:40:14 +08:00
commit b8f599a617
3867 changed files with 478663 additions and 0 deletions
@@ -0,0 +1,47 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use ArrayObject as BaseArrayObject;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Collection;
use JsonSerializable;
/**
* @template TKey of array-key
* @template TItem
*
* @extends \ArrayObject<TKey, TItem>
*/
class ArrayObject extends BaseArrayObject implements Arrayable, JsonSerializable
{
/**
* Get a collection containing the underlying array.
*
* @return \Illuminate\Support\Collection
*/
public function collect()
{
return new Collection($this->getArrayCopy());
}
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray()
{
return $this->getArrayCopy();
}
/**
* Get the array that should be JSON serialized.
*
* @return array
*/
public function jsonSerialize(): array
{
return $this->getArrayCopy();
}
}
@@ -0,0 +1,42 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class AsArrayObject implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Database\Eloquent\Casts\ArrayObject<array-key, mixed>, iterable>
*/
public static function castUsing(array $arguments)
{
return new class implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
if (! isset($attributes[$key])) {
return;
}
$data = Json::decode($attributes[$key]);
return is_array($data) ? new ArrayObject($data, ArrayObject::ARRAY_AS_PROPS) : null;
}
public function set($model, $key, $value, $attributes)
{
return [$key => Json::encode($value)];
}
public function serialize($model, string $key, $value, array $attributes)
{
return $value->getArrayCopy();
}
};
}
}
+75
View File
@@ -0,0 +1,75 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\BinaryCodec;
use InvalidArgumentException;
class AsBinary implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @param array{string} $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes
*
* @throws \InvalidArgumentException
*/
public static function castUsing(array $arguments)
{
return new class($arguments) implements CastsAttributes
{
protected string $format;
public function __construct(protected array $arguments)
{
$this->format = $this->arguments[0]
?? throw new InvalidArgumentException('The binary codec format is required.');
if (! in_array($this->format, BinaryCodec::formats(), true)) {
throw new InvalidArgumentException(sprintf(
'Unsupported binary codec format [%s]. Allowed formats are: %s.',
$this->format,
implode(', ', BinaryCodec::formats()),
));
}
}
public function get($model, $key, $value, $attributes)
{
return BinaryCodec::decode($attributes[$key] ?? null, $this->format);
}
public function set($model, $key, $value, $attributes)
{
return [$key => BinaryCodec::encode($value, $this->format)];
}
};
}
/**
* Encode / decode values as binary UUIDs.
*/
public static function uuid(): string
{
return self::class.':uuid';
}
/**
* Encode / decode values as binary ULIDs.
*/
public static function ulid(): string
{
return self::class.':ulid';
}
/**
* Encode / decode values using the given format.
*/
public static function of(string $format): string
{
return self::class.':'.$format;
}
}
@@ -0,0 +1,96 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use InvalidArgumentException;
class AsCollection implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Support\Collection<array-key, mixed>, iterable>
*
* @throws \InvalidArgumentException
*/
public static function castUsing(array $arguments)
{
return new class($arguments) implements CastsAttributes
{
public function __construct(protected array $arguments)
{
$this->arguments = array_pad(array_values($this->arguments), 2, '');
}
public function get($model, $key, $value, $attributes)
{
if (! isset($attributes[$key])) {
return;
}
$data = Json::decode($attributes[$key]);
$collectionClass = empty($this->arguments[0]) ? Collection::class : $this->arguments[0];
if (! is_a($collectionClass, Collection::class, true)) {
throw new InvalidArgumentException('The provided class must extend ['.Collection::class.'].');
}
if (! is_array($data)) {
return null;
}
$instance = new $collectionClass($data);
if (! isset($this->arguments[1]) || ! $this->arguments[1]) {
return $instance;
}
if (is_string($this->arguments[1])) {
$this->arguments[1] = Str::parseCallback($this->arguments[1]);
}
return is_callable($this->arguments[1])
? $instance->map($this->arguments[1])
: $instance->mapInto($this->arguments[1][0]);
}
public function set($model, $key, $value, $attributes)
{
return [$key => Json::encode($value)];
}
};
}
/**
* Specify the type of object each item in the collection should be mapped to.
*
* @param array{class-string, string}|class-string $map
* @return string
*/
public static function of($map)
{
return static::using('', $map);
}
/**
* Specify the collection type for the cast.
*
* @param class-string $class
* @param array{class-string, string}|class-string|null $map
* @return string
*/
public static function using($class, $map = null)
{
if (is_array($map) && is_callable($map)) {
$map = $map[0].'@'.$map[1];
}
return static::class.':'.implode(',', [$class, $map]);
}
}
@@ -0,0 +1,45 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Facades\Crypt;
class AsEncryptedArrayObject implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Database\Eloquent\Casts\ArrayObject<array-key, mixed>, iterable>
*/
public static function castUsing(array $arguments)
{
return new class implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
if (isset($attributes[$key])) {
return new ArrayObject(Json::decode(Crypt::decryptString($attributes[$key])), ArrayObject::ARRAY_AS_PROPS);
}
return null;
}
public function set($model, $key, $value, $attributes)
{
if (! is_null($value)) {
return [$key => Crypt::encryptString(Json::encode($value))];
}
return null;
}
public function serialize($model, string $key, $value, array $attributes)
{
return ! is_null($value) ? $value->getArrayCopy() : null;
}
};
}
}
@@ -0,0 +1,95 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
use InvalidArgumentException;
class AsEncryptedCollection implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Support\Collection<array-key, mixed>, iterable>
*
* @throws \InvalidArgumentException
*/
public static function castUsing(array $arguments)
{
return new class($arguments) implements CastsAttributes
{
public function __construct(protected array $arguments)
{
$this->arguments = array_pad(array_values($this->arguments), 2, '');
}
public function get($model, $key, $value, $attributes)
{
$collectionClass = empty($this->arguments[0]) ? Collection::class : $this->arguments[0];
if (! is_a($collectionClass, Collection::class, true)) {
throw new InvalidArgumentException('The provided class must extend ['.Collection::class.'].');
}
if (! isset($attributes[$key])) {
return null;
}
$instance = new $collectionClass(Json::decode(Crypt::decryptString($attributes[$key])));
if (! isset($this->arguments[1]) || ! $this->arguments[1]) {
return $instance;
}
if (is_string($this->arguments[1])) {
$this->arguments[1] = Str::parseCallback($this->arguments[1]);
}
return is_callable($this->arguments[1])
? $instance->map($this->arguments[1])
: $instance->mapInto($this->arguments[1][0]);
}
public function set($model, $key, $value, $attributes)
{
if (! is_null($value)) {
return [$key => Crypt::encryptString(Json::encode($value))];
}
return null;
}
};
}
/**
* Specify the type of object each item in the collection should be mapped to.
*
* @param array{class-string, string}|class-string $map
* @return string
*/
public static function of($map)
{
return static::using('', $map);
}
/**
* Specify the collection for the cast.
*
* @param class-string $class
* @param array{class-string, string}|class-string|null $map
* @return string
*/
public static function using($class, $map = null)
{
if (is_array($map) && is_callable($map)) {
$map = $map[0].'@'.$map[1];
}
return static::class.':'.implode(',', [$class, $map]);
}
}
@@ -0,0 +1,97 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use BackedEnum;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Collection;
use function Illuminate\Support\enum_value;
class AsEnumArrayObject implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @template TEnum of \UnitEnum
*
* @param array{class-string<TEnum>} $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Database\Eloquent\Casts\ArrayObject<array-key, TEnum>, iterable<TEnum>>
*/
public static function castUsing(array $arguments)
{
return new class($arguments) implements CastsAttributes
{
protected $arguments;
public function __construct(array $arguments)
{
$this->arguments = $arguments;
}
public function get($model, $key, $value, $attributes)
{
if (! isset($attributes[$key])) {
return;
}
$data = Json::decode($attributes[$key]);
if (! is_array($data)) {
return;
}
$enumClass = $this->arguments[0];
return new ArrayObject((new Collection($data))->map(function ($value) use ($enumClass) {
return is_subclass_of($enumClass, BackedEnum::class)
? $enumClass::from($value)
: constant($enumClass.'::'.$value);
})->toArray());
}
public function set($model, $key, $value, $attributes)
{
if ($value === null) {
return [$key => null];
}
$storable = [];
foreach ($value as $enum) {
$storable[] = $this->getStorableEnumValue($enum);
}
return [$key => Json::encode($storable)];
}
public function serialize($model, string $key, $value, array $attributes)
{
return (new Collection($value->getArrayCopy()))
->map(fn ($enum) => $this->getStorableEnumValue($enum))
->toArray();
}
protected function getStorableEnumValue($enum)
{
if (is_string($enum) || is_int($enum)) {
return $enum;
}
return enum_value($enum);
}
};
}
/**
* Specify the Enum for the cast.
*
* @param class-string $class
* @return string
*/
public static function of($class)
{
return static::class.':'.$class;
}
}
@@ -0,0 +1,93 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use BackedEnum;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Collection;
use function Illuminate\Support\enum_value;
class AsEnumCollection implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @template TEnum of \UnitEnum
*
* @param array{class-string<TEnum>} $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Support\Collection<array-key, TEnum>, iterable<TEnum>>
*/
public static function castUsing(array $arguments)
{
return new class($arguments) implements CastsAttributes
{
protected $arguments;
public function __construct(array $arguments)
{
$this->arguments = $arguments;
}
public function get($model, $key, $value, $attributes)
{
if (! isset($attributes[$key])) {
return;
}
$data = Json::decode($attributes[$key]);
if (! is_array($data)) {
return;
}
$enumClass = $this->arguments[0];
return (new Collection($data))->map(function ($value) use ($enumClass) {
return is_subclass_of($enumClass, BackedEnum::class)
? $enumClass::from($value)
: constant($enumClass.'::'.$value);
});
}
public function set($model, $key, $value, $attributes)
{
$value = $value !== null
? Json::encode((new Collection($value))->map(function ($enum) {
return $this->getStorableEnumValue($enum);
})->jsonSerialize())
: null;
return [$key => $value];
}
public function serialize($model, string $key, $value, array $attributes)
{
return (new Collection($value))
->map(fn ($enum) => $this->getStorableEnumValue($enum))
->toArray();
}
protected function getStorableEnumValue($enum)
{
if (is_string($enum) || is_int($enum)) {
return $enum;
}
return enum_value($enum);
}
};
}
/**
* Specify the Enum for the cast.
*
* @param class-string $class
* @return string
*/
public static function of($class)
{
return static::class.':'.$class;
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Fluent;
class AsFluent implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Support\Fluent, string>
*/
public static function castUsing(array $arguments)
{
return new class implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
return isset($value) ? new Fluent(Json::decode($value)) : null;
}
public function set($model, $key, $value, $attributes)
{
return isset($value) ? [$key => Json::encode($value)] : null;
}
};
}
}
@@ -0,0 +1,32 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\HtmlString;
class AsHtmlString implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Support\HtmlString, string|HtmlString>
*/
public static function castUsing(array $arguments)
{
return new class implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
return isset($value) ? new HtmlString($value) : null;
}
public function set($model, $key, $value, $attributes)
{
return isset($value) ? (string) $value : null;
}
};
}
}
@@ -0,0 +1,32 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Stringable;
class AsStringable implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Support\Stringable, string|\Stringable>
*/
public static function castUsing(array $arguments)
{
return new class implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
return isset($value) ? new Stringable($value) : null;
}
public function set($model, $key, $value, $attributes)
{
return isset($value) ? (string) $value : null;
}
};
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Uri;
class AsUri implements Castable
{
/**
* Get the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Support\Uri, string|Uri>
*/
public static function castUsing(array $arguments)
{
return new class implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
return isset($value) ? new Uri($value) : null;
}
public function set($model, $key, $value, $attributes)
{
return isset($value) ? (string) $value : null;
}
};
}
}
+104
View File
@@ -0,0 +1,104 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
class Attribute
{
/**
* The attribute accessor.
*
* @var callable
*/
public $get;
/**
* The attribute mutator.
*
* @var callable
*/
public $set;
/**
* Indicates if caching is enabled for this attribute.
*
* @var bool
*/
public $withCaching = false;
/**
* Indicates if caching of objects is enabled for this attribute.
*
* @var bool
*/
public $withObjectCaching = true;
/**
* Create a new attribute accessor / mutator.
*
* @param callable|null $get
* @param callable|null $set
*/
public function __construct(?callable $get = null, ?callable $set = null)
{
$this->get = $get;
$this->set = $set;
}
/**
* Create a new attribute accessor / mutator.
*
* @param callable|null $get
* @param callable|null $set
* @return static
*/
public static function make(?callable $get = null, ?callable $set = null): static
{
return new static($get, $set);
}
/**
* Create a new attribute accessor.
*
* @param callable $get
* @return static
*/
public static function get(callable $get)
{
return new static($get);
}
/**
* Create a new attribute mutator.
*
* @param callable $set
* @return static
*/
public static function set(callable $set)
{
return new static(null, $set);
}
/**
* Disable object caching for the attribute.
*
* @return static
*/
public function withoutObjectCaching()
{
$this->withObjectCaching = false;
return $this;
}
/**
* Enable caching for the attribute.
*
* @return static
*/
public function shouldCache()
{
$this->withCaching = true;
return $this;
}
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace Illuminate\Database\Eloquent\Casts;
class Json
{
/**
* The custom JSON encoder.
*
* @var callable|null
*/
protected static $encoder;
/**
* The custom JSON decode.
*
* @var callable|null
*/
protected static $decoder;
/**
* Encode the given value.
*/
public static function encode(mixed $value, int $flags = 0): mixed
{
return isset(static::$encoder)
? (static::$encoder)($value, $flags)
: json_encode($value, $flags);
}
/**
* Decode the given value.
*/
public static function decode(mixed $value, ?bool $associative = true): mixed
{
return isset(static::$decoder)
? (static::$decoder)($value, $associative)
: json_decode($value, $associative);
}
/**
* Encode all values using the given callable.
*/
public static function encodeUsing(?callable $encoder): void
{
static::$encoder = $encoder;
}
/**
* Decode all values using the given callable.
*/
public static function decodeUsing(?callable $decoder): void
{
static::$decoder = $decoder;
}
}