You are here

abstract class Client in Zircon Profile 8

Same name in this branch
  1. 8 vendor/symfony/http-kernel/Client.php \Symfony\Component\HttpKernel\Client
  2. 8 vendor/symfony/browser-kit/Client.php \Symfony\Component\BrowserKit\Client
  3. 8 vendor/fabpot/goutte/Goutte/Client.php \Goutte\Client
  4. 8 vendor/guzzlehttp/guzzle/src/Client.php \GuzzleHttp\Client
  5. 8 vendor/behat/mink-goutte-driver/src/Goutte/Client.php \Behat\Mink\Driver\Goutte\Client
Same name and namespace in other branches
  1. 8.0 vendor/symfony/browser-kit/Client.php \Symfony\Component\BrowserKit\Client

Client simulates a browser.

To make the actual request, you need to implement the doRequest() method.

If you want to be able to run requests in their own process (insulated flag), you need to also implement the getScript() method.

@author Fabien Potencier <fabien@symfony.com>

Hierarchy

  • class \Symfony\Component\BrowserKit\Client

Expanded class hierarchy of Client

5 files declare their use of Client
BrowserKitDriver.php in vendor/behat/mink-browserkit-driver/src/BrowserKitDriver.php
Client.php in vendor/symfony/http-kernel/Client.php
Client.php in vendor/fabpot/goutte/Goutte/Client.php
ClientTest.php in vendor/symfony/browser-kit/Tests/ClientTest.php
ErrorHandlingTest.php in vendor/behat/mink-browserkit-driver/tests/Custom/ErrorHandlingTest.php

File

vendor/symfony/browser-kit/Client.php, line 29

Namespace

Symfony\Component\BrowserKit
View source
abstract class Client {
  protected $history;
  protected $cookieJar;
  protected $server = array();
  protected $internalRequest;
  protected $request;
  protected $internalResponse;
  protected $response;
  protected $crawler;
  protected $insulated = false;
  protected $redirect;
  protected $followRedirects = true;
  private $maxRedirects = -1;
  private $redirectCount = 0;
  private $isMainRequest = true;

  /**
   * Constructor.
   *
   * @param array     $server    The server parameters (equivalent of $_SERVER)
   * @param History   $history   A History instance to store the browser history
   * @param CookieJar $cookieJar A CookieJar instance to store the cookies
   */
  public function __construct(array $server = array(), History $history = null, CookieJar $cookieJar = null) {
    $this
      ->setServerParameters($server);
    $this->history = $history ?: new History();
    $this->cookieJar = $cookieJar ?: new CookieJar();
  }

  /**
   * Sets whether to automatically follow redirects or not.
   *
   * @param bool $followRedirect Whether to follow redirects
   */
  public function followRedirects($followRedirect = true) {
    $this->followRedirects = (bool) $followRedirect;
  }

  /**
   * Sets the maximum number of requests that crawler can follow.
   *
   * @param int $maxRedirects
   */
  public function setMaxRedirects($maxRedirects) {
    $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects;
    $this->followRedirects = -1 != $this->maxRedirects;
  }

  /**
   * Sets the insulated flag.
   *
   * @param bool $insulated Whether to insulate the requests or not
   *
   * @throws \RuntimeException When Symfony Process Component is not installed
   */
  public function insulate($insulated = true) {
    if ($insulated && !class_exists('Symfony\\Component\\Process\\Process')) {
      throw new \RuntimeException('Unable to isolate requests as the Symfony Process Component is not installed.');
    }
    $this->insulated = (bool) $insulated;
  }

  /**
   * Sets server parameters.
   *
   * @param array $server An array of server parameters
   */
  public function setServerParameters(array $server) {
    $this->server = array_merge(array(
      'HTTP_HOST' => 'localhost',
      'HTTP_USER_AGENT' => 'Symfony2 BrowserKit',
    ), $server);
  }

  /**
   * Sets single server parameter.
   *
   * @param string $key   A key of the parameter
   * @param string $value A value of the parameter
   */
  public function setServerParameter($key, $value) {
    $this->server[$key] = $value;
  }

  /**
   * Gets single server parameter for specified key.
   *
   * @param string $key     A key of the parameter to get
   * @param string $default A default value when key is undefined
   *
   * @return string A value of the parameter
   */
  public function getServerParameter($key, $default = '') {
    return isset($this->server[$key]) ? $this->server[$key] : $default;
  }

  /**
   * Returns the History instance.
   *
   * @return History A History instance
   */
  public function getHistory() {
    return $this->history;
  }

  /**
   * Returns the CookieJar instance.
   *
   * @return CookieJar A CookieJar instance
   */
  public function getCookieJar() {
    return $this->cookieJar;
  }

  /**
   * Returns the current Crawler instance.
   *
   * @return Crawler|null A Crawler instance
   */
  public function getCrawler() {
    return $this->crawler;
  }

  /**
   * Returns the current BrowserKit Response instance.
   *
   * @return Response|null A BrowserKit Response instance
   */
  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()
   */
  public function getResponse() {
    return $this->response;
  }

  /**
   * Returns the current BrowserKit Request instance.
   *
   * @return Request|null A BrowserKit Request instance
   */
  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()
   */
  public function getRequest() {
    return $this->request;
  }

  /**
   * Clicks on a given link.
   *
   * @param Link $link A Link instance
   *
   * @return Crawler
   */
  public function click(Link $link) {
    if ($link instanceof Form) {
      return $this
        ->submit($link);
    }
    return $this
      ->request($link
      ->getMethod(), $link
      ->getUri());
  }

  /**
   * Submits a form.
   *
   * @param Form  $form   A Form instance
   * @param array $values An array of form field values
   *
   * @return Crawler
   */
  public function submit(Form $form, array $values = array()) {
    $form
      ->setValues($values);
    return $this
      ->request($form
      ->getMethod(), $form
      ->getUri(), $form
      ->getPhpValues(), $form
      ->getPhpFiles());
  }

  /**
   * Calls a URI.
   *
   * @param string $method        The request method
   * @param string $uri           The URI to fetch
   * @param array  $parameters    The Request parameters
   * @param array  $files         The files
   * @param array  $server        The server parameters (HTTP headers are referenced with a HTTP_ prefix as PHP does)
   * @param string $content       The raw body data
   * @param bool   $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload())
   *
   * @return Crawler
   */
  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);
    if (!empty($server['HTTP_HOST'])) {
      $uri = preg_replace('{^(https?\\://)' . preg_quote($this
        ->extractHost($uri)) . '}', '${1}' . $server['HTTP_HOST'], $uri);
    }
    if (isset($server['HTTPS'])) {
      $uri = preg_replace('{^' . parse_url($uri, PHP_URL_SCHEME) . '}', $server['HTTPS'] ? 'https' : 'http', $uri);
    }
    $server = array_merge($this->server, $server);
    if (!$this->history
      ->isEmpty()) {
      $server['HTTP_REFERER'] = $this->history
        ->current()
        ->getUri();
    }
    $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);
    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'));
  }

  /**
   * Makes a request in another process.
   *
   * @param object $request An origin request instance
   *
   * @return object An origin response instance
   *
   * @throws \RuntimeException When processing returns exit code
   */
  protected function doRequestInProcess($request) {
    $process = new PhpProcess($this
      ->getScript($request), null, null);
    $process
      ->run();
    if (!$process
      ->isSuccessful() || !preg_match('/^O\\:\\d+\\:/', $process
      ->getOutput())) {
      throw new \RuntimeException(sprintf('OUTPUT: %s ERROR OUTPUT: %s', $process
        ->getOutput(), $process
        ->getErrorOutput()));
    }
    return unserialize($process
      ->getOutput());
  }

  /**
   * Makes a request.
   *
   * @param object $request An origin request instance
   *
   * @return object An origin response instance
   */
  protected abstract function doRequest($request);

  /**
   * Returns the script to execute when the request must be insulated.
   *
   * @param object $request An origin request instance
   *
   * @throws \LogicException When this abstract class is not implemented
   */
  protected function getScript($request) {
    throw new \LogicException('To insulate requests, you need to override the getScript() method.');
  }

  /**
   * Filters the BrowserKit request to the origin one.
   *
   * @param Request $request The BrowserKit Request to filter
   *
   * @return object An origin request instance
   */
  protected function filterRequest(Request $request) {
    return $request;
  }

  /**
   * Filters the origin response to the BrowserKit one.
   *
   * @param object $response The origin response to filter
   *
   * @return Response An BrowserKit Response instance
   */
  protected function filterResponse($response) {
    return $response;
  }

  /**
   * Creates a crawler.
   *
   * This method returns null if the DomCrawler component is not available.
   *
   * @param string $uri     A URI
   * @param string $content Content for the crawler to use
   * @param string $type    Content type
   *
   * @return Crawler|null
   */
  protected function createCrawlerFromContent($uri, $content, $type) {
    if (!class_exists('Symfony\\Component\\DomCrawler\\Crawler')) {
      return;
    }
    $crawler = new Crawler(null, $uri);
    $crawler
      ->addContent($content, $type);
    return $crawler;
  }

  /**
   * Goes back in the browser history.
   *
   * @return Crawler
   */
  public function back() {
    return $this
      ->requestFromRequest($this->history
      ->back(), false);
  }

  /**
   * Goes forward in the browser history.
   *
   * @return Crawler
   */
  public function forward() {
    return $this
      ->requestFromRequest($this->history
      ->forward(), false);
  }

  /**
   * Reloads the current browser.
   *
   * @return Crawler
   */
  public function reload() {
    return $this
      ->requestFromRequest($this->history
      ->current(), false);
  }

  /**
   * Follow redirects?
   *
   * @return Crawler
   *
   * @throws \LogicException If request was not a redirect
   */
  public function followRedirect() {
    if (empty($this->redirect)) {
      throw new \LogicException('The request was not redirected.');
    }
    if (-1 !== $this->maxRedirects) {
      if ($this->redirectCount > $this->maxRedirects) {
        throw new \LogicException(sprintf('The maximum number (%d) of redirections was reached.', $this->maxRedirects));
      }
    }
    $request = $this->internalRequest;
    if (in_array($this->internalResponse
      ->getStatus(), array(
      302,
      303,
    ))) {
      $method = 'get';
      $files = array();
      $content = null;
    }
    else {
      $method = $request
        ->getMethod();
      $files = $request
        ->getFiles();
      $content = $request
        ->getContent();
    }
    if ('get' === strtolower($method)) {

      // Don't forward parameters for GET request as it should reach the redirection URI
      $parameters = array();
    }
    else {
      $parameters = $request
        ->getParameters();
    }
    $server = $request
      ->getServer();
    $server = $this
      ->updateServerFromUri($server, $this->redirect);
    $this->isMainRequest = false;
    $response = $this
      ->request($method, $this->redirect, $parameters, $files, $server, $content);
    $this->isMainRequest = true;
    return $response;
  }

  /**
   * Restarts the client.
   *
   * It flushes history and all cookies.
   */
  public function restart() {
    $this->cookieJar
      ->clear();
    $this->history
      ->clear();
  }

  /**
   * Takes a URI and converts it to absolute if it is not already absolute.
   *
   * @param string $uri A URI
   *
   * @return string An absolute URI
   */
  protected function getAbsoluteUri($uri) {

    // already absolute?
    if (0 === strpos($uri, 'http://') || 0 === strpos($uri, 'https://')) {
      return $uri;
    }
    if (!$this->history
      ->isEmpty()) {
      $currentUri = $this->history
        ->current()
        ->getUri();
    }
    else {
      $currentUri = sprintf('http%s://%s/', isset($this->server['HTTPS']) ? 's' : '', isset($this->server['HTTP_HOST']) ? $this->server['HTTP_HOST'] : 'localhost');
    }

    // protocol relative URL
    if (0 === strpos($uri, '//')) {
      return parse_url($currentUri, PHP_URL_SCHEME) . ':' . $uri;
    }

    // anchor?
    if (!$uri || '#' == $uri[0]) {
      return preg_replace('/#.*?$/', '', $currentUri) . $uri;
    }
    if ('/' !== $uri[0]) {
      $path = parse_url($currentUri, PHP_URL_PATH);
      if ('/' !== substr($path, -1)) {
        $path = substr($path, 0, strrpos($path, '/') + 1);
      }
      $uri = $path . $uri;
    }
    return preg_replace('#^(.*?//[^/]+)\\/.*$#', '$1', $currentUri) . $uri;
  }

  /**
   * Makes a request from a Request object directly.
   *
   * @param Request $request       A Request instance
   * @param bool    $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload())
   *
   * @return Crawler
   */
  protected function requestFromRequest(Request $request, $changeHistory = true) {
    return $this
      ->request($request
      ->getMethod(), $request
      ->getUri(), $request
      ->getParameters(), $request
      ->getFiles(), $request
      ->getServer(), $request
      ->getContent(), $changeHistory);
  }
  private function updateServerFromUri($server, $uri) {
    $server['HTTP_HOST'] = $this
      ->extractHost($uri);
    $scheme = parse_url($uri, PHP_URL_SCHEME);
    $server['HTTPS'] = null === $scheme ? $server['HTTPS'] : 'https' == $scheme;
    unset($server['HTTP_IF_NONE_MATCH'], $server['HTTP_IF_MODIFIED_SINCE']);
    return $server;
  }
  private function extractHost($uri) {
    $host = parse_url($uri, PHP_URL_HOST);
    if ($port = parse_url($uri, PHP_URL_PORT)) {
      return $host . ':' . $port;
    }
    return $host;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Client::$cookieJar protected property
Client::$crawler protected property
Client::$followRedirects protected property
Client::$history protected property
Client::$insulated protected property
Client::$internalRequest protected property
Client::$internalResponse protected property
Client::$isMainRequest private property
Client::$maxRedirects private property
Client::$redirect protected property
Client::$redirectCount private property
Client::$request protected property
Client::$response protected property
Client::$server protected property
Client::back public function Goes back in the browser history.
Client::click public function Clicks on a given link.
Client::createCrawlerFromContent protected function Creates a crawler.
Client::doRequest abstract protected function Makes a request. 4
Client::doRequestInProcess protected function Makes a request in another process.
Client::extractHost private function
Client::filterRequest protected function Filters the BrowserKit request to the origin one. 1
Client::filterResponse protected function Filters the origin response to the BrowserKit one. 3
Client::followRedirect public function Follow redirects?
Client::followRedirects public function Sets whether to automatically follow redirects or not.
Client::forward public function Goes forward in the browser history.
Client::getAbsoluteUri protected function Takes a URI and converts it to absolute if it is not already absolute.
Client::getCookieJar public function Returns the CookieJar instance.
Client::getCrawler public function Returns the current Crawler instance.
Client::getHistory public function Returns the History instance.
Client::getInternalRequest public function Returns the current BrowserKit Request instance.
Client::getInternalResponse public function Returns the current BrowserKit Response instance.
Client::getRequest public function Returns the current origin Request instance. 1
Client::getResponse public function Returns the current origin response instance. 1
Client::getScript protected function Returns the script to execute when the request must be insulated. 3
Client::getServerParameter public function Gets single server parameter for specified key.
Client::insulate public function Sets the insulated flag.
Client::reload public function Reloads the current browser.
Client::request public function Calls a URI.
Client::requestFromRequest protected function Makes a request from a Request object directly.
Client::restart public function Restarts the client.
Client::setMaxRedirects public function Sets the maximum number of requests that crawler can follow.
Client::setServerParameter public function Sets single server parameter.
Client::setServerParameters public function Sets server parameters.
Client::submit public function Submits a form.
Client::updateServerFromUri private function
Client::__construct public function Constructor. 1