简体   繁体   English

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

[英]Laravel Service as Controller - working with multiples controllers

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). 好吧,实际上我的问题更多是一个常规问题,因为直到现在我还没有使用Laravel服务(到目前为止,我的应用程序非常简单)。

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... 以及以同样的方式扩展CRUDController的许多其他类......

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). 我想创建一个控制器(在这里称为CRUDController)来重用模式所说的方法(创建,读取,更新和删除)。 To be really objective here I'll use the create method as an example. 为了真正客观,我将使用create方法作为示例。 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). 除此之外,我希望我的网站路由调用另一个控制器(UserController)来存储新用户......但同样地,我将以相同的方式创建一个使用相同控制器的API(带有验证等)。 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. 这就是CRUDController中响应的目的(我将在WebSiteController中读取它们以解决要做的事情,比如显示视图,另一方面使用API​​我将基本上返回响应。

My real problem 我真正的问题

Convention and pattern. 公约和模式。 The MVC pattern is broken here. 这里打破了MVC模式。 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. 非常感谢。

You're calling the CRUD controller a controller but it does not behave as an MVC controller. 您将CRUD控制器称为控制器,但它不像MVC控制器那样运行。 At best it's just a helper class. 充其量它只是一个帮助类。 You could always do this: 你总是可以这样做:

abstract class CRUDManager {        
    //As you had the CRUDController
}

class UserManager extends CRUDManager {
     //As you had the UserController
}

In your AppServiceProvider: 在您的AppServiceProvider中:

public function boot() {
     $app->bind(UserManager::class, function ($app) {
           return new UserManager(request()->all()); //I guess that's what you need.
     });
}

Whenever you need to use it you can do: 无论何时需要使用它,您都可以:

public function register(UserManager $user) {
    $user->create();
}

Now one thing to point out. 现在有一点需要指出。 It's not a good idea to initialise the request in the constructor. 在构造函数中初始化请求不是一个好主意。 You should use dependency injection in controller methods. 您应该在控制器方法中使用依赖注入。 I don't even know if the request is available when the controller is being constructed (I know the session is not). 我甚至不知道在构造控制器时请求是否可用(我知道会话不是)。 The reason why I say this is that the middleware runs after the controller is constructed and therefore the request may be modified when the controller method is called. 我之所以这么说是因为中间件在构造控制器之后运行,因此在调用控制器方法时可以修改请求。

Another note: If you did the original solution because you needed to use certain controller methods, then you can just use the corresponding traits (because the controller itself does not really have many method). 另一个注意事项:如果你做了原始的解决方案,因为你需要使用某些控制器方法,那么你可以使用相应的特性(因为控制器本身并没有真正的方法)。 I'm guessing a trait like ValidatesRequests would be one you'd need to use . 我猜测像ValidatesRequests这样的特性会是你需要use

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). 我使用一种称为Repository Pattern的模式来解决问题(或者我尝试使用,因为它是第一次使用这种模式:也许我没有在每个步骤中以正确的方式使用)。

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. 我创建了一个名为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. Repository类是抽象的(因为另一个类必须扩展它才有意义使用。在这种情况下,UserRepository类将扩展...),使用提到的Trait。

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. 好吧,考虑到这一点,我们可以知道UserController使用UserRepositoryInterface,它提供了一个UserRepository对象:因为UserRepositoryServiceProvider在该接口上注册了它。

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. 谢谢大家。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM