Контроллеры предназначены для создания URL-адресов страниц сайта. Каждый метод контроллера, имя которого начинается с action - будет урлом страницы.
Чтобы не нагородить лишнего - опять чётко сформулируем что и как мы хотим выводить:
- Список постов
- Список аккаунтов
На данный момент пока всё.
Создание контроллера
Для этих целей создадим 2 контроллера - PostController и AccountController. Как и с моделью - я воспользуюсь Gii.
Открываем /index.php?r=gii и выбираем создание контроллера.
Controller Class пишем app\controllers\PostController
После генерации будет создан файл контроллера и файл представления.
После создания контроллера у вас сразу же будет доступна страница /index.php?r=post. В её заголовке будет текущий роут, а в теле ссылка на шаблон представления.
Сейчас основной работой будет формирование выборки постов и выдача их на странице.
Так как посты будут выдаваться постранично - создадим настройку, в которой будет указано количество постов на странице, пусть это будет 10.
Для этого я добавил переменную в файл /config/params.php
return [
'adminEmail' => '[email protected]',
'posts' => [
'on_page' => 10
],
];
Начнём работать с методом actionIndex в файле PostController.php
public function actionIndex()
{
$q = Post::find()
->limit(\Yii::$app->params['posts']['on_page']);
$posts = $q->all();
return $this->render('index', ['posts' => $posts]);
}
В файле /views/post/index.php пишем
<?php
if (!empty($posts)) {
print_r($posts);
}
?>
Проверяем. Данные из моделей успешно вывелись.
Так как фильтров до четырёх, причём они необязательны - я буду передавать их GET параметрами.
Фильтры:
- авторы
- кроме авторов
- тэги
- кроме тэгов
Для передачи фильтров в URL - я создам форму. На первом этапе будем просто вписывать id тэгов и ники авторов, потом сделаем всё юзабельным.
Создание виджета с формой
Форму сделаем вручную. Давайте оформим её в виде виджета.
В корне сайта создадим папку widgets.
В ней создадим файл PostFilterForm.php с содержимым:
namespace app\widgets;
class PostFilterForm extends \yii\bootstrap\Widget {
public function init()
{
parent::init();
}
public function run() {
echo $this->render('PostFilterForm/main');
}
}
Рядом с файлом создадим папку views и в ней папку PostFilterForm и в нём файл main.php - это будет шаблон виджета - именно этот "путь" мы передаём методу render в методе run класса PostFilterForm
В файле main.php выводим форму. Пишем обычный html код.
<form action="" method="get">
<p>включить аккаунты</p>
<input name="accounts" value="">
<p>исключить аккаунты</p>
<input name="ex_accounts" value="">
<p>включить тэги</p>
<input name="tags" value="">
<p>исключить тэги</p>
<input name="ex_tags" value="">
<input name="r" value="post/index" type="hidden">
<br /><br />
<input type="submit" value="Submit">
</form>
Я пока вывел урл страницы в скрытое поле, а то форма перекидывала на главную страницу сайта.
Теперь выведем виджет на странице post.
Сделать это можно прямо в шаблоне /views/post/index.php так:
echo \app\widgets\PostFilterForm::widget();
Проверяем:
В классе виджета(PostFilterForm) будем считывать GET переменные и отображать их в форме.
//в шапке файла
use \yii\helpers\BaseHtml;
public function run() {
//принимаем GET переменные
$accounts = BaseHtml::encode(\Yii::$app->request->get('accounts', ''));
$ex_accounts = BaseHtml::encode(\Yii::$app->request->get('ex_accounts', ''));
$tags = BaseHtml::encode(\Yii::$app->request->get('tags', ''));
$ex_tags = BaseHtml::encode(\Yii::$app->request->get('ex_tags', ''));
//вторым аргументом передаём переменные в шаблон
echo $this->render(
'PostFilterForm/main',
[
'data' => [
'accounts' => $accounts,
'ex_accounts' => $ex_accounts,
'tags' => $tags,
'ex_tags' => $ex_tags,
]
]
);
}
В шаблоне /widgets/views/PostFilterForm/main.php выводим переменные:
<form action="" method="get">
<p>включить аккаунты</p>
<input name="accounts" value="<?= $data['accounts'] ?>">
<p>исключить аккаунты</p>
<input name="ex_accounts" value="<?= $data['ex_accounts'] ?>">
<p>включить тэги</p>
<input name="tags" value="<?= $data['tags'] ?>">
<p>исключить тэги</p>
<input name="ex_tags" value="<?= $data['ex_tags'] ?>">
<input name="r" value="post/index" type="hidden">
<br /><br />
<input type="submit" value="Submit">
</form>
Как видите - я специально попытался "поломать форму" - вёрстка не нарушена.
Формирование запроса к БД
Ниже я приведу листинг метода actionIndex в классе PostController.
В нём я беру переменные с адресной строки, и на их основании формулирую SQL-запрос. Код в функции документирован.
public function actionIndex()
{
//инициализация запроса
$q = Post::find()
->limit(\Yii::$app->params['posts']['on_page']);
//получение переменных
$accounts = BaseHtml::encode(\Yii::$app->request->get('accounts', ''));
$ex_accounts = BaseHtml::encode(\Yii::$app->request->get('ex_accounts', ''));
$tags = BaseHtml::encode(\Yii::$app->request->get('tags', ''));
$ex_tags = BaseHtml::encode(\Yii::$app->request->get('ex_tags', ''));
//превращение строк в массивы
if (!empty($accounts)) {
$accounts = explode(',', $accounts);
}
if (!empty($ex_accounts)) {
$ex_accounts = explode(',', $ex_accounts);
}
if (!empty($tags)) {
$tags = explode(',', $tags);
}
if (!empty($ex_tags)) {
$ex_tags = explode(',', $ex_tags);
}
$q->where(['>', 'created', 0]);
//фильтр по авторам
if (!empty($accounts)) {
$q->andWhere(['IN', 'author', $accounts]);
}
if (!empty($ex_accounts)) {
$q->andWhere(['NOT IN', 'author', $ex_accounts]);
}
//фильтр по тэгам
if (!empty($tags)) {
$filter_array = ['or'];
foreach ($tags as $tag) {
$filter_array[] = ['LIKE', 'tags', '*' . $tag . '*'];
}
$q->andFilterWhere($filter_array);
}
if (!empty($ex_tags)) {
foreach ($ex_tags as $ex_tag) {
$q->andFilterWhere(['NOT LIKE', 'tags', '*' . $ex_tag . '*']);
}
}
//сортировка
$q->orderBy(['post_id' => SORT_DESC]);
$posts = $q->all();
return $this->render('index', ['posts' => $posts]);
}
В шаблоне контроллера /views/post/index.php выводим посты:
if (!empty($posts)) {
foreach ($posts as $post) {
echo $post->title.'<br>';
echo date('Y.m.d H:i', $post->created).'<br>';
echo $post->tags.'<br>';
echo '<hr />';
}
}
Теперь попробуем отфильтровать посты по двум аккаунтам, двум тэгам и исключить по двум другим тэгам.
У меня в БД тэги пронумерованы:
- 809 - ru--blokcheijn
- 1144 - ru--otkrytyij-kod
- 805 - golos
- 804 - ru--golos
Под датой поста я вывел номера тэгов. Если вы обратите внимание - то в этой строке обязательно есть либо 809, либо 1144, и точно нет 805 и 804(в БД посты с тэгами тэгам точно есть).
Получается фильтр работает корректно.
Более подробно о работе представлений будет в следующем уроке.
Заглавное фото с сайта kwork.ru
Первая часть - вступление
Вторая часть - модели
Индийский паровозик приветствует вас, друзья @vp-webdev! ; - )
И вам привет от моего вагона и маленькой тележки))
Вот я думаю что на голосе очень не хватает функционала чтобы подобные циклы уроков собирать в группы статей. Я понимаю что есть теги, но хотелось бы какое нибудь оглавление курса, или что-то вроде этого. Это было бы круто. Можно например сделать отдельный пост со ссылками на все уроки, типа как карта сайта, прикрепить ссылку на этот пост к каждому уроку, и когда новый урок будет добавляться в блог, редактировать пост-оглавление.
Я вот минут 5 назад подумал об этом же.
Можно не только свои, но и чужие. @ontofractal например давноооо писал несколько статей о создании ботов для голоса, они мне буквально месяц назад были нужны. Хорошо я знал что они существуют, поэтому смог их найти. А так их просто и не выцепить:)
Ваш пост поддержали следующие Инвесторы Сообщества "Добрый кит":
vas, mir, archibald116, urii, vik, tristamoff, maksina, semasping, yudina-cat, polyakov, vika-teplo, del137, nerengot, wedge, ksantoprotein, xsen, anr, chupaaa, evgeniy1989
Поэтому я тоже проголосовал за него!
Узнать подробности о сообществе можно тут:
Разрешите представиться - Кит Добрый
Правила
Инструкция по внесению Инвестиционного взноса
Вы тоже можете стать Инвестором и поддержать проект!!!
Если Вы хотите отказаться от поддержки Доброго Кита, то ответьте на этот комментарий командой "!нехочу"
dobryj.kit теперь стал Делегатом! Ваш голос важен для всего сообщества!!!
Поддержите нас на странице https://golos.io/~witnesses, вот так: