Bonjour,

Je suis en train de suivre le tutoriel sur le conteneur de dépendance, mais je sèche sur un problème, mon index.php me renvoie une erreur me disant qu'il attend un tableau mais c'est un objet qui lui ai envoyé.

J'ai suivie à la lettre le tutoriel de Grafikart, je l'ai adapté pour la version 6.0 de PHP-DI en remplacent les object par create car la function object est déprécié depuis PHP-DI 6.0

Ce que je fais

Décrivez ici votre code ou ce que vous cherchez à faire
Mon index .php

<?php

require '../vendor/autoload.php';
require '../define.php';

use App\App;
use App\Modules\BlogModule;
use DI\ContainerBuilder;
use GuzzleHttp\Psr7\ServerRequest;

$modules = [
    BlogModule::class
];

$builder = new ContainerBuilder();
$builder->addDefinitions(dirname(__DIR__, 1) . DS . 'app' . DS . 'Config' . DS . 'config.php');
foreach ($modules as $module) {
    if ($module::DEFINITIONS) {
        $builder->addDefinitions($module::DEFINITIONS);
    }
}
$builder->addDefinitions(__DIR__ . DS . 'config.php');
$container = $builder->build();

$app = new App($container, $modules);
$response = $app->run(ServerRequest::fromGlobals());
\Http\Response\send($response);

Mon blogModule

<?php

namespace App\Modules;

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

class BlogModule extends Module {

    const DEFINITIONS = __DIR__ . '/config.php';

    /**
     * @param Router $router
     * @param RendererInterface $renderer
     */
    public function __construct(string $prefix, Router $router, RendererInterface $renderer) {
        $this->renderer = $renderer;
        $this->renderer->addPath('blog', dirname(__DIR__, 2) . DS . 'public' . DS . 'themes' . DS . 'default' . DS . 'Blog' . DS . 'views');
        $router->get($prefix, [$this, 'index'], 'blog.index');
        $router->get($prefix . '/{slug:[a-z\-0-9]+}', [$this, 'show'], 'blog.show');
    }

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

    /**
     * @param ServerRequestInterface $request
     * @return string
     */
    public function show(ServerRequestInterface $request): string {
        return $this->renderer->render('@blog/show', ['slug' => $request->getAttribute('slug')]);
    }
}

le fichier Module.php

<?php

namespace App;

class Module {

    const DEFINITIONS = null;
}

et mon fichier App.php

<?php

namespace App;

use GuzzleHttp\Psr7\Response;
//use \Exception;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class App {

    /**
     * @var array
     * @var Router
     */
    private $modules = [];
    private $container;

    public function __construct(array $modules = []) {
        $this->container = $container;
        foreach ($modules as $module) {
            $this->modules[] = $container->get($module);
        }
    }

    public function run(ServerRequestInterface $request): ResponseInterface {
        $uri = $request->getUri()->getPath();
        if (!empty($uri) && $uri[-1] == "/") {
            return (new Response())
                ->withStatus(301)
                ->withHeader('Location', substr($uri, 0, -1));
        }
        $router = $this->container->get(Router::class);
        $route = $router->match($request);
        if (is_null($route)) {
            return new Response(404, [], '<h1>Erreur 404</h1>');
        }
        $params = $route->getParams();
        $request = array_reduce(array_keys($params), function ($request, $key) use ($params) {
            return $request->withAttribute($key, $params[$key]);
        }, $request);
        $response = call_user_func_array($route->getCallback(), [$request]);
        if (is_string($response)) {
            return new Response(200, [], $response);
        } elseif ($response instanceof ResponseInterface) {
            return $response;
        } else {
            throw new \Exception('The response is not a string or an instance of ResponseInterface');
        }
    }
}

Ce que je veux

Je voudrais que m'erreur ci dessous disparaisse

Ce que j'obtiens

Voici l'erreur que j'obtiens

Fatal error: Uncaught TypeError: Argument 1 passed to App\App::__construct() must be of the type array, object given, called in C:\wamp64\www\public\index.php on line 40 and defined in C:\wamp64\www\app\App.php:34 Stack trace: #0 C:\wamp64\www\public\index.php(40): App\App->__construct(Object(DI\Container), Array) #1 {main} thrown in C:\wamp64\www\app\App.php on line 34

Je vous remercie d'avance pour l'aide que vous m'apporterai !

Bonne après midi !

17 réponses


Mael-91
Auteur
Réponse acceptée

Problème résolu, dans la vidéo du conteneur de dépendance à 19:06 min (https://youtu.be/JuB90IYXOwU?t=1146) quand Grafikart supprime ContainerInterface $container il ne faut pas le supprimer et le laisser

Salut Mael es-tu arriver au chapitre "Administration du blog" ?
J'ai justement un problème avec cette fameuse variable $container que je ne parviens plus à instancier dans mon BlogModule dans les paramètres de ma fonction __construct


<?php

namespace App\Blog;

use App\Blog\Actions\AdminBlogAction;
use App\Blog\Actions\BlogAction;
use DI\Container;
use function DI\get;
use Framework\Module;
use Framework\Renderer\RendererInterface;
use Framework\Router;
use Psr\Container\ContainerInterface;

class BlogModule extends Module
{
    const DEFINITIONS = __DIR__ . '\config.php';

    const MIGRATIONS = __DIR__ . '\db\migrations';

    const SEEDS = __DIR__ . '\db\seeds';

    public function __construct(ContainerInterface $container)
    {
        $container->get(RendererInterface::class)->addPath('blog', __DIR__ . '\views');
        $router = $container->get(Router::class);
        $router->get($container->get('blog.prefix'), BlogAction::class, 'blog.index');
        $router->get($container->get('blog.prefix').'/{slug:[a-z\-0-9]+}-{id:[0-9]+}', BlogAction::class, 'blog.show');

        if ($container->has('admin.prefix')) {
            $prefix = $container->get('admin.prefix');
            $router->get("$prefix\posts", AdminBlogAction::class, 'admin.blog.index');
        }
    }
}
Mael-91
Auteur

Je ne pourrai pas t'aider pour le moment, je n'y suis pas encore mais vérifie au niveau de ton index.php tu doit avoir une erreur

Ca fait plusieurs jours que je cherche sans trouver de solutions tu sembles maîtriser suffisamment pour adapter ton environnement pour travailler avec le php-di 6.0. Dans mon index.php il ne semble pas y avoir d'erreurs ettoutest correctement instancié.

<?php

require dirname(__DIR__) . '/vendor/autoload.php';

$modules = [
    \App\Admin\AdminModule::class,
    \App\Blog\BlogModule::class
];

$builder = new \DI\ContainerBuilder();
$builder->addDefinitions(dirname(__DIR__) . '\config\config.php');
foreach ($modules as $module) {
    if ($module::DEFINITIONS) {
        $builder->addDefinitions($module::DEFINITIONS);
    }
}

$builder->addDefinitions(dirname(__DIR__) . '\config.php');
$container = $builder->build();
$app = new \Framework\App($container, $modules);

if (php_sapi_name() !== "cli") {
    $response = $app->run(\GuzzleHttp\Psr7\ServerRequest::fromGlobals());
    \Http\Response\send($response);
}

Dans mon App.php ma variable container en tant que ContainerInterface est pourtant injecter de la même manière dans les paramètres de la function construct et il ne semble pas y avoir de problème.

Tu fais parti des rares personnes encore interressé par cette formation je voudrais pas être trop intrusif mais si on pouvait s'entraider ou au moins sur cette partie ca pourrait être sympa. ^^

Mael-91
Auteur

Salut,

Pour ma part, dans mon fichier BlogModule, dans la methode __construct, j'ai ceci public function __construct(string $prefix, Router $router, RendererInterface $renderer) {

Je ne lui demande pas le ContainerInterface, car il est instancié grace au fichier App.php, et lorsque les modules sont chargé, il sont charger grace à la variable $container

Tu as une erreur qui s'affiche ?

Merci pour la réponse rapide

Arrivé à 'Administration du blog' justement il dit qu'il n'est même plus nécessaire de passer les différentes variables que tu as renseigné en paramètre dans ta fonction __construct et que c'est plus intéressant de ne passer en paramètre que la variable $container en tant que ContainerInterface et de là tout plante alors que jusqu'à présent tout fonctionnait correctement.

Il est possible que mon erreur vienne de mon App puisque apparemment mes modules doivent être chargés par le biais de cette variable $container.

Voici l'erreur qui m'est retourné

Fatal error: Uncaught DI\Definition\Exception\DefinitionException: Entry "App\Blog\BlogModule" cannot be resolved: Entry "Psr\Container\ContainerInterface" cannot be resolved: the class is not instantiable Full definition: Object ( class = #NOT INSTANTIABLE# Psr\Container\ContainerInterface scope = singleton lazy = false ) Full definition: Object ( class = App\Blog\BlogModule scope = singleton lazy = false __construct( $container = get(Psr\Container\ContainerInterface) ) ) in C:\wamp64\www\sdlv\vendor\php-di\php-di\src\DI\Definition\Exception\DefinitionException.php:16 Stack trace: #0 C:\wamp64\www\sdlv\vendor\php-di\php-di\src\DI\Definition\Resolver\ObjectCreator.php(154): DI\Definition\Exception\DefinitionException::create(Object(DI\Definition\ObjectDefinition), 'Entry "App\Blog...') #1 C:\wamp64\www\sdlv\vendor\php-di\php-di\src\DI\Definition\Resolver\ObjectCreator.php(70): DI\Definition\Resolver\ObjectCreator->createInstance(Object(DI\Definition\ObjectDefinition) in C:\wamp64\www\sdlv\vendor\php-di\php-di\src\DI\Definition\Exception\DefinitionException.php on line 16

Il est clairement relevé que le ContainerInterface n'est pas instanciable

Mael-91
Auteur

Dès que je serais arriver à cette partie, je reviens vers toi (encore 3 chapitres) pour le moment, essaye de poser ta question sur le Discord de Grafikart, il t'aidera sans doute mieux que moi.

Bon, en tout cas, dès que j'y suis, et que j'ai la même erreur, je te refais signe.

Si tu ttrouve la solution, n'hésite pas à la poster

Ah je ne savais pasque je pouvais fair eça depuis discord, c'est Grafikart qui me répond en personne ?!??. Je me crée un compte maintenant.

Mais c'est quand même bizarre parceque dans mon App il utilise bien la variabe $container pour générer mes différents modules èt ca ne semble pas lui poser de problèmes.

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

    /**
     * App constructor.
     * @param ContainerInterface $container
     * @param string[] $modules Listes des modules à charger
     */
    public function __construct(ContainerInterface $container, array $modules = [])
    {
        $this->container = $container;
        foreach ($modules as $module) {
            $this->modules[] = $container->get($module);
        }
    }

Merci beaucoup, oui je referais un post si j'arrives à trouver une solution.

Mael-91
Auteur

C'est pas forcément grafikart, il y a pas mal de personne dessus qui pourront t'aider

Je n'ai pas eu de réponse masi je me suis refait son ancien tutoriel sur php-di 5 et en ajoutant cette ligne à mon index.php tout remarche

$container->set(\Psr\Container\ContainerInterface::class, $container);

Cependant pour accéder à mon admin\posts c'est la 404 :\
Donc problème partiellement résolu malheureusement. Et de ton côté tu n'as pas rencontré de problème ?

Mael-91
Auteur

Pas pour le moment, je suis sur l'affichage des articles pour le moment

Toujours bloqué au même chapitre à peine le précédent problème résolu je me retrouve bloqué de manière complètement incompréhensible par une erreur 404 quand j'essaie d'accéder à l'url admin/posts j'ai pourtant la bonne architecture.
Peut-être que mon addPath de mon AdminModule n'est pas pris en compte il est pourtant chargé avant mon BlogModule.

<?php

namespace App\Admin;

use Framework\Module;
use Framework\Renderer\RendererInterface;

class AdminModule extends Module
{
    const DEFINITIONS = __DIR__ . '\config.php';

    public function __construct(RendererInterface $renderer)
    {
        $renderer->addPath('admin', __DIR__ . '\views');
    }
}

Mon index.php

<?php
/**
 * Created by PhpStorm.
 * User: Abel
 * Date: 07/03/2019
 * Time: 16:58
 */
require dirname(__DIR__) . '/vendor/autoload.php';

$modules = [
    \App\Admin\AdminModule::class,
    \App\Blog\BlogModule::class
];

$builder = new \DI\ContainerBuilder();
$builder->addDefinitions(dirname(__DIR__) . '\config\config.php');
foreach ($modules as $module) {
    if ($module::DEFINITIONS) {
        $builder->addDefinitions($module::DEFINITIONS);
    }
}

$builder->addDefinitions(dirname(__DIR__) . '\config.php');
$container = $builder->build();
$container->set(\Psr\Container\ContainerInterface::class, $container);
$app = new \Framework\App($container, $modules);

if (php_sapi_name() !== "cli") {
    $response = $app->run(\GuzzleHttp\Psr7\ServerRequest::fromGlobals());
    \Http\Response\send($response);
}

Je commence réellement à désepsérer et encore aucune réponse du côté de Discord. :/
Une erreur que j'aurais manqué ?
Tout se passe bien de ton côté sinon ?

Abels667: Au lieu de vouloir résoudre ton problème sur le sujet de quelqu'un d'autre, utilises plutôt le sujet que tu as créé par rapport à ton problème.

Oui désolée mais je ne parviens pas à trouver de réponse je pensais enfin tenir quelque chose

Mael-91
Auteur

Perso chez moi j'ai pas eu de pb avec le conteneur de dépendance, tout marche parfaitement et j'ai meme refait certaine chose à ma sauce, re regarde bien le début

dis, pour contourner ton erreur 404 sur le blog Admin/posts, modifie dans src/Admin/config.php, modifie le admin.prefix par autre chose que /admin. moi j'ai utilisé /local à la place pour résoudre les problèmes de redirection que je rencontrai. bonne contnuation!

Mael-91
Auteur

@Jeaner , j'ai résolu mon pb depuis longtemps.

Je tiens a précisé, que je n'est pas la même structure que dans le tuto de grafikart j'ai mon dossier App qui regroupe le coeur du système avec en sous dossier Controllers (Ce qui rend la vue et qui recupère les diverses infos) et Models (Partie bdd) et un dossier public pour la partie vue.

J'espère pour toi qui tu as regler ton pb

Bonne soirée