ЗаписиТеперь займёмся основной частью нашего сайта - ведением записей. Всю нужную работу будет выполнять контроллер с именем Records. Создайте его с
помощью утилиты yiic командой "crud Records" (
http://www.yiiframework.com/doc/guide/ru/q...start.first-app и
http://www.yiiframework.com/doc/guide/ru/topics.console ). Не забудьте предварительно создать и соответствующую модель,
иначе контроллер просто не сможет быть создан и в командную строку выплеснется множество ошибок.
Откроем файл /protected/controllers/RecordsController.
php и обратим внимание на его методы. Первый из интересующих нас -
"accessRules" (http://www.yiiframework.com/doc/guide/ru/topics.auth#access-control-filter). Здесь содержатся правила доступа
к действиям контроллера. Сразу после создания они следующие:
1. Любым пользователям разрешено просматривать записи в виде списка и по отдельности (методы list и show)
2. Авторизированным пользователям разрешено добавлять записи и изменять их (методы create, update)
3. Администраторам разрешены функции администрирования и удаления (методы admin, delete)
4. Всё остальное всем запрещено
В принципе, нам ничего тут менять не нужно. Только лишь передать права удаления авторизированным пользователям и стереть из
прав действие admin. Его функционал будет заменён, поэтому можете удалить и само действие. Мы сделаем так, чтоб каждый смог
управлять своими записями, в том числе и удалять их.
Действие create. В самом начале происходит проверка наличия отправленных пользователем
данных. Если таковые присутствуют то
они вносятся в базу, в ином случае - обрабатывается шаблон "create". Он содержит в себе пару ссылок и вызов шаблона "_form".
Отображению "_form", в свою очередь, передаётся параметр update. Почти такой-же код есть и в шаблоне обновления сообщения. Вообщем,
здесь для двух действий используется одна и та же форма, только передаются ей, при обработке, разные значения параметра "update".
Код кнопок можете спокойно затирать, оставьте лишь вызов формы. А код отображаемого шаблона _form заменим на следующий.
HTML |
<?if($update):?> <h2>Обновление записи</h2> <?else:?> <h2>Создание новой записи</h2> <?endif;?> <div class="actionBar"> </div> <?if($update):?> <form action="/records/update/" method="POST"> <?else:?> <form action="/records/create/" method="POST"> <?endif;?> <table width="100%"> <tr> <td width="20%"><span class="text">Название записи</span></td> <td> <input type="text" name="Records[title]" class="long_field" value="<?=$model->title?>"/> </td> </tr> <tr> <td colspan="2"><span class="text">Текст записи:</span></td> </tr> <tr> <td colspan="2"><textarea name="Records[text]" class="long_textarea" rows="20"><?=$model->text?></textarea></td> </tr> <tr> <td colspan="2"> <input type="submit" name="createRecord" value="Добавить запись"> </td> </tr> </table> </form> |
Здесь мы отправляем 2 параметра - название записи и её содержимое. Но в базе есть ещё 3 поля - время публикации, номер автора и
количество просмотров. Добавим их в POST-массив перед помещением данных в модель, и уже всё вместе занесём в БД. Вот код который должен
быть вызван в том случае если массив $_POST["Records"] обнаружен.
PHP |
$_POST['Records']['pub_date'] = time(); $_POST['Records']['author_id'] = Yii::app()->user->getId(); $_POST['Records']['views'] = 0; // Вносим все данные в модель $model->attributes=$_POST['Records']; // Сохраняем if($model->save()) $this->redirect(array('show','id'=>$model->id)); |
После сохранения пользователь будет перенесён на действие show, контроллера Records, передав в качестве параметра id номер новоиспечённой
записи (ссылка типа /records/show/id/5/).
Метод actionShow. Он отображает запрошенную запись, в зависимости от указанного id. Его код состоит из одной строки. В ней вызывается
соответствующий шаблон, принимая результат работы метода loadRecords. В отображении этот результат обрабатывается, и полученные данные
выводятся пользователю. Всё идеально, но есть небольшая загвоздка. В
данных сообщения нет одного - имени автора. Есть только его идентификатор
(поле author_id). Давайте настроим связь между моделями Records и Users так, чтоб при запросе одной или нескольких записей автоматически запрашивались
имена их авторов (
http://www.yiiframework.com/doc/guide/ru/d...ng-relationship ). Для этого в первой модели найдите метод "relations"
и в возвращаемый им массив внесите ячейку "author", куда будет помещена связь со второй моделью.
PHP |
'author' => array(self::BELONGS_TO,'Users','author_id'), |
Теперь в каждой записи кроме основных полей будет добавлено поле author, содержащее результат работы запроса "SELECT * FROM users WHERE id=$author_id".
В отображение все эти данные поступят вместе с остальными, так что нам нужно всего лишь напечатать свойство "$model->author->login". Вот полный код
шаблона show.
HTML |
<?if($model === null):?> Запрашиваемой записи не существует. <?else:?> <h2><?php echo $model->title; ?>(<?=date("d-m-Y",$model->pub_date)?>/<?=$model->author->login;?>)</h2><br /> <p><?=$model->text;?></p> <!-- Если текущий пользователь является автором этого сообщения то выводим ссылки "Редактировать" и "Удалить" --> <?if($model->author_id == Yii::app()->user->getId()):?> <a href="/records/edit/id/<?=$model->id?>/">Редактировать</a> &amp;amp;amp;amp;amp;nbsp;|&amp;amp;amp;amp;amp;nbsp; <a href="/records/delete/id/<?=$model->id?>/">Удалить</a> <?endif;?> <?endif;?> |
Ничего сверхъестественного. Попробуйте добавить запись и просмотреть её.
Метод actionList - просмотр списка записей. Разберём всё что в нём делается. Сначала создаётся объект класса CDbCriteria
(
http://www.yiiframework.com/doc/api/CDbCriteria ). С помощью него, при выборке
данных из
базы, указывается сколько записей нужно выбрать
( количество указано в константе PAGE_SIZE нашего контроллера ). Затем эти данные извлекаются. Они передаются в отображение и выводятся на экран.
В конце создаётся объект класса CPagination (
http://www.yiiframework.com/doc/api/CPagination ), отвечающий за разбиение материала на страницы.
В самом действии почти ничего не нужно менять. Надо внести лишь 2 небольших изменения. Во-первых, значение константы PAGE_SIZE измените на 3.
Во-вторых изменим код самого контроллера так, чтобы он показывал список не всех сообщений, а того пользователя, чей идентификатор передан в параметре
"user_id" ( ссылка будет выглядеть вот так -
http://yii/records/list/user_id/3 ). В самое начало кода добавим обработку поступившего номера пользователя.
PHP |
$user_id = (int) $_GET['user_id']; |
А сразу после создания объекта класса CDbCriteria заполним его свойство "condition", содержащее условия для выборки.
PHP |
$criteria->condition = "author_id={$user_id}"; |
Обратите внимание вот на что. В начале шаблона ( то есть до обработки полученных данных ) мы должны вывести надпись "Список сообщений пользователя...".
Для того чтоб получить имя автора можно написать в модели соответствующую функцию, вызвать её, передав в качестве исходных данных номер пользователя в
базе, и результат отдать в отображение. А можно взять его сразу из массива сообщений ещё до их обработки. Например, из нулевой записи
Возможно первый вариант в чём-то лучше, но мы будем использовать второй - он проще и быстрее.
На очереди шаблон "list". Сотрите из него весь код и внесите туда вот что.
HTML |
<h2>Список сообщений пользователя <?=$models[0]->author->login;?></h2><br /> <?php foreach($models as $n=>$model): ?> <h2><?php echo $model->title; ?>(<?=date("d-m-Y",$model->pub_date)?>)</h2> <p><a class="text" href="/records/show/id/<?=$model->id;?>"><?=substr($model->text,0,200);?>...</a></p> <br /> <?endforeach;?> <!--шаблон страниц--> <?php $this->widget('CLinkPager',array('pages'=>$pages)); ?> |
Здесь мы сначала сообщаем чей список записей в данный момент просматривает пользователь, а затем выводим и сами сообщения, отображая в виде анонса 200
первых символов текста. Можете сейчас пройти по ссылке
http://yii/records/list/user_id/5 и Вы увидите блог пользователя Николай.
В правом нижнем углу страницы можно заметить перекорёженое изображение постраничной навигации. Оно выводится виджетом CLinkPager. Здесь мы напоролись
на один из минусов Yii. По каким-то причинам отображений у CLinkPager нет. HTML-код, который Вы видите, находится прямо в PHP-коде виджета. Исправим
это. Откройте файл ClinkPager.
php, находящийся в директории /base/framework/web/widgets/pagers/. Нас интересует методы run и createPageButton. Первый
собирает общий html-код и выводит его на экран. Второй - формирует код кнопок. Переделаем код под более-менее стандартный вид. Для этого мы создадим
дерикторию views в папке с виджетом, и поместим туда 2 шаблона. Первый - pageButton.
php. Он содержит код одной ссылки на страницу.
HTML |
<?if(!$hidden):?> <?if($selected):?> <b><?=$label?></b>&amp;amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;amp;nbsp; <?else:?> <a class="text" href="/records/list/user_id/<?=(int)$_GET['user_id']?>/page/<?=$page+1?>"><?=$label?></a> <?endif;?> <?endif;?> |
Второй - pagesLayout, содержащий код отбражения страниц.
HTML |
<br /> <br /> <br /> <br /> <center> <p> <?foreach($buttons as $button):?> <?=$button?> <?endforeach;?> </p> </center><br /><br /> |
Теперь обратимся к методу createPageButton. Вначале, в зависимости от переменных $hidden и $selected формируется класс тега <li>,
затем сам тег собирается и возвращается в виде результата. Заменим всё это одной строкой. Возвратим об
работанный шаблон нашей кнопки, куда
передадим все поступившие в функцию данные. В этом нам поможет метод renderPartitional (
http://www.yiiframework.com/doc/api/CContr...rPartial-detail ), класса CController - он не выводит об
работанное отображение, а возвращает его.
PHP |
return Ccontroller::renderPartial("pageButton",Array('page'=>$page,'label'=>$label,'hidden'=>$hidden, 'selected'=>$selected), true); |
В методе run мы просто сотрём весь код начиная с объявления переменной $htmlOptions. За место него вызовем всё тот-же renderPartitional, передав
ему код кнопок.
PHP |
echo CController::renderPartial("pagesLayout",Array("buttons"=>$buttons)); |
Всё, после этих манипуляций виджет работает с шаблонами и отображает нормальную по виду строку с выбором страниц. Осталось только осуществить
перевод слов типа Next, Last и т.д. Для этого откроем наш языковой файл и внесём туда следующие ячейки.
PHP |
"Next &amp;amp;amp;amp;gt;" => "Следующая &amp;amp;amp;amp;gt;", "&amp;amp;amp;amp;lt; Previous" => "&amp;amp;amp;amp;lt; Предыдущая", "&amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; First" => "&amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; Первая", "Last &amp;amp;amp;amp;gt;&amp;amp;amp;amp;gt;" => "Последняя &amp;amp;amp;amp;gt;&amp;amp;amp;amp;gt;", "Go to page:" => "Страницы:", |
А в методе run, виджета, в самом начале, изменим категории в вызовах метода t, с "yii" на "common"
PHP |
if($this->nextPageLabel===null) $this->nextPageLabel=Yii::t('common','Next &amp;amp;amp;amp;gt;'); if($this->prevPageLabel===null) $this->prevPageLabel=Yii::t('common','&amp;amp;amp;amp;lt; Previous'); if($this->firstPageLabel===null) $this->firstPageLabel=Yii::t('common','&amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; First'); if($this->lastPageLabel===null) $this->lastPageLabel=Yii::t('common','Last &amp;amp;amp;amp;gt;&amp;amp;amp;amp;gt;'); if($this->header===null) $this->header=Yii::t('common','Go to page: '); |
Теперь постраничная навигация отображается по-русски.
Изменение записей. Редактирование сообщений осуществляется через метод actionUpdate. Как Вы помните из описания метода actionCreate, он использует
форму "_form". Единственное, что здесь требует редактирования, это шаблон update. Удалите там всё кроме вызова формы.
PHP |
<?php echo $this->renderPartial('_form', array('model'=>$model, 'update'=>true,)); |
Для того чтобы пользователи не могли редактировать чужие сообщения можно сразу после объявления переменной $model, в методе actionUpdate, вставить
одну строку.
PHP |
if($model->author_id != Yii::app()->user->getId()) $this->redirect("/"); |
Она сверит номер автора сообщения с номером текущего пользователя и в случае их несовпадения завершит работу, перебросив пользователя на главную страницу.
Действие delete. В нём требуется только вставить проверку авторства пользователя и исправить редирект после удаления. Для этого мы в начало метода
внесём следующий код.
PHP |
$record=$this->loadRecords(); if($record->author_id != Yii::app()->user->getId()) $this->redirect("/"); |
А код редиректа заменим на такой.
PHP |
$this->redirect(array('list','user_id'=>$record->author_id)); |
Вот и всё. Можно приступить к следующему этапу.