In Laravel 5, why is Request::root() different whe

2019-06-15 08:25发布

问题:

I defined a test which tests the creation of a user. The controller is set to redirect back to the same page on error (using validation through a generated App\Http\Requests\Request). This works correctly when manually clicking in a browser, but fails during a test. Instead of being redirected to:

http://localhost/account/create

The test redirects to (missing a slash):

http://localhostaccount/create

Neither of these urls are what I have setup in the .htaccess or in the $url variable in config/app.php. Which is (On OSX Yosemite):

http://~username/laravel_projects/projectname/public

I finally pinpointed the issue to have something to do with how the result of Request::root() is generated. Making a call to this outside of a test results in the expected value defined in .htaccess and $url. Inside the test it results in:

http://localhost

What configuration needs to change in order to get this function to return the correct value in both contexts?

I should also mention I made the painful upgrade from Laravel 4 to the current version 5.0.27.

****** UPDATE *******

I was able to figure out an acceptable solution/workaround to this issue!

In Laravel 5, FormRequests were introduced to help move validation logic out of controllers. Once a request is mapped to the controller, if a FormRequest (or just Request) is specified, this is executed before hitting the controller action.

This FormRequest by default handles the response if the validation fails. It attempts to construct a redirect based on the route you posted the form data to. In my case, possibly related to an error of mine updating from Laravel 4 to 5, this default redirect was being constructed incorrectly. The Laravel System code for handling the response looks like this:

 /**
 * Get the proper failed validation response for the request.
 *
 * @param  array  $errors
 * @return \Symfony\Component\HttpFoundation\Response
 */
public function response(array $errors)
{
    if ($this->ajax() || $this->wantsJson())
    {
        return new JsonResponse($errors, 422);
    }
    return $this->redirector->to($this->getRedirectUrl())
                                    ->withInput($this->except($this->dontFlash))
                                    ->withErrors($errors, $this->errorBag);
}

Notice how the returned redirect is NOT the same as calling Redirect::route('some_route'). You can override this response function by including use Response in your Request class.

After using Redirect::route() to create the redirect, the logic in my tests passed with the expected results. Here is my Request code that worked:

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Http\Requests\Request;
use Response;

class AccountRequest 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 [
                  'email' => 'required|max:50|email|unique:users',
                  'password' => 'required|min:6',
                  'password_confirmation' => 'required|same:password'

                ];
    }

  public function response(array $errors){
    return \Redirect::route('account_create');
  }

}

The important part is that I called Redirect::route instead of letting the default response code execute.

回答1:

Override the response function in the FormRequest validation handler to force the redirect to be constructed with Redirect::route('named_route') instead of allowing the default redirect.



回答2:

You need to change config/app.php file's url value. Default value is http://localhost

Doc from config/app.php

This URL is used by the console to properly generate URLs when using the Artisan command line tool. You should set this to the root of your application so that it is used when running Artisan tasks.



回答3:

I know this isn't an exact answer to your question since it is not a configuration update that solves the problem. But I was struggling with a related problem and this seems to be the only post on the internet of someone dealing with something similar - I thought I'd put in my two cents for anyone that wants a different fix.

Please note that I'm using Laravel 4.2 at the moment, so this might have changed in Laravel 5 (although I doubt it).

You can specify the HTTP_HOST header when you're testing a controller using the function:

$response = $this->call($method, $uri, $parameters, $files, $server, $content);

To specify the header just provided the $server variable as an array like so:

array('HTTP_HOST' => 'testing.mydomain.com');

When I did the above, the value produced for my Request::root() was http://testing.mydomain.com.

Again, I know this isn't a configuration update to solve you're issue, but hopefully this can help someone struggling with a semi-related issue.