使用Laravel Eloquent ORM从“胖模型,瘦控制器”的角度进行工作的实践是什么?

麦克风

在阅读以下内容后,我一直在“ Fat模型,瘦控制器”的概念上吸引其他开发人员的注意:

大多数受访者都在使用我认为的胖控制器。

尽管话题已经在Stack Overflow上讨论了,但实际上我还没有找到对该方法的详尽描述。

我刚刚在这里找到一个老的相关问题

安东尼奥·卡洛斯·里贝罗

瘦控制器

您将在PHP(香草,Laravel或Symfony)中看到的越来越多,这是有史以来最纤细的控制器。这是您在Rails中已经看到的东西,并且人们也开始将其称为六边形(通过一些其他实践)。控制器中只需要一行代码,实际上他们说这应该是所有方法的目标。这是一个示例,是的,还不止于此,但仍然很瘦:

<?php

class PostController extends Controller {

    private $repository;

    public function __construct(PostRepositoryInterface $repository)
    {
        $this->repository = $repository;
    }

    public function store()
    {
        try 
        {
            $this->repository->create(Input::all());
        }
        catch (ValidationException $e) 
        {
            return Redirect::back()->withInput()->withErrors($e->all());
        }

        return Redirect::route('posts');
    }

}

控制器是HTTP请求,业务逻辑和表示层之间的桥梁。因此,它应该接收一个请求,将其发送到注入的对象,该对象将对其进行处理,然后重定向到负责向客户(或用户)提供反馈的路由(或渲染视图)。其他所有内容,包括验证,都应在您的存储库,服务,模型(MVC,是的!)等中进行。

但是我们可以以六边形的方式重构此控制器,以达到每方法一线的目标:

<?php

class PostController extends Controller {

    private $repository;

    public function __construct(PostRepositoryInterface $repository)
    {
        $this->repository = $repository;
    }

    public function store()
    {
        return $this->repository->create(Input::all(), $this);
    }

    public function createSucceeded()
    {
        return Redirect::route('posts');
    }

    public function createFailed()
    {
        return Redirect::back()->withInput()->withErrors($e->all());
    }

}

基本上,您的存储库类将使用自己的调用程序($this)触发succeededfailed方法。

胖存储库/服务/模型

模型与您的数据过于相关,有时它们是您的ORM,并且直接与您的数据库服务器对话,因此,如今,您会看到人们将存储库和服务用作它们之间的层。

储存库

存储库是一类,通过直接与您的模型进行对话,处理和收集应用程序所需的信息。您的应用程序应该不知道在数据库中选择某些信息,选择,位置,顺序,分组依据是什么,而有时候这些只是您的模型应该知道的,所以这是一个存储库:

class PostRepository implements PostRepositoryInterface {

    private $model;

    public function __construct(PostInterface $model)
    {
        $this->model = $model;
    }

    public function create($input)
    {
        return $this->model->create($input);
    }

    public findBySlug($slug)
    {
        return $this->model->where('slug', $slug)->first();
    }

}

服务

一切不直接属于您的业务逻辑的东西,主要是外部服务,离您的应用程序代码最远,构建它们的解耦越好。为这些服务创建外部程序包(Composer程序包)是将它们与其他所有功能分离的好方法,并且,如果您使它们与框架无关,则您将获得10个Sturgeon点在Laravel中,您可以通过集成三种类来创建服务:

1)服务类:负责执行您的服务必须做的事情,所有服务逻辑都在这里。

2)服务提供者:负责启动您的服务并将其添加到Laravel的IoC容器中,以便可以随时使用,但是请注意,Laravel仅在您的应用程序真正使用它们时才实例化您的服务类。

3)Facade:可让您使用静态(::)语法从应用程序中的任何位置访问服务:

Mailer::send($user->id, 'Thanks for registering', 'emails.registered');

邮件服务:

服务等级

<?php namespace ACR\Services\Mailer;

use Illuminate\Mail\Mailer as IlluminateMailer;
use Sentry;

class Service {

    public function __construct(IlluminateMailer $mailer)
    {
        $this->mailer = $mailer;    
    }

    public function send($userId, $subject, $view, $data = [])
    {
        return $this->mailer->queue($view, $data, function($message) use ($userId, $subject)
        {
            $user = Sentry::findUserById($userId);

            $message->to($user->email, $user->name);

            $message->subject($subject);
        });
    }

}

服务提供者

<?php namespace ACR\Services\Mailer;

use Illuminate\Support\ServiceProvider as  IlluminateServiceProvider;
use ACR\Services\Mailer\Service as Mailer;

class ServiceProvider extends IlluminateServiceProvider {

    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = true;

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('acr.mailer', function($app) {

            return new Mailer($app->make('mailer'));

        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return array('acr.mailer');
    }

}

正面

<?php namespace ACR\Services\Mailer;

use Illuminate\Support\Facades\Facade as IlluminateFacade;

class Facade extends IlluminateFacade {

    protected static function getFacadeAccessor() { return 'acr.mailer'; }

}

型号/ ORM

这些家伙应该是高度可交换的,今天您可能正在使用Eloquent作为您的ORM,将数据存储在数据库中,但是您可能需要将其更改为其他内容,某些fok会将其100%的数据存储在Redis中,所以您更好通过在ORM和域loginc之间使用接口(合同)层为这种变化做好准备,并真正为接口而不是具体的类进行开发。泰勒·奥特威尔(Taylor Otwell)在他的书中甚至说,您应该完全删除您的models文件夹。

interface PostInterface {

    public function all();

    public function find($id);

}

class DbPost extends Eloquent implements PostInterface {

}

class RedisPost extends Eloquent implements PostInterface {

}

其背后的想法是轻松交换实现,因此在Laravel中,您可以使用IoC容器来告诉Laravel您正在使用哪个实现:

App::bind('PostInterface', 'DbPost');

因此,如果您的存储库正在使用PostInterface:

class PostRepository implements PostRepositoryInterface {

    private $model;

    public function __construct(PostInterface $model)
    {
        $this->model = $model;
    }

}

Laravel IoC容器将使用DbPost实例自动实例化此存储库。而且,如果您需要将其更改为Redis,则只需更改一行:

App::bind('PostInterface', 'RedisPost');

视图/演示者

最愚蠢的敬畏者。

观看次数

视图仅负责显示信息。视图不应该知道您的模型,服务,存储库或系统中的任何其他内容。视图应该可由webesigners编辑,因此,您在视图上拥有的代码越多,您的非php-programmer-designer所添加的错误也就越多。您的控制器应从存储库中收集信息,并将其传递给您的视图:

<?php

class PostController extends Controller {

    private $repository;

    public function __construct(PostRepositoryInterface $repository)
    {
        $this->repository = $repository;
    }

    public function index()
    {
        return View::make('posts.index')->with('posts', $this->repository->getPaginated());
    }

}

您视图的唯一责任应该是显示以下数据:

@extends('layout')

@section('contents')
    <ul>
        @foreach($posts as $post)
            <li>
                {{ $post->title }} - {{ $post->author }} - {{ $post->published_at }}
            </li>
        @endforeach
    </ul>

    {{ $users->links() }}
@stop

演讲者

您如何格式化数据?您可以在视图中编写原始属性,但是在幕后,应该使用演示者来演示数据。演示者通常使用装饰器设计模式来格式化要在页面中显示的数据。这是使用Shawn McCool的LaravelAutoPresenter的示例:

<?php namespace App\Presenters;

use McCool\LaravelAutoPresenter\BasePresenter;

class Post extends BasePresenter {

    public function __construct(UserModel $user)
    {
        $this->resource = $user;
    }

    public function author()
    {
        return $this->resource->author->name;
    }

    public function published_at()
    {
        return $this->date($this->resource->created_at);
    }

    public function dateTime($date)
    {
        return \Carbon\Carbon::createFromFormat('d-m-Y', $date, 'Sao_Paulo/Brazil')
                     ->toFormattedDateString();
    }    
}

相关书籍

泰勒·奥特威尔(Taylor Otwell)的Laravel:从学徒到工匠

Chris Fidao的实现Laravel

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用数组更新Laravel Eloquent ORM

来自分类Dev

使用Laravel Eloquent ORM的空间点功能

来自分类Dev

使用Laravel / Eloquent订购相关模型

来自分类Dev

使用 Laravel 的 Eloquent 进行查询构建

来自分类Dev

Laravel eloquent 模型关系

来自分类Dev

为什么laravel在控制器而不是Eloquent模型中定义验证?

来自分类Dev

使用Eloquent ORM laravel连接多个表模型

来自分类Dev

LARAVEL 框架和 Eloquent ORM 模型

来自分类Dev

Laravel Eloquent模型的临时属性

来自分类Dev

Laravel Eloquent 模型之间的关系

来自分类Dev

获得 Laravel eloquent 模型关系

来自分类Dev

Laravel Eloquent属于不工作

来自分类Dev

使用Laravel Eloquent ORM实现MySQL Spatial函数

来自分类Dev

是否可以将Laravel Eloquent ORM与API结合使用

来自分类Dev

使用Laravel Eloquent ORM实现MySQL Spatial函数

来自分类Dev

Laravel Eloquent Create什么也没做

来自分类Dev

如何在助手类中使用Laravel Eloquent模型

来自分类Dev

避免使用Laravel多次/无限次触发Eloquent模型事件

来自分类Dev

如何在 Laravel Eloquent 模型中使用 where

来自分类Dev

Laravel 审计 - 如何使用 Eloquent 模型方法获取特定列

来自分类Dev

进行子查询以使用Laravel Eloquent检索属性的答案

来自分类Dev

如何在 Laravel 5.8 中使用 Eloquent 进行查询?

来自分类Dev

在 Laravel 中使用 Eager Loading 的查询构建器 Eloquent

来自分类Dev

laravel 5.6 Eloquent:eloquent 关系模型创建问题

来自分类Dev

Laravel Eloquent时间戳的格式是什么?

来自分类Dev

Laravel Eloquent时间戳的格式是什么?

来自分类Dev

Ruby on Rails-“胖模型,瘦控制器”实践

来自分类Dev

关于胖模型,瘦控制器实践的问题

来自分类Dev

laravel eloquent store 子模型和模型

Related 相关文章

热门标签

归档