ORM/src/Abstracts/Model.php

282 lines
7.3 KiB
PHP

<?php
namespace Benzine\ORM\Abstracts;
use Benzine\ORM\Interfaces\ModelInterface;
use Camel\CaseTransformer;
use Camel\Format;
abstract class Model implements ModelInterface, \Serializable
{
protected array $_primary_keys = [];
protected array $_autoincrement_keys = [];
protected array $_original;
public function __construct(array $data = [])
{
if ($data) {
$this->exchangeArray($data);
}
$this->__setUp();
}
/**
* Overrideable __setUp function that will allow you to hijack
* it and create any related objects that need to be recreated.
*/
public function __setUp(): void
{
}
public function __wakeup(): void
{
$this->__setUp();
}
/**
* @return array
*/
public function __toArray()
{
$array = [];
$transformer = new CaseTransformer(new Format\StudlyCaps(), new Format\StudlyCaps());
foreach ($this->getListOfProperties() as $property) {
$getFunction = "get{$property}";
$currentValue = $this->{$getFunction}();
$array[$transformer->transform($property)] = $currentValue;
}
return array_merge($array);
}
/**
* @return array
*/
public function __toRawArray()
{
$array = [];
$transformer = new CaseTransformer(new Format\StudlyCaps(), new Format\StudlyCaps());
foreach ($this->getListOfProperties() as $dbField => $property) {
$currentValue = $this->{$property};
if ($currentValue instanceof \DateTime) {
$array[$dbField] = $currentValue->format('Y-m-d H:i:s');
} else {
$array[$dbField] = $currentValue;
}
}
return $array;
}
public function __toPublicArray(): array
{
$publicArray = [];
foreach ($this->getListOfProperties() as $property) {
$publicArray[ucfirst($property)] = $this->{$property};
}
return $publicArray;
}
public function __fromPublicArray(array $publicArray): self
{
foreach ($this->getListOfProperties() as $property) {
$this->{$property} = $publicArray[ucfirst($property)];
}
return $this;
}
public function __serialize(): array
{
return $this->__toPublicArray();
}
public function __unserialize(array $data): void
{
$this->__fromPublicArray($data);
}
public function __pre_save(): void
{
// Stub function to be overridden.
}
public function __post_save(): void
{
// Stub function to be overridden.
}
public function __set($name, $value): void
{
$this->{$name} = $value;
}
public function __get($name)
{
return $this->{$name};
}
public static function factory(array $data = [])
{
$class = get_called_class();
return new $class($data); // @phpstan-ignore-line
}
public function getPrimaryKeys(): array
{
$primaryKeyValues = [];
foreach ($this->_primary_keys as $internalName => $dbName) {
$getFunction = "get{$internalName}";
$primaryKeyValues[$internalName] = $this->{$getFunction}();
}
return $primaryKeyValues;
}
public function getPrimaryKeys_dbColumns(): array
{
$primaryKeyValues = [];
foreach ($this->_primary_keys as $internalName => $dbName) {
$getFunction = "get{$internalName}";
$primaryKeyValues[$dbName] = $this->{$getFunction}();
}
return $primaryKeyValues;
}
/**
* Return autoincrement key values in an associative array.
*
* @return array
*/
public function getAutoIncrementKeys()
{
$autoIncrementKeyValues = [];
foreach ($this->_autoincrement_keys as $autoincrement_key => $autoincrement_db_column) {
$getFunction = "get{$autoincrement_key}";
$autoIncrementKeyValues[$autoincrement_key] = $this->{$getFunction}();
}
return $autoIncrementKeyValues;
}
/**
* Returns true if the primary key isn't null.
*
* @return bool
*/
public function hasPrimaryKey()
{
foreach ($this->getPrimaryKeys() as $primaryKey) {
if (null != $primaryKey) {
return true;
}
}
return false;
}
public function getListOfProperties(): array
{
// @todo make this into an interface entry
throw new \Exception('getListOfProperties in Abstract Model should never be used.');
}
/**
* Returns whether or not the data has been modified inside this model.
*/
public function hasDirtyProperties(): bool
{
return count($this->getListOfDirtyProperties()) > 0;
}
/**
* Returns an array of dirty properties.
*/
public function getListOfDirtyProperties(): array
{
$transformer = new CaseTransformer(new Format\CamelCase(), new Format\StudlyCaps());
$dirtyProperties = [];
foreach ($this->getListOfProperties() as $property) {
$originalProperty = $transformer->transform($property);
//echo "Writing into \$this->{$originalProperty}: getListOfDirtyProperties\n";
if (!isset($this->_original[$originalProperty]) || $this->{$property} != $this->_original[$originalProperty]) {
$dirtyProperties[$property] = [
'before' => isset($this->_original[$originalProperty]) ? $this->_original[$originalProperty] : null,
'after' => $this->{$property},
];
}
}
return $dirtyProperties;
}
public function isDirty(): bool
{
$clean = true;
foreach ($this->_original as $key => $originalValue) {
foreach ($this->getListOfProperties() as $existingKey) {
if (strtolower($key) == strtolower($existingKey)) {
if ($this->{$existingKey} != $originalValue) {
$clean = false;
}
}
}
}
return !$clean;
}
public function serialize(): string
{
return json_encode($this->__toRawArray(), JSON_PRETTY_PRINT);
}
public function unserialize($serialized): void
{
$unserialized = json_decode($serialized);
foreach ($unserialized as $k => $v) {
$this->__set($k, $v);
}
}
abstract public function getPropertyMeta(): array;
/**
* Give a human-readable label for this record. Should be an ID by default.
* Or over-ridden with something more useful.
*/
public function label(): string
{
if (method_exists($this, 'getName')) {
return $this->getName();
}
$labelParts = [];
$primaryKeyFields = array_keys($this->getPrimaryKeys());
foreach ($primaryKeyFields as $primaryKeyField) {
$labelParts[] = $this->__get($primaryKeyField);
}
return implode('-', $labelParts);
}
/**
* @deprecated
*/
public function destroyThoroughly(): int
{
return $this->destroyRecursively();
}
protected function getProtectedMethods(): array
{
return ['getPrimaryKeys', 'getProtectedMethods', 'getDIContainer'];
}
}