Bonjour,

J'ai décidé de passer d'un Cakephp à une structure beaucoup plus simple pour mon site via Slim.

J'ai donc regardé le tuto Slim de Grafikart, et j'ai voulu mettre en place une structure similaire à la sienne (avec le Router, Controller, ...) en utilisant les namespaces et l'autoloader de composer.

Je précise que j'ai encore du mal avec les namespaces (je découvre seulement).

Mon problème est que lorsque je tente d'accèder à mon site (en utilisant les namespaces et l'autoloader) j'ai cette erreur :

Fatal error: Class 'App\Core\Router' not found

Alors que tout se passe bien si je require mes classes à la main et que je ne les mets pas dans un namespace.

J'ai mis mon router et mes controller dans le namespace App\Core.

j'ai tenté en ajoutant :

"autoload": {
    "psr-4": {"App\\Core\\": "app" }
  }

et

"autoload": {
    "psr-4": {"App\\": "app" }
  }

à mon composer.js mais j'ai toujours une erreur. J'aimerais donc bien comprendre comment ça se fait.

7 réponses


Grafikart
Réponse acceptée

Alors je ne pense pas que le "Core" soit justifié dans ton cas. Le namespace App\ donc dans ton composer tu fais

"autoload": {
    "psr-4": {"App\\": "app/" }
  }

Puis tu n'oublie pas de rechercher l'autoloader avec

composer dump-autoload

Et ta classe Router tu met

namespace App;

class Router{

}
elhebert
Auteur
Réponse acceptée

C'est la première chose que j'ai tenté mais ça me retourne une erreur de syntaxte (détectée par phpstorm par ailleurs). Ce qui donne l'erreur php suivante :

Parse error: syntax error, unexpected '$controller_name' (T_VARIABLE), expecting identifier (T_STRING)

Du coup, j'ai été relire un peu la doc php, et j'ai trouvé comment préciser un namespace lors de l'appelle d'une class de cette façon là :

$controller_name = '\\App\\' . $action[0] . 'Controller';

Mais, maintenant il me dit qu'il ne trouve pas ma class :

Fatal error: Class '\App\IndexController' not found

Pour que ça fonctionne j'ai du ajouter à la main les require de mes classes. Comme si l'autoloader ne les avaient pas pris en compte lors de l'autoload. Du coup, est-ce qu'il y a une manipulation spéciale à faire pour dire à l'autoloader de charger aussi les fichiers de tous les sous dossier de app/ ?

EDIT : C'est bon j'ai trouvé la réponse à ma question dans la doc de composer. Je suis vraiment trop con, je suis passé 3-4 fois dans la doc, et je n'arrivais pas à trouver ma réponse xD

Au final j'ai fait comme ça :

"autoload": {
    "psr-4": {
      "App\\": ["app/", "app/Controller/"]
    }
  }

Si il y a une autre méthode, je suis tout ouïe :)

djtec
Réponse acceptée

Un simple

$controller_name = '\\App\\Controller\\' . $action[0] . 'Controller';

Vu que tu lui dit que App est dans app il suffit de lui lui ajouter Controller au namespace pour qu'il cherche dedans.

En psr-4 les namespace suivent l'architectute des dossiers donc si tu lui dit que ton namespace App est dans le dossier app si tu veux IndexController qui est dans le dossier controller et faut mettre ce que j'ai mit plus haut sinon il cherche IndexController à la racine du dossier app

Et comment est l'architecture de ton dossier app

elhebert
Auteur

Ah oui, j'ai oublié de l'ajouter à mon post :D

app\
    app\Controller
        Controller.php
        mes controllers
    app\Router.php
elhebert
Auteur

Merci Graf' !

J'avais utilisé le App\Core pour différencier les classes propre au coeur de mon app et ceux de mes helpers (Que je comptais mettre dans App\helper par exemple).

J'ai encore une question, via l'autoloader, il inclus tout ce qui se trouve dans le namespace précisé. Du coup mes controllers qui se trouve aussi dans le namespace App\ sont inclus, mais, comment je dois faire pour les appeler ?

Un exemple plus concret, si je reprends ton tuto sur Slim, dans ton Router.php tu appelles tes controllers via :

  $controller = new $controller_name($this->app);
  call_user_func_array([$controller, $method], func_get_args());

Comment intégrer les namespaces dans ce genre de cas ?

Et tant que j'y suis, y a-t-il des bonnes pratiques pour les namespaces, les pièges à éviter ?

Essaye ceci

$controller = new \TonNamespace\$controller_name($this->app);