Špatná relativní cesta k souborům
- Stormwinter
- Člen | 11
Ahoj, už nějakou dobu si hraju s Nette, ale narazil jsem na problém:
Potřebuji hledat obrázky ve složce a cestu k ní mám napsanou takto:
const LOGO_IMG_DIR = '../www/design/logo_img/';
Při načtení indexu se mi obrázky načtou, jenže nastává problém, pokud zobrazím např. http://server/aktivace/id/. V tu chvíli vede cesta k obrázkům jako http://server/…/www/design/…
Hledal jsem tady na foru ale nechápu jak mám nastavit tu basedir jako konstantu atd.
Abych přesně popsal oč jde, Potřebuju hrábnout do složky, najít všechny očíslované soubory, zjistit maximální hodnotu v názvech souborů a poté náhodně zobrazit jeden ze souborů tak aby se to dělo na každé zobrazené stránce.
Předem díky za pomoc :)
- Stormwinter
- Člen | 11
Díky, s __DIR__
jsem si hrál, ale až po nakopnutí tebou mě
napadlo si s tím vytvořit konstantu v index.php :)
- GEpic
- Člen | 566
Tak, na práci se soubory je nejlepší udělat službu, tu zaregistrovat
v config.neon a té předávat v konstruktoru cestu zaregistrovanou třeba
v bootstrap.php. Služba poté bude pracovat se všemi soubory
a bude vždy jisté, že cesty budou správně. Takhle volat konsantu
__DIR__
na více místech aplikace v jiných složkách, to je
potom za trest řešit chyby. :)
Např takto – bootstrap.php
(pokud ho máš ve složce
/app/bootstrap.php
)
# klasicky mezi
$configurator = new Nette\Configurator;
#---- rest of code
# treba wwwDir takto
$configurator->addParameters([
"wwwDir" => str_replace("app", "www", __DIR__)
]);
#---- rest of code
#a toto
$container = $configurator->createContainer();
A pak v config.neon
services:
- App\Service\FileManager(%wwwDir%)
No a služba může vypadat například takto:
class FileManager # samozřejmě pozor na namespace
{
/** @var string $wwwDir */
protected $wwwDir;
public function __construct($wwwDir)
{
$this->wwwDir = $wwwDir;
}
public function getImages()
{
$images = [];
foreach (Finder::findFiles('*.jpg')->in($this->wwwDir . DIRECTORY_SEPARATOR . "images") as $key => $file) {
$images[$key] = $file;
}
return $images;
}
}
A poté presenter (když už to píšu, tak se vším všudy)
class GalleryPresenter extends BasePresenter
{
/**
* @var FileManager
* @inject
*/
public $fileManager;
public function renderDefault()
{
$this->template->images = $this->fileManager->getImages();
}
}
A latéčko už asi netřeba, tam můžeš využít
proměnnou {$basePath}
Editoval GEpic (28. 5. 2016 0:00)
- Aurielle
- Člen | 1281
@GEpic: toto prosím nikdy nedělej. Lepší je odvodit cestu přímo od bootstrapu.
$configurator->addParameters([
"wwwDir" => str_replace("app", "www", __DIR__)
]);
edit: parametry můžeš definovat i v config.neon, a to, cos popsal, není služba, ale právě jen to předání parametru.
Editoval Aurielle (28. 5. 2016 16:38)
- GEpic
- Člen | 566
Aurielle napsal(a):
@GEpic: toto prosím nikdy nedělej. Lepší je odvodit cestu přímo od bootstrapu.
$configurator->addParameters([ "wwwDir" => str_replace("app", "www", __DIR__) ]);
edit: parametry můžeš definovat i v config.neon, a to, cos popsal, není služba, ale právě jen to předání parametru.
Však ano, předání parametru do služby, kterou si můžeš pomocí DI injectovat všude, ne? Kdybys mi ukázal, jak definovat parametry přímo v configu, byl bych ti taky vděčný.
A navíc pokud definuji v bootstrapu parameter, tak __DIR__ je přesně adresář bootstrapu.
Editoval GEpic (29. 5. 2016 11:48)
- Aurielle
- Člen | 1281
@GEpic: třeba takto:
parameters:
wwwDir: %appDir%/../www
str_replace na cestu je špatný, minimálně z toho důvodu, že se ti
v cestě jinde může vyskytovat „app“ a pak ti vznikne neexistující
blbost. Nebo máš úplně jinou adresářovou strukturu. Analogicky podle
příkladu výše bys odvodil cestu v bootstrapu
(__DIR__ . '/../www'
).
A předávání parametrů skrz konstruktor je dobré, ale jen do momentu,
než potřebuješ zároveň přes konstruktor autowirovat služby. Proto je
lepší toto řešit setterem v setup
sekci definice dané služby,
nebo si udělat nějaký value object, který bude hodnotu držet, a bude se už
autowirovat sám (nejlepší řešení).
Editoval Aurielle (29. 5. 2016 12:20)
- GEpic
- Člen | 566
Aurielle napsal(a):
@GEpic: třeba takto:
parameters: wwwDir: %appDir%/../www
str_replace na cestu je špatný, minimálně z toho důvodu, že se ti v cestě jinde může vyskytovat „app“ a pak ti vznikne neexistující blbost. Nebo máš úplně jinou adresářovou strukturu. Analogicky podle příkladu výše bys odvodil cestu v bootstrapu (
__DIR__ . '/../www'
).A předávání parametrů skrz konstruktor je dobré, ale jen do momentu, než potřebuješ zároveň přes konstruktor autowirovat služby. Proto je lepší toto řešit setterem v
setup
sekci definice dané služby, nebo si udělat nějaký value object, který bude hodnotu držet, a bude se už autowirovat sám (nejlepší řešení).
Já samozřejmě neuváděl PŘESNÝ příklad toho jak tu cestu definovat,
jenom způsob, jakým to jde udělat. Samozřejmě, každý už si to pak
navolí podle svého. Ale jinak chápu, v cestě se může ještě vyskytovat
někde ještě adresář app
jednou, ale postoval jsem to doopravdy
jen jako ukázku toho, jak jsem to použil na jednom projektu já.
A k druhé části tvé odpovědi, ano, opět záleží na tom, co od služby očekáváš a jak s ní chceš nakládat do budoucna. Samozřejmě prevence je lepší, než posléze refactorovat půlku projektu, ale pokud si autor tohoto topicu přeje tahat pouze obrázky, tak si myslím, že to jako začátek stačí. Nemá cenu podle mě zbytečně komplikovat odpověď na relativně jednoduchou otázku složitým případem nabušené služby.
PS: Díky za ukázku toho configu :)
PS2: „/“ v cestách také nemusí být vždy úplně správně, ale to se stává pouze okrajově.
Editoval GEpic (29. 5. 2016 12:58)