Domare Slim 2.0

Slim è una struttura leggera che racchiude un sacco di punch per il suo ingombro ridotto. Ha un incredibile sistema di routing e offre una solida base su cui lavorare senza intralciarti. Lascia che ti mostri!

Ma questo non vuol dire che Slim non abbia alcuni problemi; la configurazione a un solo file diventa ingombra man mano che l'applicazione cresce. In questo articolo, esamineremo come strutturare un'applicazione Slim non solo per sostenere, ma migliorare la sua funzionalità e mantenere le cose pulite e sistematiche.


Vanilla Slim

Iniziamo guardando un codice Slim comune per identificare il problema. Dopo aver installato Slim through Composer, è necessario creare un'istanza di Sottile oggetto e definisci i tuoi percorsi:

 get ('/', function () echo "Home Page";); $ app-> get ('/ testPage', function () usa ($ app) $ app-> render ('testpage.php');); $ App-> run ();

Trasformiamo l'oggetto Slim nel "controller".

La prima chiamata al metodo imposta una nuova rotta per l'URI radice (/) e collega la funzione data a quella rotta. Questo è abbastanza dettagliato, ma facile da configurare. La seconda chiamata al metodo definisce un percorso per l'URI TestPage. All'interno del metodo fornito, usiamo Slim's render () metodo per rendere una vista.

Qui sta il primo problema: questa funzione (una chiusura) non viene chiamata nel contesto corrente e non ha modo di accedere alle funzionalità di Slim. Questo è il motivo per cui dobbiamo usare il uso parola chiave per passare il riferimento all'app Slim.

Il secondo numero deriva dall'architettura di Slim; è pensato per essere definito tutto in un unico file. Ovviamente, puoi esternalizzare la variabile su un altro file, ma diventa solo disordinato. Idealmente, vogliamo la possibilità di aggiungere controller per modulare la struttura in singoli componenti. Come bonus, sarebbe bello se questi controller offrissero l'accesso nativo alle funzionalità di Slim, eliminando la necessità di passare i riferimenti nelle chiusure.


Un po 'di ingegneria inversa

È discutibile se la lettura del codice sorgente da un progetto open-source sia considerata ingegneria inversa, ma è il termine con cui continuerò. Capiamo come usare Slim, ma cosa succede sotto il cofano? Diamo un'occhiata a un percorso più complicato per arrivare alla radice di questa domanda:

 $ app-> get ('/ users /: name', function ($ name) echo "Hello". $ name;);

Questa definizione di rotta utilizza i due punti con la parola, nome. Questo è un segnaposto e il valore utilizzato al suo posto viene passato alla funzione. Per esempio, / Utenti / gabriel corrisponde a questa rotta e "gabriel" viene passato alla funzione. La strada, / utenti, d'altra parte, non è una corrispondenza perché manca il parametro.

Se ci pensi logicamente, ci sono una serie di passaggi che devono essere completati per elaborare un percorso.

  • Primo passo: controlla se la rotta corrisponde all'URI corrente.
  • Passo due: estrae tutti i parametri dall'URI.
  • Passaggio tre: chiama la chiusura connessa e passa i parametri estratti.

Per ottimizzare al meglio il processo, Slim - utilizzando callback e gruppi regex - memorizza i segnaposto mentre controlla le corrispondenze. Questo combina due passaggi in uno, lasciando solo la necessità di eseguire la funzione connessa quando Slim è pronto. Diventa chiaro che l'oggetto del percorso è autonomo e, francamente, tutto ciò che è necessario.

Nell'esempio precedente, abbiamo avuto accesso alle funzionalità di Slim durante l'analisi dei percorsi, ma avevamo bisogno di passare un riferimento a un oggetto Slim perché altrimenti non sarebbe disponibile all'interno del contesto di esecuzione della funzione. Questo è tutto ciò che serve per la maggior parte delle applicazioni, in quanto la logica dell'applicazione dovrebbe verificarsi nel controller.

Con questo in mente, estraiamo la porzione "routing" in una classe e trasformiamo l'oggetto Slim nel "controller".


Iniziare

Per iniziare, scarica e installa "vanilla Slim" se non lo hai già fatto. Presumo che tu abbia installato Composer, ma in caso contrario, segui i passaggi .

All'interno di una nuova directory, crea un file chiamato composer.json, e aggiungi quanto segue:

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

In una finestra di terminale, accedere a detta directory e digitare installazione di compositore. Ti guiderò attraverso questi pacchetti, se questa è la prima volta che usi Slim.

  • sottile / sottile - la struttura Slim attuale.
  • sottile / extra - un set di classi opzionali per estendere Slim.
  • ramoscello / ramoscello - il motore di Twig Templating.

Tecnicamente non hai bisogno degli extra sottili o di Twig per questo tutorial, ma mi piace usare Twig al posto dei modelli PHP standard. Se usi Twig, tuttavia, hai bisogno degli extra Slim perché fornisce un'interfaccia tra Twig e Slim.

Ora aggiungiamo i nostri file personalizzati e inizieremo aggiungendo una directory al fornitori cartella. Chiamerò il mio Nettuts, ma sentiti libero di nominare ciò che desideri. Se si è ancora nel terminale, assicurarsi che la finestra del terminale si trovi nella directory del progetto e digitare quanto segue:

mkdir vendor / Nettuts

Adesso, modifica composer.json aggiungendo il riferimento a questa nuova cartella:

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

Vogliamo che la nostra app carichi automaticamente le classi dal Nettuts namespace, quindi questo indica a Composer di mappare tutte le richieste Nettuts allo standard PSR-0 a partire dal venditore cartella.

Ora esegui:

compositore dump-autoload

Questo ricompila il caricatore automatico per includere il nuovo riferimento. Quindi, crea un file, denominato Router.php, all'interno del Nettuts directory e immettere quanto segue:

  

Abbiamo visto che ogni oggetto del percorso ha una funzione autonoma che determina se corrisponde all'URI fornito. Quindi, vogliamo una serie di percorsi e una funzione per analizzarli. Avremo anche bisogno di un'altra funzione per aggiungere nuovi percorsi e un modo per recuperare l'URI dalla richiesta HTTP corrente.

Iniziamo aggiungendo alcune variabili membro e il costruttore:

 Class Router route $ protette; richiesta $ protetta; funzione pubblica __construct () $ env = \ Slim \ Environment :: getInstance (); $ this-> request = new \ Slim \ Http \ Request ($ env); $ this-> routes = array (); 

Abbiamo impostato il itinerari variabile per contenere i percorsi, e il richiesta variabile per memorizzare Slim Richiesta oggetto. Successivamente, abbiamo bisogno della possibilità di aggiungere percorsi. Per attenersi alle migliori pratiche, suddividerò questo in due passaggi:

funzione pubblica addRoutes ($ routes) foreach ($ routes as $ route => $ path) $ method = "any"; if (strpos ($ path, "@")! == false) list ($ path, $ method) = explode ("@", $ path);  $ func = $ this-> processCallback ($ path); $ r = new \ Slim \ Route ($ route, $ func); $ R-> setHttpMethods (strtoupper ($ metodo)); array_push ($ this-> routes, $ r); 

Questa funzione pubblica accetta un array associativo di rotte nel formato di percorso => ​​percorso, dove itinerario è un percorso Slim standard e sentiero è una stringa con la seguente convenzione:

Facoltativamente, puoi escludere determinati parametri per utilizzare un valore predefinito. Ad esempio, il nome della classe verrà sostituito con Principale se lo lasci fuori, indice è l'impostazione predefinita per i nomi di funzioni omessi e l'impostazione predefinita per il metodo HTTP è qualunque. Ovviamente, qualunque non è un vero metodo HTTP, ma è un valore che Slim utilizza per corrispondere a tutti i tipi di metodi HTTP.

Il addRoutes la funzione inizia con a per ciascuno ciclo che scorre attraverso i percorsi. Successivamente, impostiamo il metodo HTTP predefinito, opzionalmente sovrascrivendolo con il metodo fornito se il @ il simbolo è presente. Quindi passiamo il resto del percorso a una funzione per recuperare una richiamata e collegarla a una rotta. Infine, aggiungiamo il percorso all'array.

Ora diamo un'occhiata al processCallback () funzione:

funzione protetta processCallback ($ path) $ class = "Main"; if (strpos ($ path, ":")! == false) list ($ class, $ path) = explode (":", $ path);  $ function = ($ path! = "")? $ percorso: "indice"; $ func = function () usa ($ class, $ function) $ class = '\ Controllers \\'. $ Classe; $ class = new $ class (); $ args = func_get_args (); return call_user_func_array (array ($ class, $ function), $ args); ; return $ func; 

Il secondo numero deriva dall'architettura di Slim; è pensato per essere definito tutto in un unico file.

Per prima cosa impostiamo la classe predefinita Principale, e sovrascrivi quella classe se viene trovato il simbolo dei due punti. Successivamente, determiniamo se una funzione è definita e usa il metodo predefinito indice se necessario. Quindi passiamo i nomi di classi e funzioni a una chiusura e li restituiamo alla rotta.

All'interno della chiusura, anteponiamo il nome della classe allo spazio dei nomi. Creiamo quindi una nuova istanza della classe specificata e recuperiamo l'elenco degli argomenti passati a questa funzione. Se ricordi, mentre Slim controlla se una rotta corrisponde, costruisce lentamente un elenco di parametri basati su caratteri jolly dalla rotta. Questa funzione (func_get_args ()) può essere usato per ottenere i parametri passati in un array. Quindi, usando il call_user_func_array () il metodo ci consente di specificare la classe e la funzione, passando i parametri al controller.

Non è una funzione molto complicata una volta capito, ma è un ottimo esempio di quando le chiusure tornano utili.

Per ricapitolare, abbiamo aggiunto una funzione al nostro Router che consente di passare un array associativo contenente rotte e percorsi che si associano a classi e funzioni. L'ultimo passo è elaborare i percorsi ed eseguire qualsiasi corrispondenza. Mantenendo la convenzione di denominazione Slim, chiamiamola correre:

funzione pubblica run () $ display404 = true; $ uri = $ this-> request-> getResourceUri (); $ method = $ this-> request-> getMethod (); foreach ($ this-> routes as $ i => $ route) if ($ route-> matches ($ uri)) if ($ route-> supportsHttpMethod ($ method) || $ route-> supportsHttpMethod ("ANY ")) call_user_func_array ($ route-> getCallable (), array_values ​​($ route-> getParams ())); $ display404 = falso;  if ($ display404) echo "404 - route not found"; 

Iniziamo impostando il display404 variabile, che non rappresenta percorsi trovati, a vero. Se troviamo un percorso corrispondente, lo imposteremo su falso e ignorare il messaggio di errore. Successivamente, usiamo l'oggetto request di Slim per recuperare il metodo URI e HTTP corrente.

Useremo queste informazioni per scorrere e trovare le corrispondenze dal nostro array.

Una volta l'oggetto del percorso partite () la funzione viene eseguita, è possibile chiamare getparams () per recuperare i parametri analizzati. Usando quella funzione e il getCallable () metodo, siamo in grado di eseguire la chiusura e passare i parametri necessari. Infine, viene visualizzato un messaggio 404 se nessuna route corrisponde all'URI corrente.

Creiamo la classe controller che contiene i callback per queste rotte. Se hai seguito, potresti aver capito che non abbiamo mai forzato un protocollo o un tipo di classe. Se non si desidera creare una classe controller, qualsiasi classe funzionerà correttamente.

Quindi perché creare una classe controller? La risposta breve è che non abbiamo ancora usato Slim! Abbiamo usato parti di Slim per la richiesta HTTP e le rotte, ma il punto essenziale di questo era avere un facile accesso a tutte le proprietà di Slim. La nostra classe controller estenderà l'attuale classe Slim, ottenendo l'accesso a tutti i metodi di Slim.

Puoi tranquillamente saltare questa sottoclasse Slim direttamente dai tuoi controller.


Costruire il controller

Questo controller ti consente fondamentalmente di modificare Slim mantenendo comunque la vaniglia. Nominare il file controller.php, e scrivi il seguente codice:

data = $ settings ['model'];  genitore :: __ costrutto ($ impostazioni); 

Quando si inizializza Slim, è possibile passare a una varietà di impostazioni, che vanno dalla modalità di debug dell'applicazione al motore dei template. Invece di codificare i valori nel costruttore, li carico da un file chiamato settings.php e passare quella matrice nel costruttore del genitore.

Poiché stiamo estendendo Slim, ho pensato che sarebbe stato bello aggiungere un'impostazione di "modello", consentendo alle persone di agganciare il proprio oggetto dati direttamente al controller.

Questa è la sezione che puoi vedere nel mezzo del codice sopra. Controlliamo se il modello l'impostazione è stata impostata e assegnarla al controller dati proprietà se necessario.

Ora crea un file chiamato settings.php nella radice del tuo progetto (la cartella con il composer.json file) e inserire quanto segue:

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

Queste sono le impostazioni Slim standard ad eccezione del modello. Qualunque valore è assegnato al modello la proprietà è passata al dati variabile; questo potrebbe essere un array, un'altra classe, una stringa, ecc ... L'ho impostato su un oggetto perché mi piace usare il -> notazione invece della notazione parentesi (matrice).

Ora possiamo testare il sistema. Se ricordi in Router classe, anteponiamo il nome della classe con "controllore"namespace. Apri composer.json aggiungere quanto segue direttamente dopo la definizione di psr-0 per Nettuts namespace:

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

Quindi, come prima, basta scaricare il caricatore automatico:

compositore dump-autoload

Se impostiamo semplicemente il percorso di base nella directory radice, allora lo spazio dei nomi controllore verrà mappato in una cartella denominata "controllore"nella radice della nostra app. Quindi crea quella cartella:

Controller mkdir

All'interno di questa cartella, crea un nuovo file chiamato main.php. All'interno del file, dobbiamo dichiarare lo spazio dei nomi e creare una classe che estenda la nostra controllore classe base:

dati-> messaggio;  public function test () echo "Pagina di test"; 

Questo non è complicato, ma prendiamolo con moderazione. In questa classe, definiamo due funzioni; i loro nomi non contano perché li mapperemo alle rotte in seguito. È importante notare che accedo direttamente alle proprietà dal controller (cioè il modello) nella prima funzione, e infatti, avrai pieno accesso a tutti i comandi di Slim.

Ora creiamo il vero file pubblico. Crea una nuova directory nella radice del tuo progetto e nominala pubblico. Come suggerisce il nome, questo è il caso in cui tutte le cose pubbliche risiederanno. All'interno di questa cartella, crea un file chiamato index.php e inserisci quanto segue:

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

Includiamo la libreria di autoloading di Composer e creiamo una nuova istanza del nostro router. Quindi definiamo due percorsi, li aggiungiamo all'oggetto router e lo eseguiamo.

È inoltre necessario attivare mod_rewrite in Apache (o l'equivalente utilizzando un server Web diverso). Per configurarlo, crea un file chiamato .htaccess dentro il pubblico directory e riempirlo con il seguente:

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

Ora tutte le richieste a questa cartella (che non corrispondono a un file reale) saranno trasferite a index.php.

Nel tuo browser, vai al tuo pubblico directory, e dovresti vedere una pagina che dice "Hello World". Navigare verso "/test"e dovresti vedere il messaggio" Pagina di test ". Non è terribilmente eccitante, ma abbiamo spostato con successo tutto il codice logico in singoli controller.


Secondo round

Slim non è CodeIgniter, non è Symfony e non è Laravel.

Quindi abbiamo funzionalità di base, ma ci sono alcuni spigoli. Iniziamo con il router.

A partire da ora, viene visualizzato un semplice messaggio di errore se un percorso non esiste. In un'applicazione reale, vogliamo la stessa funzionalità del caricamento di una pagina normale. Vogliamo sfruttare la capacità di Slim di caricare le visualizzazioni e impostare il codice di errore della risposta.

Aggiungiamo una nuova variabile di classe che contiene un percorso facoltativo (proprio come gli altri percorsi). Nella parte superiore del file, aggiungi la seguente riga direttamente dopo la definizione dell'oggetto richiesta:

protetto $ errorHandler;

Quindi, creiamo una funzione che accetti un percorso e assegni una funzione di callback. Questo è relativamente semplice perché abbiamo già astratto questa funzionalità:

funzione pubblica set404Handler ($ path) $ this-> errorHandler = $ this-> processCallback ($ path); 

Ora regoliamo il correre comando per eseguire facoltativamente la richiamata invece di visualizzare semplicemente il messaggio di errore:

if ($ display404) if (is_callable ($ this-> errorHandler)) call_user_func ($ this-> errorHandler);  else echo "404 - route not found"; 

Apri la classe controller. È qui che puoi adattare la funzionalità di Slim alle tue preferenze personali. Ad esempio, vorrei l'opzione di omettere l'estensione del file durante il caricamento delle viste. Quindi, invece di scrivere $ This-> render ( "home.php");, Voglio solo scrivere: $ This-> render ( "casa");. Per fare questo, sovrascriviamo il metodo di rendering:

render public function ($ name, $ data = array (), $ status = null) if (strpos ($ name, ".php") === false) $ nome = $ nome. ".Php";  parent :: render ($ nome, $ dati, $ stato); 

Accettiamo gli stessi parametri della funzione genitore, ma controlliamo se viene fornita l'estensione del file e la aggiungiamo se necessario. Dopo questa modifica, passiamo il file al metodo genitore per l'elaborazione.

Questo è solo un esempio, ma dovremmo inserire qualsiasi altra modifica qui render () metodo. Ad esempio, se carichi le stesse pagine di intestazione e piè di pagina su tutti i tuoi documenti, puoi aggiungere una funzione renderPage (). Questa funzione carica la vista passata tra le chiamate per caricare l'intestazione e il piè di pagina regolari.

Successivamente, diamo un'occhiata al caricamento di alcune visualizzazioni. Nella radice del tuo progetto crea una cartella chiamata "Visualizzazioni"(la posizione e il nome possono essere modificati in settings.php file). Creiamo solo due viste di nome test.php e error.php.

Dentro test.php, aggiungere il seguente:

titolo

Questa è la pagina nome!

E dentro il error.php file, inserisci questo:

404

La strada che stavi cercando non è stata trovata

Inoltre, modificare il Principale controller modificando il indice() funzione al seguente:

indice di funzione pubblica () $ this-> render ("test", array ("title" => $ this-> data-> message, "name" => "Home")); 

Qui, rendiamo la visualizzazione di prova che abbiamo appena fatto e passiamo i dati da visualizzare. Successivamente, proviamo un percorso con parametri. Cambiare il test() funzione al seguente:

test di funzione pubblica ($ title) $ this-> render ("test", array ("title" => $ title, "name" => "Test")); 

Qui, facciamo un ulteriore passo in avanti recuperando il titolo della pagina dall'URI stesso. Ultimo, ma non meno importante, aggiungiamo una funzione per la pagina 404:

public function notFound () $ this-> render ('error', array (), 404); 

Noi usiamo il render () il terzo parametro opzionale della funzione, che imposta il codice di stato HTTP della risposta.

La nostra modifica finale è in index.php per incorporare i nostri nuovi percorsi:

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

Ora dovresti essere in grado di navigare verso i tre percorsi e vedere le rispettive viste.


Conclusione

Con tutto ciò che abbiamo realizzato, hai alcune domande sul perché Slim non offre già queste modifiche. Sembrano logici, non si allontanano troppo dall'implementazione di Slim, e hanno molto senso. Josh Lockhart (il creatore di Slim) ha dato il meglio:

"Slim non è CodeIgniter, non è Symfony, non è Laravel, Slim è Slim, è stato costruito per essere leggero e divertente, pur essendo in grado di risolvere circa l'80% dei problemi più comuni, invece di preoccuparsi del limite casi, si concentra sulla semplicità e sulla base di codici di facile lettura. "

A volte, come sviluppatori, siamo così presi da scenari pazzi che ci dimentichiamo di ciò che è veramente importante: il codice. Le mod, come quella in questo tutorial, sono possibili solo a causa della semplicità e della verbosità del codice. Quindi sì, ci possono essere alcuni casi limite che richiedono un'attenzione speciale, ma si ottiene una comunità attiva, che a mio parere, pesantemente supera i costi.

Spero che questo articolo ti sia piaciuto. Se hai domande o commenti, lascia un messaggio qui sotto. Puoi anche contattarmi tramite il canale IRC su Freenode al #nettuts canale.