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
$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.
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->item
je 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 | 873
@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 | 519
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žeSignControl
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
), dejSignControl
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í.
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 | 519
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\DetailControl
a 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 | 470
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\DetailControl
a 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 | 519
@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 | 313
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.