Instradamento URL applicazione PHP

Quindi sto scrivendo un framework su cui voglio basare alcune app su cui sto lavorando (il framework è lì, quindi ho un ambiente con cui lavorare e un sistema che mi consentirà, ad esempio, di utilizzare un singolo firmare)

Voglio creare questo framework e le app che utilizza un'architettura orientata alle risorse.

Ora, voglio creare una class di routing URL che sia espandibile dagli scrittori di APP (e probabilmente anche dagli utenti di app CMS, ma è WAYYYY avanti in futuro) e sto cercando di capire il modo migliore per farlo guardando come le altre app lo fanno.

Preferisco usare reg ex over per creare il mio formato poiché è noto. Ho scritto una piccola class che uso che mi permette di annidare queste tabelle di reg-es-routing. Io uso per usare qualcosa di simile che è stato implementato per ereditarietà ma non ha bisogno di ereditarietà, quindi l'ho riscritto.

Faccio un reg ex su una chiave e mappo alla mia string di controllo. Prendi l'esempio di seguito. ApiController /api/related/joe e la mia class router crea un nuovo object ApiController e chiama il suo metodo relatedDocuments(arrays('tags' => 'joe'));

 // the 12 strips the subdirectory my app is running in $index = urldecode(substr($_SERVER["REQUEST_URI"], 12)); Route::process($index, arrays( "#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags", "#^thread/(.*)/post$#Di" => "ThreadController/post/title", "#^thread/(.*)/reply$#Di" => "ThreadController/reply/title", "#^thread/(.*)$#Di" => "ThreadController/thread/title", "#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags", "#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id", "#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id", "#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle", "#^$#Di" => "HomeController", )); 

Per mantenere gli errori bassi e la semplicità puoi suddividere il tuo tavolo. In questo modo puoi inserire la tabella di routing nella class che controlla. Prendendo l'esempio precedente puoi combinare le tre chiamate in thread in una sola.

 Route::process($index, arrays( "#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags", "#^thread/(.*)$#Di" => "ThreadController/route/uri", "#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags", "#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id", "#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id", "#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle", "#^$#Di" => "HomeController", )); 

Quindi definisci ThreadController :: route in modo che sia come questo.

 function route($args) { Route::process($args['uri'], arrays( "#^(.*)/post$#Di" => "ThreadController/post/title", "#^(.*)/reply$#Di" => "ThreadController/reply/title", "#^(.*)$#Di" => "ThreadController/thread/title", )); } 

Inoltre è ansible definire qualsiasi valore di default che si desidera per la string di routing sulla destra. Basta non dimenticare di documentarli o confonderai le persone. Attualmente sto chiamando l'indice se non includi un nome di function a destra. Ecco il mio codice attuale. Si consiglia di cambiarlo per gestire gli errori come ti piace e o azioni predefinite.

Ancora un altro quadro? — Comunque…

Il trucco è con il routing è quello di passare tutto al tuo controller di routing.

Probabilmente vorresti usare qualcosa di simile a ciò che ho documentato qui:

http://www.hm2k.com/posts/friendly-urls

La seconda soluzione ti consente di utilizzare URL simili a Zend Framework.

Usa una list di Regex per abbinare l'object che dovrei usare

Per esempio

 ^/users/[\w-]+/bookmarks/(.+)/$ ^/users/[\w-]+/bookmarks/$ ^/users/[\w-]+/$ 

Vantaggi: bello e semplice, mi consente di definire i routes direttamente Contro: Dovrebbe essere ordinato, non rendendo facile aggiungere nuove cose (molto incline agli errori)

Questo è, afaik, come fa Django

Penso che molti framework utilizzino una combinazione di mod_rewrite e un front controller di Apache. Con mod_rewrite, puoi trasformare un URL come questo: / people / get / 3 in questo: index.php? Controller = people & method = get & id = 3. Index.php implementerebbe il front controller che indirizza la richiesta di pagina in base ai parametri forniti.

Come ci si potrebbe aspettare, ci sono molti modi per farlo.

Ad esempio, in Slim Framework , un esempio del motore di routing può essere il seguente (basato sul model ${OBJECT}->${REQUEST METHOD}(${PATTERM}, ${CALLBACK}) ):

 $app->get("/Home", function() { print('Welcome to the home page'); } $app->get('/Profile/:memberName', function($memberName) { print( 'I\'m viewing ' . $memberName . '\'s profile.' ); } $app->post('/ContactUs', function() { print( 'This action will be fired only if a POST request will occure'); } 

Quindi, l'istanza inizializzata ( $app ) ottiene un metodo per metodo di richiesta (ad es. Get, post, put, cancella ecc.) E ottiene un instradamento come primo parametro e callback come secondo.

Il path può get token – che è "variabile" che cambierà in fase di esecuzione sulla base di alcuni dati (come il nome del membro, l'identificativo dell'articolo, il nome dell'ubicazione dell'organizzazione o altro – lo sai, proprio come in each controller di routing).

Personalmente, mi piace in questo modo, ma non penso che sarà abbastanza flessibile per un framework avanzato.

Dato che sto lavorando attualmente con ZF e Yii, ho un esempio di router che ho creato come parte di un framework per un'azienda per cui lavoro:

Il motore del path si basa sulla regex (simile a quella di @ gradbot) ma ha una conversazione bidirezionale, quindi se un tuo cliente non può eseguire mod_rewrite (in Apache) o aggiungere regole di riscrittura sul suo server, lui o lei puoi ancora utilizzare gli URL tradizionali con la string di query.

Il file contiene un arrays, ognuno di essi, each elemento è simile a questo esempio:

 $_FURLTEMPLATES['login'] = arrays( 'i' => arrays( // Input - how the router parse an incomming path into query string params 'pattern' => '@Members/Login/[email protected]', 'matches' => arrays( 'Application' => 'Members', 'Module' => 'Login' ), ), 'o' => arrays( // Output - how the router parse a query string into a route '@Application=Members(&|&)Module=Login/[email protected]' => 'Members/Login/' ) ); 

Puoi anche utilizzare combinazioni più complesse, come ad esempio:

 $_FURLTEMPLATES['article'] = arrays( 'i' => arrays( 'pattern' => '@CMS/Articles/([\d]+)/[email protected]', 'matches' => arrays( 'Application' => "CMS", 'Module' => 'Articles', 'Sector' => 'showArticle', 'ArticleID' => '$1' ), ), 'o' => arrays( '@Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)@' => 'CMS/Articles/$4' ) ); 

La linea di fondo, come penso, è che le possibilità sono infinite, dipende solo da quanto complessi desideri che il tuo framework sia e da cosa desideri farlo.

Se, ad esempio, è solo inteso come servizio Web o semplice wrapper di siti Web, è sufficiente utilizzare lo stile di scrittura di Slim Framework: codice molto semplice e di bell'aspetto.

Tuttavia, se desideri sviluppare siti complessi che lo utilizzano, ritengo che la regex sia la soluzione.

In bocca al lupo! 🙂

Dovresti controllare Pux https://github.com/c9s/Pux

Ecco la sinossi

 <?php require 'vendor/autoload.php'; // use PCRE patterns you need Pux\PatternCompiler class. use Pux\Executor; class ProductController { public function listAction() { return 'product list'; } public function itemAction($id) { return "product $id"; } } $mux = new Pux\Mux; $mux->any('/product', ['ProductController','listAction']); $mux->get('/product/:id', ['ProductController','itemAction'] , [ 'require' => [ 'id' => '\d+', ], 'default' => [ 'id' => '1', ] ]); $mux->post('/product/:id', ['ProductController','updateAction'] , [ 'require' => [ 'id' => '\d+', ], 'default' => [ 'id' => '1', ] ]); $mux->delete('/product/:id', ['ProductController','deleteAction'] , [ 'require' => [ 'id' => '\d+', ], 'default' => [ 'id' => '1', ] ]); $route = $mux->dispatch('/product/1'); Executor::execute($route); 

Il framework MVC di Zend utilizza per default una struttura simile

 /router/controller/action/key1/value1/key2/value2 

where il router è il file del router (mappato tramite mod_rewrite , il controller proviene da un gestore di azioni del controllore definito da una class derivata da Zend_Controller_Action e l' action riferimento a un metodo nel controller, denominato actionAction . Le coppie chiave / valore possono andare in qualsiasi ordine e sono disponibili per il metodo action come arrays associativo.

Ho usato qualcosa di simile in passato nel mio codice e finora ha funzionato abbastanza bene.

Prova a dare un'occhiata al pattern MVC .
Zend Framework lo usa ad esempio, ma anche CakePHP, CodeIgniter, …

Personalmente non mi piace il model MVC, ma è il più delle volte implementato come componente "View for web".

La decisione dipende molto dalla preferenza …