Překlad id na uri a zpět + jazykové mutace
- Dimitry
- Člen | 11
Zdravím,
potýkám se s problémem, kdy se snažím na webu co nejvíce zjednodušit url z pohledu uživatele a zároveň mít url vícejazyčné. Aplikaci píši modulárně na PHP 5.3, používám vlastní Translator, vše se maximálně cachuje.
Problém nastává u PageModule, který si své routy nastavuje takhle:
public function setupRoutes($module, IRouter $router) {
// Naroutovani frontendu modulu.
$router[] = $moduleRouter = new MultiRouter('Page');
$moduleRouter[] = new Route('<lang>/<id>/', array(
'presenter' => 'Default',
'action' => 'default',
'id' => array(
Route::FILTER_IN => callback('PageModule::uriToId'),
Route::FILTER_OUT => callback('PageModule::idToUri'),
),
));
// Vrati se zmodifikovany router.
return $router;
}
Callbacky jsou definovány následovně:
static function uriToId($uri) {
$lang = Environment::getService('Translator')->getLang();
// Cachovani url pro stranky.
$cache = Environment::getCache('PageRoutes');
if (!is_array($cache[$lang])) {
// Neni-li cache zalozena, predpripravi se pole.
$cache[$lang] = array();
}
// Zjisti se, zda se id odpovidajici url.
$id = array_search($uri, $cache[$lang]);
if ($id === FALSE) {
// Id se cachi nenachazi, koukne se do databaze.
$id = dibi::fetchSingle('SELECT [pageLang.idPage]
FROM [pageLang]
WHERE [pageLang.uri] = %s', $uri);
if (!empty($id)) {
// Cachuji se jen validni adresy.
$cache[$lang] += array(
$id => $uri,
);
}
}
// Nebylo-li id nalezeno, prejde se na Error presenter.
if (empty($id)) {
throw new BadRequestException('error:pageNotFound', 404);
}
// Vrati se nalezene id.
return $id;
}
static function idToUri($id) {
$lang = Environment::getService('Translator')->getLang();
// Cachovani url pro stranky.
$cache = Environment::getCache('PageRoutes');
if (!is_array($cache[$lang])) {
// Neni-li cache zalozena, predpripravi se pole.
$cache[$lang] = array();
}
if (!isset($cache[$lang][$id])) {
// Id v cachi nebylo nalezeno, podiva se do databaze.
$uri = dibi::fetchSingle('SELECT [pageLang.uri]
FROM [pageLang]
WHERE [pageLang.idPage] = %i
AND [pageLang.lang] = %s', $id, $lang);
if (!empty($uri)) {
// Cachuji se jen validni uri.
$cache[$lang] += array(
$id => $uri,
);
}
}
return $cache[$lang][$id];
}
Problém se projevuje hlavně u přepínacích vlaječek na jazyk, ale očekávám, že se projeví u jakýchkoliv odkazů, které směřují na jinou jazykovou mutaci, než která je výchozí. Vlaječky jsou nadefinovány takto:
<!-- FLAGS START-->
<span id="flagEn" class="flag{ifCurrent this 'lang' => 'en'} langActive{/ifCurrent}"><a href="{plink this 'lang' => 'en'}" title="English"></a></span>
<span id="flagCs" class="flag{ifCurrent this 'lang' => 'cs'} langActive{/ifCurrent}"><a href="{plink this 'lang' => 'cs'}" title="Česky"></a></span>
<!-- FLAGS STOP -->
Jsem-li na stránkce „cs/kontakt“, vygenerují se vlajčky vedoucí na „cs/kontakt“ a „en/kontakt“, když se na anglickou vlajčku kliknu, url se sama „nějak“ přesměruje na „en/contact“. Potřeboval bych proto v callbacku pro generování odkazů znát cílový jazyk, na který odkaz směřuje. Nyní se tam vkládá jazyk, který je aktuálně zvolený. S tím souvisí problém, kdy někdy dojde k zacachování špatné jazykové mutace překladu.
S tím souvisí můj druhý dotaz – jde v této fázi nějak inteligentně zjistit, se kterým jazykem se zrovna pracuje? Aktuálně to tam zjišťuji parsováním url, ale to není zrovna optimální způsob. V období kolem Vánoc jsem na to nějak přišel, že jsem jazyk četl v bootstrapu nějakou metodou pro čtení persisteních parametrů, ale ten kód jsem ztratil a nedaří se mi to vymyslet znovu. Možná je to nějakou změnou v Nette.
Mockrát děkuji. Budu vděčný za jakoukoliv radu, jak to efektivně řešit.
- Filip Procházka
- Moderator | 4668
a co takhle nějak?
//edit: kód routeru přesunut na gist: SmarterRoute
a použiješ to takhle nějak
$router[] = $route = new SmarterRoute('<presenter>/<action>', array(...));
$route->addFilter('id', 'PageModule::uriToId', 'PageModule::idToUrl');
a s tím že do filteru se ti předá jako druhý argument
Nette\Application\PresenterRequest
, v původním tvaru.
static function uriToId($uri, Nette\Application\PresenterRequest $request)
{
$translator = Nette\Environment::getService('ITranslator');
$lang = $request->params['lang']; // zkratka na $request->getParams()
// dál už to znáš :)
return $id;
}
Psal jsem to z hlavy, asi tam bude pár chybek potřeba doladit :)
Editoval HosipLan (13. 2. 2011 19:04)
- Dimitry
- Člen | 11
Oh, mockrát děkuji. Opravdu funguje na výbornou. Pouze jsem musel upravit pár drobností. Kdyby to chtěl někdo použít, tak změny jsem udělal v metodě doFilterParams:
- $param se omylem změnil na $name
- přidal jsem jí další parametr PresenterRequest $request, který se předává callbackům, je pak třeba upravit volání v match a constructUrl
A díky tomuhle budu moci překládat i jména modulů, presenterů a akcí závisle na jazyce. Skvělé :-).
Pouze se mi ještě objevuje problém pokud při generování odkazů, když není nalezeno odpovídající uri, protože článek v daném jazyce neexistuje. Pak se vytvoří odkaz ve tvaru „/en/page.default/?id=3“. Nicméně správně vede na ErrorPresenter. Nedalo by se mu nějak vnutit, aby rovnou vedl na „cs/error“, kde bude chybový presenter?
Ale v ErrorPreseneru se mi za žádnou cenu nedaří přepnout jazyk na jiný, než na češtinu. I přesto, že se url změní na „/en/“, tak Error presenter má v sobě stále „lang ⇒ cs“.
O jazyky se mi stará BasePresenter:
<?php
use \Nette,
\Nette\Application\Presenter,
\Nette\Environment,
\Nette\Debug;
abstract class BasePresenter extends Presenter {
public $lang;
/**
* Zajistuje spravu persistentnich parametru.
* @return array Pole persistentnich parametru.
*/
public static function getPersistentParams() {
return array('lang');
}
/**
* Startovani vychoziho presenteru.
*/
protected function startup() {
parent::startup();
// Zvaliduje se jazyk. Pokud je nevalidni, vstoupi se na vychozi.
$langs = Environment::getVariable('langs');
if (!in_array($this->lang, $langs->toArray())) {
$this->lang = $langs[0];
}
// Jazyk se preda sablone.
$this->template->lang = $this->lang;
// Nastavi se jazyk Translatoru.
Environment::getService('Translator')->setLang($this->lang);
}
protected function createTemplate() {
$template = parent::createTemplate();
$template->setTranslator(Environment::getService('Translator'));
return $template;
}
}
?>
Pak mám ještě speciální BasePresenter pro frontend a administraci.
<?php
abstract class BaseFrontPresenter extends BasePresenter {
protected function startup() {
parent::startup();
$this->setLayout('front');
}
}
?>
Samotný Error presenter vypadá takto:
<?php
use Nette\Application\BadRequestException,
Nette\Debug;
final class ErrorPresenter extends BaseFrontPresenter {
public function actionDefault() {
}
public function renderDefault($exception) {
if ($this->isAjax()) {
// jedná-li se o ajax, zaznamená se chyba payloadu
$this->payload->error = TRUE;
} elseif ($exception instanceof BadRequestException) {
// přejde se na šablonu pro 404
$this->view = '404';
$this->template->exception = $exception->getMessage();
} else {
// přejde se na šablonu pro 500
$this->view = '500';
Debug::processException($exception);
}
}
}
?>
Je mi zvláštní, že na ostatních stránkách přepínání jazyka funguje v pořádku, ale tady ne. I když se chyba vygeneruje na anglické stránce, tak to stejně uživatele hodí na český Error presenter. Jako kdyby ten se ten $lang nepředal a byl stále na defaultní hodnotě.
- Filip Procházka
- Moderator | 4668
asi by bylo vhodné udělat si nějaký
ErrorForwardingPresenter
, který nastavíš do application
$application->errorPresenter = 'ErrorForwardingPresenter';
a v něm by bylo něco jako
use Nette\Application\BadRequestException;
final class ErrorForwardingPresenter extends BaseFrontPresenter
{
public function actionDefault($exception)
{
Nette\Debug::log($exception, Nette\Debug::ERROR);
if ($this->isAjax()) {
// jedná-li se o ajax, zaznamená se chyba payloadu
$this->payload->error = TRUE;
$this->sendPayload();
}
if ($exception instanceof BadRequestException) {
$code = '404';
} elseif ($exception->getCode()) {
$code = $exception->getCode();
} else {
$code = 500;
}
$this->redirect(':Error:default', array('code' => $code));
}
}
a tohle by ti potom dovolilo zobrazovat a přesměrovávat na
„normální“ ErrorPresenter
final class ErrorForwardingPresenter extends BaseFrontPresenter
{
public function actionDefault($code)
{
$this->setView($code);
}
}
a pak bys měl šablony podle kódů chyby, jako je teď v sandboxu :)
- Dimitry
- Člen | 11
Jo, tohle zřetězení mi také nefungovalo. Rozdělil jsem to na víc řádků:
<?php
// Naroutovani frontendu modulu.
$router[] = $moduleRouter = new MultiRouter('Page');
$route = new SmartRoute('<lang>/<id>/', array(
'lang' => $langs[0],
'presenter' => 'Default',
'action' => 'default',
));
$route->addFilter('id', 'PageModule::uriToId', 'PageModule::idToUri');
$moduleRouter[] = $route;
?>
- jann
- Člen | 30
Dík, funguje. Ještě, jde tam nějak udělat, abych mohl filtrovat i názvy presenterů? Něco jako:
<?php
$route->addFilter('presenter', 'FrontModule\LibraryModel::getPresenterByUrl', 'FrontModule\LibraryModel::getUrlByPresenter');
?>
Doteď jsem na to měl zvlášť routu pro EN a CS verzi + Route::FILTER_TABLE pro každou verzi, ale nějak to blblo. Jako by se použily obě najednou a při generování adresy tam pak byla nějaká část 2×. Respektive záleželo na pořadí. Nejprve byla routa pro CZ a ta fungovala normálně. Pod ní byla routa pro EN a tady byl problém. Provedl se totiž filtr jak z CZ, tak pak i z EN routy…
- Aurielle
- Člen | 1281
Nehodilo by se ti gettextové překládání v routách – LanguageTable? Možná je to pro tvoje potřeby trošku overkill, ale pokud vyžaduješ překlady tak to funguje spolehlivě.
- jann
- Člen | 30
Na překlady používám Nette Translator od Patrika Votočka, se kterým už
jsem se celkem sžil…
Jinak to zdvojování byla moje chyba. Pokud jsem byl na české URL a překlikl
jsem na anglickou, tak ten filtr vzal celou českou ID část url (včetně
doplněného textu) a za toto přidal anglický text. Správně to má pracovat
jen s číselnými ID, moje chyba…
- Filip Procházka
- Moderator | 4668
Doplnil a opravil jsem na gistu to filtrování presenterů
co se týče toho řetězení, tak jsem si neuvědomil, že tam je
new
a né metoda, takže se omlouvám za zmatení. :)
$router[] = $route = new SmarterRoute('<presenter>/<action>', array(...));
$route
->addFilter('id', 'PageModule::uriToId', 'PageModule::idToUrl')
->addFilter('action', 'Model::actionToId', 'Model::idToAction')
->addFilter('presenter', 'Model::presenterToId', 'Model::idToPresenter');
// ...
Editoval HosipLan (13. 2. 2011 19:02)
- jann
- Člen | 30
Co myslíš, že je lepší na překlad akcí a presenterů v URL:
1) Klasické překladové tabulky
Takto to mám aktuálně a funguje to, v jednotlivých tabulkách mám na
začátku i data ze druhé tabulky, aby se mi správě vytvořila adresa,
i když bych ručně v URL změnil kód jazyka (např při změně na EN to
akceptuje český název akce, ale přesměruje se to pak na anglický
kanonický tvar, který je na konci tabulky):
<?php
Route::addStyle('#cs-action', 'action');
Route::addStyle('#en-action', 'action');
Route::setStyleProperty('#en-action', Route::FILTER_TABLE, array(
'zeme' => 'zeme',
'polozka' => 'polozka',
'country' => 'zeme',
'item' => 'polozka',
));
Route::setStyleProperty('#cs-action', Route::FILTER_TABLE, array(
'country' => 'zeme',
'item' => 'polozka',
'zeme' => 'zeme',
'polozka' => 'polozka',
));
?>
A přidám 2 routy, pro každý jazyk jedna s následovně definovanýma akcema:
<action #cs-action> a <action #en-action>
2. Řešení pomocí tvé třídy
Tzn. že bych si přidal filtry pro prezentery i akce. A v příslušných IN
a OUT callback funkcích by bylo něco podobného jako překladová tabulka
v první verzi… Tady by teoreticky stačila jen jedna routa.
S Nette začínám, takže neznám ještě různé „best practicles“. Jde mi třeba o nějaké rychlostní problémy atd. Zatím mi funguje první metoda a pokud to nějak extra nezpomaluje nebo něco tak, tak ať to zbytečně nepředělávám…
- Filip Procházka
- Moderator | 4668
Méně rout by mělo být lepší, ale něco mi říká, že gmvaskova tabulka tohle řeší. Je to spíš o tom co ti víc vyhovuje, nejjednodužším příkladem by asi bylo
class PresenterTranslations extends Nette\Object
{
public static $translations = array(
'cs' => array(
'zeme' => 'zeme',
'polozka' => 'polozka',
),
'en' => array(
'country' => 'zeme',
'item' => 'polozka',
),
);
public static function presenterToUrl($presenter, PresenterRequest $request)
{
$lang = $request->params['lang'];
$table = array_flip(self::$translations[$lang]);
return $table[$presenter];
}
public static function urlToPresenter($url)
{
$lang = $request->params['lang'];
$table = self::$translations[$lang];
return $table[$url];
}
}
$router[] = $route = new SmartRoute('/[!<lang>]/<presenter>/<action>', array(
'presenter' => 'Homepage',
'action' => 'default',
'lang' => 'cs'
));
$route->addFilter('presenter', 'PresenterTranslations::urlToPresenter', 'PresenterTranslations::presenterToUrl');
Samozřejmě můžeš udělat to, že si tam dáš napojení na databázi a budeš tahat pouze to, co opravdu potřebuješ :)
Editoval HosipLan (13. 2. 2011 20:38)
- Dimitry
- Člen | 11
HosipLan napsal(a):
…
To s tím forward presenterem trochu nechápu. Možná jsem to špatně popsal. Jde mi to, že mám na stránce dvě vlaječky, které mění jazyk aktuální strany. Ale co když zobrazovaná strana v češtině nemá svou anglickou variantu v databázi? Jaký odkaz se má vygenerovat?
Zatím jsem to vyřešil poněkud ošklivě v metodě idToUri:
<?php
if (!isset($cache[$lang][$id])) {
// Pokud stale neznam id, pak strana neexistuje.
return 'error';
}
?>
Díky to mu se vygeneruje odkaz „/en/error“ a spadne to do error presenteru. Jde to dělat nějak chytřeji? Když to ta routa odmítne přes „return NULL;“ tak se mi odkaz zvýrazňuje rudě, když vypnu varování nevalidních linků, tak se z toho udělá jen „#“, což může být pro uživatele matoucí.
Editoval Dimitry (15. 2. 2011 22:01)
- Dimitry
- Člen | 11
Chtěl bych se ještě zeptat, zda by se to dalo rozšířit tak, aby to dokázalo překládat i názvy modulů. Název modulu mi slouží jako takový „prefix“ v url.
Zkoušel jsem to všelijak přiohnout, ale název modulu se mi pak vždycky přilepí k názvu presenteru a nedaří se mi je překládat odděleně, ani společně (je to alergické na vracené lomítko).
Jde mi o to, že mám UserModule a chtěl bych, aby měl adresy:
/cs/uzivatel/prihlasit
/cs/uzivatel/registrace
/cs/uzivatel/profil
/en/user/login
/en/user/registration
/en/user/profile
Překládání presenteru funguje, ale jak překládat ten modul? Předem děkuji.
Editoval Dimitry (20. 2. 2011 23:29)
- newPOPE
- Člen | 648
Riesim to (v sucastnosti) nejak takto (mozno ti to pomoze):
bootstrap.php
<?php
$router[] = $frontRouter = new MultiRouter('Front');
$moduleAliasTable = new AliasTable(AliasTable::MODULES);
Route::setStyleProperty('module', Route::FILTER_TABLE, (array) $moduleAliasTable);
$frontRouter[] = new Route('<lang>/<module>/<presenter>/<action>/[<id>/]', array(
'lang' => NULL,
'module' => 'Home',
'presenter' => 'Default',
'action' => 'default',
'id' => NULL,
));
?>
AliasTable.php
<?php
class AliasTable {
const PRESENTERS = "presenters.ini";
const ACTIONS = "actions.ini";
const MODULES = "modules.ini";
public function __construct($configFile) {
$request = Nette\Environment::getHttpRequest();
$lang = substr($request->getUri()->getPath(), strlen($request->getUri()->getScriptPath()), 2);
$lang = $lang ? $lang : 'sk';
$ini = parse_ini_file(CONFIG_DIR . '/aliases/' . $lang . '/' . $configFile);
foreach ($ini as $key => $value) {
$this->$key = $value;
}
}
}
?>
struktura adresarov
<?php
/app
/config
/aliases
/sk
actions.ini
presenters.ini
modules.ini
/en
...
?>
modules.ini
<?php
;
; module aliases
;
pouzivatel = User
ponuka = Category
objednavka = Order
?>
- Dimitry
- Člen | 11
Bohužel si nemyslím, že to je právě to, co potřebuji. Ty používáš ty překladové tabulky – ty jsou sice fajn, ale nebudou mi fungovat korektně pro vícejazyčné odkazy. Tj. jsem na české stránce a chci tam umístit odkaz na anglickou stránku – pak mi ta překladová tabulky vygeneruje chybně odkaz, protože bude stále pracovat v češtině.
Mě spíš jde o spojení s tím SmarterRoute. Včera jsem si s tím ještě hrál a zjistil jsem, že když nastavím do routy ‚module‘ ⇒ ‚User‘, tak to začne fungovat, jenže nedaří se mi to zkřížit s tím, když používám MultiRouter(‚User‘). Musím pak využívat MultiRouter, který není svázaný s modulem, ale to mi pak ta routa začne chytat i požadavky, které do ní nepatří a které mají spadnout do následujících route.
- Filip Procházka
- Moderator | 4668
To je proto, že když použiješ modul v MultiRoute
, tak se ti
pak do Route
nedostane. Ukaž jak to máš teď napsane.
- Dimitry
- Člen | 11
K tomu stejnému jsem dospěl také. Bohužel nevím, jak řešit, aby MultiRouter platil jen pro daný modul a zároveň ta Routa dostávala modul.
<?php
use \Nette\Application\IRouter,
\Nette\Application\MultiRouter,
\Nette\Application\Route,
\Nette\Environment,
\Nette\Application\BadRequestException,
\Nette\Application\PresenterRequest;
class UserModule implements IModule {
/**
* Nastavi cesty pro modul User.
* @param string $module
* @param IRouter $router
*/
public function setupRoutes($module, IRouter $router) {
$langs = Environment::getVariable('lang');
// Naroutovani frontendu modulu.
$router[] = $moduleRouter = new MultiRouter();
$route = new SmartRoute('[<lang>/]<module>/<presenter>/', array(
'lang' => $langs[0],
'module' => $module,
'presenter' => 'Default',
'action' => 'default',
));
$route->addFilter('module', 'Translator::urlToModule', 'Translator::moduleToUrl');
$route->addFilter('presenter', 'Translator::urlToPresenter', 'Translator::presenterToUrl');
$moduleRouter[] = $route;
// Vrati se zmodifikovany router.
return $router;
}
}
?>
Takhle to funguje, aby to začalo to module filtrovat. Problém je, že mi tahle routa zachytí v podstatě všechno a nepokračuje dál. Původně jsem to $module neměl v té routě, ale v konstruktoru MultiRouteru.
Když tam místo toho <module> dám do masky natvrdo „user“, tak se mi to zase nebude překládat v url. A mě jde právě o to, aby to bylo celé multijazyčné.
Je to vůbec správný přístup snažit se, aby každý modul se zaváděl sám? Uvažoval jsem nad tím, jak to udělat tak, aby mi to pokrylo pár route, jenže já chci mít maximální kontrolu pro podobu route jednolivých modulů a hlavně mít po každý modul pak například jiné filtrování id. Tady to ještě není dopsané, ale pak zde ještě bude routa vedoucí do submodulu Admin. Mám to koncipované tak, že aplikace se skládá z modulů, které zavádějí sebe a zároveň zavádějí svůj submodule „Admin“ pro svou administraci.
- Filip Procházka
- Moderator | 4668
Na to mám jednoduchou odpověď :) necpat do MultiRoute
moduly,
kdo to vymyslel takovou blbost teda nevim, sou s tim akorat problemy (nebo jsem
nepochopil na co je to dobre) :D :P
use \Nette\Application\IRouter,
\Nette\Application\MultiRouter,
\Nette\Application\Route,
\Nette\Environment,
\Nette\Application\BadRequestException,
\Nette\Application\PresenterRequest;
class UserModule implements IModule
{
public function setupRoutes($module, IRouter $router)
{
$langs = Environment::getVariable('lang');
// Naroutovani frontendu modulu.
$router[] = $route = new SmartRoute('[<lang>/]<module>/<presenter>/', array(
'lang' => reset($langs),
'module' => array(
Route::VALUE => $module,
Route::FILTER_IN => function($param) use ($module) {
// pokud nebude modul povolený, tak routa nematchne
if ($param !== $module) return NULL;
return $param;
}
),
'presenter' => 'Default',
'action' => 'default',
));
$route->addFilter('module', 'Translator::urlToModule', 'Translator::moduleToUrl');
$route->addFilter('presenter', 'Translator::urlToPresenter', 'Translator::presenterToUrl');
}
}
- Dimitry
- Člen | 11
Co jsem četl, tak právě MultiRouter by měl zajišťovat čistě routování právě jen pro daný modul.
Zkoušel jsem tohle řešení, jenže problém je, že když ta SmartRoute provede překlad na češtinu, tak ten FILTER_IN to začne odmítat, protože v $param namísto „user“ dostane „uzivatel“, což už se samozřejmě s názvem modulu neshoduje.
Nejlepší by asi bylo, kdyby to dokázal odmítnout přímo ten vylepšený filter. Spíše mi je divné, že to nedělá implicitně.
Editoval Dimitry (21. 2. 2011 23:17)
- Dimitry
- Člen | 11
Asi se mi toho podařilo docílit. Routování vypadá takto:
<?php
use \Nette\Application\IRouter,
\Nette\Application\MultiRouter,
\Nette\Application\Route,
\Nette\Environment,
\Nette\Application\BadRequestException,
\Nette\Application\PresenterRequest;
class UserModule implements IModule {
/**
* Nastavi cesty pro modul User.
* @param string $module
* @param IRouter $router
*/
public function setupRoutes($module, IRouter $router) {
$langs = Environment::getVariable('lang');
$router[] = $route = new SmartRoute('[<lang>/]<module>/<presenter>/', array(
'lang' => $langs[0],
'module' => $module,
'fix' => $module,
'presenter' => 'Default',
'action' => 'default',
));
$route->addFilter('module', 'Translator::urlToModule', 'Translator::moduleToUrl');
$route->addFilter('presenter', 'Translator::urlToPresenter', 'Translator::presenterToUrl');
// Vrati se zmodifikovany router.
return $router;
}
}
?>
A v samotné SmartRoute jsem zmodifikoval match a contructUrl:
<?php
/**
* @param Nette\Web\IHttpRequest $httpRequest
* @return Nette\Application\PresenterRequest|NULL
*/
public function match(Nette\Web\IHttpRequest $httpRequest) {
$appRequest = parent::match($httpRequest);
if (!$appRequest) {
return $appRequest;
}
$params = $this->doFilterParams($this->getRequestParams($appRequest), $appRequest, self::WAY_IN);
// Fixace na modul.
if (isset($params['fix']) && $params['fix'] !== $params['module']) {
return NULL;
}
if ($params) {
return $this->setRequestParams($appRequest, $params);
}
return NULL;
}
/**
* @param Nette\Application\PresenterRequest $appRequest
* @param Nette\Web\Uri $refUri
* @return string
*/
public function constructUrl(PresenterRequest $appRequest, Nette\Web\Uri $refUri) {
$paramsBefore = $this->getRequestParams($appRequest);
// Fixace na modul.
if (isset ($paramsBefore['fix']) && $paramsBefore['fix'] !== $paramsBefore['module']) {
return NULL;
}
if ($params = $this->doFilterParams($paramsBefore, $appRequest, self::WAY_OUT)) {
$appRequest = $this->setRequestParams($appRequest, $params);
return parent::constructUrl($appRequest, $refUri);
}
return NULL;
}
?>
Ten parametr fix
s sebou vždycky nese nemodifikované jméno
modulu a je-li nastaven, porovnává se s jménem modulu před/po filtru (dle
potřeby). Tím dosáhnu toho, že routa je napevno „fixována“ na
jeden modul.
- Filip Procházka
- Moderator | 4668
Opravil jsem to v https://gist.github.com/824624, ale nevyzkoušel, můžeš to zkusit? Nechce se mi rozjíždět kvůli tomu sandbox :)
- Oggy
- Člen | 306
HosipLan napsal(a):
Opravil jsem to v https://gist.github.com/824624, ale nevyzkoušel, můžeš to zkusit? Nechce se mi rozjíždět kvůli tomu sandbox :)
Funguje:-)
- Oggy
- Člen | 306
Neozkoušel jsem to teda kompletně.. jen jsem nahlédl, jestli to generuje
správné url..
ale má to problém z url dostat presenter..
<?php
public static $translations = array(
'cs' => array(
'o-nas' => 'AboutUs',
....
public static function urlToPresenter($url, PresenterRequest $request)
{
$lang = $request->params['lang'];
$table = self::$translations[$lang];
Debug::barDump($url);
if(array_key_exists($url, $table)) return $table[$url];
return NULL;
}
?>
Tam kde se url dumpuje má hodnotu ONas namísto o-nas ..
- Oggy
- Člen | 306
funguje mi to pokud pole translations vypadá takto: :-)
<?php
public static $translations = array(
'cs' => array(
'ONas' => 'AboutUs',
'NapsaliONas' => 'WroteAboutUs',
...
?>
to mě trošku zmátlo.. psal jsem to pole klasicky:
<?php
'cs' => array(
'o-nas' => 'AboutUs',
'napsali-o-nas' => 'WroteAboutUs',
?>
- Morlok
- Člen | 26
Oggy napsal(a):
Někdo tu psal, že to úspěšně používá..
pokud přidám ještě filter pro actions, přestanou mi fungovat překlady presenterů.
Neukážete prosím vaše funkční řešení?
Defaultne ma action a presenter nastavene filtre path2presenter, presenter2path …to ti tam bude robit gulas pri preklade, ja to mam nastavene takto:
<?php
$route = new FilterRoute('[<lang [a-z]{2}>/]<presenter>/<action>', array(
'presenter' => 'Default',
'action' => array(
Route::VALUE => 'default',
Route::FILTER_IN => null,
Route::FILTER_OUT => null
),
'lang' => 'cs'
));
?>
- hAssassin
- Člen | 293
Zdravim, procital sem to tady celkem detailne, ale mam dva problemy. Pouzivam
HospiLanuv FilterRoute
a je to dobra vecicka.
A ted k tem problemum:
- Potreboval bych nastavit vychozi hodnoty pro presenter a action dany route
podle jazyka. Jenze vychozi hodnoty se nastavuji uz v konstruktoru a ukladaji
se do
$metadat
a ty nemaji setter cili nejdou zmenit. Jde mi o to abych vychozi hodnoty mohl nastavit az pozdeji podle aktualniho jazyka, cili pokud bude jazykcs
aby to nastaviloUvod:hlavni
a pokud bude jazyken
tak aby to nastaviloHomepage:default
. Bohuzel se mi nedari k tomu dostat. Zkousel jsem isetStyleProperty()
aRoute::VALUE
ale to nejak nechce fungovat. Takze pokud ma nekdo nejaky reseni, budu vdecny (pokud vubec existuje). - Mam problem s moduly. Vytvori routu a jako masku predam:
admin/[<module (vycet_povolenych_modulu)>/]<presenter>/<action>/[<id>/]
Nazvy modulu bych rad pochopitelne taky prekladal. On sice preklad funguje,
ale pouze jednim smerem. Cili pokud mam modul cms
a jeho preklad je
treba sprava-obsahu
a ja do adresy natvrdo zadam
localhost/admin/sprava-obsahu/
tak to spravne zobrazi vychozi
presenter (Default
) z modulu Cms
. Problem je ze
u generovani odkazu do prislusneho modulu to generuje odkaz
localhost/admin/cms.default/
, ktery se zobrazi opet spravne, ale to
se mi nelibi. Chtel bych to mit cesky. Nejake napady jak na to jit?
P.S. u tech modulu je problem ten, ze muze byt volitelny, jelikoz napr. hlavni stranka administrace a prihlaseni je primo v modulu Admin, ostatni veci (sprava obsahu, sprava uzivatelu, apod) jsou pak v prislusnych modulech. Diky za jakykoliv navrhy a reseni…
- Aurielle
- Člen | 1281
U FilterRoute jsem narazil na problém při skládání URL, kdy se zkouší
konstrukce podle rout a definovaný filtr ve FilterRoute může změnit
parametry Nette\Application\Request
u a další filtr poté již
nematchne. Fix:
/**
* @param Nette\Application\Request $appRequest
* @param Nette\Web\Url $refUrl
* @return string
*/
public function constructUrl(Request $appRequest, Nette\Http\Url $refUrl)
{
$request = clone $appRequest;
if ($params = $this->doFilterParams($this->getRequestParams($request), self::WAY_OUT)) {
$request = $this->setRequestParams($request, $params);
$return = parent::constructUrl($request, $refUrl);
if($return !== NULL) {
$appRequest = $request;
return $return;
}
}
return NULL;
}
- hAssassin
- Člen | 293
@gmvasek > drobna chybicka tam je, radek:
if ($params = $this->doFilterParams($this->getRequestParams($request), self::WAY_OUT)) {
zmenit na:
if ($params = $this->doFilterParams($this->getRequestParams($request), $request, self::WAY_OUT)) {
Chybi tam druhy parametr, ktery musi byt Request… Ale jinak good postrech ;-)
K memu dotazu vyse, bod 2 sem se zda vyresil, ale s tim prvnim bodem si nevim co pocit, nevi nekdo jak zmenit vychozi hodnoty pro presenter a akci pozdeji? Dik.
Editoval hAssassin (21. 7. 2011 20:41)
- hAssassin
- Člen | 293
@gmvasek > tak to sorry za mystifikaci :D
@all > mam jeste jeden dotaz ohledne prekladu. jde
nejak zarucit preklad i parametru v query stringu? cili abych v anglictine
mel domena.tld/en/presenter/action/?search=1
a v
cestine domena.tld/cs/prezenter/akce/?hledat=1
? Jde mi o ten
search/hledat
. A je to vubec spravny prekladat parametry
v query? Dik
- hAssassin
- Člen | 293
@gmvasek > no bordel by to snad zpusobovat nemelo,
nebo me nenapada jak by mohlo. A jak to myslis s tou hodnotou? Ta by se ale
asi preklada az v ramci presenteru a jeho logiky a ne primo v route, ne? Tady
mi jde o to, aby napr. parametry pro filtrovani podle datumu nebyly
date_from/date_to
, ale datum_od/datum_do
coz bych sice
mohl mit, ale zase nechci motat cesky a anglicky nazvy parametru metod.
Jinak k tomu bodu 1. Treba to neni a uz sem se s tim naucil zit:-) Ale slo
mi o to, ze jako vyhozi mam Homepage:default
. Pokud to budu
prekladat, tak se automaticky bude doplnovat adresa na tvar
admin/uvod/hlavni/
pro cestinu, ale pro anglictinu bude jen
admin/
. Pokud to prekladat nebudu, tak adresa bude jen
admin/
, ale pokud to bude potreba (napr. pro zpracovani signalu) se
doplni na admin/homepage/default/?do=signal
a to se mi prave
nelibi:-) Resenim by bylo nastavit proste natvrdo do routy jako vychozi hodnoty
Uvod:hlavni
(pro cestinu) s tim ze pro jiny jazyky by se to proste
doplnovalo na plnou URL, ale nevim jestli to je uplne koser reseni. Ideal by
bylo podle jazyka nastavit vychozi hodnoty, coz vsak bohuzel asi s pouzitim
vychozi tridy Route
nejde.
- hAssassin
- Člen | 293
@gmvasek > vidis, to me vubec nenapadlo, ja totiz
preklad resim pomoci vlastniho translatoru s pouzitim toho
FilterRoute
a tam to prave doplnuje, ale ta
FILTER_TABLE
by to alespon pro ty vychozi hodnoty mohla resit…
Prave ze sem to cely chtel delat pres FILTER_TABLE
jenze ta nezna
jazyk, cili bych musel tam musel pro vsechny jazyk dat vsechny kombinace, coz
neni hezky, ale pro vychozi hodnoty by to vadit nemelo… Diky, vyzkousim a
uvidime :)