Dynamicky generované komponenty(createComponent) – Dashboard

pata.kusik111
Člen | 78
+
0
-

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

Nějaký ComponentFactoryProvider co v konstruktoru dostane pole [componentName => $factory], kde $factory je instance auto-generované továrničky?

pata.kusik111
Člen | 78
+
0
-

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

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/ProfileFactoryDashboard/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
+
0
-

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/ProfileFactoryDashboard/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 | 1182
+
+2
-

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!).

https://doc.nette.org/…onfiguration#…

Petr Parolek
Člen | 455
+
+1
-

řešil jsem něco obdobného, tady je ukázka https://github.com/…nets-sandbox

pata.kusik111
Člen | 78
+
0
-

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

Petr Parolek
Člen | 455
+
0
-

jakou cestou ses vydal?