gpt4 book ai didi

php - 从 "Fat model, skinny controller"的角度使用 Laravel Eloquent ORM 的做法是什么?

转载 作者:可可西里 更新时间:2023-11-01 12:40:52 27 4
gpt4 key购买 nike

关闭。这个问题需要更多focused .它目前不接受答案。












想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post .

7年前关闭。




Improve this question




在阅读以下内容后,我一直在为“胖模型,瘦 Controller ”的概念挑选其他开发人员的大脑:

  • http://culttt.com/2013/07/01/setting-up-your-first-laravel-4-controller/
  • http://culttt.com/2013/05/13/setting-up-your-first-laravel-4-model/

  • 大多数受访者正在使用我认为的胖 Controller 。

    虽然这个话题已经出现在 Stack Overflow 上,但我还没有在实践中找到对该方法的详尽描述。

    我刚找到一个旧的 related question here .

    最佳答案

    瘦 Controller

    您将在 PHP(vanilla 或 Laravel 或 Symfony)中看到的越来越多的是有史以来最瘦的 Controller 。这是您在 Rails 中已经看到的东西,人们也开始将其称为(通过其他一些实践)六边形。你的 Controller 中只需要一行代码,实际上他们说这应该是你所有方法的目标。这是一个例子,是的,比这多一点,但仍然很瘦:

    <?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');
    }

    }

    Controller 是 HTTP 请求、业务逻辑和表示层之间的桥梁。所以它应该接收一个请求,将它发送到一个注入(inject)的对象,该对象将处理它并重定向到负责向客户端(或用户)提供反馈的路由(或呈现 View )。其他一切,包括验证,都应该在您的存储库、服务、模型(MVC,是的!)等中进行。

    但是我们可以以六边形的方式重构这个 Controller ,以达到每个方法一行的目标:
    <?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方法。

    Fat 存储库/服务/模型

    模型与您的数据过于相关,有时它们是您的 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 points .在 Laravel 中,您可以通过集成三种类来创建服务:

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

    2)Service Provider:负责启动你的服务并将其添加到 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,将数据存储在数据库中,但你可能需要将其更改为其他东西,有些人将他们的数据 100% 存储在 Redis 中,所以你最好通过在 ORM 和域 loginc 之间使用接口(interface)(契约(Contract))层为这样的更改做好准备,并真正为您的接口(interface)而不是您的具体类进行开发。 Taylor Otwell 在他的书中甚至说你应该完全删除你的模型文件夹。
    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');

    所以,如果你有一个 Repository 正在使用你的 PostInterface:
    class PostRepository implements PostRepositoryInterface {

    private $model;

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

    }

    Laravel IoC 容器将使用 DbPost 实例自动实例化此存储库。如果您需要将其更改为 Redis,则只需更改一行:
    App::bind('PostInterface', 'RedisPost');

    View /演示者

    最笨的越厉害。

    观看次数

    View 应该只负责显示信息。 View 不应该知道您的模型、服务、存储库或系统中的任何其他内容。 View 应该可以由 websigners 编辑,因此,您拥有的代码越多,您的非 php-programmer-designer 将添加到其中的错误越多。您的 Controller 应该从您的存储库中收集信息并将它们传递给您的 View :
    <?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());
    }

    }

    您的 View 的唯一责任应该是显示数据:
    @extends('layout')

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

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

    主持人

    你如何格式化你的数据?您在 View 中编写原始属性,但您应该在幕后使用演示者来展示您的数据。展示者通常使用装饰器设计模式来格式化要在页面中展示的数据。这是一个使用 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's Laravel: From Apprentice To Artisan

    Chris Fidao's Implementing Laravel

    关于php - 从 "Fat model, skinny controller"的角度使用 Laravel Eloquent ORM 的做法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22566572/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com