2012-12-01 13 views
7

Ich habe Probleme zu begreifen, was wäre die richtige Art der Behandlung RESTful URLs.Umgang mit RESTful URLs PHP

Ich habe URLs wie diese:

http://localhost/products 
http://localhost/products/123 
http://localhost/products/123/color 

Ursprünglich:

http://localhost/index.php?handler=products&productID=123&additional=color 

Was jetzt bin ich mit mod_rewrite:

RewriteRule ^([^/]*)([/])?([^/]*)?([/])?(.*)$ /index.php?handler=$1&productID=$3&additional=$5 [L,QSA] 

Und dann bin ich rätselhaft zusammen die Anfragen in index.php, etwas wie:

if ($_GET['handler'] == 'products' && isset($_GET['productID'])) { 
    // get product by its id. 
} 

Ich habe einige gesehen eine GET-Abfrage als eine Zeichenfolge wie das Erstellen:

if ($_GET['handler'] == 'products/123/color') 

Dann tun Sie zum Beispiel reguläre Ausdrücke verwenden, um die Werte aus dem Abfrage-String zu erhalten?

Ist dies ein besserer Ansatz, um diese URLs zu behandeln? Was sind die Vor- und Nachteile dieser verschiedenen Ansätze? Gibt es einen besseren Weg?

+0

'' Deshalb mag ich diese Arten von URLs nicht.Positionsparms wie diese sind nicht so einfach zu verarbeiten wie Name/Wert-Parameter. ''. –

Antwort

6

Sie könnten einen anderen Ansatz verwenden, anstatt alle Parameter mit Apache neu zu schreiben. Sie könnten den vollständigen Anfragepfad in PHP mit preg_match abgleichen. Mit dem regulären Ausdruck PHP werden alle Parameter in das Array $args verschoben.

$request_uri = @parse_url($_SERVER['REQUEST_URI']); 
$path = $request_uri['path']; 
$selectors = array(
    "@^/products/(?P<productId>[^/]+)|/[email protected]" => 
      (array("GET" => "getProductById", "DELETE" => "deleteProductById")) 
); 

foreach ($selectors as $regex => $funcs) { 
    if (preg_match($regex, $path, $args)) { 
     $method = $_SERVER['REQUEST_METHOD']; 
     if (isset($funcs[$method])) { 
      // here the request is handled and the correct method called. 
      echo "calling ".$funcs[$method]." for ".print_r($args); 
      $output = $funcs[$method]($args); 
      // handling the output... 
     } 
    } 
} 

Dieser Ansatz hat viele Vorteile:

  • Sie haben keine Rewrite für jeden REST Service, den Sie zu entwickeln. Ich schreibe gerne neu, aber in diesem Fall brauchen Sie eine Menge Freiheit, und mit Umschreibungen müssen Sie die Apache-Konfiguration jedes Mal ändern, wenn Sie einen neuen Dienst bereitstellen/warten.
  • Sie können eine einzige PHP-Frontend-Klasse für alle eingehenden Anfragen verwenden. Das Frontend schickt alle Anfragen an den richtigen Controller.
  • Sie können iterativ ein Array von regulären Ausdrücken auf die eingehenden Anfragen anwenden und anschließend die korrekte Funktion oder Klassensteuerung/Methode entsprechend der erfolgreichen Übereinstimmung aufrufen
  • Wenn der Controller schließlich zur Bearbeitung der Anfrage instanziiert wird, können Sie dies überprüfen die HTTP-Methode in HTTP-Anforderung verwendet
+0

benötigen Sie nicht noch ein Mapping in Htaccess, um auf die Controller-PHP-Datei zu zeigen, oder wie ist das verdrahtet? –

+1

@NickHumphrey Da jede Anfrage mit index.php behandelt werden kann (Standard-Datei in 'DirectoryIndex'), müssen Sie wirklich nichts in' .htaccess 'ablegen. Naja ... Ihr Webserver sollte zumindest PHP-Seiten ausführen können. Alles, was Sie tun müssen, ist diesen Code in die Datei index.php einzubetten und die Anfrage an den richtigen Handler zu senden. – freedev

3

Dieser .htaccess Eintrag wird alles außer vorhandene Dateien index.php senden:

RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule . /index.php 

Dann können Sie so etwas wie dies tun, um die uRL in eine umwandeln Array:

$url_array = explode('/', $_SERVER['REQUEST_URI']); 
array_shift($url_array); // remove first value as it's empty 
array_pop($url_array); // remove last value as it's empty 

Dann können Sie einen Schalter verwenden thusly:

switch ($url_array[0]) { 

    case 'products' : 
     // further products switch on url_array[1] if applicable 
     break; 

    case 'foo' : 
     // whatever 
     break; 

    default : 
     // home/login/etc 
     break; 

} 

Das ist, was ich ohnehin im Allgemeinen tun.