Problème de require avec le Renderer

Ce sujet est résolu
179502
,

Bonjour,

Voila je rencontre un petit problème avec mon code, je suis en train de suivre de tutoriel sur le renderer et lorsque j'actualise mon site, celui ci me retourne une erreur avec un problème de require

Ce que je fais

Je voudrais que le require soit dans le bon répertoire sachant que actuellement il pointe vers app/Modules/views/index.php alors qu'il devrait être à la racine du projet puis dans public/themes/default/blog/views/index.php

Voici le fichier Renderer.php qui se situe dans le répertoire app\Renderer.php

<?php


namespace App;

class Renderer {

    const DEFAULT_NAMESPACE = '__MAIN';

    private $paths = [];

    public function addPath(string $namespace, ?string $path = null): void {
        if (is_null($path)) {
            $this->paths[self::DEFAULT_NAMESPACE] = $namespace;
        } else {
            $this->paths[$namespace] = $path;
        }
    }

    public function render(string $view): string {
        if ($this->hasNamespace($view)) {
            $path = $this->replaceNamespace($view) . '.php';
        } else {
            $path = $this->paths[self::DEFAULT_NAMESPACE] . DIRECTORY_SEPARATOR . $view . '.php';
        }
        ob_start();
        require($path);
        return ob_get_clean();
    }

    private function hasNamespace(string $view): bool {
        return $view[0] === '@';
    }

    private function getNamespace(string $view): string {
        return substr($view, 1, strpos($view, '/') - 1);
    }

    private function replaceNamespace(string $view): string {
        $namespace = $this->getNamespace($view);
        return str_replace('@' . $namespace, $this->paths[$namespace], $view);
    }
}

Le fichier RendererTest.php qui se situe dans tests/App/RendererTest.php

<?php


namespace Tests\App;

use App\Renderer;
use PHPUnit\Framework\TestCase;

class RendererTest extends TestCase {

    private $renderer;

    public function setUp() {
        $this->renderer = new Renderer();
    }

    public function testRenderTheRightPath() {
        $this->renderer->addPath('blog', __DIR__ . '/../public/themes/default/Blog');
        $content = $this->renderer->render('@blog/demo');
        $this->assertEquals('Salut les gens', $content);
    }

    public function testRenderTheDefaultPath() {
        $this->renderer->addPath(__DIR__ . '/../public/themes/default/Blog');
        $content = $this->renderer->render('demo');
        $this->assertEquals('Salut les gens', $content);
    }
}

Comme vous pouvez le voir, lorsque je fait le test avec PHPUnit tout ce passe bien, il trouve bien de dossier public (qui est dans n'est pas a la racine mais dans le fichier tests/public), mais sur le serveur web cela ne fonctionne pas si je veux remonter le répertoire via /../

Ainsi que le fichier BlogModule.php qui se situe

<?php

namespace App\Modules;

use App\Router;
use App\Renderer;
use Psr\Http\Message\ServerRequestInterface;

class BlogModule {

    private $renderer;

    public function __construct(Router $router) {
        $this->renderer = new Renderer();
        $this->renderer->addPath('blog', __DIR__ . '/public/themes/default/Blog/views');
        $router->get('/blog', [$this, 'index'], 'blog.index');
        $router->get('/blog/{slug:[a-z\-]+}', [$this, 'show'], 'blog.show');
    }

    public function index(ServerRequestInterface $request): string {
        return $this->renderer->render('@blog/index');
    }

    public function show(ServerRequestInterface $request): string {
        return $this->renderer->render('@blog/show');
    }
}

Ce que je veux

Je voudrais avoir la bonne redirection sans le problème de require et ainsi afficher la page index.php qui se situe dans le dossier public/themes/default/Blog/views/index.php

Ce que j'obtiens

J'obtiens une erreur sur mon serveur web (via wamp) la voici :

Warning: require(C:\wamp64\www\app\Modules/views/index.php): failed to open stream: No such file or directory in C:\wamp64\www\app\Renderer.php on line 36

Fatal error: require(): Failed opening required 'C:\wamp64\www\app\Modules/views/index.php' (include_path='.;C:\php\pear') in C:\wamp64\www\app\Renderer.php on line 36

J'ai essayer diverse chose mais cela ne fonctionner pas.

Je vous remercie d'avance.

Bonne fin de journée !

8 Réponse

17162
,

Bonsoir.
Je te conseille d'éviter d'utiliser des chemins relatifs et plutôt d'utiliser des chemins absolus.
Pour celà, il est préférable par exemple de définir des constantes, qui serviront à avoir le chemin absolu de dossiers en particulier dont tu peux souvent avoir besoin dans ton application et tu définis par exemple ces constantes dans ton fichier qui sert de point d'entrée à ton serveur.
Je te conseille également d'éviter d'utiliser le séparateur / et plutôt de définir une constante du genre :

define('DS', DIRECTORY_SEPARATOR);

Et l'orsque tu as besoin de faire un chemin vers un fichier, d'utiliser la constante définie à la place du caractère /, soit par exemple :

$path = VIEWS . 'themes' . DS . 'default' . DS . 'Blog' . DS;

Ceci t'évitera les problèmes qu'il peut y avoir entre la différence du caractère entre un OS Windows (/) et un OS Linux (\).

17162
,

Pour information, si ta version de PHP est au minimum la 7.0, tu n'as pas besoin d'imbriquer plusieurs fois la fonction dirname, car depuis la version 7.0, la fonction accepte un argument supplémentaire qui est levels :

7.0.0 Ajout du paramètre optionnel levels.
Le nombre de dossiers parents plus haut.

Doit être un entier supérieur à 0.

Source : PHP: dirname - Manual.

179502
,

Problème résolu en re regardant la vidéo !
La prochaine fois c'est ce que je ferais en premier !

17162
,

Si je me rappelle bien, il te faut passer un tableau de variable(s) en second argument de la méthode render, par exemple :

return $this->renderer->render('@blog/show', ['article' => $post, 'slug' => $request->getAttribute('slug')]);
179502
,

@Lartak

J'ai résolu mon problème mais je sais pas si c'est la meilleur méthode, j'ai mis deux dirname(dirname(DIR)) pour remonter les répertoires parents

179502
,

Donc si je comprend bien, je peux faire ceci :

define('DS', DIRECTORY_SEPARATOR);

et dans mon fichier BlogModule.php
je peux remplacer cette ligne

$this->renderer->addPath('blog', __DIR__ . '/public/themes/default/Blog/views');

par

$this->renderer->addPath('blog', dirname(dirname(__DIR__)) . DS . 'public' . DS . 'themes' . DS . 'default' . DS . 'Blog' . DS . views');

Après je sais pas si c'est convenable de mettre deux dirname pour remonter deux 2 dossiers

179502
,

Une dernière question, vers les 30mins de la vidéo Renderer, dans le fichier show.php il mets une variable slug, mais chez moi elle ne retourne rien une fois sur la page web.

Faut la définir quelque part ou elle provient d'un tableau déjà défini ?

<h1>Bievenue sur l'article <?= $slug ?></h1>
179502
,

Merci, j'ai finis par trouver tout seul, j'avais oublie dans mon fichier BlogModule d'ajouter le $requestgetAttribute('slug')