Я не большой поклонник ОРМ. Я чувствую себя очень комфортно, работая с необработанными SQL, и из-за этого я обычно использую DBAL (или PDO в старых проектах). У меня есть одна небольшая библиотека для ежедневных операций с базами данных, и сегодня я написал эту библиотеку
Прежде всего, представьте одно соединение DBAL. В этом примере я использую базу данных sqlite in-memomy, но мы можем использовать любую базу данных, поддерживаемую DBAL (она же «почти все»):
use Doctrine\DBAL\DriverManager; $conn = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', 'memory' => true ]);
Мы также можем создать одно соединение DBAL из соединения PDO. Полезно использовать DBAL в унаследованных приложениях вместо создания нового соединения (помните, что DBAL работает поверх PDO)
use Doctrine\DBAL\DriverManager; $conn = DriverManager::getConnection(['pdo' => new PDO('sqlite::memory:')]);
Теперь мы настроили базу данных для примера
$conn->exec("CREATE TABLE users ( userid VARCHAR PRIMARY KEY NOT NULL , password VARCHAR NOT NULL , name VARCHAR, surname VARCHAR );"); $conn->exec("INSERT INTO users VALUES('user','pass','Name','Surname');"); $conn->exec("INSERT INTO users VALUES('user2','pass2','Name2','Surname2');");
Наша таблица «пользователи» имеет две записи. Теперь мы можем начать использовать нашу библиотеку.
Сначала мы создаем новый экземпляр нашей библиотеки:
use G\Db; $db = new Db($conn);
Теперь простой запрос из строки:
$data = $db->select("select * from users");
Иногда мне лень и я не хочу писать всю строку SQL, и я хочу выполнить select * from table:
use G\Sql; $data = $db->select(SQL::createFromTable("users"));
Возможно, нам нужно отфильтровать наш оператор Select с предложением WHERE:
$data = $db->select(SQL::createFromTable("users", ['userid' => 'user2']));
А теперь кое-что очень интересное (по крайней мере, для меня). Я хочу перебрать набор записей и, возможно, изменить его. Конечно, я могу использовать «foreach» над $ data и делать все, что мне нужно, но я предпочитаю использовать следующий синтаксис:
$data = $db->select(SQL::createFromTable("users"), function (&$row) { $row['name'] = strtoupper($row['name']); });
Для меня это более читабельно. Я перебираю набор записей и меняю имя строки на верхний регистр. Здесь вы можете увидеть, что делает моя функция «выбор»:
/** * @param Sql|string $sql * @param \Closure $callback * @return array */ public function select($sql, \Closure $callback = null) { if ($sql instanceof Sql) { $sqlString = $sql->getString(); $parameters = $sql->getParameters(); $types = $sql->getTypes(); } else { $sqlString = $sql; $parameters = []; $types = []; } $statement = $this->conn->executeQuery($sqlString, $parameters, $types); $data = $statement->fetchAll(); if (!is_null($callback) && count($data) > 0) { $out = []; foreach ($data as $row) { if (call_user_func_array($callback, [&$row]) !== false) { $out[] = $row; } } $data = $out; } return $data; }
И, наконец, транзакции (я обычно никогда не использую autocommit, и мне нравится обрабатывать транзакции самостоятельно)
$db->transactional(function (Db $db) { $userId = 'temporal'; $db->insert('users', [ 'USERID' => $userId, 'PASSWORD' => uniqid(), 'NAME' => 'name3', 'SURNAME' => 'name3' ]); $db->update('users', ['NAME' => 'updatedName'], ['USERID' => $userId]); $db->delete('users', ['USERID' => $userId]); });
«Транзакционная» функция очень похожа на транзакционную функцию DBAL.
public function transactional(\Closure $callback) { $out = null; $this->conn->beginTransaction(); try { $out = $callback($this); $this->conn->commit(); } catch (\Exception $e) { $this->conn->rollback(); throw $e; } return $out; }
Я немного изменяюсь, потому что мне нравится возвращать значение в замыкании и разрешать делать такие вещи:
$status = $db->transactional(function (Db $db) { $userId = 'temporal'; $db->insert('users', [ 'USERID' => $userId, 'PASSWORD' => uniqid(), 'NAME' => 'name3', 'SURNAME' => 'name3' ]); $db->update('users', ['NAME' => 'updatedName'], ['USERID' => $userId]); $db->delete('users', ['USERID' => $userId]); return "OK" });
Другие функции (вставка, обновление, удаление) только обходят вызовы функций DBAL:
private $conn; public function __construct(Doctrine\DBAL\Connection $conn) { $this->conn = $conn; } public function insert($tableName, array $values = [], array $types = []) { $this->conn->insert($tableName, $values, $types); } public function delete($tableName, array $where = [], array $types = []) { $this->conn->delete($tableName, $where, $types); } public function update($tableName, array $data, array $where = [], array $types = []) { $this->conn->update($tableName, $data, $where, $types); }
И это все. Вы можете использовать библиотеку с composer и скачать на github .
Кстати, я протестировал новый продукт Sensiolabs ( SensioLabs Insight ), чтобы проанализировать код и проверить хорошие практики, и я получил платиновую медаль #yeah!