Jak napsat model rozšiřující Nette\Database (Selection?)

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

Upravuji aplikaci postavenou na Nette\Database, podobně jako v příkladu:

{foreach $database->table('book')->order('title')->limit(5) as $book}
    <h2>{$book->title} ({$book->author->name})</h2>

    {foreach $book->related('book_tag') as $book_tag}
        {$book_tag->tag->name}{sep}, {/sep}
    {/foreach}
{/foreach}

Nicméně rád bych to zpřehlednil a některé složitější konstrukce dostal z šablony někam jinam (předpokládám do vlastního modelu) a pro přístup k těmto méně banálním properties přistupoval cca takto:

$book->mainCategory->title

místo něčeho jako

$book->related('tags')->where('type = ?', '123')->orderBy('priority')->fetch()->title

Nemám představu jak takové rozšíření implementovat. Díky!

Editoval kahi (3. 10. 2012 15:38)

jansfabik
Člen | 193
+
0
-

Zkus se mrknout na https://github.com/fabik/database. Takhle nějak bys to mohl použít:

models/Book.php

<?php

namespace Web;
use Database\ActiveRow;

class Book extends ActiveRow
{
	public function getTags()
	{
		return $this->related('tags');
	}



	/** @return Tag */
	public function getMainCategory()
	{
		return $this->getTags()->where('type = ?', '123')->orderBy('priority')->fetch();
	}
}

models/Books.php

<?php

namespace Web;
use Database\Table;

class Books extends Table
{
	protected $name = 'books';



	public function listAll()
	{
		return $this->findAll()->order('title');
	}



	public function listTopFive()
	{
		return $this->listAll()->limit(5);
	}
}

models/Tag.php

<?php

namespace Web;
use Database\ActiveRow;

class Tag extends ActiveRow
{
}

models/Tags.php

<?php

namespace Web;
use Database\Table;

class Tags extends Table
{
	protected $name = 'tags';
}

config.neon

services:
	# database
	modelManager: Database\ModelManager
	rowFactory: Database\RowFactory({
		books: Web\Book # tohle namapuje řádky tabulky books na entity Web\Book
		tags: Web\Tag
	})

	# models
	books: Web\Books
	tags: Web\Tags

v presenteru pak:

<?php

namespace Web;

class BooksPresenter extends BasePresenter
{
	/** @var Web\Books */
	protected $books;



	public function inject(Books $books)
	{
		$this->books = $books;
	}



	public function renderDefault()
	{
		$this->template->books = $this->books->listTopFive();
	}
}
kahi
Člen | 32
+
0
-

@jansfabik: děkuji, vypadá to jako přesně to, co potřebuji. Bohužel to dopadne takto: http://cl.ly/…1M1t1e314412 (Nahrál jsem Database do libs a přidal ten úryvek do configu… Netuším, co tomu chybí.) :(

David Ďurika
Člen | 328
+
0
-

ukaz config.neon mas tam nieco zle nastavene, pravdepodobne pripojenie k DB
mal by si tam mat nieco taketo:

<?php
	nette:
		database:
			default:
				dsn: '%database.driver%:unix_socket=%database.socket%;host=%database.host%;dbname=%database.dbname%'
				user: %database.user%
				password: %database.password%
				# reflection: conventional
	services:
		database: @nette.database.default
?>
kahi
Člen | 32
+
0
-

@achtan Díky za pomoc, myslím že tady problém nebyl, začalo to fungovat, bohužel neumím říct proč :-)

@jansfabik Už jsem to rozjel a je to boží. Díky!

ViPEr*CZ*
Člen | 817
+
0
-
public function getTags()
{
   return $this->related('tags');
}

/** @return Tag */
public function getMainCategory()
{
   return $this->getTags()->where('type = ?', '123')->orderBy('priority')->fetch();
}

Toto $this->getTags() nevrací vždy objekt, pokud to nenajde žádný odpovídající řádek… to není úplně ok a může to končit chybou, když se na to rovnou napojí where.

jansfabik
Člen | 193
+
0
-

ViPEr*CZ Opravdu? Díval jsem se do API, volá se tam funkce Selection::getReferencingTable() a ta vrací objekt vždy.

Nebo ti to někde hází chybu? Například by mohlo vadit, že nepoužíváš InnoDB, ale třeba MyISAM. Pak je potřeba používat $this->related('tags', 'tag_id'), protože MyISAM nemá podporu pro klíče.

Editoval jansfabik (4. 10. 2012 22:31)

ViPEr*CZ*
Člen | 817
+
0
-

MyISAM nepoužívám a tento rozdíl znám. Moje chyba … nekoukl jsem do API, podle toho máš samozřejmě pravdu, když na to teď koukám. Tak kde já jsem to viděl, že mi to vždy neprošlo… a viděl „No reference found.“. Pokud to najdu (podaří se mi znovu), tak to postnu ;-)

jansfabik
Člen | 193
+
0
-

To se mi taky občas stává. Myslím, že za to může cachování v Nette\Database. Pomáhá mi promazání temp/cache. Někdy ani to nepomůže, tak se dá vypnout cachování úplně.

config.neon

services:
	nette.database.default:
		setup:
			- setCacheStorage(NULL)
David Ďurika
Člen | 328
+
0
-

mne vyhadzuje niekedy ‚Invalid argument supplied for foreach()‘ a to v nasledovnom kode:

<?php
$selection = $row->related('table');
dump($selection);
foreach($selectin as $value) { // to to hodi chybu
}
?>

ked stranku refreshnem tak to uz zbehne OK!
dump toho $selection je stale Nette\Database\Table\GroupedSelection
nevies co s tym moze byt?

jansfabik
Člen | 193
+
0
-

Pokud tam je při prvním načtení chyba a při dalším už to funguje, tak je to pravděpodobně chyba v cache. Zkusím se podívat, v čem by mohla být chyba. Do té doby se to dá asi opravit jen tím vypnutím cache.

enumag
Člen | 2118
+
0
-

@achtan: Zkus aktuální master branch. Jestli se tam tahle chyba objevila znovu tak je to celkem průšvih. @hrach nad tim strávil hodně času, aby to vychytal.

jansfabik
Člen | 193
+
0
-

Vyrobil jsem si nový projekt ze sandboxu a opravdu narazil na bug v masteru.

$articles = $connection->table('articles');

foreach ($articles as $article) {
	dump($article);
	//$author = $article->ref('users', 'author_id');
	//dump($author);
}

Když při prvním requestu nejprve načtu jenom článek a při druhém requestu odkomentuju autora, vyhazuje ten druhý dump FALSE.

Když promažu cache, tak to opět funguje.

Issue #841

Editoval jansfabik (30. 10. 2012 16:04)

enumag
Člen | 2118
+
0
-

@jansfabik: Ne, to není bug. NDB by měla fungovat správně v případech kdy jí pod rukama neměníš kód, v opačném případě není zaručeno nic.

jansfabik
Člen | 193
+
0
-

@enumag: Věci, co souvisejí s tímto bugem prosím piš na GitHub, tohle nepatří do sekce Začátečníci. Najdeš tam i moji reakci.