merged branch fabpot/browserkit-client (PR #7835)

This PR was merged into the master branch.

Discussion
----------

fixed Client implementation to return the right Response (closes #4475)

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | yes
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #4475
| License       | MIT
| Doc PR        | symfony/symfony-docs#2549

This PR addresses #4475 by trying to minimize the BC break impact.

Commits
-------

31cefc6 made some small tweaks
84ca34b alternate fix where we had accessor for the BrowerKit request/response instances
1005fd1 fixed Client implementation to return the right Response (closes #4475)
This commit is contained in:
Fabien Potencier 2013-04-25 08:32:27 +02:00
commit 7ceb6e5c99
7 changed files with 128 additions and 32 deletions

View File

@ -1,7 +1,8 @@
UPGRADE FROM 2.2 to 2.3 UPGRADE FROM 2.2 to 2.3
======================= =======================
### Form Form
----
* Although this was not officially supported nor documented, it was possible to * Although this was not officially supported nor documented, it was possible to
set the option "validation_groups" to false, resulting in the group "Default" set the option "validation_groups" to false, resulting in the group "Default"
@ -109,7 +110,8 @@
} }
``` ```
### PropertyAccess PropertyAccess
--------------
* PropertyAccessor was changed to continue its search for a property or method * PropertyAccessor was changed to continue its search for a property or method
even if a non-public match was found. This means that the property "author" even if a non-public match was found. This means that the property "author"
@ -161,7 +163,8 @@
} }
``` ```
### DomCrawler DomCrawler
----------
* `Crawler::each()` and `Crawler::reduce()` now return Crawler instances * `Crawler::each()` and `Crawler::reduce()` now return Crawler instances
instead of DomElement instances: instead of DomElement instances:

View File

@ -85,7 +85,7 @@ class Client extends BaseClient
} }
/** /**
* Makes a request. * {@inheritdoc}
* *
* @param Request $request A Request instance * @param Request $request A Request instance
* *
@ -113,6 +113,10 @@ class Client extends BaseClient
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @param Request $request A Request instance
*
* @return Response A Response instance
*/ */
protected function doRequestInProcess($request) protected function doRequestInProcess($request)
{ {

View File

@ -1,6 +1,12 @@
CHANGELOG CHANGELOG
========= =========
2.3.0
-----
* added `Client::getInternalRequest()` and `Client::getInternalResponse()` to
have access to the BrowserKit internal request and response objects
2.1.0 2.1.0
----- -----

View File

@ -33,7 +33,9 @@ abstract class Client
protected $history; protected $history;
protected $cookieJar; protected $cookieJar;
protected $server; protected $server;
protected $internalRequest;
protected $request; protected $request;
protected $internalResponse;
protected $response; protected $response;
protected $crawler; protected $crawler;
protected $insulated; protected $insulated;
@ -156,7 +158,7 @@ abstract class Client
/** /**
* Returns the current Crawler instance. * Returns the current Crawler instance.
* *
* @return Crawler A Crawler instance * @return Crawler|null A Crawler instance
* *
* @api * @api
*/ */
@ -166,9 +168,26 @@ abstract class Client
} }
/** /**
* Returns the current Response instance. * Returns the current BrowserKit Response instance.
* *
* @return Response A Response instance * @return Response|null A BrowserKit Response instance
*
* @api
*/
public function getInternalResponse()
{
return $this->internalResponse;
}
/**
* Returns the current origin response instance.
*
* The origin response is the response instance that is returned
* by the code that handles requests.
*
* @return object|null A response instance
*
* @see doRequest
* *
* @api * @api
*/ */
@ -178,9 +197,26 @@ abstract class Client
} }
/** /**
* Returns the current Request instance. * Returns the current BrowserKit Request instance.
* *
* @return Request A Request instance * @return Request|null A BrowserKit Request instance
*
* @api
*/
public function getInternalRequest()
{
return $this->internalRequest;
}
/**
* Returns the current origin Request instance.
*
* The origin request is the request instance that is sent
* to the code that handles requests.
*
* @return object|null A Request instance
*
* @see doRequest
* *
* @api * @api
*/ */
@ -250,12 +286,12 @@ abstract class Client
$server['HTTP_HOST'] = parse_url($uri, PHP_URL_HOST); $server['HTTP_HOST'] = parse_url($uri, PHP_URL_HOST);
$server['HTTPS'] = 'https' == parse_url($uri, PHP_URL_SCHEME); $server['HTTPS'] = 'https' == parse_url($uri, PHP_URL_SCHEME);
$request = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content); $this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content);
$this->request = $this->filterRequest($request); $this->request = $this->filterRequest($this->internalRequest);
if (true === $changeHistory) { if (true === $changeHistory) {
$this->history->add($request); $this->history->add($this->internalRequest);
} }
if ($this->insulated) { if ($this->insulated) {
@ -264,25 +300,25 @@ abstract class Client
$this->response = $this->doRequest($this->request); $this->response = $this->doRequest($this->request);
} }
$response = $this->filterResponse($this->response); $this->internalResponse = $this->filterResponse($this->response);
$this->cookieJar->updateFromResponse($response, $uri); $this->cookieJar->updateFromResponse($this->internalResponse, $uri);
$this->redirect = $response->getHeader('Location'); $this->redirect = $this->internalResponse->getHeader('Location');
if ($this->followRedirects && $this->redirect) { if ($this->followRedirects && $this->redirect) {
return $this->crawler = $this->followRedirect(); return $this->crawler = $this->followRedirect();
} }
return $this->crawler = $this->createCrawlerFromContent($request->getUri(), $response->getContent(), $response->getHeader('Content-Type')); return $this->crawler = $this->createCrawlerFromContent($this->internalRequest->getUri(), $this->internalResponse->getContent(), $this->internalResponse->getHeader('Content-Type'));
} }
/** /**
* Makes a request in another process. * Makes a request in another process.
* *
* @param Request $request A Request instance * @param object $request An origin request instance
* *
* @return Response A Response instance * @return object An origin response instance
* *
* @throws \RuntimeException When processing returns exit code * @throws \RuntimeException When processing returns exit code
*/ */
@ -302,16 +338,16 @@ abstract class Client
/** /**
* Makes a request. * Makes a request.
* *
* @param Request $request A Request instance * @param object $request An origin request instance
* *
* @return Response A Response instance * @return object An origin response instance
*/ */
abstract protected function doRequest($request); abstract protected function doRequest($request);
/** /**
* Returns the script to execute when the request must be insulated. * Returns the script to execute when the request must be insulated.
* *
* @param Request $request A Request instance * @param object $request An origin request instance
* *
* @throws \LogicException When this abstract class is not implemented * @throws \LogicException When this abstract class is not implemented
*/ */
@ -323,11 +359,11 @@ abstract class Client
} }
/** /**
* Filters the request. * Filters the BrowserKit request to the origin one.
* *
* @param Request $request The request to filter * @param Request $request The BrowserKit Request to filter
* *
* @return Request * @return object An origin request instance
*/ */
protected function filterRequest(Request $request) protected function filterRequest(Request $request)
{ {
@ -335,11 +371,11 @@ abstract class Client
} }
/** /**
* Filters the Response. * Filters the origin response to the BrowserKit one.
* *
* @param Response $response The Response to filter * @param object $response The origin response to filter
* *
* @return Response * @return Response An BrowserKit Response instance
*/ */
protected function filterResponse($response) protected function filterResponse($response)
{ {

View File

@ -17,6 +17,10 @@ use Symfony\Component\BrowserKit\CookieJar;
use Symfony\Component\BrowserKit\Request; use Symfony\Component\BrowserKit\Request;
use Symfony\Component\BrowserKit\Response; use Symfony\Component\BrowserKit\Response;
class SpecialResponse extends Response
{
}
class TestClient extends Client class TestClient extends Client
{ {
protected $nextResponse = null; protected $nextResponse = null;
@ -44,6 +48,15 @@ class TestClient extends Client
return $response; return $response;
} }
protected function filterResponse($response)
{
if ($response instanceof SpecialResponse) {
return new Response($response->getContent(), $response->getStatus(), $response->getHeaders());
}
return $response;
}
protected function getScript($request) protected function getScript($request)
{ {
$r = new \ReflectionClass('Symfony\Component\BrowserKit\Response'); $r = new \ReflectionClass('Symfony\Component\BrowserKit\Response');
@ -90,9 +103,6 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('http://example.com/', $client->getRequest()->getUri(), '->getCrawler() returns the Request of the last request'); $this->assertEquals('http://example.com/', $client->getRequest()->getUri(), '->getCrawler() returns the Request of the last request');
} }
/**
* @covers Symfony\Component\BrowserKit\Client::getResponse
*/
public function testGetResponse() public function testGetResponse()
{ {
$client = new TestClient(); $client = new TestClient();
@ -100,6 +110,18 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$client->request('GET', 'http://example.com/'); $client->request('GET', 'http://example.com/');
$this->assertEquals('foo', $client->getResponse()->getContent(), '->getCrawler() returns the Response of the last request'); $this->assertEquals('foo', $client->getResponse()->getContent(), '->getCrawler() returns the Response of the last request');
$this->assertInstanceOf('Symfony\Component\BrowserKit\Response', $client->getResponse(), '->getCrawler() returns the Response of the last request');
}
public function testGetInternalResponse()
{
$client = new TestClient();
$client->setNextResponse(new SpecialResponse('foo'));
$client->request('GET', 'http://example.com/');
$this->assertInstanceOf('Symfony\Component\BrowserKit\Response', $client->getInternalResponse());
$this->assertNotInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialResponse', $client->getInternalResponse());
$this->assertInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialResponse', $client->getResponse());
} }
public function testGetContent() public function testGetContent()

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel;
use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\BrowserKit\Client as BaseClient; use Symfony\Component\BrowserKit\Client as BaseClient;
use Symfony\Component\BrowserKit\Request as DomRequest; use Symfony\Component\BrowserKit\Request as DomRequest;
use Symfony\Component\BrowserKit\Response as DomResponse; use Symfony\Component\BrowserKit\Response as DomResponse;
@ -49,6 +50,26 @@ class Client extends BaseClient
$this->followRedirects = false; $this->followRedirects = false;
} }
/**
* {@inheritdoc}
*
* @return Request|null A Request instance
*/
public function getRequest()
{
return parent::getRequest();
}
/**
* {@inheritdoc}
*
* @return Response|null A Response instance
*/
public function getResponse()
{
return parent::getResponse();
}
/** /**
* Makes a request. * Makes a request.
* *
@ -100,7 +121,7 @@ EOF;
/** /**
* Converts the BrowserKit request to a HttpKernel request. * Converts the BrowserKit request to a HttpKernel request.
* *
* @param DomRequest $request A Request instance * @param DomRequest $request A DomRequest instance
* *
* @return Request A Request instance * @return Request A Request instance
*/ */
@ -167,7 +188,7 @@ EOF;
* *
* @param Response $response A Response instance * @param Response $response A Response instance
* *
* @return Response A Response instance * @return DomResponse A DomResponse instance
*/ */
protected function filterResponse($response) protected function filterResponse($response)
{ {

View File

@ -35,6 +35,10 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$client->request('GET', '/'); $client->request('GET', '/');
$this->assertEquals('Request: /', $client->getResponse()->getContent(), '->doRequest() uses the request handler to make the request'); $this->assertEquals('Request: /', $client->getResponse()->getContent(), '->doRequest() uses the request handler to make the request');
$this->assertInstanceOf('Symfony\Component\BrowserKit\Request', $client->getInternalRequest());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Request', $client->getRequest());
$this->assertInstanceOf('Symfony\Component\BrowserKit\Response', $client->getInternalResponse());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $client->getResponse());
$client->request('GET', 'http://www.example.com/'); $client->request('GET', 'http://www.example.com/');
$this->assertEquals('Request: /', $client->getResponse()->getContent(), '->doRequest() uses the request handler to make the request'); $this->assertEquals('Request: /', $client->getResponse()->getContent(), '->doRequest() uses the request handler to make the request');