Bonjour la communauté,

Je suis nouveau sur le forum et je rencontre un soucis durant la formation PHP POO. En effet Delegate n'existant plus nous devons passer par le handle de la classe RequestHandlerInterface.
J'ai donc essayé de le mettre en place mais j'obtiens une erreur:

Ce que je fais

Voici les classes en cause :

TrainlingSlashMiddleware.php

<?php
namespace App\Framework\Middleware;

use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ServerRequestInterface;

class TrailingSlashMiddleware
{
    public function __invoke(ServerRequestInterface $request, callable $next)
    {
        $uri = $request->getUri()->getPath();
        if (!empty($uri) && $uri[-1] === "/") {
            return (new Response())
                ->withStatus(301)
                ->withHeader('Location', substr($uri, 0, -1));
        }
        return $next($request);
    }
}

App.php

<?php
namespace Framework;

use DI\ContainerBuilder;
use Exception;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class App implements RequestHandlerInterface
{

    /**
     * Liste des modules
     *
     * @var array
     */
    private $modules = [];

    /**
     * @var string
     */
    private $definition;

    /**
     * @var ContainerInterface
     */
    private $container;

    /**
     * @var
     */
    private $middlewares;

    private $index = 0;

    public function __construct(string $definition)
    {
        $this->definition = $definition;
    }

    /**
     * Ajoute un module
     *
     * @param string $module
     * @return App
     */
    public function addModule(string $module): self
    {
        $this->modules[] = $module;
        return $this;
    }

    /**
     * Ajoute un middleware
     *
     * @param string $middleware
     * @return App
     */
    public function pipe(string $middleware): self
    {
        $this->middlewares[] = $middleware;
        return $this;
    }

    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $middleware = $this->getMiddleware();
        if (is_null($middleware)) {
            throw new \Exception('Aucun middleware n\'a intercepté cette requête !');
        } elseif (is_callable($middleware)) {
            return call_user_func_array($middleware, [$request, [$this, 'process']]);
        } elseif ($middleware instanceof MiddlewareInterface) {
            return $middleware->process($request, $this);
        }
    }

    /**
     * @param ServerRequestInterface $request
     * @return ResponseInterface
     * @throws Exception
     */
    public function run(ServerRequestInterface $request): ResponseInterface
    {
        foreach ($this->modules as $module) {
            $this->getContainer()->get($module);
        }
        return $this->handle($request);
    }

    /**
     * @return ContainerInterface
     * @throws Exception
     */
    public function getContainer(): ContainerInterface
    {
        if ($this->container === null) {
            $builder = new ContainerBuilder();
            $builder->addDefinitions($this->definition);
            foreach ($this->modules as $module) {
                if ($module::DEF) {
                    $builder->addDefinitions($module::DEF);
                }
            }
            $this->container = $builder->build();
        }
        return $this->container;
    }

    private function getMiddleware()
    {
        if (array_key_exists($this->index, $this->middlewares)) {
            $middleware = $this->container->get($this->middlewares[$this->index]);
            $this->index++;
            if (is_callable($middleware)) {
                return $middleware;
            } elseif ($middleware instanceof MiddlewareInterface) {
                return [$middleware, 'process'];
            }
            return $middleware;
        }

        return null;
    }

}

Ce que je veux

Donc mon objectif final est de faire fonctionner mes middlewares, j'ai déjà abandonné le middleware Whoops car j'avais le même problème. Mais là c'est essentielle pour la poursuite de la formation
(pour rappel voici le lien : https://www.grafikart.fr/formations/mise-pratique-poo/csrf-securite)

Ce que j'obtiens

Donc ici j'obtiens l'erreur suivante :

Fatal error: Uncaught TypeError: Argument 2 passed to App\Framework\Middleware\TrailingSlashMiddleware::invoke() must be callable, array given in C:\xampp\htdocs\monframework\src\Framework\Middleware\TrailingSlashMiddleware.php:15 Stack trace: #0 [internal function]: App\Framework\Middleware\TrailingSlashMiddleware->invoke(Object(GuzzleHttp\Psr7\ServerRequest), Array) #1 C:\xampp\htdocs\monframework\src\Framework\App.php(74): call_user_func_array(Object(App\Framework\Middleware\TrailingSlashMiddleware), Array) #2 C:\xampp\htdocs\monframework\src\Framework\App.php(90): Framework\App->handle(Object(GuzzleHttp\Psr7\ServerRequest)) #3 C:\xampp\htdocs\monframework\public\index.php(27): Framework\App->run(Object(GuzzleHttp\Psr7\ServerRequest)) #4 {main} thrown in C:\xampp\htdocs\monframework\src\Framework\Middleware\TrailingSlashMiddleware.php on line 15

En attendant je remercie tous ceux qui se pencherons sur le sujet.
Amicalement,

7 réponses


Salut,

L'erreur dit que le deuxième argument de la fonction __invoke(ServerRequestInterface $request, callable $next) devrait être un callable mais que tu lui as passé un array. Comment appelles tu cette fonction dans ton code ?

SetDark
Auteur

La classe est indiqué ci-dessus (TrailingSlashMiddleWare):

public function __invoke(ServerRequestInterface $request, callable $next)
    {
        $uri = $request->getUri()->getPath();
        if (!empty($uri) && $uri[-1] === "/") {
            return (new Response())
                ->withStatus(301)
                ->withHeader('Location', substr($uri, 0, -1));
        }
        return $next($request);
    }

Je pense que le soucis viens d'ici (de la classe App):

return call_user_func_array($middleware, [$request, [$this, 'process']]);

Je lui passe un tableau, chose que Grafikart fait dans la formation, mais avec le changement du Delegate en RequestHandlerInterface tout est différent et j'ai du mal à suivre

Et si tu changes callable $next par array $next dans la fonction __invoke, ça donne quoi ?

SetDark
Auteur

C'est mieux mais j'ai toujours cette erreur :

Fatal error: Uncaught Error: Call to undefined method Framework\App::process() in C:\xampp\htdocs\monframework\src\Framework\Middleware\TrailingSlashMiddleware.php:23 Stack trace: #0 [internal function]: App\Framework\Middleware\TrailingSlashMiddleware->__invoke(Object(GuzzleHttp\Psr7\ServerRequest), Array) #1 C:\xampp\htdocs\monframework\src\Framework\App.php(74): call_user_func_array(Object(App\Framework\Middleware\TrailingSlashMiddleware), Array) #2 C:\xampp\htdocs\monframework\src\Framework\App.php(90): Framework\App->handle(Object(GuzzleHttp\Psr7\ServerRequest)) #3 C:\xampp\htdocs\monframework\public\index.php(27): Framework\App->run(Object(GuzzleHttp\Psr7\ServerRequest)) #4 {main} thrown in C:\xampp\htdocs\monframework\src\Framework\Middleware\TrailingSlashMiddleware.php on line 23

Bonjour.

C'est mieux mais j'ai toujours cette erreur

Et tu ne comprend pas l'erreur ?
Elle te dit tout simplement que tu fais appel à une méthode qui n'est pas définie, soit la méthode process dans ce cas.

SetDark
Auteur

Si je comprends l'erreur je remplace la methode __invoke par process mais toujours une erreur :


Fatal error: Uncaught TypeError: Return value of Framework\App::handle() must be an instance of Psr\Http\Message\ResponseInterface, none returned in C:\xampp\htdocs\monframework\src\Framework\App.php:78 Stack trace: #0 C:\xampp\htdocs\monframework\src\Framework\App.php(90): Framework\App->handle(Object(GuzzleHttp\Psr7\ServerRequest)) #1 C:\xampp\htdocs\monframework\public\index.php(27): Framework\App->run(Object(GuzzleHttp\Psr7\ServerRequest)) #2 {main} thrown in C:\xampp\htdocs\monframework\src\Framework\App.php on line 78

Je la comprends bien aussi (il faut retourner une instance de ResponseInterface et là elle est nul) mais je fais quoi là ? car des que je change un morceau d'un côté ca casse de l'autre et je tourne en boucle. Je suis débutant en php j'essaye de suivre la formation qui n'est pas forcément à jour... (bien que je ne critique pas ce fait car l'informatique évolu rapidement)

Si tu es débutant comme tu dis alors ne fais pas cette formation ^^.
Sinon oui en effet la formation ce base sur des choses qui ont été changer comme la validation du PSR-15 par exemple.

Le plus simple serait de comprendre ce qu'il faut faire et de le faire de son côté. Pour info c'est ce que j'ai fais sur mon framework :