Skip to content

Commit db509fc

Browse files
committed
Add README
1 parent 4b4a69f commit db509fc

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# CgiHttpKernel
2+
3+
Adapter from HttpKernelInterface to CGI.
4+
5+
## The HttpKernelInterface is a lie
6+
7+
You thought that you need to rewrite your whole application to use
8+
HttpFoundation in order to benefit from HttpKernelInterface functional
9+
testing?
10+
11+
Well, it turns out that you don't need that at all. Some very smart people
12+
came up with this thing called CGI (Common Gateway Interface) which defines an
13+
interface between a web server and a web application. It's great because it
14+
uses UNIX pipes for communication, which means it is also very easy to pretend
15+
to be a web server, and just call the app with any input and env vars on the
16+
command line by hand.
17+
18+
In PHP that works by using `php-cgi`, which fortunately ships with almost
19+
every PHP distribution. The most basic way of calling it on the command line
20+
is this:
21+
22+
$ php-cgi hello.php
23+
24+
If you want to learn how to do more advanced stuff, read the fucking CGI spec.
25+
26+
So what does this have to do with HttpKernelInterface? CGI and that interface
27+
do pretty much the same thing, they abstract communication between web server
28+
and app. The kernel interface does this within PHP, CGI does it in a language
29+
agnostic way.
30+
31+
The CgiHttpKernel translates between those two interfaces. As a user of the
32+
library you interact with it as if it were a true HttpKernelInterface app, but
33+
in the background it will actually go ahead and call `php-cgi` on the command
34+
line, parse the output, and return a `Response` instance.
35+
36+
For example:
37+
38+
$kernel = new CgiHttpKernel(__DIR__.'/../phpBB');
39+
40+
$request = Request::create('/index.php');
41+
$response = $kernel->handle($request);
42+
43+
var_dump($response->getContent());
44+
45+
You can also pass a second argument to the constructor if you want all
46+
requests to go through a front controller.
47+
48+
$kernel = new CgiHttpKernel(__DIR__.'/../web', 'app.php');
49+
50+
$request = Request::create('/foo');
51+
$response = $kernel->handle($request);
52+
53+
The real power however comes from using libraries that integrate with the
54+
HttpKernelInterface, such as `Symfony\Component\HttpKernel\Client`.
55+
56+
$kernel = new CgiHttpKernel(__DIR__.'/../phpBB');
57+
$client = new Client($kernel);
58+
59+
$crawler = $client->request('GET', 'index.php');
60+
$this->assertGreaterThan(0, $crawler->filter('.topiclist')->count());
61+
62+
## Is it really a lie?
63+
64+
Not really. The CgiHttpKernel only makes sense for functional testing, since
65+
it is quite slow. It is slow because it must spawn a new process for every
66+
request. This is also the reason why some very smart people came up with
67+
FastCGI, which is like CGI but faster.
68+
69+
FastCGI allows the app to start a long-running process that listens on a port
70+
and thus does not have the process spawning overhead. In PHP land this is
71+
usually managed by PHP-FPM, aka FastCGI Process Manager.
72+
73+
FastCGI is good for production but not really practical for testing since it
74+
needs to run in a separate process, listen on a port, requires configuration,
75+
etc.
76+
77+
## When to use CgiHttpKernel?
78+
79+
It is mainly intended to write functional tests for legacy applications. That
80+
will hopefully enable you to refactor your legacy code with some confidence of
81+
not breaking stuff.
82+
83+
Good luck.

0 commit comments

Comments
 (0)