propojeni aplikace s databazi pres dibi – Best Practice
- muflix
- Člen | 92
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
- stáhnu nejnovější dibi
- rozbalím, složku
dibi
zkopíruju do složkylibs/
- v config.neon vytvořím službu:
common:
services:
database:
factory: DibiConnection( %database% )
parameters:
database:
host: localhost
username: root
password:
database: dbname
profiler: TRUE
- 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
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
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)
- muflix
- Člen | 92
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)
- Filip Procházka
- Moderator | 4668
@**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
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í
- muflix
- Člen | 92
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
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
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
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
Kód, který jsi poslal, se zdá v pořádku. Chyba bude někde jinde, nebo jsi něco změnil.
- muflix
- Člen | 92
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)
- Filip Procházka
- Moderator | 4668
@**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
:-) 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
- Filip Procházka
- Moderator | 4668
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
render
Default, ale šablona se jmenuje
novinky
.
Udělej si v tom pořádek ;)