Vysvětlí někdo na jednoduchém příkladu jak pracovat s databází?

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

Zdravím, potřeboval bych, aby mně někdo navedl na správnou cestu. Jsem začátečník, ale už jsem s nette něco dělal, takže si troufám tvrdit, že ne zas tak úplný, nicméně pořád nějak nechápu práci s databází.

V čistým PHP jsem byl zvyklý si to dělat vše po svém a ne asi úplně správně a nejlépe a nejbezpečněji, proto jsem přešel k nette, ale hrozně mě tady matou ty tutoriály. Jednak tu je Dibi a Nette\database, což jak jsem tak pochopil těží hlavně z NotORM. Jenomže možná právě čeho je moc, toho je příliš a já v tom mám guláš a to pořádnej.

Takže k mému problému vytvořil jsem si v databazi jednoduchou tabulku, kde budu ukládat nadpisy, obsahy a další věci ke každé mé stránce. Proč? Protože uživatelé to budou moci editovat.

No a teď bych chtěl vědět jak začít? Resp. Jak nejlépe začít? Resp.2. Jakou nejdřívě zvolit databazi? Dibi nebo Nette\Databaze? Asi bych byl spíše pro nette\database.

Takže potřebuji pomoc co vše potřebuji k tomu, abych například na moji úvodní stránku vysypal z databaze nadpis a obsah? Děkuji za nakopnutí a rady a pomoc…

JuniorJR
Člen | 181
+
0
-

Zjednodušený příklad pro Nette\Database (normálně by si data tahal skrz konkrétní model).

public function renderTest($id = NULL)
{
    if ($id == NULL) {
        $this->redirect('Foo:bar');
    }
    // get content of page with the given id
    $page = $this->context->database->table('page')
        ->where('id', $id)
        ->fetch();
    if (!$page) {
        $this->redirect('Foo:bar');
    }
    $this->template->page = $page;
}

V šabloně pak např.:

<h1>{$page->header}</h1>
<p>{$page->body}</p>

Editoval JuniorJR (4. 6. 2012 22:38)

wb2009
Člen | 125
+
0
-

Děkuji za ukázku, než se zeptám na ty modely, píše mi to, že nemám definovaný content, ovšem nevím přesně kde mám chybu,zkusím si s tím pohrát, snad na to přijdu.

Každopádně děkuji za příklad.

Aurielle
Člen | 1281
+
0
-

Ten kód předpokládá, že ho používáš v presenteru, kde je context přístupný přes $this->context.

motorcb
Člen | 552
+
0
-

wb2009: Také používám Nette database a jsem spokojen. Má výhodu, že složitější dotaz si v ní můžeš napsat stejným zůsobem jako v NotORM.
Začni tutoriálem na https://doc.nette.org/cs/quickstart
Ten ti dá pro začátek hodně a nebudeš muset otravovat tady na foru základníma věcma :)

Jan Tvrdík
Nette guru | 2595
+
0
-

wb2009 wrote:
Dibi nebo Nette\Databaze?

dibi považuji v současnosti za mnohem lepší volbu, obzvláště, pokud začínáš.

wb2009
Člen | 125
+
0
-

Zdravím, tak jsem si s tím, včera pohrál a podařilo se, už tahám data z db do šablony.

Navíc zdá se, že začínám i chápat tu logiku. Nette\Database se zdá velice šikovná.

Tak a teď mne opravte, jestli se mýlím. Vytvořil jsem si tedy funkci:

public function renderUvodniInformace()
{

    // get content of page with the given id
    $page = $this->context->database->table('obsahstranek')
        ->where('id', 1)
        ->fetch();

    $this->template->page = $page;
}

Která teda mi vytáhne z databáze ten řádek, kde je id=1 a pak to pomocí $this->template.. předávám do šablony.

Má otázka tedy zní, jestli chápu model správně, že nejlepší by bylo si všechny tyto funkce do modelu vytvořit a pak to z něj tedy tahat? DO presenteru si tu funkci tedy natáhnu jak? Úplně jednoduše, nebo v tom jen vidím zbytečnou složitost, která není. Každopádně moc děkuji, teď když už chápu logiku MVP, dokážu tahat věci z databáze, poradím si s presentery, tak se mi to Nette líbí ještě víc :)

vvoody
Člen | 910
+
0
-

Ano, najlepsie je tuto funkciu presunut do modelu, cize by vyzerala takto:

public function getPage($id)
{
    // get content of page with the given id
    return $this->context->database->table('obsahstranek')
        ->where('id', $id)
        ->fetch();
}

a presenter uz len

public function renderUvodniInformace()
{
    $this->template->page = $this->context->nazovModelu->getPage(1);
}

s tym ze model musis mat zaregistrovany ako sluzbu v configu, preto si ho potom mozes vybrat z contextu

wb2009
Člen | 125
+
0
-

jj ten už mám zaregistrovaný, tak díky moc, zatím to vypadá jako velká pohoda, ale nechci nic zakřiknout :)

JuniorJR
Člen | 181
+
0
-

Ja nevím, proč s tím tolik lidí nadělá takových problémů… :D

wb2009
Člen | 125
+
0
-

Tak nakonec mám problém, už jsem to přesunul do toho modelu a fungovalo to. Nevím proč, ale najednou to nefunguje…Píše to:

Service ‚obsahstranek‘: Parameter $table in Method Nette\Database\Table\Selection::__construct() is missing

model mám:

<?php

use Nette\Database\Connection,
    Nette\Database\Table\Selection;


class Obsahstranek extends Selection
{
  public function getPage($id)
{
    // get content of page with the given id
    return $this->context->database->table('obsahstranek')
        ->where('id', $id)
        ->fetch();
}

}

v presenter pak mám:

<?php

namespace FrontModule;

class OskolePresenter extends \BasePresenter {


public function renderUvodniInformace()
{
    $this->template->page = $this->context->obsahstranek->getPage(1);
}
}

a v configu to mám zaregistrovaný takto:

...

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


	services:
		database: @Nette\Database\Connection
		obsahstranek: Obsahstranek
		authenticator: Authenticator( @database::table(users) )



...

díky za rady.

JuniorJR
Člen | 181
+
0
-

Mělo by pomoci:

services:
        database: @Nette\Database\Connection
        obsahstranek: Obsahstranek( 'obsahstranek', @database )
        authenticator: Authenticator( @database::table(users) )

Jde o to, že ty tam nepředáváš požadované parametry pro vytvoření instance třídy Obsahstranek, viz. api.

Další chybu máš zde:

public function getPage($id)
{
    // nelze se odkazat na context, ten je dostupny pouze z presenteru
    return $this->context->database->table('obsahstranek')
        ->where('id', $id)
        ->fetch();
    // navrh reseni
    // return $this->where('id', $id)->fetch();
}

Editoval JuniorJR (6. 6. 2012 20:53)

wb2009
Člen | 125
+
0
-

děkuji, ale teď mi to hází chybu v latéčku:
Cannot read an undeclared property Obsahstranek::$nadpis

ale v laté to volám klasicky podle presenteru tedy:

....

<h1>{$page->nadpis}</h1>
<div class="obsah">{$page->obsah}</div>


....

Netuším :/

edit: zapomněl jsem fetch, takže už to funguje, díky.

Editoval wb2009 (6. 6. 2012 20:52)

wb2009
Člen | 125
+
0
-

Ještě tu mám jeden problém.
Jde o to, že když jsem volal tu funkci, tak jsem dostával jeden řádek, ale teď mám další funkci

<?php

class Kontaktyskoly extends Selection
{
  public function getKontakty($id)
{
    // get content of page with the given id
return $this->where('typ', $id);
}
}

no a v presenteru mám:

public function renderAdresaKontakty()
{
    $this->template->adresa = $this->context->adresaskoly->getAdresa(1);
    $this->template->reditel = $this->context->kontaktyskoly->getKontakty(1);
    $this->template->statut = $this->context->kontaktyskoly->getKontakty(2);
}

no a v latte mám:

</table>
    <hr />
    <h3>Ředitelství školy:</h3>
    <table>
        {foreach $reditel as $neco}
      <tr>
          <th>{$neco->pozice}</th>
          <td>{$neco->tit_jmeno_prijmeni}</td>
      </tr>
      <tr>
          <th>Telefon:</th>
          <td>{$neco->telefon}</td>
      </tr>
      <tr>
          <th>Fax/záznamník:</th>
          <td>{$neco->fax_zaznamnik}</td>
      </tr>
      <tr>
          <th>Email:</th>
          <td>{$neco->email}</td>
      </tr>
      {/foreach}
    </table>
    <h3>Statutární zástupci:</h3>
    <table>
        {foreach $statut as $neco2}
      <tr>
          <th>{$neco2->pozice}</th>
          <td>{$neco2->tit_jmeno_prijmeni}</td>
      </tr>
      <tr>
          <th>Telefon:</th>
          <td>{$neco2->telefon}</td>
      </tr>
      <tr>
          <th>Fax/záznamník:</th>
          <td>{$neco2->fax_zaznamnik}</td>
      </tr>
      <tr>
          <th>Email:</th>
          <td>{$neco2->email}</td>
      </tr>
      {/foreach}
    </table>

jde mi o to, že když jsem chtěl dostávat jeden řádek, použil jsem v modelu fetch(), ale když jsem chtěl více řádků, pak sem fetch z modelu odstranil. A po přidání dalšího řádku v presenteru toho samého, ale s jiným id, kde se vrátí pouze 1 vysledek, to nefunguje…nějaká rada? :)

Jinak já se to tady z toho příspěvku postupně naučím … :D

díky

JuniorJR
Člen | 181
+
0
-

Definuj slovo „nefunguje“. Jestli nebude problém v tom, že ten selection používáš jako službu a v tom případě se vrací pořád ta samá instance té služby.

Jinak pro získání všech záznamů by mělo stačit (jelikož ten model implementuješ jako hotový selection):

$this->template->adresa = $this->context->adresaskoly;

Pokud by si chtěl vracet při každém volání modelu novou instanci, zaregistruj třídu jako továrnu v configu.

Editoval JuniorJR (6. 6. 2012 22:44)

wb2009
Člen | 125
+
0
-

Ok, přesunul jsem to ze služeb do factories a lásí mí to hlášku :Service ‚adresaskoly‘ not found
tedy, že to nenašlo tu službu… :)

JuniorJR
Člen | 181
+
0
-

Když ji registruješ jako továrnu, tak ji musíš jako továrnu také volat, viz. dokumentace:

$this->template->adresa = $this->context->createAdresaskoly();

Editoval JuniorJR (6. 6. 2012 22:57)

wb2009
Člen | 125
+
0
-

Děkuji za další info, ovšem pořád to hlásí to samé… :/

JuniorJR
Člen | 181
+
0
-

Smazat cache a zkontrolovat názvy.

Editoval JuniorJR (6. 6. 2012 23:19)

wb2009
Člen | 125
+
0
-

Tak vážně nevím, proč to nejde. Nemůže to být něco v tom fetch?

Editoval wb2009 (7. 6. 2012 10:31)

bojovyletoun
Člen | 667
+
0
-

zapni si v konfigu container panel:

nette:
	container:
		debugger: yes
wb2009
Člen | 125
+
0
-

Jsem si tím nepomohl, pořád to nemůže najít službu…

wb2009
Člen | 125
+
0
-

Tak ještě jednou…
v configu mám:

common:
	parameters:
		database:
			driver: mysql
			host: localhost
			dbname: lhs
			user: root
			password:


	php:
		date.timezone: Europe/Prague
		# session.save_path: "%tempDir%/sessions"
		# zlib.output_compression: yes


	nette:

		container:
			debugger: yes
		session:
			expiration: '+ 14 days'

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


	services:
		database: @Nette\Database\Connection

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


	factories:
		obsahstranek: Obsahstranek( 'obsahstranek', @database )
		adresaskoly: Adresaskoly( 'adresaskoly', @database )
		kontaktyskoly: Kontaktyskoly( 'kontaktyskoly', @database )



production < common:

development < common:

v modelu mám(třeba model adresakontakty):

<?php

use Nette\Database\Connection,
    Nette\Database\Table\Selection;


class Adresaskoly extends Selection
{
  public function getAdresa($id)
{
    // get content of page with the given id
return $this->where('id', $id)
;
}

}

a v presenteru mám:

<?php

namespace FrontModule;

class OskolePresenter extends \BasePresenter {


public function renderUvodniInformace()
{
    $this->template->page = $this->context->createPage(1);
}
public function renderAdresaKontakty()
{
    $this->template->adresa = $this->context->createAdresa(1);
    $this->template->reditel = $this->context->createKontakty(1);
    $this->template->statut = $this->context->createKontakty(2);
}

}

a píše mi to chybu, že nemám definovanou metodu: Call to undefined method SystemContainer::createAdresa().

Je možný, že tam už mám někde chybu, z toho jak to pořád opravuju a předělávám…budu vděčný za cokoliv…
díky

bojovyletoun
Člen | 667
+
0
-

to a to jsi četl?
Máš tam jiné názvy u „$this->context->Adresa“ a factories: adresaSkoly

jenom takový nápad k těm třídám Adresaskoly. Pokud je nebudeš rozšiřovat, pak jejich existence je „zbytečná“, neboť metoda getAdresa() je nahraditelná metodou Nette\Database\Table\Selection::find()

Jak taková konfigurace může vypadat?

common:
	nette:
		database:
			a:
				dsn: sqlite:%appDir%/sites.db
	factories:
		db: @nette.database.a #jen alias
		sites:
			factory: @db::table(sites) #eq $context->nette->database->table('sites')
		news:
			factory: @db::table(news)
	services:
		texy:
			class: CTexy(/img,%wwwDir%/img)

Editoval bojovyletoun (7. 6. 2012 19:01)

wb2009
Člen | 125
+
0
-

Děkuji, nakonec jsem to vyřešil podle quickstartu, kde je toto:

class Tasks extends Selection
{
    public function __construct(\Nette\Database\Connection $connection)
    {
        parent::__construct('task', $connection);
    }
}

a pak se to vlastně všechno děje přes presenter. A tak to udělám i já. A pak přes foreach to zobrazím v latte.

Každopádně děkuji.

birkof
Člen | 15
+
0
-

Díky za návod pro dummies. Konečně mi ty modely fungují :-)