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
$basePathobejdete? 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$basePathto 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
toUrlkterý 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 | 8285
 
Issue bez návrhu, jak věc bezbolestně řešit, prosím vůbec neotevírejte.

- h4kuna
 - Backer | 741
 
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);
    }
}
?>