Skip to content

Storage

Oleg Grigoriev edited this page Mar 26, 2016 · 4 revisions

Хранилище объектов подключения

Объект подключения к базе, это объект, который обычно требуется в различных местах системы на протяжении всего времени выполнения сценария. При использовании объектов подобного рода, обычно, встаёт вопрос, а как их хранить.

В сложных системах для этого предусматриваются свои механизмы, вроде Registry, DI и тому подобного.

Для простых случаев goDB предоставляет свой механизм хранения объектов. В простых системах он позволяет даже не работать с объектами, а использовать статические методы для запросов (см. ниже).

Объект хранилища (go\DB\Storage)

Класс 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.

Clone this wiki locally