diff options
Diffstat (limited to 'WpfTest/Model.php')
| -rw-r--r-- | WpfTest/Model.php | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/WpfTest/Model.php b/WpfTest/Model.php index 26a7b49..c006ffd 100644 --- a/WpfTest/Model.php +++ b/WpfTest/Model.php @@ -3,8 +3,6 @@ namespace WpfTest; abstract class Model { private static function mangleName(string $name): string { - if ($name == 'self') - return 'uri'; $chars = str_split($name); $chars[0] = strtolower($chars[0]); for ($i = 0; $i < count($chars); $i++) { @@ -17,8 +15,6 @@ abstract class Model { } private static function unmangleName(string $name): string { - if ($name == 'uri') - return 'self'; $chars = str_split($name); for ($i = 0; $i < count($chars); $i++) { if ($chars[$i] == '_') { @@ -41,32 +37,68 @@ abstract class Model { public static function fromDbRow(array|false $columns): ?static { if ($columns === false) return null; + // create the model $obj = new static(); $refl = new \ReflectionObject($obj); + // for each field of the db row ... foreach (array_keys($columns) as $name) { $value = $columns[$name]; - $name = self::unmangleName($name); + $name = self::unmangleName($name); // guess the appropriate field in the model try { + // try to assign it directly (works for simple values) $obj->{$name} = $value; } catch (\TypeError $e) { + // if it's not the right type we have to try to wrangle it into the right one + // there's a few strategies for this $type = $refl->getProperty($name)->getType(); if ($type == null || !is_a($type, \ReflectionNamedType::class)) throw $e; - $obj->{$name} = new ($type->getName())($value); + $typeClass = $type->getName(); + if (enum_exists($typeClass)) { + // if it's an enum we can find the enum case with the same name + $obj->{$name} = (new \ReflectionEnum($typeClass))->getCase($value)->getValue(); + } elseif (is_subclass_of($typeClass, Model::class) && is_int($value)) { + // if it's another model we can try to look it up by id automatically + $obj->{$name} = $typeClass::find($value); + } else { + // otherwise try to instantiate the correct class and pass it the simple value + $obj->{$name} = new $typeClass($value); + } } } + // set up any extra-complicated fields if needed + $obj->hydrate($columns); return $obj; } + /** + * Initialises fields of the model that contain more complex objects + * @param array $row the row of the database + * @return void + */ + protected function hydrate(array $row) { + } + public static function findWhere(string $whereClause, array $parameters): ?static { $classNameParts = explode('\\', static::class); $className = $classNameParts[count($classNameParts) - 1]; $tableName = self::mangleName($className); - $stmt = Db::getInstance()->getPdo()->prepare("SELECT * FROM $tableName WHERE $whereClause"); + $stmt = Db::getInstance()->getPdo()->prepare("SELECT * FROM $tableName WHERE $whereClause LIMIT 1"); $stmt->execute($parameters); return static::fromDbRow($stmt->fetch(\PDO::FETCH_ASSOC)); } + public static function findAllWhere(string $whereClause, array $parameters): array { + $classNameParts = explode('\\', static::class); + $className = $classNameParts[count($classNameParts) - 1]; + $tableName = self::mangleName($className); + $stmt = Db::getInstance()->getPdo()->prepare("SELECT * FROM $tableName WHERE $whereClause"); + $stmt->execute($parameters); + return array_map(function ($row) { + return static::fromDbRow($row); + }, $stmt->fetchAll(\PDO::FETCH_ASSOC)); + } + public static function find(int $id): ?static { return static::findWhere('id = ?', [$id]); } |
