<?php
namespace Lm\Entity\Common;
use Lm\Service\Cache\CacheService;
use Lm\Service\Cache\LmCacheTrait;
use Lm\Util\Str;
class Entity
{
use LmCacheTrait {
LmCacheTrait::__construct as __constructLmCacheTrait;
}
const DATE_FORMAT_DEFAULT = 'Y-m-d';
const DATE_TIME_FORMAT_DEFAULT = self::DATE_FORMAT_DEFAULT.' H:i:s';
/**
* @var bool 算出プロパティの値を自動的に算出する
*/
protected static $autoCompute = true;
/**
* @var bool 算出済みの値をキャッシュする
*/
protected static $cacheComputed = true;
/**
* @var bool 空配列による初期化を許容
*/
protected $allowEmpty = false;
/**
* @var array
*/
protected $data = [];
/**
* @param array $data
* @throws \Exception
*/
public function __construct($data = [])
{
//
$this->__constructLmCacheTrait(new CacheService());
//
if (($message = $this->validate($data)) !== true) {
//
throw new \Exception("無効なデータが指定されました\n{$message}");
}
//
$this->data = array_merge($this->data, $data);
//
$this->convert($data);
}
/**
* @param array $data
* @param array $errors
* @return bool|string
*/
public function validate($data)
{
//
if ($this->allowEmpty && is_array($data) && empty($data)) {
// 空配列による初期化を許容
return true;
} else if (empty($data)) {
//
return 'データがありません';
}
// TODO: 実際の処理
//
return true;
}
/**
* @param array $data
* @return void
*/
public function convert(array $data)
{
foreach ($data as $key => $value) {
//
// // $property = Str::snakeToCamel($key);
if (preg_match('/^[a-z]/i', $key)) {
//
if (strpos($key, '_') !== false) {
$key = Str::snakeToCamel($key);
}
//
if (strpos($key, '-') !== false) {
$key = Str::kebabToCamel($key);
}
}
//
$property = $key;
//
if (property_exists($this, $property)) {
//
$this->{$property} = $value;
}
}
}
/**
* TODO: 動的なプロパティ値への対応
* @return array
*/
public function toArray()
{
return $this->data;
}
protected function allowEmpty()
{
$this->allowEmpty = true;
}
/**
* Null許容int型(?int)のポリフィル関数。
* nullはnullのまま返すが、それ以外はint型にキャストした値を返す。
* ※原則として、Entityのint型Getterメソッドの返却値はこのメソッドを通すこと。
*
* @param int|null $var
* @return int|null
*/
protected static function intNullable($var)
{
return ctype_digit($var) ? (($var !== null) ? (int)$var : null) : $var;
}
/**
* @return $this
*/
public function disableAutoCompute()
{
//
static::$autoCompute = false;
//
return $this;
}
/**
* @return $this
*/
public function enableAutoCompute()
{
//
static::$autoCompute = true;
//
return $this;
}
/**
* @return $this
*/
public function disableCacheComputed()
{
//
static::$cacheComputed = false;
//
return $this;
}
/**
* @return $this
*/
public function enableCacheComputed()
{
//
static::$cacheComputed = true;
//
return $this;
}
/**
* @param mixed $var
* @param callable $callback
* @return mixed
*/
protected static function compute(&$var, $callback)
{
//
if (static::$autoCompute) {
//
if (!static::$cacheComputed || !isset($var)) {
//
$var = $callback();
}
}
//
return $var;
}
/**
* @param Entity|array $data
* @param string|null $className
* @return Entity
* @throws \Exception
*/
public static function factory($data, $className = null)
{
//
if ($className === null) {
//
$className = static::class;
}
//
if (is_array($data)) {
//
return new $className($data);
} else if ($className === get_class($data)) {
// 型名が完全に一致する場合、そのまま返す
return $data;
} else if ($data instanceof Entity) {
// 親子関係のクラスである場合、データを配列として取得してインスタンス化する
return new $className($data->toArray());
} else {
throw new \InvalidArgumentException();
}
}
}