Jak se z presenteru dostat k hodnote Configuratoru
- markoska
- Člen | 12
Predem se omlouvam za zacatecnicky dotaz, ale verte, ze se na nej uz hodinu snazim najit odpoved…
V souboru app/Bootstrap.php mam nastaveno:
$configurator->setDebugMode(true);
Jak se k teto hodnote dostat v presenteru? Potreboval bych jednu akci podminit tim, jestli aplikace bezi ve vyvojovem nebo produkcnim rezimu. Kdyz zkousim dat:
public function renderDefault(): void
{
$conf = new Nette\Bootstrap\Configurator();
if ($conf->isDebugMode() === true) {
$this->template->debug = "jo";
} else {
$this->template->debug = "ne";
}
}
Tak mi to vraci, ze ve vyvojovem rezimu nejsem.
Diky za vasi trpelivost ;)
- Marek Bartoš
- Nette Blogger | 1280
Informace o debug módu je v parametru %debugMode%
V presenteru se k hodnotě dostaneš tak, že si presenter manuálně zaregistruješ do služeb a službě parametr předáš.
services:
- App\Presenters\ExamplePresenter(%debugMode%)
namespace App\Presenters;
class ExamplePresenter extends \Nette\Application\UI\Presenter
{
private bool $debugMode;
public function __construct(bool $debugMode)
{
$this->debugMode = $debugMode;
}
public function renderDefault(): void
{
if ($this->debugMode) {
$this->template->debug = "jo";
} else {
$this->template->debug = "ne";
}
}
}
- David Grudl
- Nette Core | 8239
Úplně nejjednodušší způsob jak si cokoliv předávat z konfigu. Vytvoř si takovouto třídu:
<?php
namespace App;
class Config
{
public function __construct(...$args)
{
\Nette\Utils\Arrays::toObject($args, $this);
}
}
A teď si do konfigu (např. soubor common.neon
) předej
jakékoliv data následujícím způsobem:
services:
- App\Config(
nazevProjektu: abc
nejakaHodnota: 123
debugMode: %debugMode%
)
V proměnné debugMode
bude aktuální stav debug režimu.
No a nakonec v presenteru, kde budu chtít mít přístup k údajům,
přidám tímto způsobem proměnnou $config
.
final class HomepagePresenter extends Nette\Application\UI\Presenter
{
/** @inject */
public \App\Config $config;
Lze ji zapsat i do společného předka, ze kterého ostatní presentery dědí, a pak data budou k dispozici všude.
A data lze číst pomocí $this->config->debugMode
.
- Pavel980
- Člen | 9
@DavidGrudl postupoval jsem presne podle tve rady a ejhle chyba.
Apache/2.4.54 (Win64) OpenSSL/1.1.1p PHP/8.1.10
Nette 3.1
Cannot write to an undeclared property
App\Model\Config::$debugMode.
David Grudl napsal(a):
Úplně nejjednodušší způsob jak si cokoliv předávat z konfigu. Vytvoř si takovouto třídu:
<?php namespace App; class Config { public function __construct(...$args) { \Nette\Utils\Arrays::toObject($args, $this); } }
A teď si do konfigu (např. soubor
common.neon
) předej jakékoliv data následujícím způsobem:services: - App\Config( nazevProjektu: abc nejakaHodnota: 123 debugMode: %debugMode% )
V proměnné
debugMode
bude aktuální stav debug režimu.No a nakonec v presenteru, kde budu chtít mít přístup k údajům, přidám tímto způsobem proměnnou
$config
.final class HomepagePresenter extends Nette\Application\UI\Presenter { /** @inject */ public \App\Config $config;
Lze ji zapsat i do společného předka, ze kterého ostatní presentery dědí, a pak data budou k dispozici všude.
A data lze číst pomocí
$this->config->debugMode
.
Editoval Pavel980 (21. 10. 2022 0:11)
- Šaman
- Člen | 2667
Imho potřebuješ v té třídě Config
mít deklarované
public property $nazevProjektu
, $nejakaHodnota
a
$debugMode
.
Když koukám, co dělá ta fce toObject
, tak opravdu jen zcela
nemagicky projde pole a každou dvojici klíč a hodnota se předá do toho
objektu (v tomto případě $this
, tedy naše třída
Config
).
Obecně tohle dělá:
- vytvoříš si nějakou třídu (
Config
), ta ale musí mít nějakou možnost nastavení hodnot (v konstruktoru, nebo settery) - nastavíš jí hodnoty v neonu (v této ukázce se předávají do konstruktoru)
- a vyžádáš si ji pak v presenteru, nebo v jiné třídě pomocí DI
- a pak s ní pracuješ – ať už čteš její public property (jako v ukázce), nebo lépe třeba přes gettery
Editoval Šaman (22. 10. 2022 0:34)
- Pavel980
- Člen | 9
@Šaman dekuji za radu doufam, ze jsem te pochopil spravne:
tak pro kazdy klic musim vytvorit setter/getter.
Class Config jsem upravil takto.
<?php
class Config
{
use Nette\SmartObject;
/** @var */
public $debugMode;
public function __construct(...$args)
{
Nette\Utils\Arrays::toObject($args, $this);
}
public function getDebugMode(): bool
{
return $this->debugMode;
}
public function setDebugMode(bool $debugMode): void
{
$this->debugMode = $debugMode;
}
}
?>
Jeste bych se chtel zeptat jak jednoduse si vytahnout parametry
z bootstrap.php?
v soucasne dobe mam v BasePresenteru.
<?php
use Nette\DI\Container;
class BasePresenters extends Presenter
{
/** @var Context */
private $context;
/** @var string*/
public $nejakyParametr_1;
public function injectContext(Container $context)
{
$this->context = $context;
}
public function getContext(): Container
{
return $this->context;
}
public function startup()
{
parent::startup();
$this->nejakyParametr_1 = $this->getContext()->parameters['parametr_1'];
}
}
?>
a v bootstrapu mam
<?php
$configurator->addDynamicParameters([
'parametr_1' => $_SERVER['XXXXX'],
'parametr_2' => $_SERVER['bbbb'],
'parametr_3' => true, /* true/flase */
]);
?>
apod. Predem moc dekuji za rady ;)
Šaman napsal(a):
Imho potřebuješ v té třídě
Config
mít deklarované public property$nazevProjektu
,$nejakaHodnota
a$debugMode
.
Když koukám, co dělá ta fcetoObject
, tak opravdu jen zcela nemagicky projde pole a každou dvojici klíč a hodnota se předá do toho objektu (v tomto případě$this
, tedy naše třídaConfig
).Obecně tohle dělá:
- vytvoříš si nějakou třídu (
Config
), ta ale musí mít nějakou možnost nastavení hodnot (v konstruktoru, nebo settery)- nastavíš jí hodnoty v neonu (v této ukázce se předávají do konstruktoru)
- a vyžádáš si ji pak v presenteru, nebo v jiné třídě pomocí DI
- a pak s ní pracuješ – ať už čteš její public property (jako v ukázce), nebo lépe třeba přes gettery
- m.brecher
- Generous Backer | 873
@markoska
Já také používám $debugMode a do všech presenterů ho dostanu takto, lze použít když presentery dědí z BasePresenter-u:
# common.neon
decorator:
App\Presenters\BasePresenter:
setup:
- $debugMode = %debugMode%
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
public bool $debugMode;
.....
}
@Pavel980 tento způsob nevyžaduje settry a je asi nejjednodušší
Editoval m.brecher (22. 10. 2022 17:06)
- Šaman
- Člen | 2667
Pavel980 napsal(a):
Jeste bych se chtel zeptat jak jednoduse si vytahnout parametry z bootstrap.php?
Tím, že to v bootstrapu předáváš do configu, tak by to mělo jít
úplně stejně, jako ten debugMode
.
Jinak ten getter/setter: to je jedna z možností. Teoreticky čistější,
prakticky asi dostačuje ta public property. Btw. ty getter a setter
nepoužíváš, protože jestli používáš ten kód od Davida, tak ten to
zapisuje přímo do oné property a ty ji máš public. Getter a setter se
většinou vytvářejí k private
a protected
proměnným. To je ale obecná teorie OOP (zapouzdření).
Rozepíšu tu dvě možnosti, jedna maličko pracnější, ale průhlednější:
Pro každou proměnnou samostatnou třídu
třída:
<?php
declare(strict_types=1);
namespace App\Model\Configuration;
class TempDirProvider
{
protected string $tempDir;
public function __construct(string $tempDir)
{
$this->tempDir = $tempDir;
}
public function get(): string
{
return $this->tempDir;
}
}
config:
services:
- App\Model\Configuration\TempDirProvider(%tempDir%)
presenter:
use App\Model\Configuration\TempDirProvider;
final class FooPresenter
{
/** @inject */
public TempDirProvider $tempDirProvider;
# a pak někde v kódu
$tempDir = $this->tempDirProvider->get();
Výhoda tohoto řešení je, že už od pohledu víš, co vlastně načítáš. Presenter si řekl o třídu, která mu má říct, kde je odkládací adresář. Tu třídu jsi v configu vytvořil a předal jí i onu proměnnou. Presenter o žadném configu, ani contextu nic neví, prostě mu někdo předal třídu. Přesně podle zásad DI. Je to čisté a přehledné.
druhá možnost je mít jednu třídu pro všechny věci ze sekce configu
třída:
<?php
namespace App\Utils;
use Nette\SmartObject;
class Configuration
{
use SmartObject;
/** @var array */
protected $configuration;
/**
* @param array
*/
public function __construct($configuration)
{
$this->configuration = $configuration;
}
/**
* @param string
* @return mixed
*/
public function getParameter($name)
{
return $this->configuration[$name];
}
}
config:
parameters:
presenterConfiguration:
tempDir: %tempDir%
secretOfUniverse: 42
services:
- App\Utils\Configuration(%presenterConfiguration%)
presenter:
use App\Utils\Configuration;
class FooPresenter
{
/** @var Configuration @inject */
public $configuration;
# a pak někde v kódu
$tempDir = $this->configuration->getParameter('tempDir');
$bar = $this->configuration->getParameter('bar'); # vyhodí chybu pro neexistující prvek pole
Výhoda je, že můžeš přidávat do configu nové položky a pak je rovnou v kódu načítat beze změny třidy, která se o to stará. Nevýhoda je, že nikde není uvedené, co všechno ta třída Config, kterou presenter vyžaduje, má obsahovat. Je to méně průhledné a namísto „potřebuji adresu odkládacího adresáře“ si presenter říká „potřebuji všechny parametry které mi náleži v configu a jestli tam nebude vše potřebné, tak možná nebudu fungovat“. Asi chápeš, že pro ladění je to ta horší možnost.
P.S. Obě třídy jsem vykopíroval z funkční aplikace, ale ta druhá je pro nějakou starší verzi PHP a Nette. Uprav si to podle sebe, šlo mi spíš o pochopení že to není žádná magie. Vždy je to stejné – máš třídu pro přenos, v configu ji nakrmíš daty a presenter si ji vyžádá.
Editoval Šaman (23. 10. 2022 1:25)
- Pavel980
- Člen | 9
Vsem dekuji za pripadne rady…
Šaman napsal(a):
Pavel980 napsal(a):
Jeste bych se chtel zeptat jak jednoduse si vytahnout parametry z bootstrap.php?
Tím, že to v bootstrapu předáváš do configu, tak by to mělo jít úplně stejně, jako ten
debugMode
.Jinak ten getter/setter: to je jedna z možností. Teoreticky čistější, prakticky asi dostačuje ta public property. Btw. ty getter a setter nepoužíváš, protože jestli používáš ten kód od Davida, tak ten to zapisuje přímo do oné property a ty ji máš public. Getter a setter se většinou vytvářejí k
private
aprotected
proměnným. To je ale obecná teorie OOP (zapouzdření).
Rozepíšu tu dvě možnosti, jedna maličko pracnější, ale průhlednější:
Pro každou proměnnou samostatnou třídu
třída:
<?php declare(strict_types=1); namespace App\Model\Configuration; class TempDirProvider { protected string $tempDir; public function __construct(string $tempDir) { $this->tempDir = $tempDir; } public function get(): string { return $this->tempDir; } }
config:
services: - App\Model\Configuration\TempDirProvider(%tempDir%)
presenter:
use App\Model\Configuration\TempDirProvider; final class FooPresenter { /** @inject */ public TempDirProvider $tempDirProvider; # a pak někde v kódu $tempDir = $this->tempDirProvider->get();
Výhoda tohoto řešení je, že už od pohledu víš, co vlastně načítáš. Presenter si řekl o třídu, která mu má říct, kde je odkládací adresář. Tu třídu jsi v configu vytvořil a předal jí i onu proměnnou. Presenter o žadném configu, ani contextu nic neví, prostě mu někdo předal třídu. Přesně podle zásad DI. Je to čisté a přehledné.
druhá možnost je mít jednu třídu pro všechny věci ze sekce configu
třída:
<?php namespace App\Utils; use Nette\SmartObject; class Configuration { use SmartObject; /** @var array */ protected $configuration; /** * @param array */ public function __construct($configuration) { $this->configuration = $configuration; } /** * @param string * @return mixed */ public function getParameter($name) { return $this->configuration[$name]; } }
config:
parameters: presenterConfiguration: tempDir: %tempDir% secretOfUniverse: 42 services: - App\Utils\Configuration(%presenterConfiguration%)
presenter:
use App\Utils\Configuration; class FooPresenter { /** @var Configuration @inject */ public $configuration; # a pak někde v kódu $tempDir = $this->configuration->getParameter('tempDir'); $bar = $this->configuration->getParameter('bar'); # vyhodí chybu pro neexistující prvek pole
Výhoda je, že můžeš přidávat do configu nové položky a pak je rovnou v kódu načítat beze změny třidy, která se o to stará. Nevýhoda je, že nikde není uvedené, co všechno ta třída Config, kterou presenter vyžaduje, má obsahovat. Je to méně průhledné a namísto „potřebuji adresu odkládacího adresáře“ si presenter říká „potřebuji všechny parametry které mi náleži v configu a jestli tam nebude vše potřebné, tak možná nebudu fungovat“. Asi chápeš, že pro ladění je to ta horší možnost.
P.S. Obě třídy jsem vykopíroval z funkční aplikace, ale ta druhá je pro nějakou starší verzi PHP a Nette. Uprav si to podle sebe, šlo mi spíš o pochopení že to není žádná magie. Vždy je to stejné – máš třídu pro přenos, v configu ji nakrmíš daty a presenter si ji vyžádá.
- whatever122
- Člen | 9
No nebo nejjednodušší bude, když použiješ $GLOBALS[‚configurator‘] a nemusíš nic nastavovat v 10 jiných souborech a fungovat to bude úplně stejně.
Editoval whatever122 (9. 12. 2022 1:13)
- Marek Bartoš
- Nette Blogger | 1280
@whatever122 Nejjednodušší do okamžiku, než proměnnou na jednom místě přejmenuješ a nic ti neřekne, že jsi nějaké místo vynechal. Nebo dokud nezačneš psát automatizované testy a nemusíš zjišťovat, které globální proměnné je třeba nastavit, abys kód dostal do správného stavu. Nebo dokud nechceš analyzovat typovou správnost kódu přes phpstan/psalm. Je to velmi neprofesionální a náchylné na chyby. Kód nepíšeme komplikovaný proto že by nás to bavilo, ale proto, že se tak při zdánlivě nesouvisející změně nesesype.
- David Grudl
- Nette Core | 8239
Odpověď je také v dokumentaci, jak se v presenteru dostat k hodnotě z configu