Nekonzistentí výstup $basePath (Presenter vs. template)
- MartinitCZ
- Člen | 580
V případě, že člověk potřebuje zjistit basePath, tak zavolá:
V presenteru:
$this->context->httpRequest->url->basePath
V templatě:
{$basePath}
Zde nastane problém v podobě výstupu, který je rozdílný:
V presenteru:
"/"
V templatě:
""
Možná to místní Guru nebudou považovat za chybu (v podstatě to asi ani není), ale minimálně to docela mate. Člověk si stále musí dávat pozor, že v presenteru nesmí za basePath psát lomeno, ale v templatě naopak ano.
- Tomáš Votruba
- Moderator | 1114
V presenteru je lepší používat přímo konstantu WWW_DIR
(APP_DIR aj.), o které víš, kam vede.
$basePath
je určena pro detekci přesné adresy, kterou do té
doby obvykle neznáš, např. pro přidání css souboru v šabloně.
To by ti mohlo vyřešit tento nesoulad.
- Tomáš Votruba
- Moderator | 1114
@nanuqcz: Chtěl jsem tím říct, že v presenteru je lepší provádět takové operace, které vyžadují pouze WWW_DIR. S věcmi vyžadujícími $basePath do šablony. Osobně mi to tak přijde čistší. Nechtěl jsem říct, že jsou stejné.
- MartinitCZ
- Člen | 580
Schmutzka: Ale v případě helperu, který cachuje obrázky a vrací jejich cestu (pro zobrazení na stránce), potřebuji basepath, nikoli WWW_DIR. V podstatě je to úplně stejné, jak si popsal to css.
nanuqcz: Přesně
- LeonardoCA
- Člen | 296
A co použít relativní cesty?
potřebuji vidět příklad, ale myslím si, že na webu se dá
téměř vždy bez $basePath obejít.
jediný případ kdy je nutné používat $basePath je
pro generování url tam kde není od čeho relativní cestu stavět,
tj. do emailu nebo iframe
v tom případě vyznikne původní „problém“, ale pokud se
zkombinuje relativní url s $basePath, tak to bude taky
fungovat :-)
Nejlepší způsob jak otestovat, jestli se url vytváří správným způsobem, je vyzkoušet funkčnost projektu v těchto variantách:
- www.projekt.tst
- www.nejaka-domena.tst/demo/projekt/
- projekt.nejaka-domena.tst
Web musí na vlastní doméně i v podadresáři libovolné domény fungovat bez jediného zásahu do kódu a css. Jediný zásah potřebný zásah bývá do .htaccess pro nastavení RewriteBase.
Editoval LeonardoCA (21. 6. 2012 15:22)
- Milo
- Nette Core | 1283
Jak se bez $basePath
obejdete? Představte si, že aplikace
běží na http://host.name/user/app
. Pokud v layoutu uvedu
relativní cestu src="css/main.css"
bez $basePath
, tak
jakmile prohlížeč načte url
http://host.name/user/app/presenter/action/id/
tak se mi styl
nenačte. S $basePath
to bude fungovat vždy, protože se
vygeneruje absolutní /user/app/css/main.css
.
- Milo
- Nette Core | 1283
@martinit: Proč to je tak jak to je, nevím, ale můžeš si přeci udělat v BasePresenteru metodu
public function getBasePath()
{
return rtrim($this->context->httpRequest->url->basePath, '/');
}
// a používat
$presenter->basePath;
Mě osobně by se ješte líbil template helper toUrl
který by
cestu ve filesystemu převedl na URL (pokud by to šlo).
Editoval Milo (21. 6. 2012 13:57)
- LeonardoCA
- Člen | 296
Milo napsal(a):
Jak se bez
$basePath
obejdete? Představte si, že aplikace běží nahttp://host.name/user/app
. Pokud v layoutu uvedu relativní cestusrc="css/main.css"
bez$basePath
, tak jakmile prohlížeč načte urlhttp://host.name/user/app/presenter/action/id/
tak se mi styl nenačte. S$basePath
to bude fungovat vždy, protože se vygeneruje absolutní/user/app/css/main.css
.
src=„../css/main.css“
To je právě asi ta finta, kterou málokdo používá, že lze
používat „..“ v cestách na obrázky, css, js. basePath zná
prohlížeč …
A to nejde použít jen tam kde jsou potřeba celé url včetně názvu
domény.
Editováno: omlouvám se za mystifikaci, tady musí být použito basepath,
myslel jsem něco jíného. Až zjistím jak se tu přeškrkavá, tak
neplatící přeškrnu..
Editoval LeonardoCA (21. 6. 2012 15:23)
- MartinitCZ
- Člen | 580
Milo napsal(a):
@martinit: Proč to je tak jak to je, nevím, ale můžeš si přeci udělat v BasePresenteru metodu
public function getBasePath() { return rtrim($this->context->httpRequest->url->basePath, '/'); } // a používat $presenter->basePath;
Mě osobně by se ješte líbil template helper
toUrl
který by cestu ve filesystemu převedl na URL (pokud by to šlo).
Právě proto jsem to nahlásil a rád bych to nějak kloudně vyřešil,
nejlépu úpravou.
Jak jsi tu sám zmínil $basePath je potřeba, tak by bylo dobré, kdyby byl
výstup v obou případech stejný!
Já používám toto, jelikož do případnéch helperů předávám kontext, ale presenter ne.
$this->context->parameters["basePath"] = preg_replace("#https?://[^/]+#A", "", rtrim($this->context->httpRequest->url->baseUrl, "/"));
Vytvořit helper toUrl
je to nejmenší, ale nebude to přímo
v Nette, což ti asi nevyhovuje.
- MartinitCZ
- Člen | 580
22: Prosimtě, udělaš to ty? Případně někdo jiný? Github nemám, takže asi ani pull request neuměl udělat. ;)
Díky.
- Aurielle
- Člen | 1281
@KingKoca: až na to, že zmíněné chování je ve frameworku již
hodně dlouho (víc jak rok? Každopádně určitě od verze 0.9.x) a dosud si
na něj nikdo nestěžoval. Dříve se používala proměnná
$baseUri
a právě z toho důvodu, že obsahovala lomítko, se
přidala i $basePath
. A z $baseUri
se pak stala
tuším absolutní adresa.
- Filip Procházka
- Moderator | 4668
Funguje to správně. Při práci v šabloně jsou jiné požadavky, než při práci v presenteru/modelu.
- Tomáš Votruba
- Moderator | 1114
HosipLan napsal(a):
Funguje to správně. Při práci v šabloně jsou jiné požadavky, než při práci v presenteru/modelu.
Konkrétní příklad by lépe podpořil/osvětlil situaci, třeba je to logické. Dáš?
- KingKoca
- Člen | 25
@gmvasek: to je to same jako veta „je tam chyba hodne dlouho.“ Treba o Windows se to rika casto :) Ikdyz jsou zde historicke duvody zrejme, moc me nezajimaji. Treba ja zacal pouzivat Nette az od verze 2.0 a tato nekonzistentnost me nemile prekvapila a sebrala mi nekolik minut diky tomu, ze jsem musel najit a opravit chybu – tedy opravit standardni chovani.
@HosipLan: A to ja mam zas naopak pozadavky na $baseUrl a $basePath stejne :) Kdyz v sablone pisu odkaz, zdroj (href=„..“, src=„..“), musim spojovat $basePath a cestu lomitkem. Kdyz v presenteru presmerovavam ($this->redirectUrl(„…“)), proc cesta najednou lomitko obsahuje? Kdyz v sablone pouzivam tag <base href>, musim tam opet dat rucne lomitko, posledni cast url bez lomitka neni soucasti „base.“ Opet zde musim myslet na to, ze v presenteru je to jinak nez v sablone.
Kazdopadne nedoufam v opravu, protoze by to rozbilo spoustu jiz hotovych projektu a mozna nez zneprijemnit zivot hromade vyvojaru spravujici stovky aplikaci, tak je lepsi zneprijemnit zivot tem, kteri sve aplikace teprve zacinaji vyvijet. Mozna kdyby to bylo v dokumentaci, mohl bych o tom vedet od zacatku.
Diky :)
- Honza Marek
- Člen | 1664
Schmutzka napsal(a):
V presenteru je lepší používat přímo konstantu WWW_DIR (APP_DIR aj.)
Pokud někde použiju takovou konstantu, můžu se rozloučit s tím, že příslušný kód půjde otestovat. V presenteru dejme tomu, ale v modelu už bych si na to netroufnul.
- KingKoca
- Člen | 25
gmvasek napsal(a):
Můžu se zeptat, proč v presenteru přesměrováváš přes redirectUrl?
Protoze nepouzivam klasickou strukturu aplikace
<module>/<presenter>/<action>. Prubeh aplikace je zavisly na
jednotlivych castech url, pouzivam vlastni Router. Nazev presenteru je prirazen
k url v databazi a jeden presenter muze spadat pod vice url adres (s ruznymi
„params“). Proto neni mozne (jednoduche?) vykonstruovat jednoznacnou url
adresu podle kodu v metode constructUrl()
v routeru. Proto
$destination
vytvarim jinak (casto se jedna o cast soucasne url,
kterou mam jiz v promenne), preskocim spoustu zbytecneho (pro mou aplikaci)
kodu a volam $this->redirectUrl()
funkci, kterou
$this->redirect()
stejne na konci vola taky.
To ale vubec nijak nesouvisi tematem. Proc je $basePath v presenteru jina nez v sablone? Mohl bych se spise ptat „je to bug nebo feature?“ Ale to bych dostal odpoved feature a nikdo by to dal neresil :) Chtel bych, aby se nad tim nekdo zamyslel..
- Filip Procházka
- Moderator | 4668
@KingKoca: Bullshit, s Nette routami uděláš všechno, používáš je špatně.
Je to feature.
- Tomáš Votruba
- Moderator | 1114
@KingKoca: Zkus napsat, co potřebuješ, v čem ti přijde Nette router nedostatečný a jak to nyní řešíš (real situation).
- KingKoca
- Člen | 25
Probuh, jak toto vsecko souvisi s tematem? Muze nekdo kvalifikovany odpovedet ohledne lomitka na konci $basePath a $baseUrl v presenteru / sablone? Proc jsou jejich hodnoty jine?
P.S.: ocenuji vsak, ze se snazite pomoci. Protoze jsem v Nette novacek, je
dost pravdepodobne, ze neco delam spatne.
Zjednodusene – mam teoreticky nekonecnou url a v jednom kroku se zpracovava
jedna cast cesty (casti se oddeluji lomitkem). Podle casti se provede nejaka
akce a prubeh te akce zavisi na nasledujici casti cesty. A takhle dal, dokud
modul nezpracuje tolik casti url, kolik modul umi.
Napr adresa galerie/chata/2010/silvestr
vede na jednu akci. na
stejnou, jako adresy: galerie
, galerie/chata
,
galerie/chata/2010
. Nebo url adresy
dalsi-galerie/subgalerie/subsubgalerie/ctvrta-uroven-galerie
.
Vsecky vedou na stejnou akci. Vystupem teto akce je seznam obrazku podle url.
Url jednotlivych galerii jsou ulozeny v databazi ve stromove strukture.
Na teoreticky nekonecnou url jsem na techto forech nasel jedinou odpoved:
vlastni router.
Generovani url adresy podle presenteru / akce nelze, protoze jak je na prikladu
videt, jedna akce muze zpracovat vice url adres. Takze generovani url probiha
jinak a nakonec se zavola redirectUrl. Je to opravdu podobne, jako s metodou
redirect. Ta generuje url na zaklade nejakych pravidel a nakonec zavola
redirectUrl. Ja generuji url take na zaklade nejakych pravidel a nakonec zavolam
redirectUrl, ale potrebuji k tomu mene kodu, je to jednodussi nez pres metodu
redirect.
A protoze nette je zname tim, ze nikomu nic nenuti, nenuti me pouzivat metodu redirect, muzu si url adresu vygenerovat jak budu chtit. Potom ale ke spravnemu presmerovani potrebuju $basePath, resp. $baseUrl. S tim by nebyl problem, kdybych necekal, ze na konci lomitko neni, jak je znamo z pouzivani v sablone. A to je cele, o co tu jde.
Editoval KingKoca (10. 7. 2012 21:10)
- Filip Procházka
- Moderator | 4668
Ano, používáš to špatně :) Dobře ti radím neobcházej to, systémové řešení je vždy lepší.
Já mám routu napsanou takto a v node můžu mít cokoliv. A pořád využívám plnou sílu Nette.
class NodeRouter extends Nette\Application\Routers\RouteList
{
/**
* @var ContentRepository\PathMap
*/
private $pathMap;
/**
* @param ContentRepository\PathMap $pathMap
*/
public function __construct(ContentRepository\PathMap $pathMap)
{
$this->pathMap = $pathMap;
$this[] = new Route('[<language [a-z]{2,3}>/][<node .*>][.<format>]?action=<action>', array(
'presenter' => 'Node',
'action' => 'default',
'language' => array(
Route::VALUE => NULL,
Route::FILTER_IN => function ($lang) {
return in_array($lang, array('cs', 'en')) ? $lang : NULL;
},
),
'node' => array(
Route::VALUE => NULL,
Route::FILTER_IN => callback($this, 'filterInNode'),
Route::FILTER_OUT => callback($this, 'filterOutNode'),
),
'format' => NULL,
));
}
/**
* @internal
* @param string $nodePath
* @return int|NULL
*/
public function filterInNode($nodePath)
{
if (is_numeric($nodePath)) {
return $nodePath;
}
return $this->pathMap->pathId(trim($nodePath, '/'));
}
/**
* @internal
* @param string $node
* @return null|string
*/
public function filterOutNode($node)
{
if (is_object($node)) {
/** @var \Kdyby\CMS\Sitemap\AbstractNode $node */
return $node->getPath() ?: NULL;
} elseif (!is_numeric($node)) {
return $node ?: NULL;
}
return $this->pathMap->absolutePath($node) ?: NULL;
}
}
Něco dalšího ke čtení
Editoval HosipLan (10. 7. 2012 23:15)
- Filip Procházka
- Moderator | 4668
Kdyby se to v šabloně jmenovalo $relativePathForStaticFiles
,
tak by tě to ani nenapadlo :)
- woytam
- Člen | 14
Jednou z možností je použít v HEAD sekci HTML příkaz pro nastavení základní URL:
<base href="{$baseUrl}/" />
- MartinitCZ
- Člen | 580
Lepší je si na to zvyknout. Pokud @httpRequest předávám do nějaké komponenty, doplnku … tak na basepath ihned hodim rtrim. Viz. Milo
- David Grudl
- Nette Core | 8218
Issue bez návrhu, jak věc bezbolestně řešit, prosím vůbec neotevírejte.
- h4kuna
- Backer | 740
Co zrušit $basePath a nahradit je makry? n:baseSrc="" a n:baseHref="" která by se zkompilovalo a vrátilo celou cestu že by basePath bylo napevno ve zkompilované šabloně?
n:baseSrc="css/screen.css" -> src="/sandbox/css/screen.css"
n:baseSrc="/css/screen.css" -> src="/sandbox/css/screen.css"
n:baseHref="//css/screen.css" -> href="http://localhost/sandbox/css/screen.css"
A udělat to tak aby bylo jedno když člověk lomítko napíše či nikoliv.
<?php
use Nette\Object;
use Nette\Http\Request;
/**
* Pathnizer
* add slash on start path and on the end remove slash
* @example
* $pathnizer->buildFs('/css/', '/screen.css'); // /css/screen.css
* $pathnizer->buildFs('/css', 'screen.css'); // /css/screen.css
* $pathnizer->buildFs('css', 'screen.css'); // /css/screen.css
* $pathnizer->buildFs('css/screen.css'); // /css/screen.css
* $pathnizer->buildFs('../css/screen.css'); // ../css/screen.css
* $pathnizer->buildFs('./css/screen.css'); // ./css/screen.css
* $pathnizer->buildFs('C:/css/screen.css'); // C:/css/screen.css
* $pathnizer->buildFs('css/screen'); // /css/screen
* $pathnizer->buildFs('css/screen/'); // /css/screen
*
* // add basePath from Request
* $pathnizer->buildUrl('/css/screen.css'); // /sandbox/www/css/screen.css
* $pathnizer->buildUrl('css/screen.css'); // /sandbox/www/css/screen.css
* $pathnizer->buildUrl('//css/screen.css'); // http://localhost/sandbox/www/css/screen.css
*
* @author h4kuna
*/
class Pathnizer extends Object {
/**
* @var bool
*/
private static $used;
/** @var Nette\Http\UrlScript */
private $url;
public function __construct(Request $request) {
$this->url = $request->getUrl();
}
/**
* @params string
* @return string
*/
public function buildUrl(/* ... */) {
$url = preg_match('~^//~', func_get_arg(0)) ? $this->url->getBaseUrl() : $this->url->getBasePath();
return $url . ltrim($this->joinPath('/', func_get_args()), '\/');
}
/**
* @params string
*/
public function buildFs(/* ... */) {
return $this->joinPath(DIRECTORY_SEPARATOR, func_get_args());
}
/**
*
* @param string $delimiter
* @param array $path
* @return string
*/
private function joinPath($delimiter, array $path) {
$outPath = NULL;
self::$used = FALSE;
foreach ($path as $p) {
if (self::isException($p)) {
$outPath = rtrim($p, '\/');
} else {
$outPath .= $delimiter . trim($p, '\/');
}
}
return $outPath;
}
/**
* @param string $path
* @return boolean
*/
private static function isException($path) {
if (self::$used) {
return FALSE;
}
self::$used = TRUE;
// windows or relative
return preg_match('~^([A-Z]:|\.{1,2})~', $path);
}
}
?>