db = Database::connect(); } public function all(): array { $stmt = $this->db->query("SELECT * FROM {$this->table}"); return $stmt->fetchAll(); } public function find(int $id): ?array { $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE {$this->primaryKey} = ? LIMIT 1"); $stmt->execute([$id]); $result = $stmt->fetch(); return $result ?: null; } public function where(string $column, $value): array { $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE {$column} = ?"); $stmt->execute([$value]); return $stmt->fetchAll(); } public function first(string $column, $value): ?array { $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE {$column} = ? LIMIT 1"); $stmt->execute([$value]); $result = $stmt->fetch(); return $result ?: null; } public function create(array $data): int { $data = $this->filterFillable($data); $columns = implode(', ', array_keys($data)); $placeholders = implode(', ', array_fill(0, count($data), '?')); $sql = "INSERT INTO {$this->table} ({$columns}) VALUES ({$placeholders})"; $stmt = $this->db->prepare($sql); $stmt->execute(array_values($data)); return (int) $this->db->lastInsertId(); } public function update(int $id, array $data): bool { $data = $this->filterFillable($data); $set = implode(' = ?, ', array_keys($data)) . ' = ?'; $sql = "UPDATE {$this->table} SET {$set} WHERE {$this->primaryKey} = ?"; $stmt = $this->db->prepare($sql); return $stmt->execute([...array_values($data), $id]); } public function delete(int $id): bool { $stmt = $this->db->prepare("DELETE FROM {$this->table} WHERE {$this->primaryKey} = ?"); return $stmt->execute([$id]); } public function query(string $sql, array $params = []): array { $stmt = $this->db->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(); } public function execute(string $sql, array $params = []): bool { $stmt = $this->db->prepare($sql); return $stmt->execute($params); } protected function filterFillable(array $data): array { if (empty($this->fillable)) { return $data; } return array_intersect_key($data, array_flip($this->fillable)); } }