2009-11-25 7 views
20

Was ist der sauberste Weg, um jeder URL in CakePHP ein Präfix hinzuzufügen, wie ein Sprachparameter?Hinzufügen eines Präfixes zu jeder URL in CakePHP

http://example.com/en/controller/action 
http://example.com/ru/admin/controller/action 

Es muss mit „echten“ Präfixen wie admin und idealerweise die bloße URL zu /DEFAULT-LANGUAGE/controller/action/controller/action könnte umgeleitet werden arbeiten.

Es funktioniert jetzt in einer Retro-angepassten Anwendung, aber es war eine Art Hack, und ich muss den Sprachparameter von Hand in die meisten Links einfügen, was nicht gut ist.

Die Frage ist also eine doppelte:

  • Was ist der beste Weg, die Routen zu strukturieren, so dass die Sprachparameter implizit standardmäßig enthalten, ohne für jede neu definierte Strecke angegeben werden muss?
  • Router::connect('/:controller/:action/*', ...) sollte implizit das Präfix enthalten.
  • Der Parameter sollte in $this->params['lang'] oder irgendwo ähnlich sein, um in AppController::beforeFilter() ausgewertet zu werden.
  • Wie erhalten Router::url() automatisch das Präfix in der URL enthalten, wenn nicht explizit angegeben?
    • Router::url(array('controller' => 'foo', 'action' => 'bar')) sollte /en/foo/bar
    • Seit Controller::redirect() zurückkehren, Form::create() oder sogar Router::url() direkt das gleiche Verhalten haben müssen, jede einzelne Funktion ist nicht wirklich eine Option überschrieben wird. Html::image() sollte beispielsweise eine URL ohne Präfix erzeugen.

Die folgenden Methoden scheinen Router::url zu nennen.

  • Controller::redirect
  • Controller::flash
  • Dispatcher::__extractParams über Object::requestAction
  • Helper::url
  • JsHelper::load_
  • JsHelper::redirect_
  • View::uuid, aber nur für einen Hash-Erzeugungs

Aus diesen scheint die Controller und Helper-Methoden überschrieben werden müssen, könnte ich ohne die JsHelper leben. Meine Idee wäre, eine allgemeine Funktion in oder vielleicht nur in bootstrap.php schreiben, um die Parametereinfügung zu behandeln. Die überschriebenen Controller- und Helper-Methoden würden diese Funktion verwenden, genau wie ich, wenn ich Router::url manuell aufrufen möchte. Wäre das ausreichend?

Antwort

14

Dies ist im Wesentlichen der gesamte Code ich dieses Problem am Ende zu lösen umgesetzt (zumindest glaube ich das ist alles ;-)):

/config/bootstrap.php

define('DEFAULT_LANGUAGE', 'jpn'); 

if (!function_exists('router_url_language')) { 
    function router_url_language($url) { 
     if ($lang = Configure::read('Config.language')) { 
      if (is_array($url)) { 
       if (!isset($url['language'])) { 
        $url['language'] = $lang; 
       } 
       if ($url['language'] == DEFAULT_LANGUAGE) { 
        unset($url['language']); 
       } 
      } else if ($url == '/' && $lang !== DEFAULT_LANGUAGE) { 
       $url.= $lang; 
      } 
     } 

     return $url; 
    } 
} 

/config/core.php

Configure::write('Config.language', 'jpn'); 

/app_helper.php

class AppHelper extends Helper { 

    public function url($url = null, $full = false) { 
     return parent::url(router_url_language($url), $full); 
    } 

} 

/app_controller.php

class AppController extends Controller { 

    public function beforeFilter() { 
     if (isset($this->params['language'])) { 
      Configure::write('Config.language', $this->params['language']); 
     } 
    } 

    public function redirect($url, $status = null, $exit = true) { 
     parent::redirect(router_url_language($url), $status, $exit); 
    } 

    public function flash($message, $url, $pause = 1) { 
     parent::flash($message, router_url_language($url), $pause); 
    } 

} 

/config/routes.php

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home')); 
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display')); 
Router::connect('/:language/', array('controller' => 'pages', 'action' => 'display', 'home'), array('language' => '[a-z]{3}')); 
Router::connect('/:language/pages/*', array('controller' => 'pages', 'action' => 'display'), array('language' => '[a-z]{3}')); 
Router::connect('/:language/:controller/:action/*', array(), array('language' => '[a-z]{3}')); 

Dies ermöglicht Standard-URLs wie /controller/action die Standardsprache zu verwenden (JPN in mein Fall), und URLs wie /eng/controller/action, um eine Alternative zu verwenden ative Sprache. Diese Logik kann in der router_url_language() Funktion ziemlich leicht geändert werden.

Damit dies funktioniert muss ich auch zwei Routen für jede Route definieren, eine mit dem Parameter /:language/ und eine ohne. Zumindest konnte ich nicht herausfinden, wie ich es anders machen könnte.

+0

Große Antwort, das hat mir wirklich geholfen. – gacrux

+2

@gacrux Beachten Sie, dass dies in Cake 1.3, das anpassbare Präfixe enthält, viel weniger komplex sein sollte. Das oben Gesagte gilt für Kuchen 1.2, der nur * ein * Präfix kannte. :) – deceze

0

Ein einfacherer Weg könnte darin bestehen, die gewählte Sprache in einem Cookie zu speichern und dann nicht alle URLs neu schreiben zu müssen. Sie könnten die Browsersprache des Benutzers auch automatisch erkennen.

jedoch wäre Suchmaschinen unwahrscheinlich, dass die verschiedenen Sprachen zur Abholung und Sie würden auch die Sprache verlieren, wenn jemand versucht, den Link zu teilen.

Aber liebe die vollständige Lösung, die Sie veröffentlicht haben, sehr umfassend, danke. :-)

+1

Das Problem mit "URL-less" Sprachumschaltungen ist Suchmaschinen. Sie werden nur eine einzige Sprache indexieren oder ihr Höschen in einem Haufen bekommen, wenn sie unter derselben URL unterschiedliche Inhalte sehen. Das funktioniert nur für private (nur Login) Bereiche Ihrer Seite. – deceze

+0

Oh, ja, das ist ein guter Punkt. Ich werde meine Antwort aktualisieren, um das zu beachten. –

Verwandte Themen