153 lines
4.0 KiB
PHP
153 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Core\App;
|
|
use App\Services\Database\Connection;
|
|
use PDO;
|
|
|
|
abstract class Model
|
|
{
|
|
protected static ?PDO $db = null;
|
|
protected string $table;
|
|
protected string $primaryKey = 'id';
|
|
protected array $attributes = [];
|
|
|
|
public function __construct(array $attributes = [])
|
|
{
|
|
$this->attributes = $attributes;
|
|
if (self::$db === null && isset(App::$app)) {
|
|
$connection = App::$app->container->get(Connection::class);
|
|
self::$db = $connection->getPdo();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get active database connection.
|
|
*/
|
|
public static function getDb(): PDO
|
|
{
|
|
if (self::$db === null) {
|
|
$connection = App::$app->container->get(Connection::class);
|
|
self::$db = $connection->getPdo();
|
|
}
|
|
return self::$db;
|
|
}
|
|
|
|
/**
|
|
* Magic getter for attributes.
|
|
*/
|
|
public function __get(string $name)
|
|
{
|
|
return $this->attributes[$name] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Magic setter for attributes.
|
|
*/
|
|
public function __set(string $name, $value): void
|
|
{
|
|
$this->attributes[$name] = $value;
|
|
}
|
|
|
|
public function getAttributes(): array
|
|
{
|
|
return $this->attributes;
|
|
}
|
|
|
|
/**
|
|
* Find a record by ID.
|
|
*/
|
|
public static function find(int|string $id): ?static
|
|
{
|
|
$instance = new static();
|
|
$db = self::getDb();
|
|
|
|
$sql = "SELECT * FROM {$instance->table} WHERE {$instance->primaryKey} = :id AND deleted_at IS NULL LIMIT 1";
|
|
$stmt = $db->prepare($sql);
|
|
$stmt->execute(['id' => $id]);
|
|
|
|
$data = $stmt->fetch();
|
|
if (!$data) {
|
|
return null;
|
|
}
|
|
|
|
return new static($data);
|
|
}
|
|
|
|
/**
|
|
* Fetch all active records.
|
|
*/
|
|
public static function all(): array
|
|
{
|
|
$instance = new static();
|
|
$db = self::getDb();
|
|
|
|
$sql = "SELECT * FROM {$instance->table} WHERE deleted_at IS NULL";
|
|
$stmt = $db->query($sql);
|
|
|
|
$results = [];
|
|
while ($row = $stmt->fetch()) {
|
|
$results[] = new static($row);
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Save the active record (INSERT or UPDATE).
|
|
*/
|
|
public function save(): bool
|
|
{
|
|
$db = self::getDb();
|
|
$id = $this->attributes[$this->primaryKey] ?? null;
|
|
|
|
if ($id) {
|
|
// Update flow
|
|
$fields = [];
|
|
$params = [];
|
|
foreach ($this->attributes as $key => $value) {
|
|
if ($key === $this->primaryKey || $key === 'created_at' || $key === 'updated_at') {
|
|
continue;
|
|
}
|
|
$fields[] = "`{$key}` = :{$key}";
|
|
$params[$key] = $value;
|
|
}
|
|
$params[$this->primaryKey] = $id;
|
|
|
|
$sql = "UPDATE `{$this->table}` SET " . implode(', ', $fields) . " WHERE `{$this->primaryKey}` = :{$this->primaryKey}";
|
|
$stmt = $db->prepare($sql);
|
|
return $stmt->execute($params);
|
|
} else {
|
|
// Insert flow
|
|
$keys = array_keys($this->attributes);
|
|
$placeholders = array_map(fn($key) => ":{$key}", $keys);
|
|
|
|
$sql = "INSERT INTO `{$this->table}` (" . implode(', ', array_map(fn($k) => "`{$k}`", $keys)) . ") VALUES (" . implode(', ', $placeholders) . ")";
|
|
$stmt = $db->prepare($sql);
|
|
$success = $stmt->execute($this->attributes);
|
|
|
|
if ($success) {
|
|
$this->attributes[$this->primaryKey] = (int)$db->lastInsertId();
|
|
}
|
|
return $success;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Soft delete active record.
|
|
*/
|
|
public function delete(): bool
|
|
{
|
|
$db = self::getDb();
|
|
$id = $this->attributes[$this->primaryKey] ?? null;
|
|
if (!$id) {
|
|
return false;
|
|
}
|
|
|
|
$sql = "UPDATE `{$this->table}` SET deleted_at = NOW() WHERE `{$this->primaryKey}` = :id";
|
|
$stmt = $db->prepare($sql);
|
|
return $stmt->execute(['id' => $id]);
|
|
}
|
|
}
|