1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<?php
namespace Codeception\Lib\Connector;
use Codeception\Lib\Connector\Lumen\DummyKernel;
use Codeception\Lib\Connector\Shared\LaravelCommon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Facade;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Client;
class Lumen extends Client
{
use LaravelCommon;
/**
* @var \Laravel\Lumen\Application
*/
private $app;
/**
* @var \Codeception\Module\Lumen
*/
private $module;
/**
* @var bool
*/
private $firstRequest = true;
/**
* @var object
*/
private $oldDb;
/**
* Constructor.
*
* @param \Codeception\Module\Lumen $module
*/
public function __construct($module)
{
$this->module = $module;
$components = parse_url($this->module->config['url']);
$server = ['HTTP_HOST' => $components['host']];
// Pass a DummyKernel to satisfy the arguments of the parent constructor.
// The actual kernel object is set in the initialize() method.
parent::__construct(new DummyKernel(), $server);
// Parent constructor defaults to not following redirects
$this->followRedirects(true);
$this->initialize();
}
/**
* Execute a request.
*
* @param SymfonyRequest $request
* @return Response
*/
protected function doRequest($request)
{
if (!$this->firstRequest) {
$this->initialize($request);
}
$this->firstRequest = false;
$this->applyBindings();
$this->applyContextualBindings();
$this->applyInstances();
$this->applyApplicationHandlers();
$request = Request::createFromBase($request);
$response = $this->kernel->handle($request);
$method = new \ReflectionMethod(get_class($this->app), 'callTerminableMiddleware');
$method->setAccessible(true);
$method->invoke($this->app, $response);
return $response;
}
/**
* Initialize the Lumen framework.
*
* @param SymfonyRequest|null $request
*/
private function initialize($request = null)
{
// Store a reference to the database object
// so the database connection can be reused during tests
$this->oldDb = null;
if (isset($this->app['db']) && $this->app['db']->connection()) {
$this->oldDb = $this->app['db'];
}
if (class_exists(Facade::class)) {
// If the container has been instantiated ever,
// we need to clear its static fields before create new container.
Facade::clearResolvedInstances();
}
$this->app = $this->kernel = require $this->module->config['bootstrap_file'];
// Lumen registers necessary bindings on demand when calling $app->make(),
// so here we force the request binding before registering our own request object,
// otherwise Lumen will overwrite our request object.
$this->app->make('request');
$request = $request ?: SymfonyRequest::create($this->module->config['url']);
$this->app->instance('Illuminate\Http\Request', Request::createFromBase($request));
// Reset the old database if there is one
if ($this->oldDb) {
$this->app->singleton('db', function () {
return $this->oldDb;
});
Model::setConnectionResolver($this->oldDb);
}
$this->module->setApplication($this->app);
}
}