Context vs. inject metody

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

Zdravím,
pár hodin pročítám fórum, hledám na google, ale nedopídil jsem se výsledku. $this->context je prý zastaralé a nemá se používat, místo toho má existovat injectování. Něco jsem si k tomu přečetl, ale moc jasné mi to zatím není.

Konkrétní problém:

BasePresenter

<?php

namespace App\Model;

use Nette;

class Base extends \Nette\Object
{

    public $database;

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

    public function fetchAll() {

	return $this->database->table('articles');
    }
}

HomepagePresenter

<?php

namespace AdminModule;


/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{

	public function renderDefault() {

	    $this->template->articles = $this->context->articles->fetchAll();

	}


    }

Jde mi o to, jak se tedy vyhnout contextu a vypsat všechny články z db pomocí injectu.

A je tedy nutnost dále registrovat model jako službu?

mkoubik
Člen | 728
+
+1
-
namespace AdminModule;

use App\Model\Articles;

class HomepagePresenter extends BasePresenter
{
	private $articles;

	public function __construct(Articles $articles)
	{
		$this->articles = $articles;
	}

	public function renderDefault()
	{
		$this->template->articles = $this->articles->fetchAll();
	}

Službu pořád musíš registrovat v DI kontejneru, jen ji nemusíš pojmenovávat.

services:
	- App\Model\Articles
Freestyler
Člen | 50
+
0
-

Super, díky. Funguje to.

Ještě se jenom zeptám (protože nerad jen kopíruju kód, ale chci mu rozumět).

Tím konstruktorem

public function __construct(Articles $articles)

si předávám proměnnou $articles do třídy Articles a tam si jí potom jen zavolám. Je to tak?

Je teda škoda, že je to o dost kódu víc, ale v tomhle případu mi to asi nevadí, protože třídu Articles stejně mám. Každopádně jsem to všechno chtěl mít v Base modelu, ale to by asi byl bad-practice cpát vše do jednoho modelu …

MartinitCZ
Člen | 580
+
+4
-

Tohle je lepší:

namespace AdminModule;

class HomepagePresenter extends BasePresenter
{
    /**
     * @var \App\Model\Articles
     * @inject
     */
    public $articles;

    public function renderDefault()
    {
        $this->template->articles = $this->articles->fetchAll();
    }

Editoval martinit (21. 6. 2014 20:25)

Freestyler
Člen | 50
+
0
-

Super, tohle funguje dobře, ale narazil jsem na další problém. V HomepagePresenteru potřebuju ještě pár dalších funkcí, tam jsem si řekl, že na menu při úpravě článku si udělám továrničku, takže něco jako:

 public function createComponentArticleMenu() {

$form = new Form();
$form->addSelect('category','Kategorie', $this->category->getCategory()->fetchPairs('id','category_name'));
return $form;

samozřejmě na začátku souboru mám uvedno public $category, stejně jako public $articles

Továrničku vykresluji klasicky ve view přes {control articleMenu}

Pro úplnost ještě přidám metodu v modelu Articles

public function getCategory() {

    return $this->database->table('category');

}

Cílem tohoto je vykreslit rozbalovací menu s názvy kategorií (načtené z db z tabulky category, která je přes cizí klíč category.id propojena na tabulku articles.category).

Zajímavé je, že jakmile prohodím ty dva publicy na začátku, tak ten první funguje a druhý ne. Co dělám špatně?

Případně jestli na toto „ArticleMenu“ jdu úplně špatně budu rád za popostrčení správným směrem.

Díky.

Tabetha
Člen | 140
+
0
-

máš pri oboch @inject?

Freestyler
Člen | 50
+
0
-

Mám to takhle:

<?php

namespace AdminModule;

use Nette\Application\UI\Form;

/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{

    /**
     * @var \App\Model\Articles
     * @inject
     */

   public $articles;
   public $category;

    public function renderDefault()
    {
        $this->template->articles = $this->articles->fetchAll();

    }

    public function createComponentArticleMenu() {



$form = new Form();
$form->addSelect('category','Kategorie', $this->category->getCategory()->fetchPairs('id','category_name'));

return $form;

    }



    }

Zajímavý je, že když v tu továrničku přepíšu takto:

    public function createComponentArticleMenu() {



$form = new Form();
$form->addSelect('category','Kategorie', $this->articles->getCategory()->fetchPairs('id','category_name'));

return $form;

    }

Tak funguje. (Je tam nahrazeno $this->category za $this->articles. Není možný, že nette nějak umí cizí klíče a dohledá si to? Každopádně mi není jasný proč to nefunguje když si zadefinuju public $category; a v modelu se dotazuju do správný tabulky a chci z ní jen dostat data do presenteru a vypsat je v šabloně …

Editoval Freestyler (24. 6. 2014 23:03)

Tabetha
Člen | 140
+
0
-
<?php

namespace AdminModule;

use Nette\Application\UI\Form;

/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{

    /**
     * @var \App\Model\Articles
     * @inject
     */

   public $articles;
    /**
     * @var \NamespaceTridyCategory
     * @inject
     */
   public $category;

    public function renderDefault()
    {
        $this->template->articles = $this->articles->fetchAll();

    }

    public function createComponentArticleMenu() {



$form = new Form();
$form->addSelect('category','Kategorie', $this->category->getCategory()->fetchPairs('id','category_name'));

return $form;

    }

    }

nebude to takto fungovať?

Freestyler
Člen | 50
+
0
-

Tak to je ještě víc zajímavý. Já mám všechno v modelu Articles (všechno co pracuje se články), tzn. zatím dvě funkce.

Pokud uvedu dvě @inject anotace, tak to začne fungovat, ale to se mi moc nelíbí. Nešlo by to nějak lépe? Přijde mi to jako zbytečné opakování kódu.

/**
     * @var \App\Model\Articles
     * @inject
     */

    public $articles;
    /**
     * @var \App\Model\Articles
     * @inject
     */
   public $category;

Předpokládám, že na to budu muset použít inject metody?

Editoval Freestyler (24. 6. 2014 23:38)

David Matějka
Moderator | 6445
+
0
-

Pokud to mas vsechno v jedne modelove tride, tak ji injectuj jen jednou…

Editoval matej21 (24. 6. 2014 23:42)

Freestyler
Člen | 50
+
0
-

matej21 napsal(a):

Pokud to mas vsechno v jedne modelove tride, tak ji injectuj jen jednou…

Ano to mám, ale pokud tam ten inject neuvedu 2×, tak to nefunguje:

Call to a member function getCategory() on a non-object

A je to vidět už když píšu změnu z articles na category, tak netbeans mi ukáže, že articles patří do App\Model\Articles a category do \AdminModule\HomepagePresenter což je samozřejmě blbost … namespace jsem všude kontroloval a je správně a nefungovalo by to i kdybych tu inject anotaci napsal třeba 100×. Takže problém bude jinde, ale už jsem bez nápadu :(.

A teď babo raď :).

David Matějka
Moderator | 6445
+
0
-

Ten model/sluzbu mas injectnutej v property articles, tak pouzivej $this->articles Az budes mit nejakou tridu App\Model\Category nebo cokoliv, tak si to injectnes do property categories

Filip Procházka
Moderator | 4668
+
+1
-

Annotace @inject není opakování kódu. To je použití hotového kódu. To je jako bys říkal, že sis napsal třídu s nějakou funkčností abys ji mohl použít na více místech, ale odmítal jsi dvakrát napsat new SomeClass, protože „je to opakování kódu“, což je hloupost :)