Commit 49ccc60a authored by DevPilot's avatar DevPilot

fix(core): route params coerced to declared type, request errors no longer render as BOOT FAILURE

اتنين أعطال بنيوية طلعوا من فحص الـ 830 شاشة:

1. الراوتر بيبعت بارامترات الـ URL كـ string، وفي ١٣ كنترولر معرّفينها int،
   ومع strict_types ده TypeError بيقع الشاشة. الراوتر دلوقتي بيقرا النوع
   المطلوب من الميثود نفسها ويحوّل ليه.

2. public/index.php كان لافف الـ dispatch والـ boot في try واحدة، فأي
   استثناء جوه الطلب بيطلّع «BOOT FAILURE» بـ 500 حتى لو كان 404 أو 403.
   الطلب دلوقتي ليه try لوحده بيسلّم لـ ExceptionHandler اللي بيحترم الكود.
parent 2d5219ad
......@@ -133,6 +133,46 @@ final class Router
return $stack($request);
}
/**
* بارامترات الـ route بتيجي من الـ URL كـ string دايمًا، لكن في كنترولرز
* بتعرّفها int. ومع declare(strict_types=1) ده بيرمي TypeError ويقع الصفحة.
* فبنحوّل القيمة للنوع اللي الميثود نفسها طالباه.
*/
private function coerceParams(object $controller, string $method, array $params): array
{
try {
$ref = new \ReflectionMethod($controller, $method);
} catch (\ReflectionException $e) {
return $params;
}
// أول بارامتر هو الـ Request، فبنبدأ من اللي بعده
$expected = array_slice($ref->getParameters(), 1);
foreach ($params as $i => $value) {
if (!isset($expected[$i]) || !is_string($value)) {
continue;
}
$type = $expected[$i]->getType();
if (!$type instanceof \ReflectionNamedType || !$type->isBuiltin()) {
continue;
}
switch ($type->getName()) {
case 'int':
$params[$i] = (int) $value;
break;
case 'float':
$params[$i] = (float) $value;
break;
case 'bool':
$params[$i] = (bool) $value;
break;
}
}
return $params;
}
private function callHandler(string $handler, Request $request, array $params): Response
{
[$controllerName, $method] = explode('@', $handler);
......@@ -148,7 +188,9 @@ final class Router
return $this->handleError(500, "Method not found: {$controllerClass}@{$method}");
}
$result = $controller->$method($request, ...array_values($params));
$args = $this->coerceParams($controller, $method, array_values($params));
$result = $controller->$method($request, ...$args);
if ($result instanceof Response) {
return $result;
......
......@@ -58,9 +58,16 @@ try {
$app->boot();
// ── Dispatch request ──
$request = App\Core\Request::capture();
$response = $app->router()->dispatch($request);
$response->send();
// مهم: الأخطاء اللي بتحصل جوه الطلب نفسه بتروح لـ ExceptionHandler عشان
// يحترم كود الاستثناء (404/403/401). لو لفّيناها مع الـ boot هنا، أي سجل
// مش موجود كان بيطلّع صفحة «BOOT FAILURE» بكود 500.
try {
$request = App\Core\Request::capture();
$response = $app->router()->dispatch($request);
$response->send();
} catch (\Throwable $requestError) {
App\Core\ExceptionHandler::handleException($requestError);
}
} catch (\Throwable $e) {
// If we get here during boot, show the REAL error
......
......@@ -62,14 +62,26 @@ def login(session, base, username, password):
def error_summary(html):
m = re.search(r'Message:\s*</strong>?\s*([^<\n]{0,160})', html)
if m:
return m.group(1).strip()
m = re.search(r'(SQLSTATE\[[^\]]+\][^<\n]{0,140})', html)
if m:
return m.group(1).strip()
m = re.search(r'Exception:\s*</strong>?\s*([^<\n]{0,80})', html)
return m.group(1).strip() if m else ''
"""بيطلّع نوع الاستثناء والرسالة والملف من صفحة الخطأ."""
text = re.sub(r'<[^>]+>', '\n', html)
text = text.replace('&quot;', '"').replace('&#039;', "'").replace('&amp;', '&')
lines = [l.strip() for l in text.split('\n') if l.strip()]
def after(label):
for i, l in enumerate(lines):
if l.rstrip(':') == label and i + 1 < len(lines):
return lines[i + 1]
return ''
exc = after('Exception')
msg = after('Message')
where = ''
for l in lines:
if l.startswith('File:'):
where = l[5:].strip().replace('/var/www/html/', '')
break
parts = [p for p in (exc, msg, where) if p]
return ' | '.join(parts)[:220]
def main():
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment