| <?php |
| |
| /** |
| * This file is part of the Carbon package. |
| * |
| * (c) Brian Nesbitt <brian@nesbot.com> |
| * |
| * For the full copyright and license information, please view the LICENSE |
| * file that was distributed with this source code. |
| */ |
| namespace Carbon\Traits; |
| |
| use Carbon\Exceptions\InvalidFormatException; |
| use ReturnTypeWillChange; |
| use Throwable; |
| |
| /** |
| * Trait Serialization. |
| * |
| * Serialization and JSON stuff. |
| * |
| * Depends on the following properties: |
| * |
| * @property int $year |
| * @property int $month |
| * @property int $daysInMonth |
| * @property int $quarter |
| * |
| * Depends on the following methods: |
| * |
| * @method string|static locale(string $locale = null, string ...$fallbackLocales) |
| * @method string toJSON() |
| */ |
| trait Serialization |
| { |
| use ObjectInitialisation; |
| |
| /** |
| * The custom Carbon JSON serializer. |
| * |
| * @var callable|null |
| */ |
| protected static $serializer; |
| |
| /** |
| * List of key to use for dump/serialization. |
| * |
| * @var string[] |
| */ |
| protected $dumpProperties = ['date', 'timezone_type', 'timezone']; |
| |
| /** |
| * Locale to dump comes here before serialization. |
| * |
| * @var string|null |
| */ |
| protected $dumpLocale; |
| |
| /** |
| * Embed date properties to dump in a dedicated variables so it won't overlap native |
| * DateTime ones. |
| * |
| * @var array|null |
| */ |
| protected $dumpDateProperties; |
| |
| /** |
| * Return a serialized string of the instance. |
| * |
| * @return string |
| */ |
| public function serialize() |
| { |
| return serialize($this); |
| } |
| |
| /** |
| * Create an instance from a serialized string. |
| * |
| * @param string $value |
| * |
| * @throws InvalidFormatException |
| * |
| * @return static |
| */ |
| public static function fromSerialized($value) |
| { |
| $instance = @unserialize((string) $value); |
| |
| if (!$instance instanceof static) { |
| throw new InvalidFormatException("Invalid serialized value: $value"); |
| } |
| |
| return $instance; |
| } |
| |
| /** |
| * The __set_state handler. |
| * |
| * @param string|array $dump |
| * |
| * @return static |
| */ |
| #[ReturnTypeWillChange] |
| public static function __set_state($dump) |
| { |
| if (\is_string($dump)) { |
| return static::parse($dump); |
| } |
| |
| /** @var \DateTimeInterface $date */ |
| $date = get_parent_class(static::class) && method_exists(parent::class, '__set_state') |
| ? parent::__set_state((array) $dump) |
| : (object) $dump; |
| |
| return static::instance($date); |
| } |
| |
| /** |
| * Returns the list of properties to dump on serialize() called on. |
| * |
| * @return array |
| */ |
| public function __sleep() |
| { |
| $properties = $this->getSleepProperties(); |
| |
| if ($this->localTranslator ?? null) { |
| $properties[] = 'dumpLocale'; |
| $this->dumpLocale = $this->locale ?? null; |
| } |
| |
| return $properties; |
| } |
| |
| /** |
| * Set locale if specified on unserialize() called. |
| */ |
| #[ReturnTypeWillChange] |
| public function __wakeup() |
| { |
| if (get_parent_class() && method_exists(parent::class, '__wakeup')) { |
| // @codeCoverageIgnoreStart |
| try { |
| parent::__wakeup(); |
| } catch (Throwable $exception) { |
| // FatalError occurs when calling msgpack_unpack() in PHP 7.4 or later. |
| ['date' => $date, 'timezone' => $timezone] = $this->dumpDateProperties; |
| parent::__construct($date, unserialize($timezone)); |
| } |
| // @codeCoverageIgnoreEnd |
| } |
| |
| $this->constructedObjectId = spl_object_hash($this); |
| |
| if (isset($this->dumpLocale)) { |
| $this->locale($this->dumpLocale); |
| $this->dumpLocale = null; |
| } |
| |
| $this->cleanupDumpProperties(); |
| } |
| |
| /** |
| * Prepare the object for JSON serialization. |
| * |
| * @return array|string |
| */ |
| #[ReturnTypeWillChange] |
| public function jsonSerialize() |
| { |
| $serializer = $this->localSerializer ?? static::$serializer; |
| |
| if ($serializer) { |
| return \is_string($serializer) |
| ? $this->rawFormat($serializer) |
| : $serializer($this); |
| } |
| |
| return $this->toJSON(); |
| } |
| |
| /** |
| * @deprecated To avoid conflict between different third-party libraries, static setters should not be used. |
| * You should rather transform Carbon object before the serialization. |
| * |
| * JSON serialize all Carbon instances using the given callback. |
| * |
| * @param callable $callback |
| * |
| * @return void |
| */ |
| public static function serializeUsing($callback) |
| { |
| static::$serializer = $callback; |
| } |
| |
| /** |
| * Cleanup properties attached to the public scope of DateTime when a dump of the date is requested. |
| * foreach ($date as $_) {} |
| * serializer($date) |
| * var_export($date) |
| * get_object_vars($date) |
| */ |
| public function cleanupDumpProperties() |
| { |
| foreach ($this->dumpProperties as $property) { |
| if (isset($this->$property)) { |
| unset($this->$property); |
| } |
| } |
| |
| return $this; |
| } |
| |
| private function getSleepProperties(): array |
| { |
| $properties = $this->dumpProperties; |
| |
| // @codeCoverageIgnoreStart |
| if (!\extension_loaded('msgpack')) { |
| return $properties; |
| } |
| |
| if (isset($this->constructedObjectId)) { |
| $this->dumpDateProperties = [ |
| 'date' => $this->format('Y-m-d H:i:s.u'), |
| 'timezone' => serialize($this->timezone ?? null), |
| ]; |
| |
| $properties[] = 'dumpDateProperties'; |
| } |
| |
| return $properties; |
| // @codeCoverageIgnoreEnd |
| } |
| } |