-
Notifications
You must be signed in to change notification settings - Fork 11
Storage
Объект подключения к базе, это объект, который обычно требуется в различных местах системы на протяжении всего времени выполнения сценария. При использовании объектов подобного рода, обычно, встаёт вопрос, а как их хранить.
В сложных системах для этого предусматриваются свои механизмы, вроде Registry
, DI
и тому подобного.
Для простых случаев goDB предоставляет свой механизм хранения объектов. В простых системах он позволяет даже не работать с объектами, а использовать статические методы для запросов (см. ниже).
Класс go\DB\Storage
описывает хранилище объектов подключений.
Каждый объект хранится в хранилище под своим именем.
$Storage = new go\DB\Storage();
$db1 = go\DB\DB::create($params1);
$db2 = go\DB\DB::create($params2);
$Storage->set($db1, 'db-for-data'); // save database object with name "db-for-data"
$Storage->set($db2, 'db-for-logs');
if ($Storage->exists('db-for-data')) {
// some code ...
}
// some code ...
/* Use object from storage */
$db = $Storage->get('db-for-data');
$db->query($pattern, $data);
Также для Storage
определены магические методы __get
, __set
и __isset
:
$Storage->name1 = $db1;
$Storage->name2 = $db2;
// some code ...
$db = $Storage->name1;
При попытке получить доступ к базе по имени не существующем в хранилище, выбрасывается исключение StorageNotFound.
При попытке записать в хранилище базу под уже занятым именем, выбрасывается исключение StorageEngaged.
Можно создать множество объектов хранилищ и хранить в них объекты баз данных. Но здесь мы возвращаемся к изначальному вопросу - а где нам теперь хранить эти объекты хранилищ?
go\DB предоставляет объект центрального хранилища, доступный наподобие синглтона:
$Storage = go\DB\Storage::getInstance();
$Storage->set($db, 'db-for-data');
// some code ...
go\DB\Storage::getInstance()->get('db-for-data')->query($pattern, $data);
Центральное хранилище можно перезаписать своим объектом:
go\DB\Storage::setInstance($Storage);
Центральное хранилище доступно в любой части сценария.
Если нам нужно создать объект базы и сохранить его в хранилище, то мы можем сделать это за две операции:
$db = go\DB\DB::create($params);
$Storage->set($db, $name);
или воспользоваться методом create()
(создаёт базу с параметрами $params
и сохраняет под именем $name
):
$Storage->create($params, $name);
Рассмотрим другой случай. Часто параметры баз хранятся в конфигурационных массивах наподобие следующего:
$config = [
'db-for-data' => [
'_adapter' => 'mysql',
'host' => 'localhost',
'username' => 'test',
'password' => 'test',
'dbname' => 'test',
],
'db-for-logs' => [
'_adapter' => 'sqlite',
'filename' => '/var/log/mylog.sqlite',
],
'db-for-users' => 'db-for-data',
);
В этом случае мы может создать сразу объекты всех баз и сохранить в хранилище:
$Storage->fill($config);
Хранилище Storage
заполняется объектами баз с заданными параметрами (именами считаются ключи массива).
Либо хранилище можно наполнить сразу при создании:
$Storage = new go\DB\Storage($config);
Либо сразу заполнить и сделать центральным (setInstance()
может принимать как объект хранилища, так и конфигурационный массив):
go\DB\Storage::setInstance($config);
Заметьте, что в отличии от go\DB\DB::create()
в этих методах нет отдельного аргумента для имени адаптера.
Адаптер должен быть указан в параметрах ("_adapter"
).
В примере с конфигурационным массивом, базе db-for-users
соответствует не массив параметров подключения, а строка с именем другой базы (db-for-data
).
В этом случае не будет создаваться отдельный объект, а в db-for-users
будет сохранён тот же объект, что был создан для db-for-data
.
Это удобно, когда подразумевается разнесение отдельных частей системы по различным базам, но на начальном этапе все эти части лежат в одной базе.
В текущей версии не допускаются цепочки ассоциаций.
То есть в примере db-for-data
должен содержать массив параметров подключения, а не ссылаться на другую базу.
При попытке ассоциировать базу с именем, которого нет в конфигурационном массиве, выбрасывается исключение StorageAssoc.
База, сохранённая в хранилище под именем равным пустой строке, считается центральной базой этого хранилища.
К этой базе можно обращаться через get
, set
и другие методы не указывая имени.
Для объекта хранилища определён метод __invoke
, который выполняет запрос к центральной базе хранилища.
$row = $Storage('SELECT * FROM `table` WHERE `id`=?i', [$id])->row();
Статический метод query()
выполняет запрос к центральной базе центрального хранилища:
$row = go\DB\Storage::query('SELECT * FROM `table` WHERE `id`=?i', [$id])->row();
Для него есть алиас:
$row = go\DB\query('SELECT * FROM `table` WHERE `id`=?i', [$id])->row();
Смысл всего этого: в большинстве случаев в приложении используется одна БД или одна БД является наиболее используемой. Можно сделать её центральной и не задумываясь об объектах, выполнять запросы через доступные везде функции.
/* At the beginning */
$configDB = [ /* Databases config */ ];
go\DB\Storage::getInstance()->create($configDB); // create main database in main storage
/* Inside application code - query */
$rowId = go\DB\query('INSERT INTO `table` VALUES (?l)', [$values], 'id');
Разница между go\DB\query()
и go\DB\Storage::query()
такая же, как и между go\DB\create()
и go\DB\DB::create()
.
Первый вариант короче и правильнее, но для его использования нужно быть уверенным, что файл DB.php
подключён.
При использовании же второго варианта сработает автозагрузчик.
При попытке запроса к центральной базе хранилища, в котором она не определена, выбрасывается исключение StorageDBCentral.