julienmonnerie/kirby/src/Toolkit/Properties.php
2025-04-21 18:57:21 +02:00

152 lines
3.4 KiB
PHP

<?php
namespace Kirby\Toolkit;
use Exception;
use ReflectionMethod;
/**
* Properties
* @deprecated 4.0.0 Will be remove in Kirby 5
* @codeCoverageIgnore
*
* @package Kirby Toolkit
* @author Bastian Allgeier <bastian@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
trait Properties
{
protected $propertyData = [];
/**
* Creates an instance with the same
* initial properties.
*
* @param array $props
* @return static
*/
public function clone(array $props = [])
{
return new static(array_replace_recursive($this->propertyData, $props));
}
/**
* Creates a clone and fetches all
* lazy-loaded getters to get a full copy
*
* @return static
*/
public function hardcopy()
{
$clone = $this->clone();
$clone->propertiesToArray();
return $clone;
}
protected function isRequiredProperty(string $name): bool
{
$method = new ReflectionMethod($this, 'set' . $name);
return $method->getNumberOfRequiredParameters() > 0;
}
protected function propertiesToArray()
{
$array = [];
foreach (get_object_vars($this) as $name => $default) {
if ($name === 'propertyData') {
continue;
}
if (method_exists($this, 'convert' . $name . 'ToArray') === true) {
$array[$name] = $this->{'convert' . $name . 'ToArray'}();
continue;
}
if (method_exists($this, $name) === true) {
$method = new ReflectionMethod($this, $name);
if ($method->isPublic() === true) {
$value = $this->$name();
if (is_object($value) === false) {
$array[$name] = $value;
}
}
}
}
ksort($array);
return $array;
}
protected function setOptionalProperties(array $props, array $optional)
{
$this->propertyData = array_merge($this->propertyData, $props);
foreach ($optional as $propertyName) {
if (isset($props[$propertyName]) === true) {
$this->{'set' . $propertyName}($props[$propertyName]);
} else {
$this->{'set' . $propertyName}();
}
}
}
protected function setProperties($props, array|null $keys = null)
{
foreach (get_object_vars($this) as $name => $default) {
if ($name === 'propertyData') {
continue;
}
$this->setProperty($name, $props[$name] ?? $default);
}
return $this;
}
protected function setProperty($name, $value, $required = null)
{
// use a setter if it exists
if (method_exists($this, 'set' . $name) === false) {
return $this;
}
// fetch the default value from the property
$value ??= $this->$name ?? null;
// store all original properties, to be able to clone them later
$this->propertyData[$name] = $value;
// handle empty values
if ($value === null) {
// replace null with a default value, if a default handler exists
if (method_exists($this, 'default' . $name) === true) {
$value = $this->{'default' . $name}();
}
// check for required properties
if ($value === null && ($required ?? $this->isRequiredProperty($name)) === true) {
throw new Exception(sprintf('The property "%s" is required', $name));
}
}
// call the setter with the final value
return $this->{'set' . $name}($value);
}
protected function setRequiredProperties(array $props, array $required)
{
foreach ($required as $propertyName) {
if (isset($props[$propertyName]) !== true) {
throw new Exception(sprintf('The property "%s" is required', $propertyName));
}
$this->{'set' . $propertyName}($props[$propertyName]);
}
}
}