Article controller

The ArticleController class is responsible for rendering, search, sort and filter articles.

controller/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');

The actionIndex method lists of articles. Class areto/data/ActiveDataProvider is used for sorting and pagination. Parameter query contains a query that searches for a list of published articles.

Use the sort option to display a list of items in a different order. Select article's attributes to be sorted in the attrs property. For default sort order using defaultOrder.

By default, the ActiveDataProvider class uses a pagination (10 items per page). This is required for a eye-candy display and reduce database load. Use pageSize parameter to select a different page size. If you want the entire list, set pagination: null.

controller/ArticleController.js

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

The actionSearch method lists articles filtered by the search text. This implementation is similar to the actionIndex method except query option.

controller/ArticleController.js

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

The actionView method displays a single article. If a request is received in POST format (isPost), it is treated as a form to create a new comment.

To create a new comment, load a form data (comment.load(this.getBodyParams())) to the Comment class object. Set user's IP and an article that relates with a comment.

After a comment has been successfully saved, user will receive a message (setFlash). The message is saved in the session and will be once displayed the next time page loads. Finally, reload the page this.redirect to reset the current POST request. If saving fails, a error will be shown on comment's form.

controller/ArticleController.js

async actionView () {
  const model = await this.getModel({
    with: ['category', 'mainPhoto', 'photos', 'tags']
  });
  const comment = this.spawn(Comment);
  if (this.isGet()) {
    return this.renderView(model, comment);
  }
  comment.load(this.getPostParams());
  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]);
}

The renderView method displays an article contained in the model argument. Comments related to article, are displayed via the ActiveDataProvider provider that generates paged list.

controller/ArticleController.js

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

The actionTagged method lists articles filtered by tag.

First, find a model tag by its name. This name is passed in the GET parameter tag. Create a new Tag model and set the name attribute by request data. Validate the data. If there are no errors, then create a search query by tag name. If a tag model is found, initialize the ActiveDataProvider provider. As a data source query, select the tag.relArticles() relation that returns articles with this tag.

controller/ArticleController.js

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