Vlastní router a presenter z db
- BombajS
- Člen | 9
Zdravím,
snažim se napsat svůj vlastní router:
mám tabulku v databázi, kde mám uložený slug a presenter
Mělo by to fungovat asi tímto způsobem:
domain.tld/<slug>/<action>[/<id>]
s tím, že nevím jaký presenter budu chtít použít. Ve vlastním routeru
se snažím jen najít presenter k danému slugu.
SlugRouter:
<?php
namespace App;
use Model;
use Nette\Application\Routers;
use Nette\Application as App;
use Nette;
use Nette\Http;
class SlugRouter extends Routers\Route implements Nette\Application\IRouter
{
/** @var SlugManager */
private $slugManager;
public function __construct($mask, $metadata = array(), $flags = 0, Model\SlugManager $slugManager)
{
parent::__construct($mask, $metadata, $flags);
$this->slugManager = $slugManager;
}
/**
* Maps HTTP request to a Request object.
*
* @return App\Request|NULL
*/
public function match(Http\IRequest $httpRequest)
{
$request = parent::match($httpRequest);
if ($request === NULL) {
return NULL;
}
$slug = $request->getPresenterName();
$params = $request->parameters;
$row = $this->slugManager->getPresenterBySlug(strtolower($slug));
if ($row) {
$slug = $row;
$params['slug'] = $row;
}
return new App\Request($slug, $httpRequest->getMethod(), $params, $httpRequest->getPost(), $httpRequest->getFiles(), array(App\Request::SECURED => $httpRequest->isSecured()));
}
/**
* Constructs absolute URL from Request object.
*
* @return string|NULL
*/
public function constructUrl(App\Request $appRequest, Http\Url $refUrl)
{
$row = $this->slugManager->getSlugById($appRequest->getPresenterName());
$appRequest->setParameters(array('slug' => NULL));
if ($row) {
$appRequest->setPresenterName($row);
}
parent::constructUrl($appRequest, $refUrl);
//translate presenter into slug
//call parent
}
}
SlugManager:
<?php
namespace Model;
use Nette;
class SlugManager extends Nette\Object
{
/** @var Nette\Database\Context */
private $tree;
public function __construct(Nette\Database\Context $database)
{
$this->tree = $database->table("tree");
}
public function getPresenterBySlug($slug)
{
$presenter = $this->tree->where("slug", $slug)->select('presenter')->fetch();
if($presenter) {
return $presenter->presenter;
} else {
return NULL;
}
}
public function getSlugById($id)
{
$slug = $this->tree->where("presenter", $id)->select('slug')->fetch();
if($slug) {
return $slug->slug;
} else {
return NULL;
}
}
}
RouterFactory
<?php
namespace App;
use Nette\Application\Routers\Route;
use Nette;
use Nette\Application\Routers\RouteList;
use Model;
/**
* Router factory.
*/
class RouterFactory
{
/** @var SlugManager */
private $SlugManager;
public function __construct(Model\SlugManager $SlugManager)
{
$this->SlugManager = $SlugManager;
}
/**
* @return \Nette\Application\IRouter
*/
public function createRouter()
{
$router = new RouteList();
$router[] = new SlugRouter('<presenter>/<action>[/<id>]', 'Homepage:default', 0, $this->SlugManager);
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
return $router;
}
}
Celé se to chová divně, asi mám nějakou chybu v návrhu.
Nějaké nápady/připomínky? Mám to celé zahodit a udělat jinak?
Díky
- BombajS
- Člen | 9
- když zavolám <slug>/<action>, tak se mi zavolá správný presenter, ale akci bere pořád default.
- některé url se mi presměrují z <slug> na <presenter>?slug=<slug>
- generování adres mi nefunguje tak, jak by mělo
- prostě jen chci, aby se při match() zaměnil presenter za presenter nalezený v db u daného slugu a u constructUrl bych chtěl, abych mohl tvořit adresy něco jako <slug>/<action>…
Nějak jsem se do toho zamotal :D
- honos
- Člen | 109
BombajS napsal(a):
Nějak jsem se do toho zamotal :D
Jsem se do toho ted take zamotal, jak jsem to chtel rozlustit k cemu to vlastne mas..
Osobne mam na localhostu/u rozdelanou aplikaci vyuzivajici moduly kde kazdy modul definuje vlastni routy ulozenim do tabulky v db pod foreign_key k tabulce definujici modul. Ale jako router mam pouzit obycejny RouteList a funguje mi to bez problemu. Mel jsem tam rozdelany 4 moduly: galery, presentation, blog a slug ale ponechal jsem si ted tam prave pouze ten slug abych to vystiloval. Ale taky jsem mel problemy ze se volal spatny presenter. Vyresil jsem to tak ze jsem musel definovat vahu jednotlivych modulu ale i vahu jednotlivych rout v ramci mmodulu. Co se tyce routovani tak ted mi to funguje bezvadne.
P.S. Vlastne jsem zapomel jeste na to ze administraci systemu(ne modulu jako takovych), prihlaseni/registraci, ACL mam reseny jako moduly a funguje bez problemu.
EDIT: Jinak ti v tom RoterManager chybi RouteList(‚index.php‘…
Editoval honos (12. 1. 2014 11:17)
- BombajS
- Člen | 9
O co se snažím:
/vitejte
⇒ presenter = page, action = default, slug = vitejte
/domy
⇒ presenter = reality, aciton = default, slug = domy
/domy/detail/36
⇒ presenter = reality, aciton = detail, slug = domy, id = 36
tzn. že presenter nechci mít uveden v url, ale získám ho pomocí slugu z db a slug si dám jako parametr (který ale také nemá být vidět v url)
- honos
- Člen | 109
BombajS napsal(a):
tzn. že presenter nechci mít uveden v url, ale získám ho pomocí slugu z db a slug si dám jako parametr (který ale také nemá být vidět v url)
Presne tak to mam taky. Z DB se vytahnou roury k modulum setridene podle vahy a zaregistrujise do routeru. Ale pokud to chapu dobre tak si vlastne chces zrychlit aplikaci tim ze omezis pocet rout?
To ti nevim čeče. Ale mohl bych tě snad odkazat na přednasku o routovani ale popravde mi byla k nicemu, ja jsem to vyresil jak jiz jsem psal vyse..
- BombajS
- Člen | 9
honos napsal(a):
Ale pokud to chapu dobre tak si vlastne chces zrychlit aplikaci tim ze omezis pocet rout?
Jo, přesně, nechce se mi je tam všechny vypisovat, protože jich může být opravdu hodně.
jenicek napsal(a):
A musis tam mit <presenter>/<action>[/<id>]? Co misto presenteru dat slug?
To jsem zkusil, ale jak potom budu generovat url?
- Jan Suchánek
- Člen | 404
Jednoduše, vytahes podle id ci jinych parametru (kombinace presenter+id
apod.) A zahodis presenter a nechas vygenerovat url, me to tak maka s tim
rozdilem ze predavam manager pres filter metodu.
Jo a pouzivam cache taky.
- BombajS
- Člen | 9
Tak jsem to celé přepsal a funguje:
/<slug>/<action>/<id>?query
slug = router z db podle slugu zjistí, jaký presenter zavolat. V url ale
presenter nesmí být vidět!
action = zavolá akci daného presenteru
id = id…
ostatní parametry = query a také slug, který se předá do presenteru
Vytváření url:
Slug:Action, … – parametry
Router a ostatní soubory:
RouterFactory:
<?php
namespace App;
use Nette\Application\Routers\Route;
use Nette;
use Nette\Application\Routers\RouteList;
use Model;
/**
* Router factory.
*/
class RouterFactory
{
/** @var SlugManager */
private $SlugManager;
public function __construct(Model\SlugManager $SlugManager)
{
$this->SlugManager = $SlugManager;
}
/**
* @return \Nette\Application\IRouter
*/
public function createRouter()
{
$router = new RouteList();
$router[] = new SlugRouter($this->SlugManager);
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
return $router;
}
}
SlugRouter:
<?php
namespace App;
use Model;
use Nette\Application\Routers;
use Nette\Application as App;
use Nette;
use Nette\Http;
class SlugRouter extends Nette\Object implements Nette\Application\IRouter
{
/** @var SlugManager */
private $slugManager;
public function __construct(Model\SlugManager $slugManager)
{
$this->slugManager = $slugManager;
}
/**
* Maps HTTP request to a Request object.
*
* @param \Nette\Http\IRequest $httpRequest
* @throws \Nette\Application\BadRequestException
* @return App\Request|NULL
*/
public function match(Http\IRequest $httpRequest)
{
// 1) PARSE URL
$url = $httpRequest->getUrl();
$path = trim($url->path, $url->scriptPath);
if ($path !== '') {
$parts = explode($url->scriptPath, $path, 4);
//get row by slug
$row = $this->slugManager->getRowBySlug($parts[0]);
} else {
$parts = array('Homepage', 'default');
$row = $this->slugManager->getDefault();
}
if(!$row) {
throw new Nette\Application\BadRequestException('Page does not exist');
}
// 2) PARAMS
$params = array();
//action
if(isset($parts[1])) {
$action = $parts[1];
} else {
$action = 'default';
}
//id
if(isset($parts[2])) {
$id = $parts[2];
}
//params
$params['action'] = $action;
$params['page_id'] = $row->id;
if(isset($id)) {
$params['id'] = $id;
}
//$url->query into params
if($url->getQuery() !== '') {
$query = explode('&', $url->getQuery());
foreach($query as $singlequery) {
$result = explode('=', $singlequery);
$params[$result[0]] = $result[1];
}
}
// 3) GET PRESENTER
$presenter = $row->presenter;
return new App\Request($presenter, $httpRequest->getMethod(), $params, $httpRequest->getPost(), $httpRequest->getFiles(), array(App\Request::SECURED => $httpRequest->isSecured()));
}
/**
* Constructs absolute URL from Request object.
*
* @return string|NULL
*/
public function constructUrl(App\Request $appRequest, Http\Url $refUrl)
{
$params = $appRequest->getParameters();
$query = $params;
unset($query['action'], $query['page_id'], $query['slug'], $query['id']);
if(isset($params['slug'])) {
$slug = strtolower($params['slug']);
} else {
if(isset($params['page_id'])) {
$row = $this->slugManager->getSlugById($params['page_id']);
if($row) {
$slug = $row->slug;
} else {
return NULL;
}
} else {
return NULL;
}
}
$url = $refUrl->getScheme() . '://' . $refUrl->getHost() . $refUrl->getPath() . $slug;
$params = $appRequest->getParameters();
if(isset($params['action']) && $params['action'] !== 'default') {
$url .= $refUrl->getPath() . $params['action'];
}
if(isset($params['id'])) {
if($params['action'] == 'default' && isset($params['action'])) {
$url .= $refUrl->getPath() . $params['action'];
}
$url .= $refUrl->getPath() . $params['id'];
}
if(count($query)>0){
$queryString = '?';
foreach($query as $key=>$parameter){
$queryString .= $key . '=' . $parameter . '&';
}
$finalQueryString = substr($queryString,0,-1);
$url .= $finalQueryString;
}
return $url;
}
}
SlugManager:
<?php
namespace Model;
use Nette;
class SlugManager extends Nette\Object
{
/** @var Nette\Database\Context */
private $database;
public function __construct(Nette\Database\Context $database)
{
$this->database = $database;
}
public function getRowBySlug($slug)
{
$row = $this->database->table("tree")->where(array("slug" => $slug))->fetch();
if($row) {
return $row;
} else {
return NULL;
}
}
public function getDefault()
{
$row = $this->database->table("tree")->where(array("default" => 1))->fetch();
if($row) {
return $row;
} else {
return NULL;
}
}
public function getSlugById($id)
{
$row = $this->database->table("tree")->get($id);
if($row) {
return $row;
} else {
return NULL;
}
}
}
Tak třeba se bude někomu hodit
Editoval BombajS (12. 1. 2014 22:06)