Изменения в Yii 1.1: CActiveDataProvider

20 февраля, 2010
yii data provider

Я всё-таки решил продолжить обсуждение фреймворка Yii. Но на этот раз затяжных циклов я не планирую :) , просто хочу рассказать о некоторых нововведениях в версиии 1.1.

Как вы, наверное, знаете, версия 1.1 довольно сильно отличается от 1.0.х. Есть и инструкция по переходу на новую версию.

Но есть момент, который может вызвать вопросы у тех, кто начинает знакомство с фреймворком с версии 1.1. Речь о классе CActiveDataProvider. Как несложно догадаться по названию, он предназначен для работы с базой данных. И если вы создадите сайт с помощью консольной утилиты yiic, то этот класс будет использован в методах actionIndex и actionAdmin контроллеров.

Класс очень удобный и позволяет сократить объём кода. Проблема в том, что документация немного отстаёт от жизни. В разделе о работе с базой данных подробно рассказывается об использовании классов CActiveRecord, CDbCriteria и других, но информация о CActiveDataProvider есть только в API.

Итак, что представляет собой этот класс.

По большому счёту это обёртка вокруг четырёх классов CActiveRecord, CDbCriteria, CPagination и CSort. Именно с их помощью выполняется основная работа с базой данных и очень часто все эти классы используются одновременно. Поэтому вполне логично, что разработчики решили создать общую оболочку для работы с ними.

Рассмотрим небольшой пример.

В версиях 1.0.х для вывода записей какой-нибудь таблицы с разбивкой на страницы (пагинацией) использовался следующий код.

$criteria=new CDbCriteria;

$pages=new CPagination(Screenshots::model()->count($criteria));
$pages->pageSize=self::PAGE_SIZE;
$pages->applyLimit($criteria);

$sort=new CSort('Screenshots');
$sort->applyOrder($criteria);

$models=Screenshots::model()->findAll($criteria);

$this->render('admin',array(
	'models'=>$models,
	'pages'=>$pages,
	'sort'=>$sort,
));

Обратите внимание, что здесь создаются экземпляры CDbCriteria, CPagination и CSort. При этом с помощью CDbCriteria мы можем изменять SQL запросы, которые создаёт модель (Screenshots). CPagination используется для настройки пагинации, а CSort – сортировки записей. Массив с объектами CActiveRecord возвращает метод findAll модели. Обратите внимание, что для настройки, которые хранятся в CDbCriteria используются всеми остальными классами.

Теперь взгляните на то, как решается эта же задача в версии 1.1.

$dataProvider=new CActiveDataProvider('Screenshots', array(
	'pagination'=>array(
		'pageSize'=>self::PAGE_SIZE,
	),
));

$this->render('admin',array(
	'dataProvider'=>$dataProvider,
));

Правда, значительно лучше выглядит? ;) Хотя, на самом деле, работает код точно также. Просто все экземпляры объектов CPagination, CSort и CDbCriteria находятся внутри CActiveDataProvider.

Обратите внимание, что в первом параметре конструктора мы передаём название модели, данные которой нужно получить. CActiveDataProvider сам вызовет соответствующие методы find() или findAll().

Тут возникает вполне резонный вопрос: «Каким образом настраивать поиск, разбивку на страницы и т.п.?» Всё очень просто, нужно передать массив с соответствующими параметрами в конструкторе. Например.

$dataProvider=new CActiveDataProvider('Post', array(
	'criteria'=>array(
		'condition'=>'status=1 AND tags LIKE :tags',
		'params'=>array(':tags'=>$_GET['tags']),
		'with'=>array('author'),
	),
	'pagination'=>array(
		'pageSize'=>20,
	),
));

Как видите, настройки указываются точно так же, как и в предыдущих версиях (по большому счёту это они и есть). Т.е. вы можете спокойно использовать документацию по CDbCriteria при настройке CActiveDataProvider.

Кроме того, если возникнет необходимость, можно использовать методы getCriteria(), setCriteria(), getSort(), setSort() для чтения и установки соответствующих объектов.

Передача данных в представление.

Как несложно заметить по листингам, в версиях 1.0.х необходимо было передавать три параметра: с данными, настройками пагинации и сортировки. В новом варианте передаётся только один – сам объект CActiveDataProvider.

При этом если вы будете вручную вытягивать из него данные, код получится довольно объёмным. Но в версию 1.1 входят компоненты zii, один из которых (zii.widgets.grid.CGridView) специально разработан для использования вместе с CActiveDataProvider. Т.е. вы передаёте ему экземпляр CActiveDataProvider и заголовки столбцов, а он на основе этих данных формирует таблицу.

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

Интересно почитать

Раскрутка сайта занятие увлекательное, но ошибки обойдутся недёшево.

Понравилась статья? Подписывайтесь на продолжение rss link !

Или на мой твиттер twitter link

]]>

Добавьте эту страницу в google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru

]]>

Опубликовано в MySQL, PHP, Web разработка, Yii Комментарии (26) »

]]>

Вы можете оставить комментарий. Трекбеки закрыты.

  • xandeadx

    а можно результат работы виджета zii.widgets.grid.CGridView в виде скрина?

  • xandeadx

    а можно результат работы виджета zii.widgets.grid.CGridView в виде скрина?

  • http://rmcreative.ru/ Sam

    http://www.zhex.net/wp-content/uploads/2009/12/GRIDVIEW1.JPG

    Кстати, text-align: justify тут выглядит ужасно!

    • http://www.simplecoding.org/ Владимир

      Где именно? В статье?

  • http://rmcreative.ru/ Sam

    http://www.zhex.net/wp-content/uploads/2009/12/GRIDVIEW1.JPG

    Кстати, text-align: justify тут выглядит ужасно!

    • http://www.simplecoding.org/ Владимир

      Где именно? В статье?

  • http://dodreams.blogspot.com/ VanSanblch

    Yii весьма… неоднозначный фреймворк. Особенно после CI :)
    Но понравился очень. Быстрый, удобный, красивый. Правда для себя отметил два "но".
    Во-первых очень своеобразные конфиги. Непривычно писать конфиг в виде return.
    А второе, поправьте меня если я не прав, но Yii это фреймворк сам в себе. Поясню. Мне очень нравится как написаны контроллеры, чуть меньше нравится работа представлений, но вот модель… Даже не сама модель, а часть работы с базой мне не нравится. Чуть усложнишь базу и нативная модель даёт сбой. Приходится подключать Doctrine. В этом плане нравится symfony, где работа с моделью сразу ведётся средствами Doctrine или Proper на выбор.
    В частности пришлось писать свой класс DoctrineDataProvider (к счастью не очень сложно). А с учётом того что в версии 1.1.1 планируется класс CActiveFrom… Опять они очень сильно специализируются…

    • http://www.simplecoding.org/ Владимир

      По большому счету, они нигде не говорили, что их библиотека для работы с БД – аналог Doctrine или Propel.

      Конфиги – дело привычки. Настройки хранятся в виде массива, а используется return или нет – дело десятое (на мой взгляд).

      • http://dodreams.blogspot.com/ VanSanblch

        Аналог, не аналог, но и то и другое и третье – ORM с различным уровнем возможностей. Что-то удобнее, что-то… менее удобнее. Но это, как и конфиги, вы правильно выразались – дело привычки. И я бы ещё добавил – особенности проектируемого приложения. В одном у меня замечально работаеит их нативый AR. Но для другого – он не подходит и понадобился Doctrine.

        • http://www.tvoya-kariera.ru/ АлексZ

          Расскажите для каких задач не подходит их AR?

        • http://www.simplecoding.org/ Владимир

          Полностью согласен насчет особенностей проектируемого приложения.

          Но насчет терминологии поспорю. Active Record, Data Gateway, Object Relational Mapping – это все разные паттерны. И если всех их считать производными от ORM, то тогда проще их просто назвать "библиотеками для работы с БД" и вообще не морочить себе голову с названиями.

          И, если можно, вопрос. На ваш взгляд, человеку, который вообще не работал с ORM, какой из них будет понятнее (Propel, Doctrine или что-нибудь попроще, вроде RedBean)? Я планирую пост на эту тему, но нужен хороший пример, не хочется что бы получилась просто очередная инструкция "как подключить ORM".

  • http://dodreams.blogspot.com VanSanblch

    Yii весьма… неоднозначный фреймворк. Особенно после CI :)
    Но понравился очень. Быстрый, удобный, красивый. Правда для себя отметил два "но".
    Во-первых очень своеобразные конфиги. Непривычно писать конфиг в виде return.
    А второе, поправьте меня если я не прав, но Yii это фреймворк сам в себе. Поясню. Мне очень нравится как написаны контроллеры, чуть меньше нравится работа представлений, но вот модель… Даже не сама модель, а часть работы с базой мне не нравится. Чуть усложнишь базу и нативная модель даёт сбой. Приходится подключать Doctrine. В этом плане нравится symfony, где работа с моделью сразу ведётся средствами Doctrine или Proper на выбор.
    В частности пришлось писать свой класс DoctrineDataProvider (к счастью не очень сложно). А с учётом того что в версии 1.1.1 планируется класс CActiveFrom… Опять они очень сильно специализируются…

    • http://www.simplecoding.org/ Владимир

      По большому счету, они нигде не говорили, что их библиотека для работы с БД – аналог Doctrine или Propel.

      Конфиги – дело привычки. Настройки хранятся в виде массива, а используется return или нет – дело десятое (на мой взгляд).

      • http://dodreams.blogspot.com VanSanblch

        Аналог, не аналог, но и то и другое и третье – ORM с различным уровнем возможностей. Что-то удобнее, что-то… менее удобнее. Но это, как и конфиги, вы правильно выразались – дело привычки. И я бы ещё добавил – особенности проектируемого приложения. В одном у меня замечально работаеит их нативый AR. Но для другого – он не подходит и понадобился Doctrine.

        • http://www.tvoya-kariera.ru АлексZ

          Расскажите для каких задач не подходит их AR?

        • http://www.simplecoding.org/ Владимир

          Полностью согласен насчет особенностей проектируемого приложения.

          Но насчет терминологии поспорю. Active Record, Data Gateway, Object Relational Mapping – это все разные паттерны. И если всех их считать производными от ORM, то тогда проще их просто назвать "библиотеками для работы с БД" и вообще не морочить себе голову с названиями.

          И, если можно, вопрос. На ваш взгляд, человеку, который вообще не работал с ORM, какой из них будет понятнее (Propel, Doctrine или что-нибудь попроще, вроде RedBean)? Я планирую пост на эту тему, но нужен хороший пример, не хочется что бы получилась просто очередная инструкция "как подключить ORM".

  • гост

    Если использовать CSort и в модель добавить relations связь со второй таблицей, то при сортировке по полю, имеющему такое же имя полей в 1-ой и во 2-ой выдает ошибку 1052. Как с этим бороться еще не решил.
    Надеюсь доступно объяснил)

    • гост

      Нашел такое решение. для сортировки по значению из первой таблицы:
      таблица 1, поля: page_id,title,type,created
      таблица 2, поля: type_id,title,…
      Метод relations в модели.

      public function relations()
      {
      return array('page_type' =>
      array(self::BELONGS_TO, 'Page_type', 'type','select'=>'page_type.title'));
      }

      Выборка в контроллере:

      $criteria=new CDbCriteria;
      $pages=new CPagination(Page::model()->count($criteria));
      $sort=new CSort('Page');
      $sort->applyOrder($criteria);
      $criteria->with=array('page_type');
      $criteria->order='t.'.$criteria->order;

      $models=Page::model()->findAll($criteria);

      Насколько данный метод правильный?

      • http://www.simplecoding.org/ Владимир

        Я не сталкивался с такой ситуацией, поэтому точно не отвечу. Но выглядит вполне нормально. В документации так и сказано, если имена полей одинаковы, то к ним нужно добавлять имя таблицы. Вы так и сделали ;)

        • гост

          Я думал, что можно где то в метода прописать что нужно и yii автоматом все сделает:)
          Во всяком случае, если найду более красивое решение – отпишусь.
          Спасибо)

  • гост

    Если использовать CSort и в модель добавить relations связь со второй таблицей, то при сортировке по полю, имеющему такое же имя полей в 1-ой и во 2-ой выдает ошибку 1052. Как с этим бороться еще не решил.
    Надеюсь доступно объяснил)

    • гост

      Нашел такое решение. для сортировки по значению из первой таблицы:
      таблица 1, поля: page_id,title,type,created
      таблица 2, поля: type_id,title,…
      Метод relations в модели.

      public function relations()
      {
      return array('page_type' =>
      array(self::BELONGS_TO, 'Page_type', 'type','select'=>'page_type.title'));
      }

      Выборка в контроллере:

      $criteria=new CDbCriteria;
      $pages=new CPagination(Page::model()->count($criteria));
      $sort=new CSort('Page');
      $sort->applyOrder($criteria);
      $criteria->with=array('page_type');
      $criteria->order='t.'.$criteria->order;

      $models=Page::model()->findAll($criteria);

      Насколько данный метод правильный?

      • http://www.simplecoding.org/ Владимир

        Я не сталкивался с такой ситуацией, поэтому точно не отвечу. Но выглядит вполне нормально. В документации так и сказано, если имена полей одинаковы, то к ним нужно добавлять имя таблицы. Вы так и сделали ;)

        • гост

          Я думал, что можно где то в метода прописать что нужно и yii автоматом все сделает:)
          Во всяком случае, если найду более красивое решение – отпишусь.
          Спасибо)

  • Anton

    "В версиях 1.1.х для вывода записей какой-нибудь таблицы с разбивкой на страницы (пагинацией) использовался следующий код"

    Опечатка? В версиях 1.0.*

  • http://www.simplecoding.org Владимир

    Вы правы, исправил.
    Спасибо!

]]>
Tweet