Какой применить подход для обработки сущности в контроллере?

Использую фреймворк Laravel 5. Есть реальный пример, на котором бы хотелось понять какой можно применить шаблон проектирования, либо какой-то другой подход, чтобы убрать дублирование кода.

В проекте существует много контроллеров с однотипным кодом создать/обновить сущность (новости, комментарии, отзывы и т.д.).

Возьмем новости:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;

class PostsController
{
    /**
     * Создание новой записи.
     *
     * @param  Request  $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function store(Request $request)
    {
        $post = new Post;
        $post->author_id = $request->user()->id;
        $post->title = trim($request->get('title'));
        $post->slug  = str_slug($post->title);
        $post->description = trim($request->get('description'));
        $post->content = $request->get('content');

        if ($request->hasFile('cover')) {
            $file = $request->file('cover');
            $fileName = str_random(8) . '.' . $file->getClientOriginalExtension();
            $fileDirectory = '/storage/' . strtolower(substr($fileName, 0, 2));
            $file->move(public_path($fileDirectory), $fileName);
            $post->cover = "$fileDirectory/$fileName";
        }

        $post->save();
    }

    /**
     * Обновление записи.
     *
     * @param  Request  $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function update(Request $request, $id)
    {
        $post = Post::find($id);
        $post->title = trim($request->get('title'));
        $post->slug  = str_slug($post->title);
        $post->description = trim($request->get('description'));
        $post->content = $request->get('content');

        if ($request->hasFile('cover')) {
            $file = $request->file('cover');
            $fileName = str_random(8) . '.' . $file->getClientOriginalExtension();
            $fileDirectory = '/storage/' . strtolower(substr($fileName, 0, 2));
            $file->move(public_path($fileDirectory), $fileName);
            $post->cover = "$fileDirectory/$fileName";
        }

        $post->save();
    }
}


Первое, что приходит в голову — создать приватный метод в контроллере:

class PostsController
{
    public function store(Request $request)
    {
        $post = new Post;

        $this->save($request, $post);
    }

    public function update(Request $request, $id)
    {
        $post = Post::find($id);

        $this->save($request, $post);
    }

    private function save($request, $post)
    {
        $post->title = trim($request->get('title'));
        $post->slug  = str_slug($post->title);
        $post->description = trim($request->get('description'));
        $post->content = $request->get('content');

        if ($request->hasFile('cover')) {
            $file = $request->file('cover');
            $fileName = str_random(8) . '.' . $file->getClientOriginalExtension();
            $fileDirectory = '/storage/' . strtolower(substr($fileName, 0, 2));
            $file->move(public_path($fileDirectory), $fileName);
            $post->cover = "$fileDirectory/$fileName";
        }

        $post->save();
    }
}


На GitHub я встречал несколько проектов, в которых такая проблема решалась с использованием репозитория:

App\Repositories\PostRepository.php
<?php
class PostRepository
{
    public function __construct(Post $post)
    {
        $this->post = $post;
    }

    public function store(Request $request)
    {
        $post = new $this->post;

        $this->save($request, $post);

        return $post;
    }

    public function update(Request $request, Post $post)
    {
        return $this->save($request, $post);
    }

    private function save($request, $post)
    {
        $post->title = trim($request->get('title'));
        $post->slug  = str_slug($post->title);
        $post->description = trim($request->get('description'));
        $post->content = $request->get('content');

        if ($request->hasFile('cover')) {
            $file = $request->file('cover');
            $fileName = str_random(8) . '.' . $file->getClientOriginalExtension();
            $fileDirectory = '/storage/' . strtolower(substr($fileName, 0, 2));
            $file->move(public_path($fileDirectory), $fileName);
            $post->cover = "$fileDirectory/$fileName";
        }

        return $post->save();
    }
}


App\Http\Controllers\PostController.php
class PostController extends Controller
{
    protected $postRepository;

    public function __construct(PostRepository $postRepository)
    {
        $this->postRepository = $postRepository;
    }

    public function store(Request $request)
    {
        if ($this->postRepository->create($request)) {
            // Created
        } else {
            // Fail
        }
    }

    public function update(Request $request, $id)
    {
        $post = Post::find($id);

        if ($this->postRepository->update($request, $post)) {
            // Updated
        } else {
            // Fail
        }
    }
}


но т.к. я плохо знаком с шаблонами проектирования, то не уверен, что это правильный подход.
  • Вопрос задан
  • 467 просмотров
Пригласить эксперта
Ответы на вопрос 2
Можно сделать менеджер модели (сущьности) или контекстный менеджер, типа менеджер постов, который будет фасадом (иметь необходимое api) для работы с постами или почтой или чем угодно... А он уже в свою очередь будет дергать репозитории, применять стратегии обработки, спецификации...
Таким методом вы создаете слой между контроллером и низкоуровневым api, который будет применять логику. А репозитории они в основном для выборки и сохранения обработаных моделей.
Если у вас сложная логика, то в менеджере можно использовать такой подход: выбираем стратегию обработки на основе композитных спецификаций (или еще каких, их там несколько), применяем участок стратегии контекстом обработки и потом уже обработаную модель в репозиторий на сохранение.
Ответ написан
Комментировать
@Nc_Soft
Запихайте логику в модели, сделайте тонкие контроллеры и толстые модели.
На счет репозитория https://habrahabr.ru/post/316836/
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы