Skip to content

Commit 849f6e3

Browse files
committed
refactor: Gt->GT compatibility
1 parent 927c28e commit 849f6e3

File tree

9 files changed

+176
-34
lines changed

9 files changed

+176
-34
lines changed

gt-namespace-compatibility.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
<?php
23
/**
34
* Namespace compatibility layer for Gt -> GT transition.
@@ -9,6 +10,12 @@
910
spl_autoload_register(function(string $class):void {
1011
if(str_starts_with($class, 'GT\\')) {
1112
$legacyClass = 'Gt' . substr($class, 2);
12-
class_alias($legacyClass, $class, true);
13+
// Trigger autoloading for the legacy class
14+
spl_autoload_call($legacyClass);
15+
// Only create alias if it was loaded and target doesn't already exist
16+
if((class_exists($legacyClass, false) || interface_exists($legacyClass, false) || trait_exists($legacyClass, false))
17+
&& !class_exists($class, false) && !interface_exists($class, false) && !trait_exists($class, false)) {
18+
class_alias($legacyClass, $class);
19+
}
1320
}
14-
}, true, false);
21+
}, true, true);

src/Application.php

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
<?php
22
namespace GT\WebEngine;
33

4-
use GT\Config\Config;
5-
use GT\Config\ConfigFactory;
6-
use GT\Http\Response;
7-
use Gt\Http\ServerRequest;
8-
use GT\Http\Stream;
9-
use GT\ProtectedGlobal\Protection;
4+
use Closure;
5+
use Throwable;
6+
use ErrorException;
107
use GT\WebEngine\Debug\OutputBuffer;
118
use GT\WebEngine\Debug\Timer;
129
use GT\WebEngine\Redirection\Redirect;
13-
use GT\Http\RequestFactory;
14-
use ErrorException;
15-
use Throwable;
10+
use GT\WebEngine\Dispatch\Dispatcher;
11+
use GT\WebEngine\Dispatch\DispatcherFactory;
12+
use Gt\Config\Config;
13+
use Gt\Config\ConfigFactory;
14+
use Gt\Http\RequestFactory;
15+
use Gt\Http\Response;
16+
use Gt\Http\ServerRequest;
17+
use Gt\Http\Stream;
18+
use Gt\ProtectedGlobal\Protection;
1619

1720
/**
1821
* The fundamental purpose of any PHP framework is to provide a mechanism for
@@ -26,9 +29,11 @@ class Application {
2629
private Redirect $redirect;
2730
private Timer $timer;
2831
private OutputBuffer $outputBuffer;
32+
private RequestFactory $requestFactory;
2933
/** @var array<string, array<string, string>> */
3034
private array $globals;
3135
private Config $config;
36+
private DispatcherFactory $dispatcherFactory;
3237
private Dispatcher $dispatcher;
3338
private bool $finished = false;
3439

@@ -39,13 +44,25 @@ class Application {
3944
public function __construct(
4045
?Redirect $redirect = null,
4146
?Config $config = null,
47+
?Timer $timer = null,
48+
?OutputBuffer $outputBuffer = null,
49+
?RequestFactory $requestFactory = null,
50+
?DispatcherFactory $dispatcherFactory = null,
4251
?array $globals = null,
52+
?Closure $handleShutdown = null,
4353
) {
4454
$this->gtCompatibility();
45-
$this->config = $config ?? $this->loadConfig();
4655
$this->redirect = $redirect ?? new Redirect();
56+
$this->config = $config ?? $this->loadConfig();
57+
$this->timer = $timer ?? new Timer(
58+
$this->config->getFloat("app.slow_delta"),
59+
$this->config->getFloat("app.very_slow_delta"),
60+
);
61+
$this->outputBuffer = $outputBuffer ?? new OutputBuffer();
62+
$this->requestFactory = $requestFactory ?? new RequestFactory();
63+
$this->dispatcherFactory = $dispatcherFactory ?? new DispatcherFactory();
4764
$this->globals = $globals ?? $GLOBALS;
48-
register_shutdown_function($this->handleShutdown(...));
65+
register_shutdown_function($handleShutdown ?? $this->handleShutdown(...));
4966
}
5067

5168
public function start():void {
@@ -56,37 +73,32 @@ public function start():void {
5673
// This timer is only used again at the end of the call, when finish() is
5774
// called - at which point the entire duration of the request is logged out (and
5875
// slow requests are highlighted as a NOTICE).
59-
$this->timer = new Timer(
60-
$this->config->getFloat("app.slow_delta"),
61-
$this->config->getFloat("app.very_slow_delta"),
62-
);
76+
$this->timer->start();
6377

6478
// Starting the output buffer is done before any logic is executed, so any calls
6579
// to any area of code will not accidentally send output to the web browser.
66-
$this->outputBuffer = new OutputBuffer();
80+
$this->outputBuffer->start();
6781

6882
// PHP.GT provides object-oriented interfaces to all values stored in $_SERVER,
6983
// $_FILES, $_GET, and $_POST - to enforce good encapsulation and safe variable
7084
// usage, the globals are protected against accidental misuse.
7185
$this->protectGlobals();
7286

73-
$requestFactory = new RequestFactory();
74-
7587
/** @var ServerRequest $request */
76-
$request = $requestFactory->createServerRequestFromGlobalState(
77-
$this->globals["server"],
78-
$this->globals["files"],
79-
$this->globals["get"],
80-
$this->globals["post"],
88+
$request = $this->requestFactory->createServerRequestFromGlobalState(
89+
$this->globals["_SERVER"] ?? [],
90+
$this->globals["_FILES"] ?? [],
91+
$this->globals["_GET"] ?? [],
92+
$this->globals["_POST"] ?? [],
8193
);
8294

83-
$this->dispatcher = new Dispatcher(
95+
$this->dispatcher = $this->dispatcherFactory->create(
8496
$this->config,
8597
$request,
86-
$this->globals["get"],
87-
$this->globals["post"],
88-
$this->globals["files"],
89-
$this->globals["server"],
98+
$this->globals["_GET"],
99+
$this->globals["_POST"],
100+
$this->globals["_FILES"],
101+
$this->globals["_SERVER"],
90102
);
91103

92104
try {

src/Debug/OutputBuffer.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ public function __construct(
2121
) {
2222
$this->obStartHandler = $obStartHandler ?? fn() => ob_start();
2323
$this->obGetCleanHandler = $obGetCleanHandler ?? fn() => ob_get_clean();
24+
}
25+
26+
public function start():void {
2427
($this->obStartHandler)();
2528
}
2629

src/Debug/Timer.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ public function __construct(
3232
}
3333

3434
$this->timeGetter = $timeGetter ?? fn() => microtime(true);
35+
}
36+
37+
public function start():void {
3538
$this->startTime = ($this->timeGetter)();
3639
}
3740

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?php
2-
namespace GT\WebEngine;
2+
namespace GT\WebEngine\Dispatch;
33

44
use Gt\Config\Config;
55
use Gt\Http\Request;

src/Dispatch/DispatcherFactory.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
namespace GT\WebEngine\Dispatch;
3+
4+
use Gt\Config\Config;
5+
use Gt\Http\Request;
6+
7+
class DispatcherFactory {
8+
public function create(
9+
Config $config,
10+
Request $request,
11+
array $globalGet,
12+
array $globalPost,
13+
array $globalFiles,
14+
array $globalServer,
15+
):Dispatcher {
16+
return new Dispatcher(
17+
$config,
18+
$request,
19+
$globalGet,
20+
$globalPost,
21+
$globalFiles,
22+
$globalServer,
23+
);
24+
}
25+
}

test/phpunit/ApplicationTest.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,95 @@
11
<?php
22
namespace GT\WebEngine\Test;
33

4+
use GT\Http\RequestFactory;
5+
use GT\Http\Response;
6+
use GT\WebEngine\Application;
7+
use GT\WebEngine\Debug\OutputBuffer;
8+
use GT\WebEngine\Debug\Timer;
9+
use GT\WebEngine\Dispatch\Dispatcher;
10+
use GT\WebEngine\Dispatch\DispatcherFactory;
11+
use GT\WebEngine\Redirection\Redirect;
412
use PHPUnit\Framework\TestCase;
513

614
class ApplicationTest extends TestCase {
15+
public function testStart_callsRedirectExecute():void {
16+
$redirect = self::createMock(Redirect::class);
17+
$redirect->expects(self::once())
18+
->method("execute");
719

20+
$sut = new Application(
21+
redirect: $redirect,
22+
);
23+
$sut->start();
24+
}
25+
26+
public function testStart_callsTimerFunctions():void {
27+
$timer = self::createMock(Timer::class);
28+
$timer->expects(self::once())
29+
->method("start");
30+
$timer->expects(self::once())
31+
->method("stop");
32+
$timer->expects(self::once())
33+
->method("logDelta");
34+
35+
$sut = new Application(
36+
timer: $timer,
37+
);
38+
$sut->start();
39+
}
40+
41+
public function testStart_callsOutputBufferFunctions():void {
42+
$outputBuffer = self::createMock(OutputBuffer::class);
43+
$outputBuffer->expects(self::once())
44+
->method("start");
45+
$outputBuffer->expects(self::once())
46+
->method("debugOutput");
47+
48+
$sut = new Application(
49+
outputBuffer: $outputBuffer,
50+
);
51+
$sut->start();
52+
}
53+
54+
public function testStart_callsRequestFactoryFunctions():void {
55+
$requestFactory = self::createMock(RequestFactory::class);
56+
$requestFactory->expects(self::once())
57+
->method("createServerRequestFromGlobalState");
58+
59+
$sut = new Application(
60+
requestFactory: $requestFactory,
61+
);
62+
$sut->start();
63+
}
64+
65+
/**
66+
* This test is really important because it shows that all of the
67+
* components that make up the request/response can be injected into the
68+
* application, so everything can be meticulously tested in detail.
69+
*/
70+
public function testStart_callsDispatcherFactoryFunctions():void {
71+
$response = self::createMock(Response::class);
72+
$dispatcher = self::createMock(Dispatcher::class);
73+
74+
$dispatcherFactory = self::createMock(DispatcherFactory::class);
75+
$dispatcherFactory->expects(self::once())
76+
->method("create")
77+
->willReturn($dispatcher);
78+
79+
$dispatcher->expects(self::once())
80+
->method("generateResponse")
81+
->willReturn($response);
82+
83+
$response->expects(self::once())
84+
->method("getStatusCode");
85+
$response->expects(self::once())
86+
->method("getHeaders");
87+
$response->expects(self::once())
88+
->method("getBody");
89+
90+
$sut = new Application(
91+
dispatcherFactory: $dispatcherFactory,
92+
);
93+
$sut->start();
94+
}
895
}

test/phpunit/Debug/OutputBufferTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
class OutputBufferTest extends TestCase {
88
public function testEchoIsCaptured():void {
99
$sut = new OutputBuffer();
10+
$sut->start();
1011
echo "Hello world";
1112
$buffer = $sut->getBuffer();
1213
self::assertSame("Hello world", $buffer);
1314
}
1415

1516
public function testVarDumpIsCaptured():void {
1617
$sut = new OutputBuffer();
18+
$sut->start();
1719
$var = ["a" => 1, "b" => 2];
1820
var_dump($var);
1921
$buffer = $sut->getBuffer();

test/phpunit/Debug/TimerTest.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ public function testDeltaWithInjectedTimeGetter():void {
1515
};
1616

1717
$sut = new Timer(timeGetter: $timeGetter);
18+
$sut->start();
1819
$sut->stop();
1920
self::assertSame(2.5, $sut->getDelta());
2021
}
2122

2223
public function testStopMultipleTimesUsesLatestEndTime():void {
23-
$times = [10.0, 15.0, 20.0];
24+
$times = [10.0, 20.0, 40.0, 80.0, 160.0];
2425
$index = 0;
2526
$timeGetter = function() use (&$times, &$index) {
2627
$value = $times[$index] ?? end($times);
@@ -29,10 +30,12 @@ public function testStopMultipleTimesUsesLatestEndTime():void {
2930
};
3031

3132
$sut = new Timer(timeGetter: $timeGetter);
33+
$sut->start();
3234
$sut->stop();
33-
self::assertSame(5.0, $sut->getDelta());
35+
self::assertSame(10.0, $sut->getDelta());
3436

37+
$sut->start();
3538
$sut->stop();
36-
self::assertSame(10.0, $sut->getDelta());
39+
self::assertSame(40.0, $sut->getDelta());
3740
}
3841
}

0 commit comments

Comments
 (0)