Potřebujete spouštět různé úlohy z příkazové řádky, ve kterých je třeba tvořit url adresy nadefinované routami, a nevíte jak na to? Čtěte dále...
Problém
Jak docílím routování na správné presentery a akce v CLI módu (příkazová řádka) stejně jako u HTTP (url adresa), abych nemusel psát url adresy "natvrdo" a těžce vypocené routy tak nepřišly vniveč?
Nejjednoduší je problém vysvětlit na nějakém příkladě:
Řekněme že máme nějaký cron (úloha běžící na pozadí), který odesílá emaily uživatelům s odkazem na stránku přihlášení.
Dále máme routy pro HTTP požadavky tvořené Nette\Application\Routers\Route, které popisují jak má vypadat url adresa pro nějakou akci.
Náš příklad obsahuje tři akce. Dvě pro HTTP požadavek a jednu pro CLI požadavek.
Jednoduchý Presenter obsluhující tyto tři akce by mohl vypadat následovně:
use Nette\Application\Responses\TextResponse,
Nette\Security\AuthenticationException;
class DefaultPresenter extends BasePresenter
{
public function renderDefault()
{
$source = '<h1>Úvodní stránka</h1><a href="' . $this->link('login') . '">Přihlášení</a>';$
$this->sendResponse(new TextResponse($source));
}
public function renderLogin()
{
$source = '<h1>Přihlášení</h1>';
$this->sendResponse(new TextResponse($source));
}
public function actionCron()
{
if (!$this->getContext()->params['consoleMode']) {
throw new AuthenticationException;
}
$link = $this->link('//login');
// odeslani napr. mailu s linkem
echo $link;
$this->terminate();
}
}
Routy by pak mohly vypadat takto:
use Nette\Application\Routers\Route,
Nette\Application\Routers\CliRouter;
if ($container->params['consoleMode']) {
$application->allowedMethods = FALSE;
$router[] = new CliRouter('Default:default');
} else {
$router[] = new Route('index.php', 'Default:default', Route::ONE_WAY);
$router[] = new Route('prihlaseni', 'Default:login');
$router[] = new Route('<presenter>/<action>[/<id>]', 'Default:default');
}
CliRouter definovaný výše mi nefungoval, následující řešení ano.
(MartyIX k 4.10.2011)
$this[] = new CliRouter(array("action"=>'Default:default'));
O routování HTTP požadavků se nám postará Nette, které zjistí na jaké doméně je akce volána, jaký je použit protokol, port, atp.
Problém ale je, že v režimu příkazové řádky HTTP požadavek neexistuje, tudíž Nette nemá jak zjistit doménu, protokol, apod.
Řešení
Řešení je velmi jednoduché. Je potřeba "podstrčit" Nette vlastní nadefinovaný objekt reprezentující HTTP požadavek.
Nette s ním pak pracuje jako by si ho vytvořil sám ;-).
Díky tomu že Nette používá k získaní objektu [api:Nette\Http\Request] službu, k jejiž inicializaci je použita továrna, není nic jednoduššího než říct Nette:
"Pro vytvoření Http\Request nevolej svou továrnu, ale volej mou lepší továrnu :-)"
A vzhledem k tomu, že další text by byl zbytečný, tak zde je upravený bootstrap.php, který se o vše postará:
use Nette\Diagnostics\Debugger,
Nette\Utils\Strings,
Nette\Application\Routers\Route,
Nette\Application\Routers\CliRouter,
Nette\Application\Routers\SimpleRouter,
Nette\Http\Url,
Nette\Http\UrlScript,
Nette\Http;
// Load Nette Framework
$params['libsDir'] = __DIR__ . '/../libs';
require $params['libsDir'] . '/Nette/loader.php';
// Enable Nette Debugger for error visualisation & logging
Debugger::$logDirectory = __DIR__ . '/../log';
Debugger::$strictMode = TRUE;
Debugger::enable();
// Load configuration from config.neon file
$configurator = new Nette\Configurator;
$configurator->container->params += $params;
$configurator->container->params['tempDir'] = __DIR__ . '/../temp';
$container = $configurator->loadConfig(__DIR__ . '/config.neon');
// Registrace vlastni tovarny na vytvareni 'Nette\Http\IRequest'.
if ($container->params['consoleMode']) {
$container->removeService('httpRequest');
$container->addService('httpRequest', function() {
// Podle potreby muzeme pouzit nastaveni z configu nebo vzit z parametru prikazove radky, aj.
$uri = new UrlScript;
$uri->scheme = 'http';
$uri->port = Url::$defaultPorts['http'];
$uri->host = 'example.com';
$uri->path = '/';
$uri->canonicalize();
$uri->path = Strings::fixEncoding($uri->path);
$uri->scriptPath = '/';
return new Http\Request($uri, array(), array(), array(), array(), array(), 'GET', null, null);
});
}
// Init application
$application = $container->application;
// Setup router
$router = $container->router;
if ($container->params['consoleMode']) {
$application->allowedMethods = FALSE;
$router[] = new CliRouter('Default:default');
} else {
$router[] = new Route('index.php', 'Default:default', Route::ONE_WAY);
$router[] = new Route('prihlaseni', 'Default:login');
$router[] = new Route('<presenter>/<action>[/<id>]', 'Default:default');
}
// Configure and run the application!
$application = $container->application;
//$application->catchExceptions = TRUE;
$application->errorPresenter = 'Error';
$application->run();
Potřebujete spouštět různé úlohy z příkazové řádky, ve kterých je třeba tvořit url adresy nadefinované routami, a nevíte jak na to? Čtěte dále...
Problém
Jak docílím routování na správné presentery a akce v CLI módu (příkazová řádka) stejně jako u HTTP (url adresa), abych nemusel psát url adresy "natvrdo" a těžce vypocené routy tak nepřišly vniveč?
Nejjednoduší je problém vysvětlit na nějakém příkladě:
Náš příklad obsahuje tři akce. Dvě pro HTTP požadavek a jednu pro CLI požadavek.
Jednoduchý
Presenter
obsluhující tyto tři akce by mohl vypadat následovně:Routy by pak mohly vypadat takto:
CliRouter
definovaný výše mi nefungoval, následující řešení ano. (MartyIX k 4.10.2011)Přes webový prohlížeč se dostaneme k akcím:
default
->http://example.com/
login
->http://example.com/prihlaseni
Přes příkazovou řádku se dostaneme k akci:
cron
->C:\test-cli-routing\www>php index.php Default:cron
O routování HTTP požadavků se nám postará Nette, které zjistí na jaké doméně je akce volána, jaký je použit protokol, port, atp. Problém ale je, že v režimu příkazové řádky HTTP požadavek neexistuje, tudíž Nette nemá jak zjistit doménu, protokol, apod.
Řešení
Řešení je velmi jednoduché. Je potřeba "podstrčit" Nette vlastní nadefinovaný objekt reprezentující HTTP požadavek. Nette s ním pak pracuje jako by si ho vytvořil sám ;-).
Díky tomu že Nette používá k získaní objektu [api:Nette\Http\Request] službu, k jejiž inicializaci je použita továrna, není nic jednoduššího než říct Nette: "Pro vytvoření
Http\Request
nevolej svou továrnu, ale volej mou lepší továrnu :-)"A vzhledem k tomu, že další text by byl zbytečný, tak zde je upravený
bootstrap.php
, který se o vše postará: