e0dfc3ec82
API CI/CD / Validate (composer + pint) (push) Successful in 3m15s
API CI/CD / Test (PHPUnit) (push) Failing after 5m4s
API CI/CD / Build frontend assets (push) Successful in 1m3s
API CI/CD / Security audit (push) Failing after 49s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
136 lines
3.8 KiB
PHP
136 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
class BaseModel extends Model
|
|
{
|
|
private static ?array $tableColumnsCache = null;
|
|
|
|
public function __construct(array $attributes = [])
|
|
{
|
|
$keyName = $this->getKeyName();
|
|
$keyValue = $attributes[$keyName] ?? null;
|
|
|
|
parent::__construct($attributes);
|
|
|
|
if ($keyValue !== null && ! array_key_exists($keyName, $this->attributes)) {
|
|
$this->setAttribute($keyName, $keyValue);
|
|
}
|
|
}
|
|
|
|
public function getFillable(): array
|
|
{
|
|
$fillable = parent::getFillable();
|
|
if ($this->timestamps) {
|
|
if (! in_array('created_at', $fillable, true)) {
|
|
$fillable[] = 'created_at';
|
|
}
|
|
if (! in_array('updated_at', $fillable, true)) {
|
|
$fillable[] = 'updated_at';
|
|
}
|
|
}
|
|
|
|
return $fillable;
|
|
}
|
|
|
|
private function tableColumns(): array
|
|
{
|
|
if (self::$tableColumnsCache === null) {
|
|
self::$tableColumnsCache = $this->loadTableColumns();
|
|
}
|
|
|
|
return self::$tableColumnsCache[$this->getTable()] ?? [];
|
|
}
|
|
|
|
private function loadTableColumns(): array
|
|
{
|
|
$map = [];
|
|
$pattern = null;
|
|
if (function_exists('database_path')) {
|
|
try {
|
|
$pattern = database_path('migrations/*.php');
|
|
} catch (\Throwable $e) {
|
|
$pattern = null;
|
|
}
|
|
}
|
|
|
|
if ($pattern === null) {
|
|
$pattern = __DIR__.'/../../database/migrations/*.php';
|
|
}
|
|
|
|
$files = glob($pattern) ?: [];
|
|
|
|
foreach ($files as $file) {
|
|
$contents = file_get_contents($file);
|
|
if ($contents === false) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($this->parseSqlCreateTables($contents) as $table => $columns) {
|
|
$map[$table] = $columns;
|
|
}
|
|
|
|
foreach ($this->parseSchemaCreateTables($contents) as $table => $columns) {
|
|
if (! isset($map[$table]) || empty($map[$table])) {
|
|
$map[$table] = $columns;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
|
|
private function parseSqlCreateTables(string $contents): array
|
|
{
|
|
$map = [];
|
|
if (preg_match_all('/CREATE TABLE `([^`]+)`\\s*\\((.*?)\\)\\s*(?:ENGINE|;)/is', $contents, $matches, PREG_SET_ORDER)) {
|
|
foreach ($matches as $match) {
|
|
$table = $match[1];
|
|
$colsBlock = $match[2];
|
|
preg_match_all('/`([^`]+)`\\s+[^,]+/m', $colsBlock, $colsMatch);
|
|
$columns = $colsMatch[1] ?? [];
|
|
if (! empty($columns)) {
|
|
$map[$table] = $columns;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
|
|
private function parseSchemaCreateTables(string $contents): array
|
|
{
|
|
$map = [];
|
|
if (! preg_match_all('/Schema::create\\(\\s*[\'"]([^\'"]+)[\'"]\\s*,\\s*function\\s*\\([^)]*\\)\\s*\\{(.*?)\\n\\s*\\}\\);/is', $contents, $matches, PREG_SET_ORDER)) {
|
|
return $map;
|
|
}
|
|
|
|
foreach ($matches as $match) {
|
|
$table = $match[1];
|
|
$body = $match[2];
|
|
$columns = [];
|
|
|
|
if (preg_match_all('/\\$table->\\w+\\(\\s*[\'"]([^\'"]+)[\'"]/', $body, $colMatches)) {
|
|
$columns = array_merge($columns, $colMatches[1]);
|
|
}
|
|
|
|
if (str_contains($body, 'timestamps(') || str_contains($body, 'timestamps()')) {
|
|
$columns[] = 'created_at';
|
|
$columns[] = 'updated_at';
|
|
}
|
|
|
|
if (str_contains($body, 'softDeletes(') || str_contains($body, 'softDeletes()')) {
|
|
$columns[] = 'deleted_at';
|
|
}
|
|
|
|
if (! empty($columns)) {
|
|
$map[$table] = $columns;
|
|
}
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
}
|