可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm new to Laravel (only experienced Laravel 5, so no legacy hang up here)
I'd like to know how to extend the core Request class. In addition to how to extend it, i'd like to know if it's a wise design decision to do so.
I've read through the documentation extensively (especially with regards to registering service providers and the manner in which it provides Facades access to entries within the dependency container) - but I can see (and find) no way to replace the \Illuminate\Http\Request
instance with my own
回答1:
Here is Official Document: Request Lifecycle
Content of app/Http/CustomRequest.php
<?php namespace App\Http;
use Illuminate\Http\Request as BaseRequest;
class CustomRequest extends BaseRequest {
// coding
}
add this line to public/index.php
$app->alias('request', 'App\Http\CustomRequest');
after
app = require_once __DIR__.'/../bootstrap/app.php';
change the code at public/index.php
Illuminate\Http\Request::capture()
to
App\Http\CustomRequest::capture()
回答2:
I guess you will have to extend also RequestForm
. I use trait to avoid code duplication. Code below is relevant for Laravel 5.3.
app/Http/ExtendRequestTrait.php
<?php
namespace App\Http\ExtendRequestTrait;
trait ExtendRequestTrait {
methodFoo(){}
methodBar(){}
}
app/Http/Request.php
<?php
namespace App\Http;
use Illuminate\Http\Request as BaseRequest;
class Request extend BasicRequest {
use ExtendRequestTrait;
}
app/Http/FormRequest.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\FormRequest as BaseFormRequest;
class FormRequest extend BasicFormRequest {
use ExtendRequestTrait;
}
For phpunit test working you will have to override call
method to make it using right Request
class here Request::create
.
test/TestCase.php
<?php
use App\Http\Request;
abstract class TestCase extends Illuminate\Foundation\Testing\TestCase{
// just copy Illuminate\Foundation\Testing\TestCase `call` method
// and set right Request class
public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
{
$kernel = $this->app->make('Illuminate\Contracts\Http\Kernel');
$this->currentUri = $this->prepareUrlForRequest($uri);
$this->resetPageContext();
$request = Request::create(
$this->currentUri, $method, $parameters,
$cookies, $files,
array_replace($this->serverVariables, $server),
$content
);
$response = $kernel->handle($request);
$kernel->terminate($request, $response);
return $this->response = $response;
}
}
and don't forget to switch Illuminate\Http\Request::capture()
to App\Http\Request::capture()
in public/index.php
file and to add $app->alias('request', 'App\Http\Request');
after or inside $app = require_once __DIR__.'/../bootstrap/app.php';
回答3:
I was working on the same issue today and I think it's worth mention that you may just change
Illuminate\Http\Request::capture()
to
App\Http\CustomRequest::capture()
without adding line
$app->alias('request', 'App\Http\CustomRequest');
because inside capture()
method laravel actually binds provided class to service container with 'request' as a key
回答4:
I was able to add custom request object using FormRequest
in Laravel 5.5 as follows.
First, just create FormRequest
:
php artisan make:request MyRequest
Then just make it look like this:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MyRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}
You can then use MyRequest
as drop-in replacement in any function that takes Request
as parameter:
public function get(MyRequest $request)
{
}
I do realize that FormRequest
s are actually meant to be used for a different purpose, but whatever works.
Documentation on FormRequest
: https://laravel.com/docs/5.0/validation#form-request-validation
回答5:
Yerkes answer inspired me to write a custom class, for use with pagination, but only on specific requests
<?php
namespace App\Http\Requests;
use Illuminate\Http\Request;
class PaginatedRequest extends Request
{
public function page(): int
{
return max(1, (int) ($this['page'] ?? 1));
}
public function perPage(): int
{
$perPage = (int) ($this['per_page'] ?? 100);
return max(1, min($perPage, 500));
}
public function offset(): int
{
return ($this->page() - 1) * $this->perPage();
}
}
I then also had to register a new ServiceProvider in /config/app.php, which looks like
<?php
namespace App\Providers;
use App\Http\Requests\PaginatedRequest;
use Illuminate\Support\ServiceProvider;
class PaginatedRequestServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app->resolving(PaginatedRequest::class, function ($request, $app) {
PaginatedRequest::createFrom($app['request'], $request);
});
}
}
Now I can simply inject the PaginatedRequest in my controller methods only when I need it
<?php
namespace App\Http\Controllers;
use App\Http\Requests\PaginatedRequest;
class MyController
{
public function __invoke(PaginatedRequest $request)
{
$request->page();
// ...
}
}