I have a resource controller in laravel to manage my users. This creates a route to update users info that takes a request with HTTP PUT method.
This shows artisan route:list
command output:
+--------+--------------------------------+-----------------------------------------------------------+--------------------------------------+--------------------------------------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+--------------------------------+-----------------------------------------------------------+--------------------------------------+--------------------------------------------------------------------------------+------------+
...
| | PUT | users/{users} | users.update | App\Http\Controllers\Users\UsersController@update | auth |
It works correctly on my web browser but when I try to run a test with codeception and I submit the form I get a method not allowed exception and the test fails.
I tried to see why this is happening and it seems to be the request made by codeception. That request is made with POST instead of PUT method preventing Laravel from matching the route.
HTML forms doesn't suport PUT methods so Laravel Form
helper class creates the form as follows:
<form method="POST" action="https://myapp.dev/users/172" accept-charset="UTF-8">
<input name="_method" value="PUT" type="hidden">
...
However, it seems that codeception is not reading the _method
value.
How can I fix this?
EDIT: Looking deeply on the code I found that test don't override the request method beacause of a constant in th Request
class called Request::$httpMethodParameterOverride
.
/**
* Gets the request "intended" method.
*
* If the X-HTTP-Method-Override header is set, and if the method is a POST,
* then it is used to determine the "real" intended HTTP method.
*
* The _method request parameter can also be used to determine the HTTP method,
* but only if enableHttpMethodParameterOverride() has been called.
*
* The method is always an uppercased string.
*
* @return string The request method
*
* @api
*
* @see getRealMethod()
*/
public function getMethod()
{
if (null === $this->method) {
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
if ('POST' === $this->method) {
if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
$this->method = strtoupper($method);
} elseif (self::$httpMethodParameterOverride) {
$this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
}
}
}
return $this->method;
}
The previous constant value should be true
but shomehow, when I run the test its value is false
.
I found a solution but I don't think this is the right place to write it.
I added a simple line of code on the Connector\Laravel5
class.
public function __construct($module)
{
$this->module = $module;
$this->initialize();
$components = parse_url($this->app['config']->get('app.url', 'http://localhost'));
$host = isset($components['host']) ? $components['host'] : 'localhost';
parent::__construct($this->app, ['HTTP_HOST' => $host]);
// Parent constructor defaults to not following redirects
$this->followRedirects(true);
// Added to solve the problem of overriding the request method
Request::enableHttpMethodParameterOverride();
}
This solves my problem.
You can not use PUT
method in HTML form tag. For that you need to use laravel's blade template format to define form tag.
e.g.
{!! Form::open(['url' => 'users/{users}','method' => 'put','id' => 'form' ]) !!}
Also you can use route
attribute to define route instead of url
.
来源:https://stackoverflow.com/questions/34922592/laravel-and-codeception-test-fails-on-put-forms