Routy závislé na databázi
- maarlin
- Člen | 207
Protože jsem dosud nenašel nikde k dispozici žádný použitelný kus kódu na routování s databází, napsal jsem si vlastní, inspiroval jsem se přitom trochu od Davida – https://forum.nette.org/…ovnove-routy?…
Používám prefixed verzi Nette, pokud někdo používá klasickou, musí si umazat Nka. ;-)
Snad to někomu přijde vhod:
<?php
/**
* Shop route
*
* Example of use:
* <code>
* $router[] = new ShopRoute('Categories', 'list',
* '#([a-z0-9-]+)#i',
* array(
* 'table' => 'categories',
* 'column' => 'url_key'
* ));
* </code>
*
* @author Radek Simko <radek.simko@gmail.com>
*/
class ShopRoute extends NObject implements IRouter
{
private $presenterName;
private $actionName;
private $regex;
private $sqlQuery;
private $paramName;
public function __construct (
$presenterName, $actionName,
$regex, $sqlQuery, $paramName = 'id')
{
$this->presenterName = $presenterName;
$this->actionName = $actionName;
$this->regex = $regex;
$this->sqlQuery = $sqlQuery;
$this->paramName = $paramName;
}
/**
* Maps HTTP request to a NPresenterRequest object.
* @param Nette\Web\IHttpRequest
* @return PresenterRequest|NULL
*/
public function match(IHttpRequest $context)
{
$uri = preg_replace (
'#^'.$context->getUri()->scriptPath.'(.*)$#i',
'\\1', $context->getUri()->path);
preg_match($this->regex, $uri, $matches);
if (!isset ($matches[1])) {
return NULL;
}
if (dibi::fetchSingle(
'SELECT COUNT(*) FROM ['.$this->sqlQuery['table'].
'] WHERE '.$this->sqlQuery['column'].'=%s',
$matches[1]) === '0') {
return NULL;
}
$params = $context->getQuery();
$params[$this->paramName] = $matches[1];
$params['action'] = $this->actionName;
return new NPresenterRequest(
$this->presenterName,
$context->getMethod(),
$params,
$context->getPost(),
$context->getFiles(),
array('secured' => $context->isSecured())
);
}
/**
* Constructs URL path from NPresenterRequest object.
* @param Nette\Web\IHttpRequest
* @param PresenterRequest
* @return string|NULL
*/
public function constructUrl(NPresenterRequest $request, IHttpRequest $context)
{
$actualPresenter = $request->getPresenterName();
$actualParams = $request->getParams();
if ($actualPresenter != $this->presenterName &&
$actualParams['action'] != $this->actionName) {
return NULL;
}
if (!isset($actualParams[$this->paramName])) {
return NULL;
}
$uri = $context->getUri()->basePath.
rawurlencode($actualParams[$this->paramName]);
unset($actualParams[$this->paramName], $actualParams['action']);
$query = http_build_query($actualParams, '', '&');
if ($query !== '') $uri .= '?' . $query;
return $uri;
}
}
Mám v plánu napsat ještě podobnou záležitost, resp. Davidovo 2.alternativu, kdy všechny URL keys budou uložené v databázi v tabulce a u nich budou patřičné presentery a actions. Faktem je, že by to bylo znatelně rychlejší.
Editoval maarlin (9. 1. 2010 20:48)
- Panda
- Člen | 569
Ta rychlost je dost relativní. Kdyby jsi dělal v každém
match
a constructUrl
dotaz na databázi, tak tím
veškeré pokusy o rychlost spolehlivě zabiješ. A pokud by jsi to zase
načetl při prvním požadavku celé do PHP, tak tím tu rychlost u většího
počtu položek zabiješ taky.
Jinak v podstatě totéž jde udělat jednoduše například takto:
<?php
class DatabaseRoute extends Route
{
// Parametry si nadefinuješ někde v konstruktoru,
// případně si třídu podědíš a přepíšeš
protected $column = 'uri';
protected $table = 'table';
public function match(IHttpRequest $httpRequest)
{
$request = parent::match($httpRequest);
if ($request === NULL)
return NULL;
$params = $request->getParams();
if (dibi::fetchSingle(
'SELECT COUNT(*) FROM %n', $this->table,
'WHERE %n = %s', $this->column, $params[$this->column]
) == 0)
return NULL;
return $request;
}
}
?>
A routu si pak nadefinuješ například takto:
$router[] = new DatabaseRoute('<uri>/<action>', array(
'presenter' => 'Presenter',
'action' => 'action'
));
Značnou výhodou je fakt, že můžeš využívat veškeré schopnosti routování z Nette.
- Petr Mašát
- Člen | 101
Ahoj,
chci se jenom zeptat Maarlina zda nějak dořešil to že bude mít všechny
názvy presenterů s actions v databázi a u toho patřičné url?
Právě řeším něco podobného a toto by se mi docela i hodilo.
Díky moc,
pm*