Špatná relativní cesta k souborům

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Stormwinter
Člen | 11
+
0
-

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 :)

Aurielle
Člen | 1281
+
+2
-

Použij konstantu __DIR__, z ní pak můžeš odvozovat další cesty.

Stormwinter
Člen | 11
+
0
-

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 :)

CZechBoY
Člen | 3608
+
0
-

Lepsi by bylo zaregistrovat tu konstantu v konfiguraku. Bud pomoci ConstantExtension nebo do parametru.

GEpic
Člen | 566
+
0
-

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
+
+1
-

@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
+
0
-

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
+
+2
-

@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
+
0
-

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)