php – 使用Laravel Eloquent ORM从“胖模型,瘦模控制器”角度工
阅读后,我一直在选择其他开发人员的大脑“脂肪模型,瘦身控制器”的概念:
> http://culttt.com/2013/07/01/setting-up-your-first-laravel-4-controller/ 大多数受访者正在使用我认为的胖控制器. 虽然这个主题已经出现在Stack Overflow上,但我还没有在实践中找到对该方法的详尽描述. 我刚刚找到一个旧的related question here.
瘦的控制器
您将在PHP(vanilla或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,yay!)等中. 但是我们可以以六边形的方式重构这个控制器,以达到每个方法的一行目标: <?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)来触发成功和失败的方法. 脂肪库/服务/模型 模型与您的数据太相关,有时它们是您的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)服务提供商:负责启动您的服务并将其添加到Laravel的IoC容器中,以便随时可以使用它,但请注意,Laravel只会在您的应用程序真正使用它们时实例化您的服务类. 3)Facade:允许您使用static(::)语法从应用程序的任何位置访问您的服务: Mailer::send($user->id,'Thanks for registering','emails.registered'); 这是梅勒服务: 服务类 <?php namespace ACRServicesMailer; use IlluminateMailMailer 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 ACRServicesMailer; use IlluminateSupportServiceProvider as IlluminateServiceProvider; use ACRServicesMailerService 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 ACRServicesMailer; use IlluminateSupportFacadesFacade as IlluminateFacade; class Facade extends IlluminateFacade { protected static function getFacadeAccessor() { return 'acr.mailer'; } } 型号/ ORM 那些人应该是高度可交换的,今天你可能正在使用Eloquent作为你的ORM,将数据存储在数据库中,但你可能需要将其更改为其他东西,有些人将其数据存储在Redis中,所以你更好通过在ORM和域loginc之间使用接口(契约)层来为这样的更改做好准备,并为您的接口而不是具体的类开发. 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'); 观点/演示者 最狡猾的人. 查看 视图应仅负责显示信息.视图不应该知道您的模型,存储库或系统中的任何其他内容.视图应该可以被webesigners编辑,你拥有的代码越多,你的非php程序员设计者将添加的bug越多.您的控制器应该从您的存储库收集信息并将它们传递给您的视图: <?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 主持人 您如何格式化数据?您在视图中编写原始属性,但是您应该在幕后使用演示者,提供您的数据.演示者通常使用Decorator设计模式来格式化要在页面中显示的数据.这是使用Shawn McCool的LaravelAutoPresenter的一个例子: <?php namespace AppPresenters; use McCoolLaravelAutoPresenterBasePresenter; 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 CarbonCarbon::createFromFormat('d-m-Y',$date,'Sao_Paulo/Brazil') ->toFormattedDateString(); } } 相关书籍 Taylor Otwell’s Laravel: From Apprentice To Artisan Chris Fidao’s Implementing Laravel (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |