Jak zavolat v prezenteru komponentu ?

- Allconius
- Člen | 317
Ahoj, koukal jsem na dokumentaci https://doc.nette.org/…n/components a vytvořil jsem si komponentu (SignComponent.php):
<?php
declare(strict_types=1);
namespace App\Presenters;
use Nette\Application\UI\Control;
class SignControl extends Control
{
public function render(): void
{
// vložíme do šablony nějaké parametry
$this->template->param = 7;
// a vykreslíme ji
$this->template->render(__DIR__ . '/SignComponent.latte');
}
}
První dotaz je jestli u komponenty je dobře „namespace App\Presenters;“? Bez toho mi to nějak vůbec prezenter neviděl. Pak mám BasePresenter.php kde chci tu komponentu načíst:
<?php
declare(strict_types=1);
namespace App\Presenters;
use Nette;
use App\Components\Sign\SignComponent;
use Tracy\Debugger;
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
protected function createComponentSign(): SignControl
{
$sign = new SignControl;
$sign->items = $this->item;
return $sign;
}
protected function startup()
{
parent::startup();
$sign = $this->getComponent('sign');
}
}
V HomePresenter.php nemám nic:
<?php
declare(strict_types=1);
namespace App\Presenters;
use Nette;
class HomePresenter extends BasePresenter
{
}
a vždycky se mi to zasekne na tom vytváření items:
Cannot read an undeclared property App\Presenters\HomePresenter::$item.
Editoval Allconius (24. 4. 2023 11:47)

- dakur
- Člen | 493
Cannot read an undeclared property App\Presenters\HomePresenter::$item.
Říká ti to, že nezná property $item v home presenteru.
V tom sice nic není, ale dědí od base presenteru, takže musíš hledat
i o úroveň výš.
V metodě createComponentSign() máš totiž
$sign->items = $this->item no a to
$this->item nemáš nikde definované, takže proto ti
to píše.

- Allconius
- Člen | 317
dakur napsal(a):
Cannot read an undeclared property App\Presenters\HomePresenter::$item.
Říká ti to, že nezná property
$itemv home presenteru. V tom sice nic není, ale dědí od base presenteru, takže musíš hledat i o úroveň výš.V metodě
createComponentSign()máš totiž$sign->items = $this->itemno a to$this->itemnemáš nikde definované, takže proto ti to píše.
No to je právě to co nechápu proč v té inicializaci komponety je v dokumentaci nějaký items:
class DefaultPresenter extends Nette\Application\UI\Presenter
{
protected function createComponentPoll(): PollControl
{
$poll = new PollControl;
$poll->items = $this->item;
return $poll;
}
}
nebo to má být jen jako příklad použití, že si do komponenty můžeš načíst nějaké prvky z presenteru ?

- dakur
- Člen | 493
Ano, je to jen příklad, jak do ní předat data. I když uznávám, že ne úplně šťastný, protože jednak je v něm překlep a druhak se to v celém článku už nikde nepoužívá, takže není ani jasné, proč to tam, co to má představovat, kde se to tam bere etc. :-) Prostě jestli to nepotřebuješ, tak ten řádek smaž.

- dakur
- Člen | 493
P.S.: na předání dat do komponenty pak viz níže: https://doc.nette.org/…n/components#…
Asi to $this->item je nějaký zapomenutý kód..

- Allconius
- Člen | 317
dakur napsal(a):
P.S.: na předání dat do komponenty pak viz níže: https://doc.nette.org/…n/components#…
Asi to
$this->itemje nějaký zapomenutý kód..
Ahoj, díky a toto tam musí být?:
$sign = $this->getComponent('sign');
mě se ta komponenta načte i bez toho jen tím:
createComponentSign()

- m.brecher
- Generous Backer | 911
@Allconius
Ahoj, díky a toto tam musí být?:
$sign = $this->getComponent('sign');
Záleží na tom, jestli proměnnou $sign někde dál použiješ, pokud ne tak je to zbytečné, komponenta se zavolá automaticky při vykreslování/signálu.
První dotaz je jestli u komponenty je dobře „namespace App\Presenters;“?
Dal bych to do jiného namespace než presenter, ale potom když někde třídu komponenty použiješ, musíš buďto a) napsat jméno třídy včetně namespace, nebo b) importovat třídu pomocí use – třeba use App\Components\Sign – asi proto ti to nefungovalo v presenterech.

- dakur
- Člen | 493
Allconius napsal(a):
Ahoj, díky a toto tam musí být?:
$sign = $this->getComponent('sign');mě se ta komponenta načte i bez toho jen tím:
createComponentSign()
Nene, komponenty se instanciují automaticky ve chvíli, kdy je použiješ v šabloně, takže pokud nepotřebuješ komponentu použít i v presenteru, není to třeba.

- Allconius
- Člen | 317
m.brecher napsal(a):
@Allconius
Ahoj, díky a toto tam musí být?:
$sign = $this->getComponent('sign');Záleží na tom, jestli proměnnou $sign někde dál použiješ, pokud ne tak je to zbytečné, komponenta se zavolá automaticky při vykreslování/signálu.
První dotaz je jestli u komponenty je dobře „namespace App\Presenters;“?
Dal bych to do jiného namespace než presenter, ale potom když někde třídu komponenty použiješ, musíš buďto a) napsat jméno třídy včetně namespace, nebo b) importovat třídu pomocí use – třeba use App\Components\Sign – asi proto ti to nefungovalo v presenterech.
Ahoj,
to právě mám v presenteru přes use (BasePresenter.php):
<?php
declare(strict_types=1);
namespace App\Presenters;
use Nette;
use App\Components\Sign\SignComponent;
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
protected function createComponentSign(): SignControl
{
$sign = new SignControl;
return $sign;
}
akorát je divný že když mám v té komponentě namespace App\Presenters; tak to funguje (SignComponent.php):
<?php
declare(strict_types=1);
namespace App\Presenters;
//namespace App\Components;
use Nette\Application\UI\Control;
class SignControl extends Control
{
public function render(): void
{
// vložíme do šablony nějaké parametry
$this->template->param = 7;
// a vykreslíme ji
$this->template->render(__DIR__ . '/SignComponent.latte');
}
}
ale když tam dám namespace App\Components; tak to hodí:
Error
Class "App\Presenters\SignControl" not found
na tom řádku:
$sign = new SignControl;

- nightfish
- Člen | 528
Allconius napsal(a):
akorát je divný že když mám v té komponentě namespace App\Presenters; tak to funguje (SignComponent.php):
…
ale když tam dám namespace App\Components; tak to hodí:
Class „App\Presenters\SignControl“ not found
@Allconius
To je očekávané chování.
V BasePresenteru máš use App\Components\Sign\SignComponent;
(všimni si, že na konci je SignComponent). V metodě
createComponentSign() pak voláš new SignControl
(všimni si, že je to SignControl, nikoliv
SignComponent). A protože SignControl nikde
neimportuješ pomocí use, tak se očekává, že je ve stejném
namespace jako presenter.
Udělej si pořádek v pojmenování komponenty (doporučuji spíš
používat SignControl než SignComponent), dej
SignControl do „správného“ namespace
(App\Components\Sign), pak ji v BasePresenteru naimportuj pomocí
use App\Components\Sign\SignControl a vše bude fungovat dle
očekávání.

- Allconius
- Člen | 317
nightfish napsal(a):
Allconius napsal(a):
akorát je divný že když mám v té komponentě namespace App\Presenters; tak to funguje (SignComponent.php):
…
ale když tam dám namespace App\Components; tak to hodí:
Class „App\Presenters\SignControl“ not found@Allconius
To je očekávané chování.
V BasePresenteru mášuse App\Components\Sign\SignComponent;(všimni si, že na konci jeSignComponent). V metoděcreateComponentSign()pak volášnew SignControl(všimni si, že je toSignControl, nikolivSignComponent). A protožeSignControlnikde neimportuješ pomocíuse, tak se očekává, že je ve stejném namespace jako presenter.Udělej si pořádek v pojmenování komponenty (doporučuji spíš používat
SignControlnežSignComponent), dejSignControldo „správného“ namespace (App\Components\Sign), pak ji v BasePresenteru naimportuj pomocíuse App\Components\Sign\SignControla vše bude fungovat dle očekávání.
Ahoj, upravil jsem názvy a mám teď 2 soubory
App\Components\Contacts\DetailControl.php a
App\Components\Contacts\DetailControl.latte
DetailControl.php:
<?php
declare(strict_types=1);
namespace App\Components;
use Nette\Application\UI\Control;
class DetailControl extends Control{
public function render(): void
{
$this->template->render(__DIR__.'/DetailControl.latte');
}
}
a HomePresenter.php:
<?php
declare(strict_types=1);
namespace App\Presenters;
use Nette;
use App\Components\Contacts\DetailControl;
class HomePresenter extends BasePresenter
{
protected function createComponentDetail(): DetailControl
{
$detail = new DetailControl;
return $detail;
}
}
Ale stejně mi to píše:
Error
Class "App\Components\Contacts\DetailControl" not found
Co tam mám špatně ?

- nightfish
- Člen | 528
Allconius napsal(a):
Ahoj, upravil jsem názvy a mám teď 2 souboryApp\Components\Contacts\DetailControl.php…
DetailControl.php:
namespace App\Components;
class DetailControl extends Control
…
Co tam mám špatně ?
Špatně máš namespace komponenty DetailControl. Není až
tak důležité, v jakém adresáři je soubor uložen, nýbrž jaký má
namespace. A ty máš namespace App\Components, tedy
plný název třídy je App\Components\DetailControl a nikoliv
App\Components\Contacts\DetailControl, jak uvádíš
v presenteru.
Doporučuji se při organizaci tříd držet PSR-4, které
říká, že namespace odpovídá adresáři. Ve tvém případě tedy změníš
namespace App\Components; na
namespace App\Components\Contacts\DetailControl; a bude to
fungovat.

- Allconius
- Člen | 317
nightfish napsal(a):
Allconius napsal(a):
Ahoj, upravil jsem názvy a mám teď 2 souboryApp\Components\Contacts\DetailControl.php…
DetailControl.php:
namespace App\Components;
class DetailControl extends Control
…
Co tam mám špatně ?Špatně máš namespace komponenty
DetailControl. Není až tak důležité, v jakém adresáři je soubor uložen, nýbrž jaký mánamespace. A ty máš namespaceApp\Components, tedy plný název třídy jeApp\Components\DetailControla nikolivApp\Components\Contacts\DetailControl, jak uvádíš v presenteru.Doporučuji se při organizaci tříd držet PSR-4, které říká, že namespace odpovídá adresáři. Ve tvém případě tedy změníš
namespace App\Components;nanamespace App\Components\Contacts\DetailControl;a bude to fungovat.
Ahoj, díky moc konečně jsem to pochopil že NAMESPACE je adresář a USE je soubor :-)
namespace App\Components\Contacts;
use App\Components\Contacts\DetailControl;

- Kcko
- Člen | 473
Allconius napsal(a):
nightfish napsal(a):
Allconius napsal(a):
Ahoj, upravil jsem názvy a mám teď 2 souboryApp\Components\Contacts\DetailControl.php…
DetailControl.php:
namespace App\Components;
class DetailControl extends Control
…
Co tam mám špatně ?Špatně máš namespace komponenty
DetailControl. Není až tak důležité, v jakém adresáři je soubor uložen, nýbrž jaký mánamespace. A ty máš namespaceApp\Components, tedy plný název třídy jeApp\Components\DetailControla nikolivApp\Components\Contacts\DetailControl, jak uvádíš v presenteru.Doporučuji se při organizaci tříd držet PSR-4, které říká, že namespace odpovídá adresáři. Ve tvém případě tedy změníš
namespace App\Components;nanamespace App\Components\Contacts\DetailControl;a bude to fungovat.Ahoj, díky moc konečně jsem to pochopil že NAMESPACE je adresář a USE je soubor :-)
namespace App\Components\Contacts; use App\Components\Contacts\DetailControl;
Namespace žádný adresář není.
Namespace (jmenný prostor) je množinou symbolů, které slouží k uspořádání objektů různého druhu, takže tyto objekty mohou být označeny jménem. Například: – programovací jazyky organizují své proměnné, funkce a podprogramy v oborech jmen – u počítačových sítí a distribuovaných systémů se přiřazují názvy zdrojům, jako jsou počítače, tiskárny, webové stránky apod. – v rámci Internetu jsou webové zdroje rozděleny do hierarchických struktur za pomoci DNS – souborové systémy jsou jmenné prostory, které přiřazují názvy souborům a adresářům

- Allconius
- Člen | 317
Ještě dotaz ohledně továrny, můžu si načítat spojení s DB třeba z modelu a předávat přes továrnu do komponenty ? (DetailControlFactory.php):
<?php
declare(strict_types=1);
namespace App\Components\Contacts;
use Nette;
use Nette\Mail\Message;
use Nette\Mail\SendmailMailer;
use Nette\Utils\Image;
use App\Model\DbManager;
class DetailControlFactory
{
public function __construct(
private DbManager $dbManager,
) {
}
public function create(int $id): DetailControl
{
return new DetailControl($id, $this->dbManager);
}
}
Nebo jak nejlépe řešit spojení s DB v komponentě ?

- Allconius
- Člen | 317
Takto mi to funguje jen nevím jestli to není zbytečně složitý (DetailControl.php) :
<?php
declare(strict_types=1);
namespace App\Components\Contacts;
use Nette\Application\UI\Control;
use Nette\Mail\Message;
use Nette\Mail\SendmailMailer;
use Nette\Utils\Image;
use App\Model\DbManager;
class DetailControl extends Control {
/**
* @param $id
*/
private $id;
private $dbManager;
function __construct($id, DbManager $dbManager)
{
$this->id = $id;
$this->dbManager = $dbManager;
}
public function render(): void
{
$oo = $this->dbManager->najdiSouhlas(77777);
$this->template->oscis = $this->id;
$this->template->render(__DIR__.'/DetailControl.latte');
}
}

- nightfish
- Člen | 528
@Allconius
Můžeš použít generovanou továrnu, tzn. kód továrny nahraď za
<?php
declare(strict_types=1);
namespace App\Components\Contacts;
interface DetailControlFactory
{
public function create(int $id): DetailControl;
}
Pokud při registraci továrny v DI kontejneru používáš
type: nebo class:, tak jej nahraď za
implement (protože nahrazuješ třídu rozhraním). Nette se pak
postará o vytvoření továrny ± ve stejném rozsahu, jako byla tvá
původní továrna. Tato automaticky generovaná továrna pak zajistí
předání (autowiring) všech argumentů konstruktoru
DetailControl, které nemáš v továrně uvedeny jako argumenty
metody create(). Čtení k tématu: https://doc.nette.org/…tion/factory#…

- Allconius
- Člen | 317
nightfish napsal(a):
@Allconius
Můžeš použít generovanou továrnu, tzn. kód továrny nahraď za<?php declare(strict_types=1); namespace App\Components\Contacts; interface DetailControlFactory { public function create(int $id): DetailControl; }Pokud při registraci továrny v DI kontejneru používáš
type:neboclass:, tak jej nahraď zaimplement(protože nahrazuješ třídu rozhraním). Nette se pak postará o vytvoření továrny ± ve stejném rozsahu, jako byla tvá původní továrna. Tato automaticky generovaná továrna pak zajistí předání (autowiring) všech argumentů konstruktoruDetailControl, které nemáš v továrně uvedeny jako argumenty metodycreate(). Čtení k tématu: https://doc.nette.org/…tion/factory#…
A co znamená hláška, že vlastnost nesmí být použita před inicializací?:
Error
Typed property App\Presenters\BasePresenter::$signControlFactory must not be accessed before initialization

- mystik
- Člen | 320
To znamena ze se z property pokousis cist hodnotu aniz bys tam pred tim nejakou nastavil. Kde ji nastavit zalezi na kontextu. Muzes ji nastavit jako default v definici, v konstruktoru nebo si pohlidat poradi v jakem se ti volaji metody, aby se ta co hodnotu nastavuje vzdy volala pred tou, kde se cte.