dpsfay2510 2017-04-14 23:59
浏览 188
已采纳

作为控制器的Laravel服务 - 使用多个控制器

I'am a Brazilian developer, so... sorry for my limited English right away.

Well, in fact my problem is more a convention problem because until now I hadn't use services with Laravel (my apps were that simple so far).

I read about it before ask this question, but nothing helped with this specific situation. I'll try to describe in a objective way.

before that, just a comment: I know about the mistake using just controllers in these example. The ask is really about that mistake.

Well, the actual structure is:

abstract class CRUDController extends Controller {

    protected function __construct($data, $validatorData) {
        // store the data in a attribute
        // create with Validator facade the validation and store too
    }

    abstract protected function createRecord();

    protected function create() {
        try {
            // do the validation and return an Response instance with error messages
            // if the data is ok, store in the database with models
            // (here's where the magic takes place) in that store!
            // to do that, calls the method createRecord (which is abstract)
            $this->createRecord();
            // return a success message in an Response instance
        }
        catch(\Exception $e) {
            // return an Response instance with error messages
        }
    }

}

class UserController extends CRUDController {

    public function __construct($data) {
        parent::__construct($data, [
            'rules' => [
                 // specific user code here
             ],
            'messages' => [
                 // specific user code here
             ],
            'customAttributes' => [
                 // specific user code here
             ]
        ]);
    }

    protected function createRecord() {
        $user = new UserModel();
        // store values here...
        $user->save();
        return $user;
    }

}

// here's the route to consider in that example
Route::post('/user', 'WebsiteController@register');

class WebsiteController extends Controller {

    private $request;

    public function __construct(Request $request) {
        $this->request = $request;
    }

    public function register() {
        $user = new UserController();
        $user->create($this->request);
        // here's the problem: controller working with another controller
    }

}

class UserAPIController extends Controller {
    // use here the UserController too
}

and many other classes that extends CRUDController in the same way...

What I want

I want to create a controller (called here as CRUDController) to reuse methods like the pattern says (create, read, update and delete). To be really objective here I'll use the create method as an example. With the code above it seems clear the purpose? I think so... all my controllers have that code of validation equal and reusable. That's the thing. Besides that, I want to my route of website call another controller (UserController) to store new users... but in the same way, I'll create an API that uses the same controller in the same way (with validations etc). That's the purpose of Responses in the CRUDController (I'll read them in the WebSiteController to resolve what to do, like show a view and in the other hand with the API I'll basically return the Response.

My real problem

Convention and pattern. The MVC pattern is broken here. Controller calling another controller is wrong and I know that. I want to know what thing I should use! Services? Is that right? I see a lot (really) of examples of services but nothing like that, working with models and reusing code, etc. I never use Services but I know how to use, but I don't know if it's right to these cases.

I really hope that someone can help here and sorry once again for the mistakes with the English. Thanks a lot.

  • 写回答

2条回答 默认 最新

  • duanpao4172 2017-04-17 14:00
    关注

    I'll answer my own question. I use a pattern called Repository Pattern to resolve the problem (or I try to use, because it's the first time using this pattern: maybe I don't use in the right way in every steps).

    Files structure

    Controllers
      UserController.php
    Models
      UserModel.php
    Providers
      UserRepositoryServiceProvider.php
    Repositories
     RepositoryInterface.php
     Repository.php
     User
       UserRepositoryInterface.php
       UserRepository.php
    Traits
      InternalResponse.php
    

    With that structure I did what I wanted in my question without working just with controllers.

    I create a trait called InternalResponse. That trait contains a few methods that receive a transaction, validate if it's the case and then return a Response (called "internal" in my logic because the controller will read and maybe change the Response before return it in the end).

    The Repository class, which is abstract (because another class must extend it to make sense to use. In this case the class UserRepository will extend...), uses the Trait mentioned.

    Well, with it in mind, it's possible to know that the UserController uses the UserRepositoryInterface, that provides an object UserRepository: because the UserRepositoryServiceProvider register this with that interface.

    I think there's no need to write code here to explain, because the problem is about an pattern, and these words explain well the problem (in the question) and the resolution with this answer here.

    I'll write here a conclusion, I mean, the files structure with comments to explain a little bit more, to end the answer.

    Conclusion: Files structure with comments

    Controllers
      UserController.php
        // the controller uses dependency injection and call methods of 
        // UserRepository, read and changes the Response receveid to finally
        // create the final Response, like returning a view or the response
        // itself (in the case it's an API controller)
    Models
      UserModel.php
        // an normal model
    Providers
      UserRepositoryServiceProvider.php
        // register the UserRepositoryInterface to
        // return a UserRepository object
    Repositories
     RepositoryInterface.php
       // the main interface for the Repository
     Repository.php
       // the main repository. It's an abstract class.
       // All the others repositories must extend that class, because
       // there's no reason to use a class Repository without an Model
       // to access the database... That class share methods like create,
       // read, update and delete, and the methods validate and transaction
       // too because uses the trait InternalResponse.
     User
       UserRepositoryInterface.php
         // the interface for UserRepository class
       UserRepository.php
         // that class extend Repository and uses the UserModel
    Traits
      InternalResponse.php
        // trait with methods like validate and transaction. the method
        // validate, read and validate the data receveid for the methods
        // create and update. and all the CRUD methods uses the method
        // transaction to perform the data to the database and return a
        // response of that action.
    

    That's what I do and like I said before, I don't know if it's a hundred percent correct in reference to Repository Pattern.

    I hope this can help someone else too. Thanks for all.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog