PageRenderTime 65ms CodeModel.GetById 39ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/codeception/codeception/src/Codeception/Lib/Connector/Yii2.php

https://gitlab.com/itlboy/yii2-starter-installed
PHP | 280 lines | 196 code | 41 blank | 43 comment | 17 complexity | 5ab7620c66fbe64e672de31fc0636f95 MD5 | raw file
  1. <?php
  2. namespace Codeception\Lib\Connector;
  3. use Codeception\Lib\Connector\Yii2\Logger;
  4. use Codeception\Lib\Connector\Yii2\TestMailer;
  5. use Codeception\Util\Debug;
  6. use Codeception\Util\Stub;
  7. use Symfony\Component\BrowserKit\Client;
  8. use Symfony\Component\BrowserKit\Cookie;
  9. use Symfony\Component\BrowserKit\Response;
  10. use Yii;
  11. use yii\base\ExitException;
  12. use yii\web\HttpException;
  13. use yii\web\Response as YiiResponse;
  14. class Yii2 extends Client
  15. {
  16. use Shared\PhpSuperGlobalsConverter;
  17. /**
  18. * @var string application config file
  19. */
  20. public $configFile;
  21. public $defaultServerVars = [];
  22. /**
  23. * @var array
  24. */
  25. public $headers;
  26. public $statusCode;
  27. /**
  28. * @var \yii\web\Application
  29. */
  30. private $app;
  31. /**
  32. * @var \yii\db\Connection
  33. */
  34. public static $db; // remember the db instance
  35. /**
  36. * @var TestMailer
  37. */
  38. public static $mailer;
  39. /**
  40. * @return \yii\web\Application
  41. */
  42. public function getApplication()
  43. {
  44. if (!isset($this->app)) {
  45. $this->startApp();
  46. }
  47. return $this->app;
  48. }
  49. public function resetApplication()
  50. {
  51. $this->app = null;
  52. }
  53. public function startApp()
  54. {
  55. $config = require($this->configFile);
  56. if (!isset($config['class'])) {
  57. $config['class'] = 'yii\web\Application';
  58. }
  59. /** @var \yii\web\Application $app */
  60. $this->app = Yii::createObject($config);
  61. $this->persistDb();
  62. $this->mockMailer($config);
  63. $this->mockAssetManager();
  64. \Yii::setLogger(new Logger());
  65. }
  66. public function resetPersistentVars()
  67. {
  68. static::$db = null;
  69. static::$mailer = null;
  70. \yii\web\UploadedFile::reset();
  71. }
  72. /**
  73. *
  74. * @param \Symfony\Component\BrowserKit\Request $request
  75. *
  76. * @return \Symfony\Component\BrowserKit\Response
  77. */
  78. public function doRequest($request)
  79. {
  80. $_COOKIE = $request->getCookies();
  81. $_SERVER = $request->getServer();
  82. $this->restoreServerVars();
  83. $_FILES = $this->remapFiles($request->getFiles());
  84. $_REQUEST = $this->remapRequestParameters($request->getParameters());
  85. $_POST = $_GET = [];
  86. if (strtoupper($request->getMethod()) === 'GET') {
  87. $_GET = $_REQUEST;
  88. } else {
  89. $_POST = $_REQUEST;
  90. }
  91. $uri = $request->getUri();
  92. $pathString = parse_url($uri, PHP_URL_PATH);
  93. $queryString = parse_url($uri, PHP_URL_QUERY);
  94. $_SERVER['REQUEST_URI'] = $queryString === null ? $pathString : $pathString . '?' . $queryString;
  95. $_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());
  96. parse_str($queryString, $params);
  97. foreach ($params as $k => $v) {
  98. $_GET[$k] = $v;
  99. }
  100. $app = $this->getApplication();
  101. $app->getResponse()->on(YiiResponse::EVENT_AFTER_PREPARE, [$this, 'processResponse']);
  102. // disabling logging. Logs are slowing test execution down
  103. foreach ($app->log->targets as $target) {
  104. $target->enabled = false;
  105. }
  106. $this->headers = array();
  107. $this->statusCode = null;
  108. ob_start();
  109. $yiiRequest = $app->getRequest();
  110. if ($request->getContent() !== null) {
  111. $yiiRequest->setRawBody($request->getContent());
  112. $yiiRequest->setBodyParams(null);
  113. } else {
  114. $yiiRequest->setRawBody(null);
  115. $yiiRequest->setBodyParams($_POST);
  116. }
  117. $yiiRequest->setQueryParams($_GET);
  118. try {
  119. $app->handleRequest($yiiRequest)->send();
  120. } catch (\Exception $e) {
  121. if ($e instanceof HttpException) {
  122. // Don't discard output and pass exception handling to Yii to be able
  123. // to expect error response codes in tests.
  124. $app->errorHandler->discardExistingOutput = false;
  125. $app->errorHandler->handleException($e);
  126. } elseif (!$e instanceof ExitException) {
  127. // for exceptions not related to Http, we pass them to Codeception
  128. $this->resetApplication();
  129. throw $e;
  130. }
  131. }
  132. $content = ob_get_clean();
  133. // catch "location" header and display it in debug, otherwise it would be handled
  134. // by symfony browser-kit and not displayed.
  135. if (isset($this->headers['location'])) {
  136. Debug::debug("[Headers] " . json_encode($this->headers));
  137. }
  138. $this->resetApplication();
  139. return new Response($content, $this->statusCode, $this->headers);
  140. }
  141. protected function revertErrorHandler()
  142. {
  143. $handler = new ErrorHandler();
  144. set_error_handler(array($handler, 'errorHandler'));
  145. }
  146. public function restoreServerVars()
  147. {
  148. $this->server = $this->defaultServerVars;
  149. foreach ($this->server as $key => $value) {
  150. $_SERVER[$key] = $value;
  151. }
  152. }
  153. public function processResponse($event)
  154. {
  155. /** @var \yii\web\Response $response */
  156. $response = $event->sender;
  157. $request = Yii::$app->getRequest();
  158. $this->headers = $response->getHeaders()->toArray();
  159. $response->getHeaders()->removeAll();
  160. $this->statusCode = $response->getStatusCode();
  161. $cookies = $response->getCookies();
  162. if ($request->enableCookieValidation) {
  163. $validationKey = $request->cookieValidationKey;
  164. }
  165. foreach ($cookies as $cookie) {
  166. /** @var \yii\web\Cookie $cookie */
  167. $value = $cookie->value;
  168. if ($cookie->expire != 1 && isset($validationKey)) {
  169. $data = version_compare(Yii::getVersion(), '2.0.2', '>')
  170. ? [$cookie->name, $cookie->value]
  171. : $cookie->value;
  172. $value = Yii::$app->security->hashData(serialize($data), $validationKey);
  173. }
  174. $c = new Cookie(
  175. $cookie->name,
  176. $value,
  177. $cookie->expire,
  178. $cookie->path,
  179. $cookie->domain,
  180. $cookie->secure,
  181. $cookie->httpOnly
  182. );
  183. $this->getCookieJar()->set($c);
  184. }
  185. $cookies->removeAll();
  186. }
  187. /**
  188. * Replace mailer with in memory mailer
  189. * @param $config
  190. * @param $app
  191. */
  192. protected function mockMailer($config)
  193. {
  194. if (static::$mailer) {
  195. $this->app->set('mailer', static::$mailer);
  196. return;
  197. }
  198. // options that make sense for mailer mock
  199. $allowedOptions = [
  200. 'htmlLayout',
  201. 'textLayout',
  202. 'messageConfig',
  203. 'messageClass',
  204. 'useFileTransport',
  205. 'fileTransportPath',
  206. 'fileTransportCallback',
  207. 'view',
  208. 'viewPath',
  209. ];
  210. $mailerConfig = [
  211. 'class' => 'Codeception\Lib\Connector\Yii2\TestMailer',
  212. ];
  213. if (isset($config['components']['mailer']) && is_array($config['components']['mailer'])) {
  214. foreach ($config['components']['mailer'] as $name => $value) {
  215. if (in_array($name, $allowedOptions, true)) {
  216. $mailerConfig[$name] = $value;
  217. }
  218. }
  219. }
  220. $this->app->set('mailer', $mailerConfig);
  221. static::$mailer = $this->app->get('mailer');
  222. }
  223. /**
  224. * @param $app
  225. */
  226. protected function persistDb()
  227. {
  228. // always use the same DB connection
  229. if (static::$db) {
  230. $this->app->set('db', static::$db);
  231. } elseif ($this->app->has('db')) {
  232. static::$db = $this->app->get('db');
  233. }
  234. }
  235. private function mockAssetManager()
  236. {
  237. $this->app->set('assetManager', Stub::make('yii\web\AssetManager', ['bundles' => false]));
  238. }
  239. }