Строим блог на Areto фреймворк

Контроллер статьи

Класс ArticleController отвечает за вывод, поиск, сортировку и фильтрацию статей.

controllers/ArticleController.js

const Base = require('../component/BaseController');
module.exports = class ArticleController extends Base {
  // place methods here
};
module.exports.init(module);
const ActiveDataProvider = require('areto/data/ActiveDataProvider');
const Article = require('../model/Article');

Метод actionIndex выводит основной список статей. Для сортировки и разбиения списка на страницы используется класс areto/data/ActiveDataProvider. В параметре query задается запрос, который находит список опубликованных статей.

Для вывода статей в различном порядке, используйте параметр sort. В свойстве attrs укажите атрибуты статьи, по которым доступна сортировка списка. Для сортировки по умолчанию используйте defaultOrder.

Для удобства представления и снижения нагрузки в ActiveDataProvider по умолчанию включено постраничное разбиение (10 элементов на страницу). Используйте параметр pageSize, чтобы задать другой размер страницы. Если требуется вывести весь список целиком, то установите pagination: null.

controllers/ArticleController.js

async actionIndex () {
  let provider = this.createDataProvider({
    query: Article.findPublished()
  });
  await provider.prepare();
  await this.render('index', {provider});
}

Метод actionSearch выводит список статей отфильтрованных по поисковому тексту. Реализация аналогична методу actionIndex за исключением параметра query. Пользовательский текст из GET-параметра this.getQueryParam('text') передается аргументом в статический метод Article.findBySearch.

controllers/ArticleController.js

async actionSearch () {
  let provider = this.createDataProvider({
    query: Article.findBySearch(this.getQueryParam('text'))
  });
  await this.renderDataProvider(provider, 'index', {provider});
}

Метод actionView работает с отдельной статьей. Если запрос приходит в формате POST (isPost), то обрабатывается форма создания нового комментария.

Для создания нового комментария в объект класса Comment загрузите данные формы comment.load(this.getBodyParams()). Установите статью, к которой относится комментарий, и IP пользователя.

Если комментарий успешно сохранен, то пользователю выводится соответствующее сообщение (setFlash). Сообщение записывается в сессию и однократно отобразится при следующей загрузке страницы. Затем происходит перезагрузка страницы this.redirect, чтобы сбросить текущий POST запрос. В случае провала сохранения, ошибки будут отражены на форме комментария.

controllers/ArticleController.js

async actionView () {
  let model = await this.getModel({
    with: ['category', 'mainPhoto', 'photos', 'tags']
  });
  let comment = new Comment;
  if (this.isGet()) {
    return this.renderView(model, comment);
  }
  comment.load(this.getBodyParams());
  comment.set('articleId', model.getId());
  comment.set('ip', this.req.ip);
  await comment.save();
  if (comment.hasError()) {
    return this.renderView(model, comment);
  }
  this.setFlash('comment-done', this.translate('You message has been sent successfully!'));
  this.redirect(['view', model]);
}

Метод renderView отображает отдельную статью, указанную в аргументе model. Комментарии, относящихся к статье, выводятся через ActiveDataProvider, который формирует постраничное разбиение списка.

controllers/ArticleController.js

async renderView (model, comment) {
  let comments = this.createDataProvider({
    query: model.relComments()
  });
  await comments.prepare();
  await this.render('view', {model, comments, comment});
}

Метод actionTagged выводит список статей отфильтрованных по метке.

Сначала нужно найти модель метки по ее названию, которое передается в параметре tag GET-запроса. Создайте новую модель Tag, установите атрибут name. Проверьте полученные данные. В случае отсутствия ошибок, создайте запрос поиска метки по имени. Если метка найдена, то инициализируйте провайдер ActiveDataProvider, где в качестве источника данных query укажите отношение tag.relArticles(), возвращающее все статьи с данной меткой.

controllers/ArticleController.js

async actionTagged () {
  let tagName = this.getQueryParam('tag');
  let tag = new Tag;
  tag.set('name', tagName);
  if (!await tag.validate()) {
    return this.render('tagged', {tagName});
  }
  let model = await Tag.findByName(tagName).one();
  if (!model) {
    return this.render('tagged', {tagName});
  }
  let provider = this.createDataProvider({
    query: tag.relArticles()
  });
  await this.renderDataProvider(provider, 'tagged', {provider, tagName});
}