Я новичок в ООП и MVC с PHP, и в настоящее время я учусь, создавая собственное приложение MVC для целей тестирования. Я еще не использую Symfony, но я интегрировал Twig, и у меня есть проблема с ним, когда я вызываю ошибку 404 вне контроллера в двух следующих случаях:
У меня есть следующая ошибка:
Fatal error: Uncaught Error: Class 'Twig\Loader\FilesystemLoader' not found in /Applications/XAMPP/xamppfiles/htdocs/librairies/Renderer.php:32
Stack trace: #0 /Applications/XAMPP/xamppfiles/htdocs/librairies/Renderer.php(21): Renderer::loadTwig()
#1 /Applications/XAMPP/xamppfiles/htdocs/librairies/Http.php(26): Renderer::render('errors/404', Array)
#2 /Applications/XAMPP/xamppfiles/htdocs/librairies/Application.php(35): Http::error404()
#3 /Applications/XAMPP/xamppfiles/htdocs/index.php(9): Application::process()
#4 {main} thrown in /Applications/XAMPP/xamppfiles/htdocs/librairies/Renderer.php on line 32
Однако, если я вызываю нужный контроллер с помощью существующего метода, все работает нормально (например, http://localhost/article/show/123). Если я вызываю ошибку 404 внутри метода контроллера (например, если $_GET ID статьи не существует в БД), все тоже работает нормально, и мой шаблон ошибки 404 отображается правильно.
Я использую статический метод Http::error404()
, который отображает мой шаблон Twig с ошибкой 404.
class Http
{
/**
* Display a 404 error - page not found
*
* @return void
*/
public static function error404(): void
{
header('HTTP/1.1 404 Not Found');
$pageTitle = "Erreur 404 - Page non-trouvée";
Renderer::render('errors/404', compact('pageTitle'));
exit;
}
}
В моем приложении используется мини-маршрутизатор с именем Application. Он проверяет, существуют ли контроллер и вызываемый метод. Если нет, вызовите ошибку 404 с помощью Http::error404()
, и именно в этом случае появляется вышеуказанная фатальная ошибка.
class Application
{
/**
* This is the app process, called in index.php file.
* Use controllers and methods directly in URL.
* URL are rewritten by .htaccess file at app root.
*
* Usage : https://example.com/controller/task/{optionnal_parameter}
* Ex : https://example.com/article/show/145
*
* @return void
*/
public static function process()
{
// By default, call homepage
$controllerName = 'ArticleController';
$task = 'home';
if (!empty($_GET['controller'])) {
$controllerName = ucfirst($_GET['controller'] . 'controller');
}
if (!empty($_GET['task'])) {
$task = $_GET['task'];
}
$controllerPath = "\controllers\\" . $controllerName;
// Check if this controller & method exists
if (!method_exists($controllerPath, $task)) {
Http::error404(); // <-- Here, i'm not in a controller (line 35)
}
$controller = new $controllerPath();
$controller->$task();
}
}
Здесь есть странная вещь: если я определяю какой-либо контроллер перед вызовом ошибки 404, все работает так, как я хотел, и мой шаблон ошибки 404 отображается правильно. Но это не чистое и элегантное решение...
// Check if this controller & method exists
if (!method_exists($controllerPath, $task)) {
new \Controllers\ArticleController(); // <-- Not clean, but solve my fatal error
Http::error404();
}
То же самое происходит в моем 404.php
файле, который вызывается сервером и объявляется в .htaccess
, когда файл вызывается, а он не существует. Мой файл 404 PHP содержит всего несколько строк:
require_once 'librairies/autoload.php';
Http::error404();
Если я определяю какой-либо контроллер, он работает отлично, и фатальная ошибка исчезает.
require_once 'librairies/autoload.php';
new Controllers\ArticleController();
Http::error404();
Это мой класс рендеринга. В этом файле появляется фатальная ошибка, как показано в строке 32 ниже, когда класс Http
с методом error404 отображает ошибки/шаблон Twig 404.
require_once 'librairies/autoload.php';
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\TwigFunction;
class Renderer
{
/**
* Print a HTML template with $var injection
*
* @param string $path
* @param array $var
*/
public static function render(string $path, $var = [])
{
$template = self::loadTwig()->load("$path.html.twig");
echo $template->display($var);
}
/**
* Load Twig
*
* @return Environment
*/
public static function loadTwig()
{
$loader = new FilesystemLoader('templates'); // <-- Line 32 is here !
$twig = new Environment($loader, [
'auto_reload' => true,
'autoescape' => 'html'
]);
$twig->addFunction(
new TwigFunction('notificationDisplay', function() { return Notification::display(); })
);
return $twig;
}
}
Я добавил только код, который, как мне кажется, связан с моей проблемой. Не стесняйтесь спрашивать, есть ли какие-то моменты, которые необходимо уточнить.
Я искал решение этой ошибки в течение семи дней и не нашел решения. Ваша помощь - моя последняя надежда. Большое спасибо!
Вы уверены, что twig
загружается в require_once 'librairies/autoload.php';? Does the controller
ArticleController`, загружая какие-либо дополнительные зависимости?
@NicoHaase Это, безусловно, ошибка с моей стороны, плохая практика. Каково правило включения автозагрузчика? Должен ли я добавить его только в файл index.php?
@DarkBee Да, мой собственный автозагрузчик зарегистрирован в файле composer.json. Мое приложение использует только две зависимости: Twig и PHP Mailer, и все работает нормально, мои шаблоны Twig правильно загружаются и отображаются, за исключением случая этой ошибки 404...
Обычно это нужно только один раз. Кроме того, что вы пытались проверить, почему ошибка не возникает при загрузке любого дополнительного контроллера?
Я удалил весь ненужный require_once
автозагрузчик в файлах приложения и оставил только один в index.php
, как указал @NicoHaase.
С этого момента Twig больше не обнаруживается, и при всех запросах появляется одно и то же сообщение об ошибке!
Решение было легко найти: в моем файле index.php
я использовал неправильный автозагрузчик. Я вызывал свой пользовательский автозагрузчик вместо того, который был в Composer...
Я просто меняю:
require_once 'librairies/autoload.php';
\Application::process();
К :
require_once 'vendor/autoload.php';
\Application::process();
И теперь все работает нормально! Спасибо @NicoHaase и @DarkBee за то, что направили меня на правильный путь!
Зачем вам автозагрузчик во всех файлах? Вы проверили, может ли автозагрузчик найти данный класс?