dbms/app/Models/CommonModel.php
2025-05-12 16:58:29 +09:00

221 lines
7.7 KiB
PHP

<?php
namespace App\Models;
use CodeIgniter\Model;
use App\Libraries\LogCollector;
abstract class CommonModel extends Model
{
protected $table = '';
protected $primaryKey = '';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = false;
protected $protectFields = true;
protected $allowedFields = [];
protected bool $allowEmptyInserts = false;
protected bool $updateOnlyChanged = true;
protected array $casts = [];
protected array $castHandlers = [];
// Dates
protected $useTimestamps = false;
protected $dateFormat = 'datetime';
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
protected $deletedField = 'deleted_at';
// Validation
protected $validationRules = [];
protected $validationMessages = [];
protected $skipValidation = false;
protected $cleanValidationRules = true;
// Callbacks
protected $allowCallbacks = true;
protected $beforeInsert = [];
protected $afterInsert = [];
protected $beforeUpdate = [];
protected $afterUpdate = [];
protected $beforeFind = [];
protected $afterFind = [];
protected $beforeDelete = [];
protected $afterDelete = [];
protected function __construct()
{
parent::__construct();
}
final public function getTable(): string
{
return constant("static::TABLE");
}
final public function getPKField(): string
{
return constant("static::PK");
}
final public function getTitleField(): string
{
return constant("static::TITLE");
}
final public function getFields(): array
{
return $this->allowedFields;
}
//Primary Key로 uuid를 사용시 해당 모델에 아래 변수 반드시 추가 필요
// protected $useAutoIncrement = false;
// protected $beforeInsert = ['generateUUID'];
// allowedFields에는 PK넣으면 않됨, Column Type: CHAR(36)
//
final protected function generateUUID(): string
{
$data = random_bytes(16);
// UUID version 4 (random)
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // version 0100
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // variant 10
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
final protected function getFieldRules(string $action, array $fields, $rules = []): array
{
foreach ($fields as $field) {
$rules[$field] = $this->getFieldRule($action, $field);
}
return $rules;
}
public function getFieldRule(string $action, string $field): string
{
if (is_array($field)) {
throw new \Exception(__FUNCTION__ . "=> field가 array 입니다.\n" . var_export($field, true));
}
switch ($field) {
case $this->getPKField():
// 수동입력인 경우
if (!$this->useAutoIncrement) {
$rule = "required|regex_match[/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/]";
$rule .= in_array($action, ["create", "create_form"]) ? "|is_unique[{$this->table}.{$field}]" : "";
} else {
$rule = "required|numeric";
}
break;
case $this->getTitleField():
$rule = "required|trim|string";
break;
case 'image':
$rule = "is_image[{$field}]|mime_in[{$field},image/jpg,image/jpeg,image/gif,image/png,image/webp]|max_size[{$field},300]|max_dims[{$field},2048,768]";
break;
case "status":
$rule = "if_exist|in_list[use,unuse]";
break;
case "updated_at":
case "created_at":
case "deleted_at":
$rule = "if_exist|valid_date";
break;
default:
$rule = "if_exist|string";
break;
}
return $rule;
}
// create, modify 직전 작업용 작업
protected function convertEntityData(string $field, array $formDatas): mixed
{
switch ($field) {
case $this->getPKField():
// $formDatas에 전달된 값이 없는 경우
if (!array_key_exists($field, $formDatas)) {
$randomBytes = bin2hex(random_bytes(32));
$value = sprintf(
'%08s-%04s-%04x-%04x-%12s',
substr($randomBytes, 0, 8),
substr($randomBytes, 8, 4),
substr($randomBytes, 12, 4),
substr($randomBytes, 16, 4),
substr($randomBytes, 20, 12)
);
} else {
$value = $formDatas[$field];
}
break;
case "editor": // content 등 textarea를 사용한 Field
$value = htmlentities($formDatas[$field], ENT_QUOTES);
break;
default:
$value = $formDatas[$field];
break;
}
return $value;
}
private function save_process(mixed $entity): mixed
{
// 최종 변경사항이 없으면
if (!$entity->hasChanged()) {
return $entity;
}
// 최종 저장 시 오류 발생하면
if (!$this->save($entity)) {
$message = sprintf(
"\n------%s 오류-----\n%s\n%s\n------------------------------\n",
__FUNCTION__,
$this->getLastQuery(),
var_export($this->errors(), true)
);
LogCollector::error($message);
throw new \Exception($message);
}
return $entity;
}
final function create(array $formDatas, mixed $entity): mixed
{
// Field에 맞는 Validation Rule 재정의
$this->setValidationRules($this->getFieldRules(__FUNCTION__, $this->allowedFields));
foreach (array_keys($formDatas) as $field) {
$value = $this->convertEntityData($field, $formDatas);
$entity->$field = $value;
}
// primaryKey가 자동입력이 아니면
if (!$this->useAutoIncrement) {
$pkField = $this->getPKField();
$entity->$pkField = $this->generateUUID();
}
$entity = $this->save_process($entity);
// primaryKey가 자동입력이면
if ($this->useAutoIncrement) {
$pkField = $this->getPKField();
$entity->$pkField = $this->getInsertID();
}
LogCollector::debug("[{$entity->getTitle()}] 입력내용");
LogCollector::debug(var_export($entity->toArray(), true));
return $entity;
}
final function modify(mixed $entity, array $formDatas): mixed
{
// Field에 맞는 Validation Rule 재정의
$this->setValidationRules($this->getFieldRules(__FUNCTION__, $this->allowedFields));
// 저장하기 전에 데이터 값 변경이 필요한 Field
LogCollector::debug("[{$entity->getPK()}/{$entity->getTitle()}] 변경 전 내용");
LogCollector::debug(var_export($entity->toArray(), true));
foreach (array_keys($formDatas) as $field) {
$entity->$field = $this->convertEntityData($field, $formDatas);
}
//수정일추가
$entity->updated_at = date("Y-m-d H:i:s");
LogCollector::debug("[{$entity->getPK()}/{$entity->getTitle()}] 변경 후 내용");
LogCollector::debug(var_export($entity->toArray(), true));
return $this->save_process($entity);
}
//List 검색용
public function setList_WordFilter(string $word): void
{
$this->orLike($this->getTable() . "." . $this->getTitleField(), $word, 'both');
}
}