Autor Zpráva
Slark
Profil *
Dobrý den,

měl bych dotaz k MVC, ač mi kód funguje tak jak potřebuji mám nějaké nejasnosti a to konkrétně rovnou uvedu na příkladu.

Mám eshop -> košík který obsluhuje CartController (+ model což není důležité). Součástí CartControlleru jsou nově i funkce na slevové kupony (protože aplikace kuponu se odehrává přímo v košíku). Problém nastává ve chvíli kdy při vytváření samotné objednávky chci některé funkce CartControlleru volat pro zpětné ověření validity kuponu. Klasicky to dělám tak, že si prostě v OrderControlleru, resp. OrderClass (která zajišťuje samotný proces zpracování objednávky) vytvořím instanci CartControlleru - $cart = new CartController; a zde si validitu kuponu ověřím, takto to funguje. Ale já se ptám, zda-li je tento postup správný, jestli není nějakým jednodušším způsobem možné "říct" třídě OrderController budeme také k práci potřebovat CartController. Tzn v třídě OrderController (OrderClass) se vyhnout řádku $cart = new CartController.

Zajímal by mě nějaký jednoduchý postup jak se toto řeší, myslím, že $cart = new CartController;
Mnohokrát děkuji za rady
Alphard
Profil
Bylo by dobré uvést detainější informace, co znamená ověření validity. Buď to nevyžaduje UI a má to být zcela součástí modelu (tipuji tuto možnost), nebo to vyžaduje UI a bude to komponenta. Rozhodně se mi nezdá vhodné vytvářet v controlleru instanci jiného controlleru.
Slark
Profil *
ověření validity myslím to zda li je kupon platný, tzn. funkce na ověření zda li objednávka má minimální hodnotu pro uplatnění kuponu, nevypršel datum platnosti kuponu apod.. Také se mi nezdá vhodné vytvářet v controlleru instaci jiného controlleru proto mě zajímá jak se toto obecně řeší. Zřejmě mi tedy naznačujete že ověření kuponu nemá v CartControlleru vůbec co dělat?

Děkuji mockrát za reakci.
Alphard
Profil
Slark:
Zřejmě mi tedy naznačujete že ověření kuponu nemá v CartControlleru vůbec co dělat?
Přesně. Takto popsané se zdá, že to má být součástí modelu.
Slark
Profil *
dobře, takže logiku kuponů přesunu do modelu. Nicméně v OrderControlleru budu tedy vytvářet model $cupons = new Cupons.
Alphard
Profil
Slark:
Nicméně v OrderControlleru budu tedy vytvářet model $cupons = new Cupons.
To je otázka, jak to řešit jinak, nebo konstatování? :-) Tento problém mi byl jasný už v [#2]; když se nebude instancializovat controller, bude se muset nějak získat instance modelu... ale nechtělo se mi do této problematiky moc pouštět.

Můj pohled je takový, že Cupons vypadají spíše jako služba a služby se nevytvářejí lokálně, ale předávají se. Takže instance nějaké CuponsService by měla být kontroleru předána. Vaše aplikace s tím zjevně vůbec nepočítá, protože dokáže vytvořit instanci třídy, která tipuji potřebuje databázi, nebo umožní instancializovat kontroler, který musí mít také hromadu závislostí.
Otázka, jak to v praxi udělat lépe, je bohužel složitější. Nejlepší řešení je zřejmě DI, avšak pro menší aplikace může docela dobře fungovat i vzor service locator nebo v nejhorším případě nějaká statická třída. Jednotlivé možnosti nebudu rozepisovat, není problém najít o nich dostatek informací.
Slark
Profil *
To je otázka, jak to řešit jinak, nebo konstatování? :-)
Konstatování a zároveň tak trochu otázka :-)

Vypadá to, že dependency injection je to co hledám, akorát implementace do mé aplikace již asi nebude úplně jednoduchá. Chápu to správně že budu instanci CuponsService předávat CartControlleru a také OrderControlleru. Jak mám ale požadovanou službu controlleru předat, když mi controllery načítá router (z get parametru) nějak takto:

$controller = $_GET["page"];
$this->controller = new $controller;

V tomto případě nemohu zajistit to jaký controller bude jaké služby využívat a jsem závislí na těle daného controlleru. Jak by měl vypadat správný návrh routeru? Články jsem ohledně DI četl, ale vždy se zabývají určitou problematikou kterou pochopím ale uniká mi spojitost využití v praxi.

Děkuji vám
Kubo2
Profil
Kontroler neinštancuj v routeri priamo, ale využi návrhový vzor Factory Object. Ten sa môže potom komplexnejšie postarať o analýzu závislostí kontroleru a ich „vpichnutím“ využitím dependency injection.


A samozrejme kontroler factory nevytváraj v routeri priamo, ale definuj ako DI závislosť routeru.
Slark
Profil *
Dobrý den,
tak jsem DI studoval trochu blíže a kódy mi připadají srozumitelné, akorát když mám dát dohromady komplexní logiku, tak mi to už tolik nejde. Přikládám testovací kód který jsem si vytvořil a zajímalo by mě, jestli tento postup je správný (nebo alespoň jestli není špatný):

Vytvořil sem si jednoduchý index:

<?php
require_once "./services/CuponsService/CuponsService.php";
require_once "./controller/CartController.php";
require_once "./DI/Container.php";

$container = new Container;

$container->createInstance("CartController", $container->createService("CuponsService"));

CartController:

<?php
class CartController {

public $cupons;
    
    function __construct(CuponsService $cupons){
            $this->cupons = $cupons;
            echo "CartController";
    }
    
}

a CuponsService:

<?php
class CuponsService {

    function __construct(){
        echo "ok";
    }
    
}

Ještě se začnu zajímat o Factory Object, který mi doporučil Kubo2 (v knize návrhové vzory v PHP jsem našel Factory Method, tak doufám, že to není něco jiného :-))

Kód který jsem napsal výše by můj požadavek splňoval (service CuponsService bych předal také OrderControlleru který by k službě mohl přistupovat a ověřit validitu (platnost) kuponu), jde mi o to zda je to ale takto správně.

Děkuji.
Alphard
Profil
Princip dependency injection pochopený zřejmě je, ale návrh Containeru podle mě moc vhodný není. I když implementaci nevidíme, nezdá se mi to moc flexibilní.
Narazil jste na twittee.org/? Pro pochopení funkce kontejneru je to myslím docela dobré. Všimněte si použití anonymních funkcí.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: