问题
I designed a multiste app. There is multisite admin (ie. http://root.com/admin) and also all sites access (ie http://site1.com, http://site2.com...).
To handle routing (multisite admin or child sites), I set the UseCanonicalName on vhost configuration :
ServerName root.com
ServerAlias media.site1.com site1.com media.site2.com, site2.com ...
UseCanonicalName On
Doing so, I'm sure that $request->server->get('SERVER_NAME') will always return in given case root.com, and I use this in routing process to make difference between root domain (for admin purposes), child sites, and 404 content.
It's working great on real life, but when it comes to testing, it seems that UseCanonicalName doesn't force SERVER_NAME with ServerName defined in vhost.
Dump from a regular Chrome client :
array(34) {
'HTTP_HOST' =>
string(9) string 'site1.com'
...
'HTTP_USER_AGENT' =>
string(105) 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36'
'SERVER_NAME' =>
string(8) 'root.com'
...
}
Dump from test client
array(16) {
'SERVER_NAME' =>
string(9) "site1.com"
'HTTP_HOST' =>
string(9) "site1.com"
'HTTP_USER_AGENT' =>
string(19) "Symfony2 BrowserKit"
...
}
I tried to force SERVER_NAME on test client :
$crawler = $this->client->request('GET', $route, [], [], ['SERVER_NAME' => 'root.com']);
But this doesn't change a thing, I still have SERVER_NAME value equals to HTTP_HOST, which screws everything when it comes to test child sites FO or BO (when difference between SERVER_NAME and HTTP_HOST matters).
So,
- Why Symfony2 BrowserKit is UseCanonicalName directive insensitive?
- How can I force it using Client class parameters?
回答1:
On a strict point of view, I finally managed to find my way through above problem : I overloaded the Client class (Symfony\Bundle\FrameworkBundle\Client), specifically request method after filterRequest call :
public function request($method, $uri, array $parameters = array(), array $files = array(), array $server = array(), $content = null, $changeHistory = true)
{
if ($this->isMainRequest) {
$this->redirectCount = 0;
} else {
++$this->redirectCount;
}
$uri = $this->getAbsoluteUri($uri);
$server = array_merge($this->server, $server);
if (isset($server['HTTPS'])) {
$uri = preg_replace('{^'.parse_url($uri, PHP_URL_SCHEME).'}', $server['HTTPS'] ? 'https' : 'http', $uri);
}
if (!$this->history->isEmpty()) {
$server['HTTP_REFERER'] = $this->history->current()->getUri();
}
if (empty($server['HTTP_HOST'])) {
$server['HTTP_HOST'] = $this->extractHost($uri);
}
$server['HTTPS'] = 'https' == parse_url($uri, PHP_URL_SCHEME);
$this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content);
$this->request = $this->filterRequest($this->internalRequest);
// MY ADDITION
//
$this->request->server->replace(array_merge($this->request->server->all(), $server));
// /MY ADDITION
//
if (true === $changeHistory) {
$this->history->add($this->internalRequest);
}
if ($this->insulated) {
$this->response = $this->doRequestInProcess($this->request);
} else {
$this->response = $this->doRequest($this->request);
}
$this->internalResponse = $this->filterResponse($this->response);
$this->cookieJar->updateFromResponse($this->internalResponse, $uri);
$status = $this->internalResponse->getStatus();
if ($status >= 300 && $status < 400) {
$this->redirect = $this->internalResponse->getHeader('Location');
} else {
$this->redirect = null;
}
if ($this->followRedirects && $this->redirect) {
return $this->crawler = $this->followRedirect();
}
return $this->crawler = $this->createCrawlerFromContent($this->internalRequest->getUri(), $this->internalResponse->getContent(), $this->internalResponse->getHeader('Content-Type'));
}
Doing so, I force a merge with $server params passed to request method and real server params contained in $this->request->server.
Such a merge is already done above ($server = array_merge($this->server, $server);) but for some reason I can't explain, filterRequest call kind of "reset" the request, sweeping away my custom server params.
I don't see clearly deep implications of this regarding subrequest. AFAIK, it will just merge my custom server params in every request or subrequest originating from the first one.
In other hand, does anybody know why filterRequest (which is only a bypasser) would reset all server variable?
PS : as I encountered another (but yet related problem) on functional testing session vars, I asked another question
来源:https://stackoverflow.com/questions/38380193/symfony2-functional-test-client-force-server-param-server-name