如何在 Laravel 5.1 上使请求类型动态(验证)

Ale*_*iro 5 php laravel laravel-5.1

我正在尝试制作一个 crud 控制器基础,从那里我扩展它并设置模型基础然后我有一些基本的 crud 方法。我让所有的工作都是动态的。但是我无法创建动态请求类型,为了验证它,我有 ChannelRequest,它的工作正常,如下所示,但我希望它是动态的:

这是我的 CrudController 类(我将扩展并设置模型):

    public function store(ChannelRequest $request)
    {
        $this->save($request); // this method get the model instantiated in parent class and save the inputs

        return redirect('admin/' . $this->plural);
    }
Run Code Online (Sandbox Code Playgroud)

在上面的这个例子中,我对依赖注入的请求类型进行了硬编码,然后它进行了验证,但我想动态更改请求类型,如下所示:

    // i know it not being work
    public function store($this->model .'Request' $request)
    {
        $this->save($request);

        return redirect('admin/' . $this->plural);
    }
Run Code Online (Sandbox Code Playgroud)

我试过这个:

    public function store()
    {
        $request = new ChannelRequest();
        $request->validate(); //hopping it runs like when dependency injection

        $this->save($request);

        return redirect('admin/' . $this->plural);
    }
Run Code Online (Sandbox Code Playgroud)

这让我犯了一个错误:

FatalErrorException in FormRequest.php line 75:
Call to a member function make() on null
in FormRequest.php line 75
at FatalErrorException->__construct() in HandleExceptions.php line 133
at HandleExceptions->fatalExceptionFromError() in HandleExceptions.php line 118
at HandleExceptions->handleShutdown() in HandleExceptions.php line 0
at FormRequest->getValidatorInstance() in ValidatesWhenResolvedTrait.php line 20
at FormRequest->validate() in CrudController.php line 67
Run Code Online (Sandbox Code Playgroud)

jar*_*dis 5

首先,我想强调的是,为每个资源(模型)设置单独的控制器是一种很好的做法,可以防止单独的关注点变得过于混杂。使用动态请求类首先违背了显式定义请求类的目的。

但是,为了尽我所能回答这个问题,我会给你一个如何解决这个问题的想法。这段代码未经测试,但概念应该是合理的。

我在这里所做的是使用 SmartRequest 类扩展标准 Request 类并覆盖__construct以允许我为给定请求类型的正确请求类运行预加载器。

这将允许您定义单独的请求类,然后SmartRequest::$subRequest根据resourceType请求参数将它们加载到属性中(如果您想修改最后一个的代码,这可以是 POST、GET 或 URL 参数的一部分)。

代码: App\Http\Requests\SmartRequest

<?php 

use App\Http\Requests\Request;

class SmartRequest extends Request {

    /**
     * Holds sub request class
     * @var Request
     */
    protected $subRequest;

    /**
     * Default constructor
     * @param array             $query      
     * @param array             $request    
     * @param array             $attributes 
     * @param array             $cookies    
     * @param array             $files      
     * @param array             $server     
     * @param string|resource   $content    
     */
    public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
    {
        // make sure standard constructor fires
        parent::__construct($query, $request, $attributes, $cookies, $files, $server, $content);

        // instantiate the sub request object, we must also pass through all the data for the base
        // request since the sub class requires this data.
        $this->loadSubRequest($query, $request, $attributes, $cookies, $files, $server, $content);
    }

    /**
     * Default constructor
     * @param array             $query      
     * @param array             $request    
     * @param array             $attributes 
     * @param array             $cookies    
     * @param array             $files      
     * @param array             $server     
     * @param string|resource   $content    
     */
    public function loadSubRequest($query, $request, $attributes, $cookies, $files, $server, $content)
    {   
        // get resource type off the request data to generate the class string
        $class = $this->getRequestClassName();

        $this->subRequest = new $class($query, $request, $attributes, $cookies, $files, $server, $content);
    }

    /**
     * Get the sub class name with namespace
     * @return string
     */
    public function getRequestClass()
    {
        return '\<path>\<to\<namespace>\\' . studly_case($this->resourceType) . 'Request';
    }

    /**
     * Returns rules based on subclass, otherwise returns default rules
     * @return array
     */
    public function rules()
    {
        // return the default rules if we have no sub class
        if (empty($this->subRequest)) return [];

        // return the rules given by the sub class
        return $this->subRequest()->rules();
    }
}
Run Code Online (Sandbox Code Playgroud)

同样,这不是真正的代码(因为我没有测试过),但这可能是完成您的请求的一种方式。这也依赖于在请求上发送了一些标识符(在这种情况下,是一个requestType参数),因为除了它被发送到哪里以及使用什么参数之外,你不会知道任何关于请求的信息。

尽管如此,我认为这与此功能的意图相悖。有显式请求并在需要它们的方法中显式使用它们要好得多。为什么?自记录代码。人们将通过阅读诸如ChannelRequest $request动作之类的内容来了解​​您在何处使用什么。像上面这样的 ( SmartRequest) 会导致某种魔法发生,任何其他开发人员在打开SmartRequest类之前都不会理解。

让我知道这是否令人困惑,或者您对为什么我认为这种方法是朝着错误方向迈出的一步有任何其他问题。