Prenasanie zavislosti – viac instancii triedy – kontajner?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Dendy
Člen | 8
+
0
-

Zdravim Vas,

som troska zmeteny ako vytvorit viac instancii jednej triedy.

Aktuálny stav
Mam triedu Objednavka, zatial iba s jednym parametrom – pripojeniu k DB:

<?php
class Objednavka extends DBConnection {

	public function __construct(Nette\Database\Context $db) {
		parent::construct($db);
    }
	// atd ...
}
?>

V prezentery sa trieda inicializuje v konstruktore cez DI:

<?php
class FormularPresenter extends BasePresenter {
	/** @var \App\Model\Objednavka */
	private $order;

	public function __construct(\App\Model\Objednavka $order) {
		$this->order = $order;
	}
?>

Tam bez problemov pracujem s $this->order. O všetky zavislosti sa postara DI.

Problem
V prezentery mozem teda pracovat s jednou Objednavkou. Ale potreboval by som

  • aby som mohol mat viac instancii triedy Objednavka. Cize pole objektov objednavok,
  • aby som mohol predavat parameter $id

Ako na to
Mam použit kontajner? V tom pripade neviem ako tam predavat pripojenie na $db. Chcel by som iba nieco taketo:

<?php
$pole[] = new \App\Model\Objednavka(5); // 5 je cislo objednavky
?>

Dakujem za akukolvek radu a usmernenie.

ViPEr*CZ*
Člen | 818
+
+1
-

Trochu špatnej návrh ne? V konstruktoru předáváte DB konekci a hned o pár řádků níže cpete do kontruktoru číslo 5? Myslím, že tomu nikdo nebudeme rozumět. Obecně pokud chcete nějakou třídu instancovat vícekrát a třída je registrovaná v configu, pak si udělejte tzv. factory, která bude umět z dané třídy dělat instance. Poté budete mít operátor new na jednom místě a o závyslosti se postará DI.

David Matějka
Moderator | 6445
+
+4
-

Pripada mi, ze michas dohromady, kdy Objednavka reprezentuje nejakou modelovou tridu pro praci s tabulkou objednavek a kdy ta stejna trida reprezentuje jednu objednavku samotnou – to neni dobry.

Tak nejdriv budes mit nejakou modelovou tridu – rikejme ji treba OrderRepository (nebudem michat cestinu a anglictinu, ze ne? :) ). Ta bude umet nacist jednu objednavku z db, pripadne vic objednavek dle nejakych kriterii

class OrderRepository
{
	private $database;

	public function __construct(Nette\Database\Context $database)
	{
		$this->database = $database;
	}

	public function find($id)
	{
		...
	}

	public function findNewOrders()
	{
		...
	}
}

tahle trida bude registrovana jako sluzba v neonu

services:
	- OrderRepository

a ted, pokud opravdu potrebujes reprezentovat jednu objednavku vlastnim objektem a nebude ti stacit treba ActiveRow z Nette\Database, tak si vytvoris novou tridu

class Order
{
	...
}

ta jiz nebude registrovana jako sluzba a jeji instance bude vytvaret OrderRepository

romiix.org
Člen | 343
+
+1
-

Nepoužívam takýto model, ale viac inštancií toho istého typu je dobré generovať továrničkou.

namespace App\Model;

interface IOrderFactory
{
	/** @return App\Model\Objednavka */
	public function create();
}

Toto si zaregistruj medzi služby:

services:
	- App\Model\IOrderFactory

Nette ti podla anotácií a typehintov vygeneruje továrničku s týmto interfacom.
Do presentra si injectni App\Model\IOrderFactory a v kóde použi:

$order = $this->orderFactory->create();
$order->id = $id;

Nestíham, stihli ma predbehnúť :)

Editoval romiix.org (4. 3. 2016 13:23)

Dendy
Člen | 8
+
0
-

v kazdom pripade dakujem za odpoved,
ale asi som to zle napisal, v podstate dva problemy, jeden porieseny:

  • cez factory sa vyriesi, ze budem si moct vytvarat viac instacii, to chapem.
  • ale ako tam budem prenasat $db? (preto som napisal iba (5) a nie ($db, 5) lebo chcel som aby sa nejak DB tam automaticky naplnila. Musim niekde o uroven vyssie si inicialozvat DB a potom to tam vlozit ako parameter?

(ospravedlnujem sa ak je to blba otazka :/ )

ViPErCZ napsal(a):

Trochu špatnej návrh ne? V konstruktoru předáváte DB konekci a hned o pár řádků níže cpete do kontruktoru číslo 5? Myslím, že tomu nikdo nebudeme rozumět. Obecně pokud chcete nějakou třídu instancovat vícekrát a třída je registrovaná v configu, pak si udělejte tzv. factory, která bude umět z dané třídy dělat instance. Poté budete mít operátor new na jednom místě a o závyslosti se postará DI.

romiix.org
Člen | 343
+
0
-

Dendy napsal(a):

v kazdom pripade dakujem za odpoved,
ale asi som to zle napisal, v podstate dva problemy, jeden porieseny:

  • cez factory sa vyriesi, ze budem si moct vytvarat viac instacii, to chapem.
  • ale ako tam budem prenasat $db? (preto som napisal iba (5) a nie ($db, 5) lebo chcel som aby sa nejak DB tam automaticky naplnila. Musim niekde o uroven vyssie si inicialozvat DB a potom to tam vlozit ako parameter?

No práve tá factory ako som ti ju napísal (genrovaná z interfacu) ti automaticky dodá objekt rovno s dodanou závislosťou na DB.

ViPEr*CZ*
Člen | 818
+
0
-

A přesně o tom jsem mluvil… Factory a o závyslosti se postará DI :-)

Dendy
Člen | 8
+
0
-

Dakujem, pomohlo.

David Matějka napsal(a):

Pripada mi, ze michas dohromady, kdy Objednavka reprezentuje nejakou modelovou tridu pro praci s tabulkou objednavek a kdy ta stejna trida reprezentuje jednu objednavku samotnou – to neni dobry.

Tak nejdriv budes mit nejakou modelovou tridu – rikejme ji treba OrderRepository (nebudem michat cestinu a anglictinu, ze ne? :) ). Ta bude umet nacist jednu objednavku z db, pripadne vic objednavek dle nejakych kriterii

class OrderRepository
{
	private $database;

	public function __construct(Nette\Database\Context $database)
	{
		$this->database = $database;
	}

	public function find($id)
	{
		...
	}

	public function findNewOrders()
	{
		...
	}
}

tahle trida bude registrovana jako sluzba v neonu

services:
	- OrderRepository

a ted, pokud opravdu potrebujes reprezentovat jednu objednavku vlastnim objektem a nebude ti stacit treba ActiveRow z Nette\Database, tak si vytvoris novou tridu

class Order
{
	...
}

ta jiz nebude registrovana jako sluzba a jeji instance bude vytvaret OrderRepository

kleinpetr
Člen | 480
+
+1
-

Udělej si nějakou modelovou vrstvu pro práci s databází. Např. třídu Table, která v konstruktoru přijme Database/Context a udělej si nějaké univerzální metody. find($id), findBy($array), apod. V téhle třídě si vytvoř protekční proměnnou $table; od téhle třídy potom budeš dědit další třídy, které budou nastavovat pouze proměnnou $table; Takže ve finále by to mohlo vypadat nějak takhle:

abstract class Table extends Nette\Object
{

    /** @var Nette\Database\Context */
    protected $db;


    public function __construct(Nette\Database\Context $db)
    {
        $this->db = $db;
    }

    protected function getTable()
    {
        return $this->db->table($this->tableName);
    }

    public function findAll()
    {
        return $this->getTable();
    }

    public function findBy(array $by)
    {
        return $this->getTable()->where($by);
    }

Model Objednávek by mohl vypadat takto

class Objednavky extends Table
{
	protected $table = 'objednavky';
}

Tento model si přidej do configu

- App\Model\Table\Objednavky

a potom v presenteru načti v konstruktoru __construct(App\Model\Table\Objednavky $objednavky){..}

a pak už jen pracuj s tím modelem:

public function renderObjednavka($id){
	$this->template->objednavka = $this->objednavky->find($id);
}

Editoval kleinpetr (4. 3. 2016 13:46)

Dendy
Člen | 8
+
0
-

Ďakujem všetkým, už je to poriešené aj na základe tohto fóra :)