propojeni aplikace s databazi pres dibi – Best Practice

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

Ahoj, kdysi sem Nette zkoušel a teď sem se k tomu vrátil byť ale nejsem webový programátor.
Dříve se mi nějakým způsobem povedlo rozchodit Dibi, ale teď nevím čeho se chytnout a možných řešení sem nalezl více byť nejsou kompletní.. proto bych se chtěl zeptat na nějaký aktuální postup jak se k databázi připojit, protože poslední dobou proběhlo spousta změn, dokonce i Nette má na databázi vlastní třídu.

Já si to představuju takto:
v /app/config/config.neon jsem našel

common:
	parameters:
		database:
			driver: mysql
			host: localhost
			dbname: test
			user:
			password:

ok to vypadá jako něco co potřebuji.. doplním a

teď je otázka kam se přesunout.. mám si vytvořit nějaký /app/models/Model.php
kde budu mít constructor který mě připojí a ten model se bude inicializovat vždy po startu nějak

nebo ručně pouštět nejaký

$application->onStartup[] = 'ConnectionModel::connect';
$application->onShutdown[] = 'ConnectionModel::disconnect';

což sem ve fóru také objevil

nebo se připojovat přes HomepagePresenter.php ?

a hlavní otázka kam vlastně mam nakopírovat stáhlý folder dibi ?

Potřeboval bych to trochu polopatě nebo nějaký step by step návod, protože ikdyž se to člověku podaří tak neví jestli to tak má správně a v tom řešení není nějaká schovaná slabina, která se projeví v budoucnu a hlavně člověk když k tomu příde třeba za rok tak vůbec netuší, proto bych si to nějak sesumíroval a sepsal si návod aspoň pro sebe, jelikož se mi nepodařilo ho najít ikdyž myslim, že tu dřív býval.. Děkuji

uestla
Backer | 799
+
0
-
  1. stáhnu nejnovější dibi
  2. rozbalím, složku dibi zkopíruju do složky libs/
  3. v config.neon vytvořím službu:
common:
	services:
		database:
			factory: DibiConnection( %database% )

	parameters:
		database:
			host: localhost
			username: root
			password:
			database: dbname
			profiler: TRUE
  1. spokojeně používám
$container->database->fetchAll("SELECT * FROM [table]");

profiler: TRUE připne panel na Debugbar (po připojení).

Lazy připojení je zajištěno díky vytvoření služby až při prvním přístupu.

muflix
Člen | 92
+
0
-

Aha, děkuju.. a ta složka může mít jakýkoliv název nebo jak Nette ví, že má z Dibi-2.0 načíst Dibi funkcinalitu ? To zajišťuje nějaký ten RobotLoader ? a ještě otázka.. ten

$container->database->fetchAll("SELECT * FROM [table]");

dam například do nějakýho modelu a v šabloně pak zavolám tu akci/metodu která bude vracet nějaký recordset/data ?

a zápisy

$result = dibi::query('SELECT * FROM `table`');
$result->fetchAll();

a

$container->database->fetchAll("SELECT * FROM [table]");

sou totožný ?

Filip Procházka
Moderator | 4668
+
0
-

RobotLoader prohledá složky, které mu nastavíš a pomocí autoloading mechanismu načítá třídy na požádání.

Třída dibi je jenom statická obálka nad DibiConnection a má téměř identické API.

Protože Nette razí cestu DI, je vhodné zaregistrovat DibiConnection do DI Containeru, pomocí configu a přistupovat k němu jako ke službě.

Jenom bych trošku doplnil @**uestla**, protože by to mohlo vypadat, že máš vždy přistupovat přes $container.

Je vhodné si vždy connection, například v presenteru, vytáhnout z DI Containeru.

class ArticlePresenter extends BasePresenter
{
	private $database;

	protected function startup()
	{
		parent::startup();
		$this->database = $this->context->database;
	}


	public function actionDefault($id)
	{
		$row = $this->database->fetch("SELECT * FROM ... ");
		// ...
	}

	// ...
}

Nebo pokud používáš modely, můžeš si connection předat rovnou do modelu a pracovat s databází přes metody modelu.

parameters:
	database:
		host: localhost
		username: root
		password:
		database: dbname
		profiler: TRUE

services:
	connection:
		class: DibiConnection(%database%)
	foo:
		class: FooModel(@connection)
	bar:
		class: BarModel(@connection, @user)

Ve vygenerovaném DI Containeru pak budou třídám předány přes konstruktor služby.

Schválně si to zkus a koukni, jaký SystemContainer ti to do tempu vygeneruje ;)

Editoval HosipLan (6. 2. 2012 20:58)

uestla
Backer | 799
+
0
-

Přístupem ke službě ve startupu přijde o krásu lazy inicializace :-'(

muflix
Člen | 92
+
0
-

Aha už tomu začínám rozumět.. ale ještě řekl bych snad poslední článek mi chybí do zprovoznění..

na odkaz
píšou, že pokuď chci použít model, tak ho musím zaregistrovat ve ‚startupu‘
defaultně, ale v config.neon startup není tak sem usoudil, že by to mohlo vypadat následovně

common:
	parameters:
		database:
			driver: mysql
			host: localhost
			dbname: nette_db
			user: root
			password: 123456
			profiler: TRUE #debug panel
		setup:
			model: Model( @database )
	services:
		database: @Nette\Database\Connection
		class: DibiConnection(%database%)

Potom musím ten model /app/models/Model.php vytvořit a teď je otázka jak správně to má vypadat.. například

<?php

class Model extends Nette\Object
{
    public $database;
    public function __construct(Nette\Database\Connection $database)
    {
        dibi::connect($database));
    }

    public function getTable()
    {
    	return dibi::query('SELECT * FROM `table`');
    }

    public function clearTable()
    {
    	return dibi::query('DELETE FROM `table`');
    }
}

no, takhle si to představuju, ale určitě to není správně, tak kdyby ste mi řekli jak to opravit ? :)
a pak taky, pokuď bych používal pouze Dibi.. mohu z config.neon smazat řádku database: @Nette\Database\Connection ?

‚Přístupem ke službě ve startupu přijde o krásu lazy inicializace :-‘(‚
je tím myšleno startup v config.neon nebo v Presenteru ? Bude moje řešení splňovat 'Lazy Style‘ ?
a ještě, má nějaký význam dávat modul třídu do namespace ?
Moc děkuju za pomoc.. zatim si píšu vlastní step-by-step postupy na Nette a postupně to určitě dostanu do ruky :)

Editoval muflix (6. 2. 2012 22:50)

uestla
Backer | 799
+
0
-

Je tu smotáno moc věcí dohromady…

Nejprve: buď dibi nebo Nette\Database

Hned poté: buď dibi:: nebo DibiConnection().

Až se rozhodneš, dáme dohromady řešení… A když nebudeš vědět, co vybrat, tak ti poradíme taky.

Editoval uestla (6. 2. 2012 23:45)

muflix
Člen | 92
+
0
-

aha dik, no nevím jestli dibi:: nebo DibiConnection() ale s dibi:: asi bude min prace? tak bych po tom sahl prvni :)

uestla
Backer | 799
+
0
-

config.neon:

common:
	parameters:
		database:
			driver: mysql
			host: localhost
			username: root
			password: ***
			lazy: TRUE
			profiler: TRUE

bootstrap.php:

dibi::connect( $container->parameters->database );
Filip Procházka
Moderator | 4668
+
0
-

@**uestla**: Proč?!

common:
        parameters:
                database:
                        driver: mysql
                        host: localhost
                        username: root
                        password: ***
                        lazy: TRUE
                        profiler: TRUE

	services:
		database:
			class: DibiConnection
			factory: dibi::connect(%database%)
			run: TRUE

a bude fungovat staticky i předávání přes DI Container

@**muflix**: cos to vytvořil za smotanici? Proč pleteš setup do parameters? Proč se ta třída jmenuje Model?

class Articles extends Nette\Object
{
	/** @var */
	public $database;

	public function __construct(DibiConnection $database)
	{
		$this->database = $database;
	}

	public function findAll()
	{
		return $this->database->fetchAll('SELECT * FROM articles');
	}
}

Dibi nepracuje s tabulkami jako Nette\Database, dibi je jedno připojení, které se předává a píší se vždy celé dotazy!

Smažte už prosím někdo třídu model… Nepojmenovávejte prosím nikdo nic v projektu slovem model. To je taková hovadina! Vždyť modelů máte mít daleko více než jeden!

RiskyNet
Člen | 20
+
0
-

HosipLan napsal(a):

Smažte už prosím někdo třídu model… Nepojmenovávejte prosím nikdo nic v projektu slovem model. To je taková hovadina! Vždyť modelů máte mít daleko více než jeden!

Dobře že to píšeš, toto mě napadlo už u Quickstartu, kde je na tomto postaven úkolníček https://doc.nette.org/cs/quickstart > Model, řekl bych že to může být matoucí

Filip Procházka
Moderator | 4668
+
0
-

A nyní i jako článek!: Nette\Database není dibi

muflix
Člen | 92
+
0
-

Tjo super už to skoro mam a dokonce bych řek, že tomu trochu i rozumim :D, akorát mi to píše jednu chybu.. popíšu jak to mam:

config.neon

common:
	parameters:
		database:
			driver: mysql
			host: localhost
			dbname: nette_db
			user: root
			password: 123456
			lazy: TRUE #s db se pracuje az kdyz je potreba
			profiler: TRUE #debug panel
...
	services:
		connection:
			class: DibiConnection(%database%)

		novinky:
			class: Model\Novinky(@connection)
		#authenticator: Authenticator( @database::table(users) )

tady sem narazil na drobnost v sanboxu je ‚user:‘ ale všude se uvádí ‚username:‘ to pak, ale vyhazuje chybu: 'Missing item 'user'' ale v database: default: sekci se to dá přenastavit, takže ok.

/app/models/Novinky.php

<?php
namespace Model;

class Novinky extends \Nette\Object
{
        private $db;

        public function __construct(\DibiConnection $connection)
        {
                $this->db = $connection;
        }

        public function getAll()
        {
                return $this->db->fetchAll('SELECT * FROM novinky');
        }
}

/app/presenters/HomepagePresenter.php

<?php

class HomepagePresenter extends BasePresenter
{
        private $novinky;
        protected function startup()
        {
            parent::startup();
            $this->novinky = $this->context->novinky;
        }
	public function renderDefault()
	{
                $rows = $this->novinky->getAll();
		$this->template->rows = $rows;
	}

}

/app/templates/Homepage/novinky.latte

{block content}
Novinky

{foreach $rows as $row}
    <tr>
     <td>{$row->id}</td>
     <td>{$row->perex}</td>
     <td>{$row->text}</td>
     <td>{$row->datum_vlozeni}</td>
    </tr>
{/foreach}

{/block}

a píše mi to chybu

DibiDriverException #1046
No database selected

takže chyba bude asi při předávání ‚dbname:‘ v config.neon? ale tam mám

...
		database:
			default:
				dsn: '%database.driver%:host=%database.host%;dbname=%database.dbname%'
				user: %database.user%
				password: %database.password%

což by mělo snad odpovídat.. v článku se dbname vůbec nenastavuje.. ?

Michal Vyšinský
Člen | 608
+
0
-

Dibi má pro název databáze „database“ a ne „dbname“ Takže v config.neon změň parametr „dbname“ na „database“ a „user“ změň na „username“. Názvy parametrů musí být stejné jako ty, který dibi příjmá.

Filip Procházka
Moderator | 4668
+
0
-

Postupně…

#authenticator: Authenticator( @database::table(users) )

Authenticator, který je v sandboxu jako výchozí, počítá s Nette\Database. Musíš ho tedy upravit tak, jak já jsem upravoval tvoje modely. Prostě bude přijímat celé DibiConnection a v metodě authenticate() budeš volat SQL dotaz.

database: default: sekci se to dá přenastavit, takže ok.

Co to má být? Opět pleteš dvě věci dohromady.

common:
	nette:
		database:
			default:
				# ...

Tohle nastavuje Nette\Database! Samotné dibi žádné default připojení nemá. Rozlišuj to, prosím.

takže chyba bude asi při předávání ‚dbname:‘ v config.neon? ale tam mám

zde opět pleteš něco s Nette\Database a moc tomu nerozumím.

Když používáš dibi, tak parametry se jmenují trochu jinak. Takže správně takto

common:
        parameters:
                database:
                        driver: mysql
                        host: localhost
                        database: projekt
                        username: root
                        password: 123456
                        lazy: TRUE #s db se pracuje az kdyz je potreba
                        profiler: TRUE #debug panel

Zbytek vypadá v pořádku.

Editoval HosipLan (7. 2. 2012 14:05)

muflix
Člen | 92
+
0
-

Aha, omlouvám se.. už mi se mi to připojuje.. akorát ještě mám někde chybu pravděpodobně v tom Presenteru, když přistoupim na stránku, kde se mi vypisujou novinky tak mi nette vyhodí chybu
‚Undefined variable: rows‘
ale $rows definuju v renderDefault metode.. nepomohlo ani přidání public $rows.. ja vim je to se mnou tezky :-)

Filip Procházka
Moderator | 4668
+
0
-

Kód, který jsi poslal, se zdá v pořádku. Chyba bude někde jinde, nebo jsi něco změnil.

muflix
Člen | 92
+
0
-

No, já nevim.. zkontroloval jsem to asi třikrát, tak sem ty soubory dal na pastebin

/app/config/config.neon
http://pastebin.com/qi92V1gC

/app/models/Novinky.php
http://pastebin.com/C5wR2kSV

/app/presenters/HomepagePresenter.php
http://pastebin.com/bBde9SFq

/app/templates/Homepage/novinky.latte
http://pastebin.com/KBe1EJt9

/app/templates/@layout.latte
http://pastebin.com/1FGCx7gn

a sandbox mam defaultní Nette-2 pro PHP-5.3
jinak chci poděkovat za všechny rady, vážně dík

a ještě obrázek, který možná pomůže

Editoval muflix (7. 2. 2012 15:35)

uestla
Backer | 799
+
0
-

HosipLan napsal(a):

@**uestla**: Proč?!

Poněvadž si přál používat dibi:: a netahat připojení z kontajnéru…

22
Člen | 1478
+
0
-

Trochu v rozporu s nadpisem vlákna imho

Filip Procházka
Moderator | 4668
+
0
-

@**muflix**: Ty si ze mě snad už děláš srandu :D

authenticator: Authenticator(DibiConnection(%database%))

Co to má být? :) Správně takto

authenticator: Authenticator(@connection)

Pokud bys chtěl našeptávání, tak musíš IDEčku říct, co je v $novinky

class HomepagePresenter extends BasePresenter
{
	/** @var Novinky */
        private $novinky;

Teď už ti bude napovídat $this->novinky->.

To u template ale není možné napovídat, protože to jsou proměnné, které nemá jak zjistit, že tam jsou. Template přes magickou metodu __set() přijímá parametry, které pak předá do šablony. IDE tedy neví, co by mělo napovídat.

Daleko víc by určitě pomohl screen laděnky, nebo ještě lépe, klikatelná laděnka (bacha ať tam není vidět heslo)

muflix
Člen | 92
+
0
-

:-) aha opravil sem to..
přidal sem i /** @var Novinky */ uložil a psal $this->template→ ale pořád to píše ‚no suggestion‘ tak možná to souvisí s tou chybou, ale jinak našeptávání zatim nepotřebuju to pak kdyžtak vyřešim pak ono i třeba css soubory mi netbeans vubec neaplikuje syntaxi byť mam stáhlou PHP verzi bez úprav :D

ale laděnku sem zkoušel uložit do .mht, ale rozklikávatelný to není, a mam to na localhostu tak jedině nějaký teamviewer nebo nevim.. tak sem aspoň udělal printscreen

obrázek chyby

Filip Procházka
Moderator | 4668
+
0
-

Ty s tím musíš dělat nějakou magii :) Parametr do šablony předáš, ale v šabloně není. WTF?

Aha… už mě to trklo, ještěže jsi psal ty cesty :)

app/templates/Homepage/novinky.latte
app/templates/Homepage/default.latte

Všimni si, že proměnnou nastavuješ v renderDefault, ale šablona se jmenuje novinky.

Udělej si v tom pořádek ;)

muflix
Člen | 92
+
0
-

YES už to funguje :D Supr moc nejvic dik :D že se to musí menovat podle tý šablony sem uplně neřešil a teď mi ta mozaika zapadla :-) takze jeste diky jednou vsem :)