Apprivoiser Slim 2.0

Slim est un framework léger qui séduit par son faible encombrement. Il dispose d'un système de routage incroyable et offre une base solide sur laquelle vous pouvez travailler sans vous gêner. Laisse moi te montrer!

Mais cela ne veut pas dire que Slim n’a pas de problèmes; sa configuration en un fichier devient encombrée à mesure que votre application grandit. Dans cet article, nous verrons comment structurer une application Slim non seulement pour maintenir, mais aussi pour améliorer ses fonctionnalités et garder les choses ordonnées et systématiques..


Vanille mince

Commençons par examiner un code Slim commun pour identifier le problème. Une fois que vous avez installé Slim via Composer, vous devez créer une instance du Svelte objet et définir vos itinéraires:

 get ('/', function () echo "Page d'accueil";); $ app-> get ('/ testPage', function () use ($ app) $ app-> render ('testpage.php');); $ app-> run ();

Tournons l'objet Slim dans le "contrôleur".

Le premier appel de méthode définit une nouvelle route pour l’URI racine (/), et connecte la fonction donnée à cette route. C'est assez bavard, mais facile à installer. Le deuxième appel de méthode définit une route pour l'URI testPage. Dans la méthode fournie, nous utilisons Slim rendre() méthode pour rendre une vue.

C'est là que réside le premier problème: cette fonction (une fermeture) n'est pas appelée dans le contexte actuel et ne permet pas d'accéder aux fonctionnalités de Slim. C’est pourquoi nous devons utiliser le utilisation mot clé pour passer la référence à l'application Slim.

Le deuxième problème découle de l'architecture de Slim; il est destiné à être défini dans un seul fichier. Bien sûr, vous pouvez externaliser la variable dans un autre fichier, mais cela devient simplement compliqué. Idéalement, nous souhaitons pouvoir ajouter des contrôleurs pour modulariser le framework en composants individuels. En prime, il serait bien que ces contrôleurs offrent un accès natif aux fonctionnalités de Slim, éliminant ainsi la nécessité de passer des références dans les fermetures..


Un peu d'ingénierie inverse

On peut se demander si la lecture du code source d'un projet à source ouverte est considérée comme une ingénierie inverse, mais c'est le terme que je vais conserver. Nous comprenons comment utiliser Slim, mais que se passe-t-il sous le capot? Regardons un itinéraire plus compliqué pour aller à la racine de cette question:

 $ app-> get ('/ utilisateurs /: nom', fonction ($ nom) echo "Bonjour". $ nom;);

Cette définition d’itinéraire utilise deux points avec le mot, prénom. Il s'agit d'un espace réservé et la valeur utilisée à sa place est transmise à la fonction. Par exemple, / utilisateurs / gabriel correspond à cette route, et "gabriel" est passé à la fonction. La route, /utilisateurs, d'autre part, n'est pas une correspondance car il manque le paramètre.

Si vous y réfléchissez logiquement, vous devez suivre un certain nombre d'étapes pour pouvoir traiter un itinéraire..

  • La première étape: vérifier si la route correspond à l'URI actuel.
  • Deuxième étape: extraire tous les paramètres de l'URI.
  • Troisième étape: appelle la fermeture connectée et passe les paramètres extraits.

Pour optimiser le processus, Slim - à l'aide de rappels et de groupes regex - stocke les espaces réservés lors de la recherche de correspondances. Cela combine deux étapes en une, ne laissant que la nécessité d’exécuter la fonction connectée lorsque Slim est prêt. Il devient clair que l’objet route est autonome et, franchement, tout ce qui est nécessaire.

Dans l'exemple précédent, nous avions accès aux fonctionnalités de Slim lors de l'analyse des itinéraires, mais nous devions passer une référence à un objet Slim car elle serait sinon indisponible dans le contexte d'exécution de la fonction. C'est tout ce dont vous avez besoin pour la plupart des applications, car la logique de votre application doit se trouver dans le contrôleur..

Dans cet esprit, extrayons la partie "routage" dans une classe et transformons l'objet Slim en "contrôleur".


Commencer

Pour commencer, téléchargeons et installons «vanilla Slim» si vous ne l’avez pas déjà fait. Je vais supposer que vous avez installé Composer, mais sinon, suivez les étapes .

Dans un nouveau répertoire, créez un fichier nommé composer.json, et ajoutez ce qui suit:

 "name": "nettuts / slim-mvc", "require": "slim / slim": "*", "slim / extras": "*", "twig / twig": "*"

Dans une fenêtre de terminal, accédez à ce répertoire et tapez compositeur installer. Je vous guiderai à travers ces paquets, si c'est la première fois que vous utilisez Slim.

  • mince / mince - le cadre Slim actuel.
  • slim / extras - un ensemble de classes optionnelles pour étendre Slim.
  • brindille / brindille - le moteur de template Twig.

Techniquement, vous n'avez pas besoin des extras Slim ni de Twig pour ce tutoriel, mais j'aime bien utiliser Twig au lieu des modèles PHP standard. Toutefois, si vous utilisez Twig, vous avez besoin des extras Slim, car il fournit une interface entre Twig et Slim..

Ajoutons maintenant nos fichiers personnalisés et commençons par ajouter un répertoire à la vendeurs dossier. Je vais nommer le mien Nettuts, mais n'hésitez pas à nommer le vôtre comme vous le souhaitez. Si vous êtes toujours dans le terminal, assurez-vous que votre fenêtre de terminal se trouve dans le répertoire du projet et tapez ce qui suit:

mkdir vendor / Nettuts

Maintenant, éditez composer.json en ajoutant la référence à ce nouveau dossier:

 "name": "nettuts / slim-mvc", "require": "slim / slim": "*", "slim / extras": "*", "twig / twig": "*", " autoload ": " psr-0 ": " Nettuts ":" vendor / "

Nous voulons que notre application charge automatiquement les classes de la Nettuts Cet espace de noms indique donc à Composer de mapper toutes les demandes de Nettuts à la norme PSR-0 à partir du vendeur dossier.

Maintenant, exécutez:

composer dump-autoload

Cela recompile l'autoloader pour inclure la nouvelle référence. Ensuite, créez un fichier, nommé Router.php, dans le Nettuts répertoire, et entrez les informations suivantes:

  

Nous avons vu que chaque objet de route a une fonction autonome qui détermine si elle correspond à l'URI fourni. Nous voulons donc un tableau de routes et une fonction pour les analyser. Nous aurons également besoin d'une autre fonction pour ajouter de nouvelles routes et d'un moyen de récupérer l'URI de la requête HTTP actuelle..

Commençons par ajouter quelques variables membres et le constructeur:

 Classe Routeur protected $ routes; protected $ request; fonction publique __construct () $ env = \ Slim \ Environment :: getInstance (); $ this-> request = new \ Slim \ Http \ Request ($ env); $ this-> routes = array (); 

Nous avons mis le itinéraires variable pour contenir les itinéraires, et la demande variable pour stocker le Slim Demande objet. Ensuite, nous devons avoir la possibilité d’ajouter des itinéraires. Pour rester fidèle aux meilleures pratiques, je vais diviser cela en deux étapes:

fonction publique addRoutes ($ routes) foreach ($ routes en tant que $ route => $ path) $ method = "any"; if (strpos ($ path, "@")! == false) liste ($ path, $ méthode) = exploser ("@", $ path);  $ func = $ this-> processCallback ($ path); $ r = new \ Slim \ Route ($ route, $ func); $ r-> setHttpMethods (strtoupper ($ method)); array_push ($ this-> routes, $ r); 

Cette fonction publique accepte un tableau associatif de routes au format: route => chemin, où route est un itinéraire Slim standard et chemin est une chaîne avec la convention suivante:

Vous pouvez éventuellement omettre certains paramètres pour utiliser une valeur par défaut. Par exemple, le nom de la classe sera remplacé par Principale si vous le laissez, indice est la valeur par défaut pour les noms de fonction omis et la valeur par défaut pour la méthode HTTP est tout. Bien sûr, tout n'est pas une vraie méthode HTTP, mais c'est une valeur que Slim utilise pour correspondre à tous les types de méthodes HTTP.

le addRoutes la fonction commence par un pour chaque boucle qui parcourt les routes. Ensuite, nous définissons la méthode HTTP par défaut, en la remplaçant éventuellement par la méthode fournie si le @ le symbole est présent. Ensuite, nous passons le reste du chemin à une fonction pour récupérer un rappel et l'attachons à une route. Enfin, nous ajoutons la route au tableau.

Maintenant regardons le processCallback () une fonction:

fonction protégée processCallback ($ path) $ class = "Main"; if (strpos ($ path, ":")! == false) liste ($ class, $ path)) = exploser (":", $ path);  $ function = ($ path! = "")? $ path: "index"; $ func = function () use ($ class, $ function) $ class = '\ Controllers \\'. $ classe; $ class = new $ class (); $ args = func_get_args (); return call_user_func_array (tableau ($ class, $ fonction), $ args); ; return $ func; 

Le deuxième problème découle de l'architecture de Slim; il est destiné à être défini dans un seul fichier.

Nous définissons d'abord la classe par défaut à Principale, et remplacer cette classe si le symbole du côlon est trouvé. Ensuite, nous déterminons si une fonction est définie et utilisons la méthode par défaut indice si nécessaire. Nous passons ensuite les noms de classe et de fonction à une fermeture et nous le renvoyons à la route..

À l'intérieur de la fermeture, nous ajoutons le nom de la classe à l'espace de noms. Nous créons ensuite une nouvelle instance de la classe spécifiée et récupérons la liste des arguments passés à cette fonction. Si vous vous en souvenez, bien que Slim vérifie si une route correspond, il crée lentement une liste de paramètres en fonction des caractères génériques de la route. Cette fonction (func_get_args ()) peut être utilisé pour obtenir les paramètres passés dans un tableau. Puis, en utilisant le call_user_func_array () Cette méthode nous permet de spécifier la classe et la fonction tout en transmettant les paramètres au contrôleur.

Ce n'est pas une fonction très compliquée une fois que vous l'avez comprise, mais c'est un très bon exemple de cas où les fermetures sont utiles.

Pour récapituler, nous avons ajouté une fonction à notre Routeur cela vous permet de passer un tableau associatif contenant des itinéraires et des chemins mappant vers des classes et des fonctions. La dernière étape consiste à traiter les itinéraires et à exécuter ceux qui correspondent. Conformément à la convention de dénomination Slim, appelons-le courir:

fonction publique run () $ display404 = true; $ uri = $ this-> request-> getResourceUri (); $ method = $ this-> request-> getMethod (); foreach ($ this-> routes comme $ i => $ route) if ($ route-> correspond ($ uri)) if ($ route-> supportsHttpMethod ($ method) || $ route-> supportsHttpMethod ("ANY ")) call_user_func_array ($ route-> getCallable (), array_values ​​($ route-> getParams ())); $ display404 = false;  if ($ display404) echo "404 - route non trouvée"; 

Nous commençons par régler le display404 variable, représentant aucun itinéraire trouvé, à vrai. Si nous trouvons un itinéraire correspondant, nous allons définir ceci sur faux et contourner le message d'erreur. Ensuite, nous utilisons l’objet requête de Slim pour récupérer l’URI et la méthode HTTP actuels..

Nous utiliserons ces informations pour parcourir et trouver les correspondances dans notre tableau..

Une fois l'objet route allumettes() fonction s'exécute, vous pouvez appeler getParams () pour récupérer les paramètres analysés. En utilisant cette fonction et le getCallable () méthode, nous sommes en mesure d’exécuter la fermeture et de transmettre les paramètres nécessaires. Enfin, nous affichons un message 404 si aucune route ne correspond à l'URI actuel..

Créons la classe de contrôleur qui contient les rappels pour ces routes. Si vous avez suivi, vous avez sans doute réalisé que nous n’avons jamais forcé un type de protocole ou de classe. Si vous ne voulez pas créer une classe de contrôleur, alors n'importe quelle classe fonctionnera correctement.

Alors pourquoi créer une classe de contrôleur? La réponse courte est que nous n’avons toujours pas vraiment utilisé Slim! Nous avons utilisé des parties de Slim pour la requête HTTP et les routes, mais l'objectif était simplement de pouvoir accéder facilement à toutes les propriétés de Slim. Notre classe de contrôleurs étendra la classe Slim actuelle, en accédant à toutes les méthodes de Slim..

Vous pouvez tout aussi facilement sauter ceci et la sous-classe Slim directement à partir de vos contrôleurs..


Construire le contrôleur

Ce contrôleur vous permet fondamentalement de modifier Slim tout en le maintenant à la vanille. Nommez le fichier Controller.php, et écrivez le code suivant:

data = $ settings ['model'];  parent :: __ construct ($ settings); 

Lorsque vous initialisez Slim, vous pouvez définir divers paramètres, allant du mode de débogage de l'application au moteur de modélisation. Au lieu de coder en dur les valeurs du constructeur, je les charge depuis un fichier nommé settings.php et passez ce tableau dans le constructeur du parent.

Étant donné que nous étendons Slim, j'ai pensé qu'il serait intéressant d'ajouter un paramètre de "modèle", permettant aux utilisateurs de connecter leur objet de données directement au contrôleur..

C'est la section que vous pouvez voir au milieu du code ci-dessus. Nous vérifions si le modèle réglage a été défini et assigné à celui du contrôleur Les données propriété si nécessaire.

Maintenant, créez un fichier nommé settings.php dans la racine de votre projet (le dossier avec le composer.json fichier) et entrez les informations suivantes:

 new \ Slim \ Extras \ Views \ Twig (), 'templates.path' => '… / Views', 'model' => (Object) array ("message" => "Hello World")); retourne $ settings;

Ce sont des réglages Slim standard à l'exception du modèle. Quelle que soit la valeur attribuée à la modèle la propriété est transmise au Les données variable; cela pourrait être un tableau, une autre classe, une chaîne de caractères, etc. Je l'ai défini sur un objet parce que j'aime utiliser le -> notation à la place de la notation crochet (tableau).

Nous pouvons maintenant tester le système. Si vous vous en souvenez dans le Routeur classe, nous ajoutons le nom de la classe avec "Manette"espace de noms. Ouvrir composer.json ajoutez ce qui suit directement après la définition de psr-0 pour le Nettuts espace de noms:

"name": "nettuts / slim_advanced", "require": "slim / slim": "2.2.0", "slim / extras": "*", "twig / twig": "*", " autoload ": " psr-0 ": " Nettuts ":" vendor / "," Controller ":" ./ "

Ensuite, comme auparavant, il suffit de vider l’autochargeur:

composer dump-autoload

Si nous venons de définir le chemin d'accès de base au répertoire racine, l'espace de noms Manette mappera vers un dossier nommé "Manette"à la racine de notre application. Créez donc ce dossier:

contrôleur mkdir

Dans ce dossier, créez un nouveau fichier nommé Main.php. Dans le fichier, nous devons déclarer l’espace de nom et créer une classe qui étend notre Manette classe de base:

data-> message;  public function test () echo "Page de test"; 

Ce n'est pas compliqué, mais prenons-le avec modération. Dans cette classe, nous définissons deux fonctions; leurs noms ne comptent pas car nous les mapperons à des itinéraires plus tard. Il est important de noter que j'accède directement aux propriétés depuis le contrôleur (c'est-à-dire le modèle) dans la première fonction. En fait, vous aurez un accès complet à toutes les commandes de Slim..

Créons maintenant le fichier public réel. Créez un nouveau répertoire à la racine de votre projet et nommez-le. Publique. Comme son nom l'indique, c'est là où réside tout le matériel public. Dans ce dossier, créez un fichier appelé index.php et entrez les informations suivantes:

 'Main: index @ get', '/ test' => 'Main: test @ get'); $ routeur-> addRoutes ($ routes); $ routeur-> run ();

Nous incluons la bibliothèque de chargement automatique de Composer et créons une nouvelle instance de notre routeur. Ensuite, nous définissons deux itinéraires, les ajoutons à l'objet routeur et l'exécutons..

Vous devez également activer mod_rewrite dans Apache (ou l’équivalent en utilisant un serveur Web différent). Pour le configurer, créez un fichier nommé .htaccess à l'intérieur de Publique répertoire et remplissez-le avec le texte suivant:

RewriteEngine sur RewriteCond% REQUEST_FILENAME! -F RewriteRule ^ index.php [QSA, L]

Désormais, toutes les demandes de ce dossier (qui ne correspondent pas à un fichier réel) seront transférées vers. index.php.

Dans votre navigateur, accédez à votre Publique répertoire, et vous devriez voir une page qui dit "Hello World". Aller vers "/tester"et le message" Page de test "devrait s'afficher. Ce n'est pas très excitant, mais nous avons réussi à transférer tout le code logique dans des contrôleurs individuels..


Deuxième round

Slim n'est pas CodeIgniter, ce n'est pas Symfony et ce n'est pas Laravel.

Nous avons donc des fonctionnalités de base, mais il y a quelques aspérités. Commençons par le routeur.

À partir de maintenant, nous affichons un simple message d'erreur si un itinéraire n'existe pas. Dans une application réelle, nous voulons les mêmes fonctionnalités que le chargement d'une page normale. Nous souhaitons tirer parti de la capacité de Slim à charger des vues et à définir le code d'erreur de la réponse..

Ajoutons une nouvelle variable de classe contenant un chemin facultatif (tout comme les autres itinéraires). En haut du fichier, ajoutez la ligne suivante directement après la définition de l'objet de la requête:

protected $ errorHandler;

Ensuite, créons une fonction qui accepte un chemin et lui assigne une fonction de rappel. Ceci est relativement simple car nous avons déjà résumé cette fonctionnalité:

fonction publique set404Handler ($ path) $ this-> errorHandler = $ this-> processCallback ($ path); 

Maintenant ajustons le courir commande pour éventuellement exécuter le rappel au lieu d'afficher le message d'erreur:

if ($ display404) if (is_callable ($ this-> errorHandler)) call_user_func ($ this-> errorHandler);  else echo "404 - route non trouvée"; 

Ouvrez la classe de contrôleur. C'est ici que vous pouvez adapter les fonctionnalités de Slim à vos préférences personnelles. Par exemple, je souhaiterais que l'option permettant d'omettre l'extension de fichier soit omise lors du chargement des vues. Donc au lieu d'écrire $ this-> render ("home.php");, Je veux juste écrire: $ this-> render ("maison");. Pour ce faire, substituons la méthode de rendu:

fonction publique render ($ name, $ data = array (), $ status = null) if (strpos ($ name, ".php") === false) $ name = $ name. ".php";  parent :: render ($ name, $ data, $ status); 

Nous acceptons les mêmes paramètres que la fonction parent, mais nous vérifions si l’extension de fichier est fournie et nous l’ajoutons si nécessaire. Après cette modification, nous passons le fichier à la méthode parente pour traitement..

Ceci est juste un exemple, mais nous devrions mettre tous les autres changements ici dans le rendre() méthode. Par exemple, si vous chargez les mêmes pages d’en-tête et de pied de page sur tous vos documents, vous pouvez ajouter une fonction. renderPage (). Cette fonction chargerait la vue transmise entre les appels pour charger l’en-tête et le pied de page normaux..

Ensuite, examinons le chargement de certaines vues. Dans la racine de votre projet, créez un dossier nommé "Des vues"(l'emplacement et le nom peuvent être ajustés dans le settings.php fichier). Créons simplement deux vues nommées test.php et error.php.

À l'intérieur test.php, ajoutez ce qui suit:

Titre

Ceci est la page name!

Et à l'intérieur du error.php fichier, entrez ceci:

404

L'itinéraire que vous recherchiez est introuvable

Aussi, modifiez le Principale contrôleur en changeant le indice() fonction à la suivante:

fonction publique index () $ this-> render ("test", array ("title" => $ this-> data-> message, "name" => "Home")); 

Ici, nous rendons la vue de test que nous venons de créer et transmettons les données à afficher. Essayons ensuite une route avec des paramètres. Changer la tester() fonction à la suivante:

fonction publique test ($ title) $ this-> render ("test", array ("title" => $ title, "name" => "Test")); 

Ici, nous allons encore plus loin en récupérant le titre de la page à partir de l'URI lui-même. Dernier point, mais non le moindre, ajoutons une fonction pour la page 404:

fonction publique notFound () $ this-> render ('error', array (), 404); 

Nous utilisons le rendre() le troisième paramètre facultatif de la fonction, qui définit le code d'état HTTP de la réponse.

Notre montage final est en index.php intégrer nos nouveaux itinéraires:

$ routes = array ('/' => ", '/ test /: title' => 'Main: test @ get'); $ routeur-> addRoutes ($ routes); $ routeur-> set404Handler (" Main: notFound "); $ routeur-> run ();

Vous devriez maintenant pouvoir naviguer sur les trois routes et voir leurs vues respectives..


Conclusion

Avec tout ce que nous avons accompli, vous vous posez des questions sur les raisons pour lesquelles Slim ne propose pas déjà ces modifications. Ils semblent logiques, ils ne s'éloignent pas trop de la mise en œuvre de Slim et ils ont beaucoup de sens. Josh Lockhart (le créateur de Slim) le dit le mieux:

"Slim n'est pas CodeIgniter, ni Symfony, ni Laravel. Slim, c'est Slim. Il a été conçu pour être léger et amusant, tout en permettant de résoudre environ 80% des problèmes les plus courants. Au lieu de vous inquiéter du contour Dans certains cas, il s’agit d’être simple et d’avoir une base de code facile à lire. "

Parfois, en tant que développeurs, nous sommes tellement pris par des scénarios loufoques que nous oublions ce qui est vraiment important: le code. Les mods, comme celui de ce tutoriel, ne sont possibles qu'en raison de la simplicité et de la verbosité du code. Donc, oui, il y a peut-être des cas critiques qui nécessitent une attention particulière, mais vous obtenez une communauté active, ce qui, à mon avis, alourdit considérablement les coûts.

J'espère que vous avez apprécié cet article. Si vous avez des questions ou des commentaires, laissez un message en bas. Vous pouvez également me contacter par le canal IRC sur Freenode à l'adresse #nettuts canal.