Skip to content

Commit 927c28e

Browse files
committed
refactor: Gt->GT compatibility
1 parent 525ecad commit 927c28e

9 files changed

Lines changed: 134 additions & 68 deletions

File tree

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@
6161
"autoload-dev": {
6262
"psr-4": {
6363
"GT\\WebEngine\\Test\\": "./test/phpunit"
64-
}
64+
},
65+
"files": [
66+
"./gt-namespace-compatibility.php"
67+
]
6568
},
6669

6770
"keywords": [

go.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* lifecycle in the documentation:
88
* https://github.com/PhpGt/WebEngine/wiki/From-request-to-response
99
*/
10-
use Gt\WebEngine\Application;
10+
use GT\WebEngine\Application;
1111

1212
chdir(dirname($_SERVER["DOCUMENT_ROOT"]));
1313
ini_set("display_errors", "on");
@@ -31,7 +31,11 @@
3131
* files exist.
3232
* @link https://getcomposer.org/doc/00-intro.md
3333
*/
34-
foreach([dirname($_SERVER["DOCUMENT_ROOT"]), __DIR__] as $dir) {
34+
$vendorDirectoryList = [
35+
dirname($_SERVER["DOCUMENT_ROOT"]),
36+
__DIR__,
37+
];
38+
foreach($vendorDirectoryList as $dir) {
3539
$autoloadPath = "$dir/vendor/autoload.php";
3640
if(file_exists($autoloadPath)) {
3741
require $autoloadPath;
@@ -50,4 +54,4 @@
5054
}
5155

5256
$app = new Application();
53-
$app->start();
57+
$app->start();

gt-namespace-compatibility.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,6 @@
99
spl_autoload_register(function(string $class):void {
1010
if(str_starts_with($class, 'GT\\')) {
1111
$legacyClass = 'Gt' . substr($class, 2);
12-
13-
if(class_exists($legacyClass)
14-
|| interface_exists($legacyClass)
15-
|| trait_exists($legacyClass)
16-
|| enum_exists($legacyClass)
17-
) {
18-
class_alias($legacyClass, $class);
19-
}
12+
class_alias($legacyClass, $class, true);
2013
}
21-
}, true, true);
14+
}, true, false);

phpstan.neon

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,12 @@ parameters:
88
- src/View
99
reportUnmatchedIgnoredErrors: false
1010
ignoreErrors:
11-
- '#^Class Gt\\[a-zA-Z\\]+ referenced with incorrect case: GT\\[a-zA-Z\\]+\.$#'
12-
- '#^Class GT\\[a-zA-Z\\]+ referenced with incorrect case: Gt\\[a-zA-Z\\]+\.$#'
11+
- '#^Class Gt\\[a-zA-Z\\]+ referenced with incorrect case: GT\\[a-zA-Z\\]+\.$#'
12+
- '#^Class GT\\[a-zA-Z\\]+ referenced with incorrect case: Gt\\[a-zA-Z\\]+\.$#'
13+
- '#^Property .+ has unknown class GT\\.+ as its type\.$#'
14+
- '#^Parameter .+ of method .+ has invalid type GT\\.+\.$#'
15+
- '#^Call to method .+ on an unknown class GT\\.+\.$#'
16+
- '#^Instantiated class GT\\.+ not found\.$#'
17+
- '#^Parameter .+ of class .+ expects Gt\\.+, GT\\.+ given\.$#'
18+
- '#^PHPDoc tag @var for variable .+ contains unknown class GT\\.+\.$#'
19+
- '#^Method .+ has invalid return type GT\\.+\.$#'

src/Application.php

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
use GT\Config\Config;
55
use GT\Config\ConfigFactory;
6-
use GT\Http\Request;
76
use GT\Http\Response;
87
use Gt\Http\ServerRequest;
98
use GT\Http\Stream;
@@ -33,11 +32,19 @@ class Application {
3332
private Dispatcher $dispatcher;
3433
private bool $finished = false;
3534

35+
/**
36+
* @param null|array<string, array<string, string>> $globals
37+
* @SuppressWarnings("PHPMD.Superglobals")
38+
*/
3639
public function __construct(
3740
?Redirect $redirect = null,
41+
?Config $config = null,
42+
?array $globals = null,
3843
) {
39-
$this->config = $this->loadConfig();
44+
$this->gtCompatibility();
45+
$this->config = $config ?? $this->loadConfig();
4046
$this->redirect = $redirect ?? new Redirect();
47+
$this->globals = $globals ?? $GLOBALS;
4148
register_shutdown_function($this->handleShutdown(...));
4249
}
4350

@@ -61,7 +68,7 @@ public function start():void {
6168
// PHP.GT provides object-oriented interfaces to all values stored in $_SERVER,
6269
// $_FILES, $_GET, and $_POST - to enforce good encapsulation and safe variable
6370
// usage, the globals are protected against accidental misuse.
64-
$this->globals = $this->protectGlobals();
71+
$this->protectGlobals();
6572

6673
$requestFactory = new RequestFactory();
6774

@@ -73,7 +80,14 @@ public function start():void {
7380
$this->globals["post"],
7481
);
7582

76-
$this->dispatcher = new Dispatcher($request);
83+
$this->dispatcher = new Dispatcher(
84+
$this->config,
85+
$request,
86+
$this->globals["get"],
87+
$this->globals["post"],
88+
$this->globals["files"],
89+
$this->globals["server"],
90+
);
7791

7892
try {
7993
$response = $this->dispatcher->generateResponse();
@@ -111,22 +125,42 @@ private function finish(
111125
}
112126

113127
/**
114-
* @return array<string, array<string, mixed>>
115-
* @SuppressWarnings("PHPMD.Superglobals")
128+
* Registers a namespace compatibility autoloader to bridge the
129+
* Gt -> GT namespace transition.
130+
*
131+
* As part of the PHP.GT rebranding for WebEngine v5, all references to
132+
* "GT" are being standardised to uppercase. However, the framework
133+
* consists of 40+ repositories that cannot all be refactored
134+
* simultaneously. This compatibility layer allows new code to reference
135+
* classes using the GT\ namespace while the underlying packages still
136+
* define classes with the Gt\ namespace.
116137
*/
117-
private function protectGlobals():array {
118-
$originalGlobals = [
119-
"server" => $_SERVER,
120-
"files" => $_FILES,
121-
"get" => $_GET,
122-
"post" => $_POST,
123-
"env" => $_ENV,
124-
"cookie" => $_COOKIE
125-
];
138+
private function gtCompatibility():void {
139+
spl_autoload_register(function(string $class):void {
140+
if(str_starts_with($class, 'GT\\')) {
141+
$legacyClass = 'Gt' . substr($class, 2);
142+
// Trigger autoloading for the legacy class
143+
spl_autoload_call($legacyClass);
144+
// Only create alias if it was loaded and target doesn't already exist
145+
if((class_exists($legacyClass, false) || interface_exists($legacyClass, false) || trait_exists($legacyClass, false))
146+
&& !class_exists($class, false) && !interface_exists($class, false) && !trait_exists($class, false)) {
147+
class_alias($legacyClass, $class);
148+
}
149+
}
150+
}, true, true);
151+
}
126152

153+
private function protectGlobals():void {
127154
$protection = new Protection();
128155
$protection->overrideInternals(
129-
$protection->removeGlobals($originalGlobals, [
156+
$protection->removeGlobals([
157+
"server" => $this->globals["_SERVER"],
158+
"files" => $this->globals["_FILES"],
159+
"get" => $this->globals["_GET"],
160+
"post" => $this->globals["_POST"],
161+
"env" => $this->globals["_ENV"],
162+
"cookie" => $this->globals["_COOKIE"],
163+
], [
130164
"_ENV" => explode(",", $this->config->getString("app.globals_whitelist_env") ?? ""),
131165
"_SERVER" => explode(",", $this->config->getString("app.globals_whitelist_server") ?? ""),
132166
"_GET" => explode(",", $this->config->getString("app.globals_whitelist_get") ?? ""),
@@ -135,8 +169,6 @@ private function protectGlobals():array {
135169
"_COOKIES" => explode(",", $this->config->getString("app.globals_whitelist_cookies") ?? ""),
136170
])
137171
);
138-
139-
return $originalGlobals;
140172
}
141173

142174
private function loadConfig():Config {
@@ -188,8 +220,15 @@ private function handleShutdown():void {
188220
$this->finish($response);
189221
}
190222
catch(Throwable $innerThrowable) {
191-
$this->dispatcher->generateBasicErrorResponse($innerThrowable, $throwable);
223+
$response = $this->dispatcher->generateBasicErrorResponse($innerThrowable, $throwable);
192224
}
225+
$this->outputHeaders(
226+
$response->getStatusCode(),
227+
$response->getHeaders(),
228+
);
229+
/** @var Stream $responseBody */
230+
$responseBody = $response->getBody();
231+
$this->outputResponseBody($responseBody);
193232
}
194233

195234
private function logError(Throwable $throwable):void {

src/Debug/Timer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ class Timer {
2222
private Closure $timeGetter;
2323

2424
public function __construct(
25-
private float $slowDelta = 0.1,
26-
private float $verySlowDelta = 0.5,
25+
private readonly float $slowDelta = 0.1,
26+
private readonly float $verySlowDelta = 0.5,
2727
?Closure $deltaLogCallback = null,
2828
?Closure $timeGetter = null,
2929
) {

src/Dispatcher.php

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

4+
use Gt\Config\Config;
45
use Gt\Http\Request;
56
use GT\Http\Response;
67
use Throwable;
78

89
readonly class Dispatcher {
10+
/**
11+
* @param array<string, mixed> $globalGet
12+
* @param array<string, mixed> $globalPost
13+
* @param array<string, mixed> $globalFiles
14+
* @param array<string, mixed> $globalServer
15+
*/
916
public function __construct(
17+
private Config $config,
1018
private Request $request,
19+
protected array $globalGet,
20+
protected array $globalPost,
21+
protected array $globalFiles,
22+
protected array $globalServer,
1123
) {}
1224

1325
public function generateResponse():Response {

src/Middleware/Lifecycle.php

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -44,53 +44,53 @@ class Lifecycle implements MiddlewareInterface {
4444
public function start():void {
4545
// Before we start, we check if the current URI should be redirected. If it
4646
// should, we won't go any further into the lifecycle.
47-
$this->handleRedirects();
47+
// $this->handleRedirects();
4848

4949
// The first thing that's done within the WebEngine lifecycle is start a timer.
5050
// This timer is only used again at the end of the call, when finish() is
5151
// called - at which point the entire duration of the request is logged out (and
5252
// slow requests are highlighted as a NOTICE).
53-
$this->timer = new Timer();
53+
// $this->timer = new Timer();
5454

5555
// Starting the output buffer is done before any logic is executed, so any calls
5656
// to any area of code will not accidentally send output to the client.
57-
ob_start();
58-
59-
$originalGlobals = [
60-
"get" => $_GET,
61-
"post" => $_POST,
62-
"files" => $_FILES,
63-
"server" => $_SERVER,
64-
];
57+
// ob_start();
58+
59+
// $originalGlobals = [
60+
// "get" => $_GET,
61+
// "post" => $_POST,
62+
// "files" => $_FILES,
63+
// "server" => $_SERVER,
64+
// ];
6565
// A PSR-7 HTTP Request object is created from the current global state, ready
6666
// for processing by the Handler.
67-
$requestFactory = new RequestFactory();
68-
$request = $requestFactory->createServerRequestFromGlobalState(
69-
$originalGlobals["server"],
70-
$originalGlobals["files"],
71-
$originalGlobals["get"],
72-
$originalGlobals["post"],
73-
);
67+
// $requestFactory = new RequestFactory();
68+
// $request = $requestFactory->createServerRequestFromGlobalState(
69+
// $originalGlobals["server"],
70+
// $originalGlobals["files"],
71+
// $originalGlobals["get"],
72+
// $originalGlobals["post"],
73+
// );
7474

7575
// The handler is an individual component that processes a request and produces
7676
// a response, as defined by PSR-7. It's where all your application's logic is
7777
// executed - the brain of WebEngine. Here we pass in a reference to the finish
7878
// function, so the RequestHandler can complete the request early if needed.
79-
$handler = new RequestHandler(
80-
ConfigFactory::createForProject(
81-
getcwd(),
82-
"vendor/phpgt/webengine/config.default.ini"
83-
),
84-
$this->finish(...),
85-
$originalGlobals["get"],
86-
$originalGlobals["post"],
87-
$originalGlobals["files"],
88-
$originalGlobals["server"],
89-
);
90-
91-
set_error_handler(function(int $errno, string $errstr, ?string $errFile = null, ?int $errLine = null, ?array $errContext = null):bool {
92-
return true;
93-
});
79+
// $handler = new RequestHandler(
80+
// ConfigFactory::createForProject(
81+
// getcwd(),
82+
// "vendor/phpgt/webengine/config.default.ini"
83+
// ),
84+
// $this->finish(...),
85+
// $originalGlobals["get"],
86+
// $originalGlobals["post"],
87+
// $originalGlobals["files"],
88+
// $originalGlobals["server"],
89+
// );
90+
91+
// set_error_handler(function(int $errno, string $errstr, ?string $errFile = null, ?int $errLine = null, ?array $errContext = null):bool {
92+
// return true;
93+
// });
9494

9595
// The request and request handler are passed to the PSR-15 process function,
9696
// which will return our PSR-7 HTTP Response.

test/phpunit/ApplicationTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
namespace GT\WebEngine\Test;
3+
4+
use PHPUnit\Framework\TestCase;
5+
6+
class ApplicationTest extends TestCase {
7+
8+
}

0 commit comments

Comments
 (0)