Dynamicky generované komponenty(createComponent) – Dashboard
- pata.kusik111
- Člen | 78
Zdravím, hledám pomoc někoho zkušeného, kdo by mě alespoň nasměroval, jak na to.
Mám tuto představu. Uživatel si může složit dashboard z vizuálních
celků nějakým způsobem drag-and-drop(jak, to není podstatné). Každý
tento celek by pak byl jedna komponenta(třída dědící on
Nette\Application\UI\Control
). Jeho konfiguraci si uložím do
databáze, tohle všechno mám vymyšlené.
Jde mi o to, jak to pak vykreslit na straně presenteru/šablony? Protože dopředu nevím, jaké použiji komponenty, tak nevím, jak je auto-wirovat do presenteru, když si na to vytvořím továrnu, tak jsem problém jenom přesunul do jiné třídy. Nevím ale ani jak se komponenty budou jmenova, potažmo kolik těch komponent v dashboardu bude (to záleží na velikosti komponent).
Potřeboval bych poradit/nasměrovat, jak tuhletu dynamičnost v presenteru/šabloně řešit.
Tady je pár nápadů co mám, jen jestli mi něco neuniká:
Šablona:
{foreach $dasboardRows as $dashboardRow}
{foreach $dasboardRow as $controlNameWithDistinctPrefix}
{control $controlNameWithDistinctPrefix}
{/foreach}
<hr>
{/foreach}
Presenter:
<?php
class Presenter
{
protected function createComponent(string $name): ?IComponent
{
if(Strings::startsWith($name, 'myUniquePrefix')) {
return $this->dashboardControlFactory->create($name);
}
return parent::createComponent($name);
}
}
final class DashboardControlFactory
{
public function create($name): ?IComponent
{
switch($name) {
case 'name1': {
return $this->getService(Control::class);
}
}
}
}
S tím, že bych potřeboval vyřešit jak na to
$this-getService
v DashboardControlFactory
.
Editoval pata.kusik111 (29. 3. 2020 13:38)
- Jan Tvrdík
- Nette guru | 2595
Nějaký ComponentFactoryProvider
co v konstruktoru dostane
pole [componentName => $factory]
, kde $factory
je
instance auto-generované továrničky?
- pata.kusik111
- Člen | 78
Jan Tvrdík napsal(a):
Nějaký
ComponentFactoryProvider
co v konstruktoru dostane pole[componentName => $factory]
, kde$factory
je instance auto-generované továrničky?
Pokud jsem to dobře pochopil, tohle řeší jenom případ, kdy bych chtěl vygenerovat jenom jednu komponentu, ale z databáze na základě nějakého resolve ze jména na komponentu.
To ale nevadí, protože jsem upravil původní příspěvek s tím co mě napadlo, jak to vyřešit.
Ale stejně i v tomhle případě se můsíš dostat do úplného pekla,
kdy těch $factory
bude třeba 50, ne?
- Felix
- Nette Core | 1245
pata.kusik111 napsal(a):
Jan Tvrdík napsal(a):
Nějaký
ComponentFactoryProvider
co v konstruktoru dostane pole[componentName => $factory]
, kde$factory
je instance auto-generované továrničky?Pokud jsem to dobře pochopil, tohle řeší jenom případ, kdy bych chtěl vygenerovat jenom jednu komponentu, ale z databáze na základě nějakého resolve ze jména na komponentu.
To ale nevadí, protože jsem upravil původní příspěvek s tím co mě napadlo, jak to vyřešit.
Ale stejně i v tomhle případě se můsíš dostat do úplného pekla, kdy těch
$factory
bude třeba 50, ne?
Resime neco podobneho, v NEONu si definujeme komponenty, klic je nazev komponenty a hodnota je tovarna na tu komponentu.
services:
- Dashboard/DashboardControlFactory([
profile: @Dashboard/Control/ProfileFactory,
timer: @Dashboard/Control/TimerFactory
])
- Dashboard/Control/ProfileFactory(@entityManager)
- Dashboard/Control/TimerFactory(@timer)
final class DashboardControlFactory
{
private array $factories = [];
public function __construct(array $factories) {}
public function create($name): AbstractDashboardControl
{
// validace, atd...
return $this->factories[$name]->create();
}
}
Jeste vlastne jedna vec, celej tento dashboard mame ve vlastni komponente a
pak prepisujeme createComponent
metodu. Bez nejakeho overovani
prefixu nebo tak. Protoze vime, ze na dashboardu se mohou zobrazit jenom urcite
komponenty, ktere si uzivatel/admin muze vybrat ze seznamu.
Pokud by jsi to chtel mit co nejvice lazy, tak by to mohlo vypadat takto.
Odstranit @
na zacatku.
@Dashboard/Control/ProfileFactory
⇒Dashboard/Control/ProfileFactory
services:
- Dashboard/DashboardControlFactoryContextAware([
profile: Dashboard/Control/ProfileFactory,
timer: Dashboard/Control/TimerFactory
], @container)
- Dashboard/Control/ProfileFactory(@entityManager)
- Dashboard/Control/TimerFactory(@timer)
final class DashboardControlFactoryContextAware
{
private array $services = [];
private Container $context;
public function __construct(array $services, Container $context) {}
public function create($name): AbstractDashboardControl
{
// validace, atd...
return $this->context->getByType($this->services[$name])->create();
}
}
- pata.kusik111
- Člen | 78
Felix napsal(a):
pata.kusik111 napsal(a):
Jan Tvrdík napsal(a):
Nějaký
ComponentFactoryProvider
co v konstruktoru dostane pole[componentName => $factory]
, kde$factory
je instance auto-generované továrničky?Pokud jsem to dobře pochopil, tohle řeší jenom případ, kdy bych chtěl vygenerovat jenom jednu komponentu, ale z databáze na základě nějakého resolve ze jména na komponentu.
To ale nevadí, protože jsem upravil původní příspěvek s tím co mě napadlo, jak to vyřešit.
Ale stejně i v tomhle případě se můsíš dostat do úplného pekla, kdy těch
$factory
bude třeba 50, ne?Resime neco podobneho, v NEONu si definujeme komponenty, klic je nazev komponenty a hodnota je tovarna na tu komponentu.
services: - Dashboard/DashboardControlFactory([ profile: @Dashboard/Control/ProfileFactory, timer: @Dashboard/Control/TimerFactory ]) - Dashboard/Control/ProfileFactory(@entityManager) - Dashboard/Control/TimerFactory(@timer)
final class DashboardControlFactory { private array $factories = []; public function __construct(array $factories) {} public function create($name): AbstractDashboardControl { // validace, atd... return $this->factories[$name]->create(); } }
Jeste vlastne jedna vec, celej tento dashboard mame ve vlastni komponente a pak prepisujeme
createComponent
metodu. Bez nejakeho overovani prefixu nebo tak. Protoze vime, ze na dashboardu se mohou zobrazit jenom urcite komponenty, ktere si uzivatel/admin muze vybrat ze seznamu.
Pokud by jsi to chtel mit co nejvice lazy, tak by to mohlo vypadat takto. Odstranit
@
na zacatku.
@Dashboard/Control/ProfileFactory
⇒Dashboard/Control/ProfileFactory
services: - Dashboard/DashboardControlFactoryContextAware([ profile: Dashboard/Control/ProfileFactory, timer: Dashboard/Control/TimerFactory ], @container) - Dashboard/Control/ProfileFactory(@entityManager) - Dashboard/Control/TimerFactory(@timer)
final class DashboardControlFactoryContextAware { private array $services = []; private Container $context; public function __construct(array $services, Container $context) {} public function create($name): AbstractDashboardControl { // validace, atd... return $this->context->getService($this->services[$name])->create(); } }
Pecka, tohle hodně pomohlo. Ještě jeden dotaz, asi víc na fungování NEONu a DI. Protože bych rád vyřešil „autoregistraci“ těch komponent. Funguje v Neonu tohle? myslím si, že význam je jasný.
parent.neon
services:
dashboardFactory:
create: DashboardControlFactory
setup:
- addControl('coreControlName', @coreControlClass)
- coreControlClass
child.neon
services:
dashboardFactory:
setup:
- addControl('extensionControlName', @extensionControlClass)
- extensionControlClass
To jest. jestli se ty 2 volání addControl
mergnou nebo jestli
se replacnou.
- Felix
- Nette Core | 1245
pata.kusik111 napsal(a):
Jasne funguje, doporucuju to i rovnou zkusit. Uvidis sam. :-)
Kdyby jsi nahodou nechtel, aby se to mergovalo, tak pridej vykricnik
(setup!
).
- pata.kusik111
- Člen | 78
Pecka, díky všem, už jsem to s vaší pomocí naprogramoval a funguje to přesně podle představ. Jestě jednou díky za rady i za inspiraci. :)