dbEngine = $engine; $this->tableName = $tableName; $this->setup = true; } public function isSetup(): bool { return $this->setup; } public function getName(): string { return 'pdo'; } /** * @return string */ public function getEngineName(): string { return 'pdo'; } /** * @return iDatabaseEngine * @throws DatabaseException */ public function getEngine(): iDatabaseEngine { if (!$this->setup) throw new DatabaseException("Could not return Engine. Engine not setup yet."); return $this->dbEngine; } /** * @param array $data * @param array $options * @return int * @throws DatabaseException */ public function create(array $data, array $options = []): int { // If no data is provided, stop now if (empty($data)) throw new DatabaseException("Could not create data. No data provided."); // Determine which fields will be inserted $fieldsArr = $this->createFields($data); $fields = $fieldsArr['fields']; $values = $fieldsArr['values']; // Generate the sql and create a PDOStatement $sql = "INSERT INTO {$this->tableName} ({$fields}) VALUES ({$values})"; /** @var PDOStatement $statement */ $this->lastStatement = $this->dbEngine->prepare($sql); // And execute the query if ($this->arrIsAssoc($data)) $this->lastStatement->execute($data); else foreach ($data as $record) $this->lastStatement->execute($record); // And return true for success return $this->lastStatement->rowCount(); } /** * @param array $filter * @param array $options * @return TableModelResult * @throws DatabaseException */ public function read(array $filter = [], array $options = []): TableModelResult { // Determine which fields to select. If none provided, select all $fields = (isset($options['fields']) && is_array($options['fields']) ? implode(',', $options['fields']) : '*'); $limit = isset($options['limit']) ? 'LIMIT ' . intval($options['limit']) : ''; // Apply the filter. If none provided, don't condition it $where = $this->filter($filter); // Generate the sql and create a PDOStatement $sql = "SELECT " . $fields . " FROM {$this->tableName} " . $where . " " . $limit; /** @var PDOStatement $statement */ $this->lastStatement = $this->dbEngine->prepare($sql); // And execute the query foreach ($filter as $key => $val) { if (is_null($val)) $this->lastStatement->bindValue(':' . $key, $val, PDO::PARAM_NULL); else $this->lastStatement->bindValue(':' . $key, $val); } $this->lastStatement->execute(); // Fetch PDO Iterable return new TableModelResult($this->lastStatement->getStatement()); } public function update(array $data, array $filter, array $options = []): int { // If no data is provided, stop now if (empty($data)) throw new DatabaseException("Could not update data. No data provided."); // Apply the filter $where = $this->filter($filter); // Determine fields and values foreach ($data as $key => $val) $fields[] = $key."=:".$key; $fields = implode(', ', $fields); // Generate the sql and create a PDOStatement $sql = "UPDATE {$this->tableName} SET {$fields} {$where}"; /** @var PDOStatement $statement */ $this->lastStatement = $this->dbEngine->prepare($sql); // Merge data and filter, since both are needed by the statement $parameters = array_merge($data, $filter); // And execute the query $this->lastStatement->execute($parameters); // And return true for success return $this->lastStatement->rowCount(); } public function delete(array $filter, array $options = []): int { // Apply the filter $where = $this->filter($filter); $limit = isset($options['limit']) ? 'LIMIT ' . intval($options['limit']) : ''; // Generate the sql and create a PDOStatement $sql = "DELETE FROM {$this->tableName} " . $where . " " . $limit; /** @var PDOStatement $statement */ $this->lastStatement = $this->dbEngine->prepare($sql); // And execute the query $this->lastStatement->execute($filter); // And return true for success return $this->lastStatement->rowCount(); } /** * @return bool * @throws TransactionException */ public function transactionStart(): bool { return $this->dbEngine->transactionStart(); } /** * @return bool * @throws TransactionException */ public function transactionEnd(): bool { return $this->dbEngine->transactionEnd(); } /** * @return bool * @throws TransactionException */ public function transactionCommit(): bool { return $this->dbEngine->transactionCommit(); } /** * @return bool * @throws TransactionException */ public function transactionRollback(): bool { return $this->dbEngine->transactionRollback(); } /** * Call methods on the PDO Engine, which calls methods on the PDO Connection * * @param $name * @param $arguments * @return PDOEngine */ public function __call($name, $arguments) { return $this->dbEngine->{$name}(...$arguments); } /** * Get properties from the PDO Engine, which gets properties from the PDO connection * * @param $name * @return mixed */ public function __get($name) { return $this->dbEngine->$name; } /** * Set properties on the PDO Connection, which sets properties on the PDO Connection * * @param $name * @param $value * @return mixed */ public function __set($name, $value) { return $this->dbEngine->$name = $value; } private function filter(array $filter = []): string { if (empty($filter)) return ''; $whereKeys = []; foreach ($filter as $filterKey => $filterVal) $whereKeys[] = $filterKey . '=:' . $filterKey; return 'WHERE ' . implode(' AND ', $whereKeys); } private function createFields(array $record): array { // If multiple data is inserted at once, search the fields in the first entry if (!$this->arrIsAssoc($record)) $record = $record[0]; // Determine the fields and values foreach ($record as $key => $val) { $fields[] = $key; $values[] = ':'.$key; } // And merge them again $fields = implode(', ', $fields); $values = implode(', ', $values); return ['fields' => $fields, 'values' => $values]; } private function arrIsAssoc(array $arr): bool { if (array() === $arr) return false; return array_keys($arr) !== range(0, count($arr) - 1); } }