Vykreslení komponenty na všech stránkách (@layout.latte) pomocí BasePresenteru

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

Zdravím,
mám hotovou komponentu – menu, které bych rád zobrazil na @layout.latte. Příjde mi blbé to mít v každém Presenteru jako render, tak mne napadlo to renderovat v BasePresenteru.
Postupoval jsem podle tohoto návodu: https://forum.nette.org/…pomoci-mysql

Nette mi ale vždy vyhodí tuhle chybu:
Recoverable Error
Argument 1 passed to FrontModule\MenuControl::__construct() must be an instance of FrontModule\Nette\Database\Context, null given, called in /home/psabrnak/web/maxsecure.cz/public_html/app/FrontModule/presenters/BasePresenter.php on line 36 and defined

Nevím si rady, pomůžete mi prosím? Děkuji.


MenuControl:

namespace FrontModule;

use Nette\Application\UI\Control;

class MenuControl extends Control
{
	/** @var Nette\Database\Context */
    private $database;

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

	public function render()
	{
		$template = $this->template;
		$template->setFile(__DIR__ . '/MenuControl.latte');
		$template->menu = $this->database->table('menu');
		$template->render();
	}
}

BasePresenter:

namespace FrontModule;

use Nette,
	App\Model;

abstract class BasePresenter extends \Nette\Application\UI\Presenter
{
	/** @var \Nette\Database\Context */
    private $database;

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

    protected function createComponentMenu()
    {
        $menu = new MenuControl($this->database);
        return $menu;
    }
}
David Matějka
Moderator | 6445
+
0
-

Pravdepodobne prekryvas konstruktor v nejakem konkretnim presenteru. Minimalne v base presenterech (ale klidne i v konkretnich presenterech) injectuj zavislosti pomoci @inject anotace

/** @var \Nette\Database\Context @inject */
public $database;

(musi byt public)

Editoval matej21 (24. 6. 2014 16:06)

Oli
Člen | 1215
+
0
-

Zkus dát před `Nette `zpětný lomítko

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

nebo použij use Nette;

Desttro
Člen | 126
+
0
-

Oli napsal(a):

Zkus dát před `Nette `zpětný lomítko

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

nebo použij use Nette;

nepomohlo, komponenty mám v app, a ne ve FrontModule jako je třeba BasePresenter

matej21 napsal(a):

Pravdepodobne prekryvas konstruktor v nejakem konkretnim presenteru. Minimalne v base presenterech (ale klidne i v konkretnich presenterech) injectuj zavislosti pomoci @inject anotace

/** @var \Nette\Database\Context @inject */
public $database;

(musi byt public)

zkusil jsem dát do BasePresenteru a nette mi vypsalo:
Compile Error
Access level to FrontModule\HomepagePresenter::$database must be public (as in class FrontModule\BasePresenter)

A když dám public $database; do HomepagePresenteru, tak to hlásí:

Argument 1 passed to FrontModule\MenuControl::__construct() must be an instance of FrontModule\Nette\Database\Context, instance of Nette\Database\Context given, called in /home/psabrnak/web/maxsecure.cz/public_html/app/FrontModule/presenters/BasePresenter.php on line 36 and defined


Dám zde ještě HomepagePresenter:

namespace FrontModule;

use Nette,
	App\Model;

class HomepagePresenter extends BasePresenter
{
    /** @var \Nette\Database\Context */
    private $database;

    /** @var \App\Components\ICategoryFactory @inject */
    public $categoryFactory;

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

    protected function createComponentCategory()
    {
        return $this->categoryFactory->create();
    }

    public function renderDefault()
    {
        $this->template->hotels = $featured;
        //$this->template->categories = $this->database->table('blog_categories');

        //$control = $this->getComponent('node');
    }
}

Editoval Desttro (24. 6. 2014 16:14)

Šaman
Člen | 2666
+
0
-

Když to injectuješ do BasePresenteru, tak už tu proměnnou samozřejmě nevytvářej v potomcích. A jestli jsi použil injectování anotací, tak ji potomkům nepředávej konstruktorem.

Obecně – proměnné předka vidí i potomek, takže pokud nepřepisuješ metody (třeba konstruktor), tak potomek databázi má automatocky a nic k tomu nepotřebuje, než podědit od BasePresenteru. Výjimkou je to předávání konstruktorem, kde si musíš znovu vyžadovat parametr $db a předat ho do parent::__construct($db);. Tomu se ale raději vyhýbej pomocí inject metody, nebo inject anotací.

Editoval Šaman (24. 6. 2014 16:27)

Desttro
Člen | 126
+
0
-

Teď jsem zkusil dát do všech presenterů, které mám ve FrontModule ten inject:

/** @var \Nette\Database\Context @inject */
public $database;

a web jede, ale asi není dobré mát proměnnou $database public že? Jde to nějak vyřešit?

David Matějka
Moderator | 6445
+
0
-

Ty properties museji byt public, aby se do nich nechalo injectnout. (ano slo by to nejakyma hackama, ale to ted resit nebudu). Je to sice poruseni zapouzdreni, ale v ramci presenteru je to tolerovatelne

Editoval matej21 (24. 6. 2014 16:25)

Šaman
Člen | 2666
+
0
-

Desttro napsal(a):

Teď jsem zkusil dát do všech presenterů, které mám ve FrontModule ten inject:

/** @var \Nette\Database\Context @inject */
public $database;

a web jede, ale asi není dobré mát proměnnou $database public že? Jde to nějak vyřešit?

Nedávej to do všech, jen do BasePresenteru. To jsou základy OOP.

Jinak nepříliš čistou property injection (tj. anotace) můžeš nahradit inject metodou. (Raději si prostuduj celou odkazovanou stránku.)

Desttro
Člen | 126
+
0
-

Šaman napsal(a):

Desttro napsal(a):

Teď jsem zkusil dát do všech presenterů, které mám ve FrontModule ten inject:

/** @var \Nette\Database\Context @inject */
public $database;

a web jede, ale asi není dobré mát proměnnou $database public že? Jde to nějak vyřešit?

Nedávej to do všech, jen do BasePresenteru. To jsou základy OOP.

Jinak nepříliš čistou property injection (tj. anotace) můžeš nahradit inject metodou. (Raději si prostuduj celou odkazovanou stránku.)

Děkuji, už jsem na to přišel, že to vlastně může dědit. Určitě nastuduji. Děkuji vám hoši.