Yii PHP framework: создание запросов с условием IN

3 июля, 2010
yii in condition

Последнее время мне довольно часто приходится работать с фреймворком Yii. И иногда возникают вопросы, ответы на которые не очевидны (во всяком случае для меня).

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

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

Т.е. нужно сформировать примерно такой запрос.

  1. SELECT * FROM tbl_users WHERE id IN (1, 2, 3)


В Полном руководстве на эту тему информации я не нашел, а копаться в методах CActiveRecord времени не было.

Вообще, я очень не люблю такие ситуации. С одной стороны, понятно как нужно написать запрос, с другой – хочется сделать это красиво, используя встроенную библиотеку. Копаться в документации не хочется, ведь на это уходит время, а запрос можно составить за считанные минуты. Но не все так просто.

Сначала покажу решение «в лоб».

  1. $ids = array(1, 2, 3);
  2.  
  3. $dataProvider=new CActiveDataProvider('User',array(
  4.     'criteria'=>array(
  5.         'condition'=>'id IN ('.implode(',', $ids).')',
  6.     )
  7. ));
  8.  
  9. $this->render('admin',array(
  10.     'model'=>$dataProvider,
  11. ));

Тут мы формируем массив со значениями, которые будут перечислены после IN. А затем, с помощью функции implode преобразуем его в строку и просто вставляем в запрос.

Недостатки такого подхода очевидны.

Во-первых, выглядит код не очень красиво.

Во-вторых, в реальном приложении значения для массива $ids будут откуда-то поступать, возможно, из параметров запроса. И если массив $ids окажется пустым, то при выполнении запроса возникнет ошибка.

В-третьих, полученные значения нужно проверить. А написать что-то вроде

  1. 'params'=>array(':id'=>implode(', ', $ids)),

не получится, т.к. результат работы функции implode будет взят в кавычки. Т.е. проверку необходимо сделать предварительно.

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

Решение с помощью библиотеки Yii.

Оно выглядит гораздо проще.

  1. $model = User::model()->findAllByAttributes(array('id'=>array(1, 2, 3)));
  2. $dataProvider=new CActiveDataProvider('User');
  3. $dataProvider->setData($model);
  4.  
  5. $this->render('index',array(
  6.     'dataProvider'=>$dataProvider,
  7. ));

Метод findAllByAttributes класса CActiveRecord позволяет искать записи в БД по названию поля и значению. При этом если значение является массивом, то используется оператор IN.

Этот же самый код можно записать немного иначе.

  1. $dataProvider=new CActiveDataProvider('User');
  2. $dataProvider->criteria->addInCondition('id', array(1,2,3));
  3.  
  4. $this->render('index',array(
  5.     'dataProvider'=>$dataProvider,
  6. ));

Тут уже используется метод addInCondition класса CDbCriteria. Если вы работаете с CActiveDataProvider, то получить доступ к объекту CDbCriteria можно с помощью свойства criteria.

Теперь проведем несколько экспериментов.

Попробуем в массиве передать строку.

  1. $dataProvider->criteria->addInCondition('id', array(1,2,'test'));

В результате будет выполнен следующий запрос.

  1. SELECT * FROM 'tbl_user' WHERE "id" IN (1, 2, 0)

Т.е. текстовое значение было заменено нулем, что вполне логично, т.к. поле id имеет тип INT.

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

  1. $dataProvider->criteria->addInCondition('id', array(1, 'admin','user'));

сформирует такой запрос

  1. SELECT * FROM 'tbl_user' WHERE "id" IN ('1','admin', 'user')

А если массив окажется пуст, то фреймворк гарантирует, что из таблицы не будет выбрана ни одна запись.

  1. $dataProvider->criteria->addInCondition('id', array());
  1. SELECT * FROM 'tbl_user' WHERE 0=1

Как видите, использование встроенных библиотек всё-таки оправдывает время, потраченное на их изучение ;)

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

Так CActiveDataProvider использует CDbCriteria для формирования условий, CPagination – для разбивки на страницы, CSort – для сортировки и т.д.

Вообще, я заметил, чем больше работаешь с фреймворком, тем логичнее кажутся решения разработчиков и тем проще ориентироваться в документации :)

Удачи!

Понравилась статья? Подписывайтесь на продолжение 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 View Comments

]]>
  • Дмитрий
    Отличная статья, спасибо
    Тут както разбирался с одной задачей, пока не могу решить, имеется в базе поле допустим cat_id в котором могут храниться ID раздела или разделов и выглядеть могут примерно так 1,2 или 33,2 или 123,65,32,78 или 34
    Тоесть в данном поле могут храниться не только один ID, и могут несколько чередуясь через запятую. Вопрос, если мне потребуется вывести раздел у которого ID допустим 65 как составить запрос?
  • Использовать в запросе оператор LIKE
  • Александр
    класс, очень познавательно.
    ещё бы очень хотелось бы если вы написали статью про модули, точнее его менеджер по модулям, подключение и удаление, и т.п.
  • хорошо, учту
  • блин, такие очевидные вещи.
    вот лучше бы углубленную документацию CGridView
    а то там некоторые вещи совсем не понятны (
  • вот там разрыв мозга
  • Вы читаете мои мысли :) (о CGridView). Я как раз планирую пост об изменении дизайна и разметки этого компонента.
  • Alexy4b
    Проверь пожалуйста мейл на gala.net, там как вопрос об использовании CGridView.
  • может на неделе напишу пост на хабре о некоторых неочевидностях
  • AmdY
    к сожалению, документация очень часто устаревает и приходится копаться в коде и даже phpdoc зачастую не спасает. Поэтому блоги наше всё, из них узнаёшь кучу тонкостей.
  • К yii нужно достаточно долго привыкать, поначалу мне казалось все непонятно, потом все очень даже логично
  • BuCeFaL
    поначалу было не понятно, но это естественный процесс. Как разобрался скажу "это гениально ! "

    когда разбирался с zf (нужно было по работе) преимущество yii для меня было очевидным, причем во всем. Возможно я не прав и это дело "вкуса"
  • Мне тоже ZF показался "навороченным". Хотя широкое использование паттернов - это хорошо.
    Думаю ZF лучше подходит для больших проектов, со сложной архитектурой. Для решения простых задач приходиться писать много "лишнего" кода.
blog comments powered by Disqus ]]>