Komponenta, která zobrazuje menu (kategorie) – připojení do databáze

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

Zdravím,
udělal jsem si menu, které je propojeno s databází a vykresluje se do šablony. Jenže jsem narazil na problém, že menu potřebuju na všech stránkách, a nechci připojení furt definovat v Presenterech. Tak jsem v dokumentaci narazil na komponenty.
Snažím se udělat jednoduchou komponentu, co v @layout.latte vykreslí menu (seznam kategoríí).

Zde mám CategroyControl:

use Nette\Application\UI;

class CategoryControl extends UI\Control
{
    private $database;

    public function __construct(Nette\Database\Connection $database)
    {
        parent::__construct();
        $this->database = $database;
    }
    public function render()
    {
        $template = $this->template;
        $template->setFile(__DIR__ . '/CategoryControl.latte');
        // vložíme do šablony nějaké parametry
        $this->template->categories = $this->database->table('blog_categories');
        // a vykreslíme ji
        $template->render();
    }
}

CategoryControl.latte

{snippet}
    {foreach $categories as $category}
        <li class="item-173"><a href="{$category->url}">{$category->title}</a></li>
    {/foreach}
{/snippet}

Vždy mi to ale vyhodí chybu:
Recoverable Error
Argument 1 passed to CategoryControl::__construct() must be an instance of Nette\Database\Connection, none given, called in /home/psabrnak/web/domena.cz/public_html/app/FrontModule/presenters/HomepagePresenter.php on line 20 and defined

Nevím si rady, co s tím. Ještě jsem se chtěk zeptat, zda musím vždy v presenterech vykreslovat komponentu – chci menu na všech stránkách, tak kde nejlépe umístit tento kód?

protected function createComponentCategory()
    {
        $category = new \CategoryControl;
        return $category;
    }

Děkuji moc za radu.

David Matějka
Moderator | 6445
+
+2
-

Komponenta vyzaduje pripojeni, musis tam tedy pripojeni pridat. Pripadne si udelej tovarnicku a zkombinuj to (jestli chces) s autowired component factories :)

Editoval matej21 (20. 6. 2014 12:38)

Desttro
Člen | 126
+
0
-

Chápu to teda dobře, že musím udělat v app/components/ nový soubor IUserTableFactory.php, kde bude:

namespace App\Components;

interface ICategoryFactory
{
    /**
     * @return Category
     */
    public function create();
}
  • tím vytvořím rozhraní, poté bude moje komponenta propojená s databázi a ještě než spustím web, tak musím do configu napsat tohle?
services:
    - App\Components\ICategoryFactory

Určitě to říkám špatně, že?

Editoval Desttro (20. 6. 2014 13:03)

David Matějka
Moderator | 6445
+
+1
-

skoro dobre:)
jen ten soubor pojmenuj „ICategoryFactory.php“ a oprav si @return anotaci, aby to spravne odkazovalo na onu komponentu, tedy \CategoryControl (pripadne presun CategoryControl do namespace App\Components a pak staci CategoryControl bez zpetneho lomitka)

Ono nette dle toho rozhrani vytvori tovarnicku na tu komponentu a komponentu vytvori spravne se vsemi zavislostmi

Desttro
Člen | 126
+
0
-

Děkuji za radu, udělal jsem to, ale furt mi to vyhazuje chybu:
Recoverable Error
Argument 1 passed to CategoryControl::__construct() must be an instance of Nette\Database\Connection, none given, called in /home/psabrnak/web/maxsecure.cz/public_html/app/FrontModule/presenters/HomepagePresenter.php on line 20 and defined

v @layout.latte mám: {control category}

ICategoryFactory.php:

namespace App\Components;

interface ICategoryFactory
{
    /**
     * @return \CategoryControl
     */
    public function create();
}

v HomepagePresenter mám:

protected function createComponentCategory()
    {
        $category = new \CategoryControl;
        return $category;
    }

když to smažu., tak to křičí logicky, že:
Nette\InvalidArgumentException
Component with name ‚category‘ does not exist.

David Matějka
Moderator | 6445
+
+1
-

tu factory musis vyuzit, viz posledni blok kodu v prvnim odkazu, pripadne druhy odkaz

Desttro
Člen | 126
+
0
-

Vypadá to, že to funguje, ale ještě mi to hlásí chybu:
Nette\MemberAccessException
Call to undefined method Nette\Database\Connection::table().

zde je ten CategoryControl

use Nette\Application\UI;

class CategoryControl extends UI\Control
{
    private $database;

    public function __construct(Nette\Database\Connection $database)
    {
        parent::__construct();
        $this->database = $database;
    }
    public function render()
    {
        $template = $this->template;
        $template->setFile(__DIR__ . '/CategoryControl.latte');
        // vložíme do šablony nějaké parametry
        $this->template->categories = $this->database->table('blog_categories');
        // a vykreslíme ji
        $template->render();
    }
}
David Matějka
Moderator | 6445
+
+1
-

vymen Nette\Database\Connection za Nette\Database\Context

Desttro
Člen | 126
+
0
-

Super, děkuji moc! Konečně už vím, jak na komponenty :)

stewestw
Člen | 42
+
0
-

ahojte,
neviete mi prosim poradit, kde robim chybu s DI?

<?php

use Nette\Application\UI\Control;

class MenuControl extends Control
{
    /** @var Nette\Database\Context */

    public $user;

    private $database;

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

    public function render()
    {

        $template = $this->template;
        $menuItems = $this->database->table('nette_menu');

        $itms = array();

        if(count($menuItems) > 0){
            foreach($menuItems as $item){
                $itmsLink = ":Admin:".((trim($item->module) !== "") ? $item->module.":" : "").((trim($item->presenter) !== "") ? $item->presenter.":" : $item->module).((trim($item->action) !== "") ? $item->action : "") ;
                $itms[] = array("link" => $itmsLink, "title" => $item->title);

            }
        }
        $this->template->menuItems = $itms;
        $template->render(__DIR__ . '/MenuControl.latte');
    }
}

stale mi to hadze chybu:

Argument 1 passed to MenuControl::__construct() must be an instance of Nette\Database\Context, none given, called in /Applications/XAMPP/xamppfiles/htdocs/custom_cms/app/presenters/BaseAdminPresenter.php on line 12 and defined

a to som siel presne podla vaseho navodu, co ste tu riesili :(
dakujem.

Etch
Člen | 403
+
0
-

A jak tu komponentu vytváříš v presenteru?

stewestw
Člen | 42
+
0
-

volam ju v AdminBasePresenteri takto:

<?php

namespace App\Presenters;


abstract class BaseAdminPresenter extends \App\Presenters\BasePresenter{
    public $database;


    protected function createComponentMenu()
    {
        $menu = new \MenuControl;
        return $menu;

    }
    protected function startup()
        {
            parent::startup();

            if (!$this->getUser()->isLoggedIn() && $this->name !== "Admin:Login:Login") {
                //die($this->name);
               $this->redirect(":Admin:Login:Login:default");

            }

        }

}
David Matějka
Moderator | 6445
+
+1
-

@stewestw precetl sis odkazovanou kapitolu v doc?

Etch
Člen | 403
+
+1
-
$menu = new \MenuControl;

ti nikdy nemůže fungovat. Použij create:

interface MenuFactory{
    /**
     * @return \MenuControl
     */
    public function create();
}

do presenteru přidej:

	/** @var \MenuFactory @inject */
	public $menuFactory;

protected function createComponentMenu(){
    return $this->menuFactory->create();

}
stewestw
Člen | 42
+
0
-

@matej21 ano, aj som skusal viac variant, ale bohuzial neuspesne. mam zaregistrovanu aj factory v configu, ale danu dependency mi nenajde.

stewestw
Člen | 42
+
0
-

prave mi to zbehlo.
chbala mi deklaracia injektu:

/** @var \App\components\IMenuFactory @inject */

@matej21 prepac.

Editoval stewestw (29. 1. 2015 11:47)