Подсказки по Yii. Глава семнадцатая.
-
primaryKey.
Если в таблице нет первичного ключа, например: `id` int(11) NOT NULL AUTO_INCREMENT + PRIMARY KEY (`id`) можно воспользоваться переопределением метода primaryKey() в модели.
Например: есть таблица `users_tel_nums` с такой структурой:
- CREATE TABLE IF NOT EXISTS `users_tel_nums` (
- `userId` int(11) NOT NULL COMMENT 'Id пользователя',
- `number` varchar(20) NOT NULL COMMENT 'Номер телефона',
- KEY `userId` (`userId`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Если в таблице будет храниться только один номер телефона пользователя, то метод primaryKey имеет вид:
- public function primaryKey() {
- return 'userId';
- }
Если же у одного пользователя может быть несколько номеров, то уже нужно использовать составной первичный ключ и метод primaryKey примет вид:
- public function primaryKey() {
- return array('userId', 'number');
- }
-
Поиск по связи HAS_MANY.
Имеются: модель Objects (список объектов), Users (список пользователей) и UsersTelNums (список телефонов пользователей). С аналогичными названиями таблиц.
Структура таблицы объектов `objects`:
- CREATE TABLE IF NOT EXISTS `objects` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `status` tinyint(1) NOT NULL COMMENT 'Статус',
- ....
- `ownerId` int(11) NOT NULL COMMENT 'Id владельца объекта',
- ...
- PRIMARY KEY (`id`),
- KEY `ownerId` (`ownerId`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Таблица users:
- CREATE TABLE IF NOT EXISTS `users` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `firstName` varchar(64) NOT NULL,
- ...
- PRIMARY KEY (`id`),
- UNIQUE KEY `email` (`email`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
И таблица users_tel_nums:
- CREATE TABLE IF NOT EXISTS `users_tel_nums` (
- `userId` int(11) NOT NULL COMMENT 'Id пользователя',
- `number` varchar(20) NOT NULL COMMENT 'Номер телефона',
- KEY `userId` (`userId`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
В модели UsersTelNums (таблица users_tel_nums) используется составной ключ в методе primaryKey. Это мы рассмотрели чуть выше.
Метод relations модели Objects:
- public function relations() {
- return array(
- ...
- 'user' => array(self::BELONGS_TO, 'Users', 'ownerId'),
- 'usersTelNums' => array(self::HAS_MANY, 'UsersTelNums', array('userId' => 'ownerId')),
- );
- }
Здесь таблица objects связывается по полю ownerId с первичным ключём (id) таблицы users. А таблица objects связывается по полю ownerId к userId (array('userId' => 'ownerId')) таблицы users_tel_nums.
Когда структура и связи описаны разберём метод search модели Objects.
В модели Objects объявим переменную ownerPhone:
Добавим название поля:
- public function attributeLabels() {
- ...
- 'ownerPhone' => 'Телефон(ы) владельца',
- }
Будем сохранять введённое значение при поиске:
- public function rules() {
- ...
- array('ownerPhone', 'safe', 'on' => 'search'),
- }
Сам метод search():
- public function search() {
- $criteria = new CDbCriteria;
-
- $criteria->compare($this->getTableAlias().'.id', $this->id);
- $criteria->compare($this->getTableAlias().'.status', $this->status, true);
-
- if ($this->ownerPhone) {
- $criteria->compare('usersTelNums.number', $this->ownerPhone, true);
- }
-
- $criteria->order = $this->getTableAlias().'.id DESC';
- $criteria->with = array(
- 'usersTelNums' => array(
- 'select'=>'usersTelNums.number',
- 'together'=>true
- ),
- );
-
-
- return new CActiveDataProvider($this, array(
- 'criteria' => $criteria,
- 'pagination'=>array(
- 'pageSize'=>50,
- ),
- ));
- }
На что хотелось бы обратить внимание - это как в таком случае нужно указывать with для $criteria.
Ну и плюс задание связи с моделью UsersTelNums:
- 'usersTelNums' => array(self::HAS_MANY, 'UsersTelNums', array('userId' => 'ownerId')),
-
CSRF и CMenu.
Есть представление view.php просмотра данных какого-то объекта.
На странице присутствует меню из ссылок на редактирование и удаление текущего объекта:
- $this->widget('zii.widgets.CMenu', array(
- 'items'=>array(
- array('label'=>tc('Update object'), 'url'=>'#', 'linkOptions'=>array('submit'=>array('update','id'=>$model->id))),
- array('label'=>tc('Delete object'), 'url'=>'#', 'linkOptions'=>array('submit'=>array('delete','id'=>$model->id),'confirm'=>'Вы действительно хотите удалить выбранный элемент?')),
- ),
- ));
Через какое-то время Вы решили добавить защиту от CSRF (http://www.yiiframework.com/doc/guide/1.1/ru/topics.security#sec-3)
И клик по таким ссылкам начал выдавать ошибку 400 "The CSRF token could not be verified.".
Решение проблемы - это добавить 'csrf' => true.
Т.е в итоге получится так:
- $this->widget('zii.widgets.CMenu', array(
- 'items'=>array(
- array('label'=>tc('Update object'), 'url'=>'#', 'linkOptions'=>array('submit'=>array('update','id'=>$model->id), 'csrf' => true)),
- array('label'=>tc('Delete object'), 'url'=>'#', 'linkOptions'=>array('submit'=>array('delete','id'=>$model->id),'confirm'=>'Вы действительно хотите удалить выбранный элемент?', 'csrf' => true)),
- ),
- ));
Обсудить статью на форуме