Контент


KO3: модуль database и модели

Предлагаю рассмотреть немногочисленные (пока) возможности по работе с БД, предоставленные «бетой» Kohana v3. Люди, «подсевшие» на комфортные ORM и Query Builder, приготовьте сердечные капли :)

Итак, для начала напомню, что все классы для работы с БД выделены в отдельный (и единственный на данный момент) модуль Database. Разработчикам показалось мало такого ущемления баз данных, они еще и исключили все драйверы, кроме MySQL (объяснив это тем, что они не используют другие СУБД, но будут рады драйверам со стороны). Однако и это еще не самое страшное. Абстрактный класс Database_Core, являющийся «сердцем» модуля, содержит в пять раз меньше методов, чем его аналог из 2.3.4.

По сути «дельными» являются только метод query($type, $sql), а также информационные list_tables() и list_columns($table). Как обычно, методы connect() и disconnect() в явном виде не требуются, т.к. в query() производится проверка на наличие линка с БД. Никаких намеков на будущее наличие методов а-ля Query Builder мы не видим, но отчаиваться не стоит — скорее всего все это будет выделено в отдельную библиотеку.

Вы заметили, что метод Database::query() принимает новый параметр $type? Возможные значения перечислены в виде констант с говорящими названиями, например Database::SELECT. Кажется, что не очень удобно, т.к. обычно из plain-запроса и так видно, какой тип. Однако давайте заглянем в библиотеку DB_Core из файла classes/db.php:

class DB_Core {
 
	public static function query($type, $sql)
	{
		return new Database_Query($type, $sql);
	}
 
	public static function select($sql)
	{
		return new Database_Query(Database::SELECT, $sql);
	}
...
}

Статические методы этой библиотеки позволят нам использовать их из любого места в приложении, например так: DB::select($sql). Теперь становится понятно, что сама по себе библиотека Database напрямую навряд ли будет использоваться, если есть такие удобные обертки.

В бете класс DB содержит 8 методов, но работать «из коробки» будут только первые два (select() и query()), остальные «ругнутся» на отсутствующие классы. По аналогии с select() можно привести в порядок методы insert(), update() и delete().

Эти методы возвращают экземпляр класса Database_Query, цель которого — сформировать и передать библиотеке Database SQL-запрос. Для заполнения запроса есть разнообразные методы, связанные с установкой внутреннего свойства $_values, оно будет использовано как хранилище плейсхолдеров. Сама подстановка значений, экранирование данных и собственно передача запроса выполняется в методе execute(). В результате, получить всех активных пользователей из таблицы users можно так:

$users = DB::select('select * from users where active=:active')
             ->values(array(':active'=>TRUE))
             ->execute();

Что с этим делать дальше? Как вы наверное догадались, метод execute() возвращает результат работы метода Database::query(), т.е. объект класса Database_Result, а еще точнее — его потомка, например Database_Mysql_Result. В целом работа с ним не изменилась (можно обрабатывать как массив, есть методы as_array() и count(), и т.д.), но есть нюанс — если в 2.3.x есть возможность указать, в каком виде возвращать записи (объекты или массивы), то в нынешнем драйвере Mysql почему-то доступны только массивы, в коде явно прописано использование mysql_fetch_assoc(). Возможно это следствие явно прослеживаемой тенденции к уменьшению количества конфигурационных файлов, увидим. В общем, забудем о $result->id, используем $result["id"].

Как я говорил в начале статьи, ORM и Query Builder отсутствуют как класс (точнее как два класса :) ), но класс Model есть. Он ничем не отличается от моделей ветки 2.3, только вместо $this->db объект Database доступен через $this->_db. Таким образом, получить все тех же многострадальных активных пользователей с использованием моделей мы сможем так:

// classes/model/user.php
class Model_User extends Model {
 
	public function get_active() {
		return DB::select('select * from users where active=:active')
             		->values(array(':active'=>TRUE))
             		->execute($this->_db);
	}
}
// classes/controller/test.php
class Controller_Test extends Controller {
	public function action_users() {
		$model = new Model_User();
		$users = $model->get_active();
		foreach($users as $user)
			$this->request->response .= "<p>".$user['username']."</p>";
	}
}

Если вспомнить о кэшировании, то на данный момент никаких встроенных методов нет. Единственное реализованное решение — метод Kohana::cache(), например он используется в Kohana::auto_load() и route::_construct() для быстрого доступа к часто повторяющейся служебной информации (в данном случае имена классов и скомпилированные REGEX‘ы маршрутов).

В общем-то это все, чем на данный момент располагает KO3. С одной стороны, тоскливо и неудобно, но с другой — какой простор для развития. :) Работайте с базами данных, используйте Kohana!

Google Bookmarks Digg Reddit del.icio.us Ma.gnolia Technorati Slashdot Yahoo My Web News2.ru БобрДобр.ru RUmarkz Ваау! Memori.ru rucity.com МоёМесто.ru Mister Wong

Опубликовано в Kohana3.

Теги: , .


Комментарии (9)

Будьте в курсе обсуждения, подпишитесь на RSS ленту комментариев к этой записи.

  1. Arhivator пишет:

    Тяжело представить конечный вариант как оно будет, но что видно сейчас, убивает на корню все удобство и красоту, которая была изначально в кохане. И это уже не впервые, что касается орм и бд.

  2. BIakaVeron пишет:

    Ну почему же так пессимистично? Мне к примеру нравится идея с использованием статических методов типа DB::select(). Query Builder сейчас уже практически закончен, сейчас разглядываю его внутренности. ORM тоже уже начали портировать, но пока что все только в зародыше.

    PS. Как по мне, весьма симпотично смотрится: QBuilder.

  3. vlad пишет:

    Здравствуйте. Спасибо вам за ваши статьи. Без них мне было бы вообще не разобраться что да как)
    Знакомство с коханой началось совсем недавно и пока что на данный момент умею лишь манипулировать данными в контролере и в views. Что никак пока не могу освоить так это вставка и выбор из БД.
    Понима, что в контроллере экземпляр класса из модели, вызываем его метод и в него подставляем данныем для insert. А в самой модели в этом классе реализована вставка в БД. Но я никак не могу понять синтаксис всего этого =((
    Вот простой пример:
    контроллер — метод в который поступают данный после валидации:

    $model = new Model_GB();
                    $query="INSERT INTO blog SET"
                               ." title_text='".$last_input['title_text']."',"
                               ." text='".$last_input['title_text']."'";
    		$model->query($query);


    Модель:
    classes/models/gb.php

     class Model_DB extends Model {
     
    	public function query($query)
            {
    		$result=mysql_query($query);
                    return $query;
    	}
    }


    понимаю что это очень примитивно, но пока мне сложно понять как обращаться с ORM или c какими-нибудь другими методами. Как понимаю Kohana 3 очень сильнов этом плане отличается от второй, а документации чтоб посмотреть примеры мало(
    Не могли бы вы привести пример простой вставки и выборки из таблицы?

  4. BIakaVeron пишет:

    Пожалуй, второй раз за сегодня «отмажусь» чужой статьей — почитайте тут.
    Только подобные вызовы лучше делать внутри модели, а в контроллере использовать public-методы модели, например get_article($title) или add_article(array $data)

  5. vlad пишет:

    опечатка — в модели вместе class Model_DB extends Model { надо class Model_Gb extends Model {

  6. vlad пишет:

    СПАСИБО ОГРОМНОЕ!!!!

  7. vlad пишет:

    все получилось) данные в базы записываются)
    но вот с выборкой возникли проблемы
    в модели:
    public function get_active()
    {
    return DB::select(‘title_text’,'text’)
    ->from(‘blog’)
    ->order_by(‘id’,'desc’)
    ->limit(10)
    //->as_object()
    ->execute($this->_db);
    }

    в контролере:
    $model = new Model_Gb();
    $posts = $model->get_active();
    но когда я смотрю что находиться в $posts — print_r($posts) мне вместо данных из базы выдает следущее:
    Database_MySQL_Result Object
    (
    [_internal_row:protected] => 0
    [_query:protected] => SELECT `title_text`, `text` FROM `blog` ORDER BY `id` DESC LIMIT 10
    [_result:protected] => Resource id #52
    [_total_rows:protected] => 7
    [_current_row:protected] => 0
    [_as_object:protected] =>
    )
    я думал данные уже будут в виде массива. Оказывается нет. Подскажите пожалуйста, как можно их получить?

  8. BIakaVeron пишет:

    Работайте с ним как с массивом, не обращайте внимание. Циклы типа foreach, обращение к элементу по его смещению — все это работает ;)

  9. vlad пишет:

    ) чтобы я делал без вашей помощи — все равботает)
    спасибо Вам!



Можно включить подсветку кода: <code><pre lang="">...</pre></code>
Разрешены некоторые HTML теги

или используйте trackback.