FILTER_IN, FILTER_OUT závislý na více parametrech
- frosty22
- Člen | 373
Zdravím,
potřebuji vyřešit problém s kategoriemi/podkategoriemi a jejich routami, požadavek na URL je například:
http://kategorie.example.com/podkategorie/
Aktuálně mám routování funkční jen s kategoriemi, a to způsobem:
<?php
$categories = array(1 => "auta", ....);
new Route("//<category_id>.example.com/", array("presenter" => "Category", "action" => "category",
"category_id" => array(
Route::FILTER_OUT => function($category_id) use ($categories) { return $categories[$category_id]; },
Route::FILTER_IN => function($seo) use ($categories) { return array_search($seo, $categories); }
)));
?>
Avšak podkategorie mohou být v daných kategoriích totožné, čili bych
potřeboval zavolat onen callback FILTER_IN/FILTER_OUT i s parametrem části
URL, kategorie nejen podkategorie,
něco jako:
<?php
$categories = array(1 => "auta", ....);
$subcategories = array("auta" => array(1 => "osobní", 2 => "tanky"), "motorky" => array(...));
new Route("//<category_id>.example.com/<subcategory_id>/", array("presenter" => "Category", "action" => "category",
"category_id" => array(
Route::FILTER_OUT => function($category_id) use ($categories) { return $categories[$category_id]; },
Route::FILTER_IN => function($seo) use ($categories) { return array_search($seo, $categories); }),
"subcategory_id" => array(
// Ted ta důležitá část
Route::FILTER_OUT => function($category_id, $subcategory_id) { return $subcategories[$category_id][$subcategory_id]; },
Route::FILTER_IN => function($category, $subcategory) { return array_search($subcategories[$category],$subcategory ); }
// EOF
)
));
?>
BTW: kategorií/podkategorií bude opravdu mnoho
Děkuji za nějaké nasměrování
Editoval frosty22 (29. 7. 2011 13:47)
- frosty22
- Člen | 373
Děkuji, děkuji, už též narazil a omlouvám se za zbytečný dotaz, případně mám ještě jeden menší – je možné změnit presenter/action na základě parametru? Aktuálně mám routy:
<?php
$frontRouter[] = $filterRoute = new FilterRoute("//<category_id>.{$domain}/<subcategory_id>/", array("presenter" => "Filter", "action" => "default", "category_id" => array(
Route::FILTER_OUT => function($category_id) use ($categories) { return $categories[$category_id]; },
Route::FILTER_IN => function($seo) use ($categories) { return array_search($seo, $categories); }
)));
$filterRoute->addFilter("subcategory_id", function($seo, $request) use ($subcategories) {
if (empty($request->params['category_id'])) return null;
return array_search($seo, $subcategories[$request->params['category_id']]);
},
function($subcategory_id, $request) use ($subcategories) {
if (empty($request->params['category_id'])) return null;
return @$subcategories[$request->params['category_id'[$subcategory_id]; });
$frontRouter[] = new Route("//<category_id>.{$domain}/", array("presenter" => "Category", "action" => "category",
"category_id" => array(
Route::FILTER_OUT => function($category_id) use ($categories) { return $categories[$category_id]; },
Route::FILTER_IN => function($seo) use ($categories) { return array_search($seo, $categories); }
)));
?>
A jak je vidět, tak v případě, že existuje podkategorie chci zobrazit Filter:default, a pokud není a je pouze kategorie, tak Category:category … předpokládám, že toto asi vyřešit jednou routu nelze a musí být využity, takto dvě?
PS: onoho zavináče si nevšímat (pole je veliké a @ bude rychlejší než isset)
- Filip Procházka
- Moderator | 4668
Bolí mě z toho tvého kódu oči, opravdu :) (neříkám že je špatný, ale je strašně nepřehledný)
Takže ti k tomu řeknu toto: Objekt
Nette\Application\Request $request
, který se předává filtrům,
se nikde neklonuje. Pokud ho ve filtru změníš, předá se změněný do
Application
a ta ho zpracuje.
$route->addFilter('id', function ($param, $request) {
$request->setPresenterName('Homepage:default');
});
PS: napadá mě, že bych to mohl přepsat na Nette 2 :)
- frosty22
- Člen | 373
Ještě by mě zajímalo, zda-li jde na základě parametru přeskočit routu, raději na příkladě:
Mám-li routu:
<?php
new FilterRoute("//<category_id>.{$domain}/<subcategory_id>[/<advert_type_id>][/<locality_id>]/", ...);
?>
následně přidám nějaký filtr:
<?php
$filterRoute->addFilter("subcategory_id", function($seo, $request) use ($subcategories) {
if (empty($request->params['category_id'])) return null;
return array_search($seo, $subcategories[$request->params['category_id']]);
},
function($subcategory_id, $request) use ($subcategories) { ... });
?>
avšak v případě, že subcategory_id nebude nalezeno, tak tato routa už
je vybraná a nepřeskočí se ..
jedno řešení, které funguje je pomocí masky:
<?php
new FilterRoute("//<category_id>.{$domain}/<subcategory_id kone|psi|kocky>[/<advert_type_id>][/<locality_id>]/", ...);
?>
avšak jelikož je těchto závislých položek na stovky, tak to není jistě ideální zde vypisovat, zároveň i mám několik dalších rout, podobně složitých, kde potřebuji vyřešit tuto problematiku.
Děkuji za nějaký nápad.
- Filip Procházka
- Moderator | 4668
To je divné, měl jsem za to, že přeskakování rout funguje. Zkus to pořádně prostudovat, po zběžné kontrole si troufám tvrdit, že můj router funguje dle očekávání.
- frosty22
- Člen | 373
Tady jde předpokládám o obecnou vlastnost, nikoliv o chybu, při matchování rout, záleží pouze na masce, nikoliv na tom, co vrátí callback filteru, či pokud vrátí null tak se přeskočí? Samozřejmě to zkusím, jen to mám na větší úpravy (vyřešil jsem to nakonec jinak).
Pokud mám následující routu:
<?php
$a = new FilterRoute("<subcategory>", array("presenter" => "Foo", "action" => "Bar"));
$a->addFilter("subcategory", function($a){ return $a == "auta" ? 1 : null });
?>
Tak URL:
http://www.example.com/auta/
→ odpovídá masce routě, a parametr bude subcategory = 1
,ale například url:
http://www.example.com/tanky/
→ odpovídá masce routě, a parametr bude subcategory = false,
A NEBO se routa přeskočí?
Pokud jsem nedělal chybu, tak se nepřeskočila právě ,že ale pouze byla hodnota parametru subcategory = false, fungovalo to snad jen, když jsem upravil onu masku:
<?php
$a = new FilterRoute("<subcategory auta>", ...);
?>
Zkusím to tedy ještě takto na jednoduchém příkladě, to jsem netestoval, předtím jsem měl rozsáhlejší routování, takže pokud jsem měl jinde chybu, tak je možné, že se to takto chovalo, ale myslím, že nikoliv. Ale jak říkám, asi to není chyba, nýbrž vlastnost.
- frosty22
- Člen | 373
Tak již jsem zjistil, kde jsem měl původně problém, mám-li routu s více volitelnými parametry, např:
[/<locality_id>][/<advert_type_id>][/subtype_id]
tak vynechám-li některý z posledních elementů, např subtype:
www.example.com/praha/poptavka
potom je to v Ok a funguje, ale vynechám-li např. lokalitu, např:
pak se onomu FILTER_IN předá u locality_id řetězec poptavka, který samozřejmě vrátí null, ale již ho nezkusí dál do dalších parametrů praha, což sice akceptuje onu routu, ale ignoruje mi tento parametr
Lze nějakým způsobem docílit tohoto chování? Aby v případě volitelného parametru zkusil zda neodpovídá další?
Děkuji moc za pomoc
- Filip Procházka
- Moderator | 4668
Jedině patterny, nebo výčet přímo v routě. Pomocí filtrů to nejspíše nepůjde.