DrupalMinkClient.php 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. <?php
  2. namespace Drupal\BuildTests\Framework;
  3. use Behat\Mink\Driver\Goutte\Client;
  4. use Symfony\Component\BrowserKit\Client as SymfonyClient;
  5. /**
  6. * Extend the Mink client for Drupal use-cases.
  7. *
  8. * This is adapted from https://github.com/symfony/symfony/pull/27118.
  9. *
  10. * @todo Update this client when Drupal starts using Symfony 4.2.0+.
  11. * https://www.drupal.org/project/drupal/issues/3077785
  12. */
  13. class DrupalMinkClient extends Client {
  14. /**
  15. * Whether to follow meta redirects or not.
  16. *
  17. * @var bool
  18. *
  19. * @see \Drupal\BuildTests\Framework\DrupalMinkClient::followMetaRefresh()
  20. */
  21. protected $followMetaRefresh;
  22. /**
  23. * Sets whether to automatically follow meta refresh redirects or not.
  24. *
  25. * @param bool $followMetaRefresh
  26. * (optional) Whether to follow meta redirects. Defaults to TRUE.
  27. */
  28. public function followMetaRefresh(bool $followMetaRefresh = TRUE) {
  29. $this->followMetaRefresh = $followMetaRefresh;
  30. }
  31. /**
  32. * Glean the meta refresh URL from the current page content.
  33. *
  34. * @return string|null
  35. * Either the redirect URL that was found, or NULL if none was found.
  36. */
  37. private function getMetaRefreshUrl() {
  38. $metaRefresh = $this->getCrawler()->filter('meta[http-equiv="Refresh"], meta[http-equiv="refresh"]');
  39. foreach ($metaRefresh->extract(['content']) as $content) {
  40. if (preg_match('/^\s*0\s*;\s*URL\s*=\s*(?|\'([^\']++)|"([^"]++)|([^\'"].*))/i', $content, $m)) {
  41. return str_replace("\t\r\n", '', rtrim($m[1]));
  42. }
  43. }
  44. return NULL;
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. public function request($method, $uri, array $parameters = [], array $files = [], array $server = [], $content = NULL, $changeHistory = TRUE) {
  50. $this->crawler = parent::request($method, $uri, $parameters, $files, $server, $content, $changeHistory);
  51. // Check for meta refresh redirect and follow it.
  52. if ($this->followMetaRefresh && NULL !== $redirect = $this->getMetaRefreshUrl()) {
  53. $this->redirect = $redirect;
  54. // $this->redirects is private on the BrowserKit client, so we have to use
  55. // reflection to manage the redirects stack.
  56. $ref_redirects = new \ReflectionProperty(SymfonyClient::class, 'redirects');
  57. $ref_redirects->setAccessible(TRUE);
  58. $redirects = $ref_redirects->getValue($this);
  59. $redirects[serialize($this->history->current())] = TRUE;
  60. $ref_redirects->setValue($this, $redirects);
  61. $this->crawler = $this->followRedirect();
  62. }
  63. return $this->crawler;
  64. }
  65. }