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

Контроллер фотографий

Класс PhotoController определяет контроллер модели фото.

modules/admin/controllers/PhotoController.js

'use strict';
const Base = require('../components/CrudController');
module.exports = class PhotoController extends Base {

  static getConstants () {
    return {
      METHODS: {
        'assign-main': ['post']
      }
    };
  }

  getModelClass () {
    return require('../models/Photo');
  }
};
module.exports.init(module);
const async = require('async');
const Article = require('../models/Article');
Создание фото

Метод actionCreate создает модель фотографии. Массив асинхронных методов async.series получает данные для списка выбора статьи Article.findToSelect, к которой может быть привязано фото.

modules/admin/controllers/PhotoController.js

...
actionCreate () {
  let model = new (this.getModelClass());
  model.scenario = 'create';
  let params = {model};
  async.series([
    cb => Article.findToSelect().all(cb)
  ], (err, result)=> {
    if (err) {
      return cb(err);
    }
    params.articles = result[0];
    if (this.isPost()) {
      model.load(this.getBodyParams()).save(err => {
        err ? this.throwError(err)
            : model.isNewRecord ? this.render('create', params) : this.backToRef();
      });
    } else { 
      this.render('create', params);
    }  
  });
}
...
Просмотр загруженного фото

Метод actionView вызывает родительский метод для загрузки необходимых отношений.

modules/admin/controllers/PhotoController.js

...
actionView () {
  super.actionView('article');
}
...
Редактирование фото

Метод actionUpload сохраняет загруженный файл на сервер. Если файл проходит проверку, то из него создается модель фотографии, не привязанная к статье.

modules/admin/controllers/PhotoController.js

...
actionUpload () {
  let File = require('../models/File');
  let file = new File;
  file.upload(this, err => {
    if (err) {
      this.throwError(err);
    } else if (file.hasError()) {
      this.sendText(this.translate(file.getFirstError()), 400);
    } else {
      let photo = new (this.getModelClass());
      photo.set('file', file.getId());
      photo.validate(err => {
        if (err) {
          this.throwError(err);
        } else if (photo.hasError()) {
          this.sendText(this.translate(photo.getFirstError()), 400);
        } else {
          this.sendText(file.getId());
        }
      }, ['file']);
    }            
  });
}
...

Метод actionAssignMain устанавливает фото как главное в статье. Сохранение статьи осуществляется через метод forceSave, который не производит валидацию модели. Если у фотографии нет связанной статьи, то устанавливается flash-сообщение об ощибке (одноразовое сообщение в пользовательской сессии) и идет переадресация на страницу просмотра фото.

modules/admin/controllers/PhotoController.js

...
actionAssignMain () {
  this.getModel(model => {
    let article = model.get('article');
    if (article) {
      article.set('mainPhotoId', model.getId());
      article.forceSave(err => {
        err ? this.throwError(err) : this.redirect(['article/view', article]);
      });
    } else {
      this.setFlash('danger', 'Article not found');
      this.redirect(['view', model]);
    }
  }, 'article');
}
...