tableName = $tableName; $this->fields = []; $this->database = $database; $this->database->Query(sprintf('DESCRIBE %s', $tableName)); $result = $this->database->getResult(); foreach ($result as $field) { $sqlType = substr_count( $field['Type'], '(') === 0 ? $field['Type'] : strstr($field['Type'], '(', true ); switch ($sqlType) { case 'varchar': case 'char': case 'text': case 'longtext': case 'mediumtext': case 'tinytext': $type = self::TYPE_STRING; break; case 'int': case 'smallint': case 'mediumint': case 'bigint': $type = self::TYPE_INTEGER; break; case 'float': case 'decimal': case 'double': case 'real': $type = self::TYPE_FLOAT; break; case 'datetime': case 'date': $type = self::TYPE_DATETIME; break; case 'tinyint': $type = self::TYPE_BOOL; break; default: throw new Exception(sprintf('Type %s of field %s couldn\'t be handled', $sqlType, $field['Field'])); } $this->addField($field['Field'], $type); if ($field['Key'] === 'PRI') { $this->primaryKey = $field['Field']; } } if (!$this->isPrimKeyManual && $id !== null) { $this->loadById($id); } } public function getPrimaryKey() { if ($this->primaryKey === null) { return null; } return $this->getField($this->primaryKey); } protected function addField(string $name, int $type): void { if (!self::IsValidType($type)) { throw new Exception( sprintf('Field %s has invalid type of %s!', $name, $type) ); } $this->fields[$name] = [self::VALUE => null, self::TYPE => $type]; } protected function loadById($id): void { try { $this->database->Query( sprintf('SELECT * FROM %s WHERE %s = :id', $this->tableName, $this->primaryKey), ['id' => $id] ); } catch (Throwable $e) { throw new Exception(); } $result = $this->database->getResult(); if (count($result) === 0) { throw new Exception(sprintf('No %s with id %d found!', $this->tableName, $id)); } foreach ($result[0] as $field => $value) { $this->setField($field, $value); } } public function Flush(): void { $this->database->Delete($this->tableName, []); } public function Delete(): void { try { $this->database->Delete($this->tableName, [$this->primaryKey => $this->getPrimaryKey()]); } catch (Throwable $e) { throw new Exception(); } foreach ($this->GetAllFieldNames() as $field) { $this->fields[$field][self::VALUE] = null; } } protected function getField(string $name) { if (!array_key_exists($name, $this->fields)) { return null; } return $this->fields[$name][self::VALUE]; } /** * Sets the value for the given field inside the database. */ protected function setField(string $name, $value): void { if (!$this->HasField($name)) { throw new Exception(sprintf('Field %s doesn\'t exist!', $name)); } if ($value === null) { $this->fields[$name][self::VALUE] = null; return; } switch ($this->fields[$name][self::TYPE]) { case self::TYPE_STRING: $this->fields[$name][self::VALUE] = (string)$value; return; case self::TYPE_INTEGER: $this->fields[$name][self::VALUE] = (int)$value; return; case self::TYPE_FLOAT: $this->fields[$name][self::VALUE] = (float)$value; return; case self::TYPE_DATETIME: try { $this->fields[$name][self::VALUE] = new DateTime((string)$value); } catch (Exception $e) { throw new Exception(); } return; case self::TYPE_BOOL: $this->fields[$name][self::VALUE] = (bool)$value; } } /** * Checks if the table has the given column. */ public function HasField(string $name): bool { return array_key_exists($name, $this->fields); } /** * Saves the whole object into the database. */ public function Save(): void { $fields = []; foreach ($this->GetAllFieldNames() as $fieldName) { $field = $this->getField($fieldName); if ($field instanceof DateTime) { $fields[$fieldName] = $field->format('Y-m-d H:i:s'); } else if (is_bool($field)) { $fields[$fieldName] = (int)$field; } else { $fields[$fieldName] = $field; } } if ($this->isPrimKeyManual) { $this->saveWithManualId($fields); } else { $this->saveWithPrimaryKey($fields); } } /** * @return string[] */ public function GetAllFieldNames(): array { $fieldNames = []; foreach ($this->fields as $name => $field) { $fieldNames[] = $name; } return $fieldNames; } /** * Checks if the index is a valid backend type. */ public static function IsValidType(int $type): bool { $validTypes = [ self::TYPE_STRING, self::TYPE_INTEGER, self::TYPE_FLOAT, self::TYPE_DATETIME, self::TYPE_BOOL, ]; return in_array($type, $validTypes); } protected function saveWithManualId(array $fields): void { if ($this->getField($this->primaryKey) === null) { throw new Exception('Manual primary key must not be null!'); } $hasKey = (bool)$this->database->Count( $this->tableName, [$this->primaryKey => $this->getField($this->primaryKey)] ); if ($hasKey) { $this->database->Update( $this->tableName, $fields, [$this->primaryKey => $this->getField($this->primaryKey)] ); } else { $this->database->Insert($this->tableName, $fields); } } protected function saveWithPrimaryKey(array $fields): void { if ($this->getField($this->primaryKey) !== null) { $this->database->Update( $this->tableName, $fields, [$this->primaryKey => $this->getField($this->primaryKey)] ); } else { $this->setField($this->primaryKey, $this->database->Insert($this->tableName, $fields)); } } }