Cannot use object of type Nette\Database\Statement as array

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

Pro zjednodušení to uvedu na tomto příkladě:
Model – User.php:

/**
 * Get users
 * @return \Nette\Database\Table\Selection
 */
public function getAllUsers()
{
    return $this->connection->query( "SELECT id, name, nick FROM users ORDER BY body DESC" );
}

Presenter:

public function renderDefault()
{
    $this->template->users= $this->context->match->getAllUsers();
}

Sablona:
Mimo jiné bych chtěl vypsat ID uživatele na indexu 0:

{$users[0]->id}

Ovšem to mi hlásí chybu: Cannot use object of type Nette\Database\Statement as array

Nevěděl by někdo jak to vyřešit?

Díky

jtousek
Člen | 951
+
0
-
/**
 * Get users
 * @return \Nette\Database\Table\Selection
 */
public function getAllUsers()
{
    return $this->connection->table('users')->order('body DESC');
}
motorcb
Člen | 552
+
0
-

@**jtousek**:
Muj SQL dotaz je hodne slozitej a je potreba ho zapsat rucne.
Proto nemohu vyuzit tvuj zapis.
Ale diky

jtousek
Člen | 951
+
0
-

Záleží jak moc složitý. Můžeš sem hodit celé SQL? Některé věci se totiž v NDB dají obejít.

duke
Člen | 650
+
0
-

Objekt Nette\Database\Statement si můžeš převést na pole pomocí funkce iterator_to_array.
Alternativně si můžeš vytáhnout první řádek pomocí metody fetch.

Editoval duke (6. 10. 2012 18:11)

motorcb
Člen | 552
+
0
-

@**jtousek**:

Nejsem ted na svem PC ale jde o takovyto dotaz ktery ma vlozeny dotaz:

SELECT b.name, (SELECT count(id) FROM `book` WHERE l.book_id = id ) AS contBook
FROM book b
LEFT JOIN lend l on b.id = l.book_id
LEFT JOIN users u on l.user_id
WHERE u.id = 5
ORDER BY l.date ASC

Vypis me pujcene knizky a zaroven spocitej kolikrat jsem mel knihu pujcenou

jtousek
Člen | 951
+
0
-

Mám pocit, že ani přímo to SQL ti nevybere přesně to co chceš. Hlavně ten poddotaz se mi nezdá.

Jinak myslím, že by to v NDB mělo jít vyřešit, jen by to asi udělalo více než jeden dotaz (což nepovažuji za nevýhodu). Ale na to bych musel vidět strukturu databáze, takhle jsem z toho poněkud zmaten. Co přesně chceš vypsat? Všechny knihy, které jsem někdy měl vypůjčené a u každé z nich počet výpůjček?

motorcb
Člen | 552
+
0
-

@**jtousek**:
Ano, presne tak: Všechny knihy, které jsem někdy měl vypůjčené a u každé z nich počet výpůjček

Caine
Člen | 216
+
0
-

Mozna mi neco unika, ale nesel by tam pouzit count misto subquery?

SELECT b.name, COUNT(l.id) AS contBook
FROM book b
LEFT JOIN lend l on b.id = l.book_id
LEFT JOIN users u on l.user_id
WHERE u.id = 5
GROUP BY b.id
ORDER BY l.date ASC

jtousek
Člen | 951
+
0
-

Mimochodem ten JOIN na tabulku users je zbytečný, dále NDB používá zásadně inner join:

SELECT b.name, COUNT(l.id) AS countBook
FROM book b
INNER JOIN lend l on b.id = l.book_id
WHERE l.user_id = 5
GROUP BY b.id
ORDER BY l.date ASC

V NDB by to mohlo jít nějak takto, ale nejsem si úplně jistý.

$connection->table('book')->select('name, COUNT(lend:id) AS countbook')->where('user_id', 5)->group('book.id')->order('lend.date');

EDIT: přidáno group()

Editoval jtousek (7. 10. 2012 11:25)

Caine
Člen | 216
+
0
-

@jtousek jj to by melo fungovat

PS: kde ze je ten slozitej dotaz, co se musi psat rucne?:)

motorcb
Člen | 552
+
0
-

@**Caine**:
A jak by to bylo kdybych chtěl navíc ještě zobrazit kolikrát jsem danou knížku měl půjčenou já? Knihu je možné si půjčit vícekrát.

Tedy:
Vypsat všechny knížky které jsem měl vypůjčené.
Název knížky, celkový počet půjčení knížky, můj počet půjčení knížky

motorcb
Člen | 552
+
0
-

PS: kde ze je ta jednoduchost co jde zapsat v Nette\Database\?!

jtousek
Člen | 951
+
0
-

To co chceš jedním dotazem nepůjde ani v SQL (nebo jen velmi velmi složitě). V NDB by to mělo jít pomocí related poměrně jednoduše – můj názor je ten že jednodušeji to asi ani jít nemůže. Bohužel momentálně nemám vůbec čas nad tím přemýšlet, už jsem agregace v NDB delší dobu nepoužíval a musel bych studovat API.

Caine
Člen | 216
+
0
-

Treba tak?

$myBooks = $connection->table('book')->select('name, COUNT(lend:id) AS countbook')->where('user_id', 5)->group('book.id')->order('lend.date');
foreach ($myBooks as $book) {
	$book['lendcount'] = $book->related('lend')->count('*');
}

PS: Mozna bys mel zacit studovat API NDB, kdyz uz to chces pouzivat..

motorcb
Člen | 552
+
0
-

Abychom se tu jen tak nedohadovali, tak to uvedu na pravou míru.
Databáze:

CREATE TABLE IF NOT EXISTS `book` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci AUTO_INCREMENT=7 ;


INSERT INTO `book` (`id`, `name`) VALUES
(1, 'kniha1'),
(2, 'kniha2'),
(3, 'kniha3'),
(4, 'kniha4'),
(5, 'kniha5'),
(6, 'kniha6');

CREATE TABLE IF NOT EXISTS `lend` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `book_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `date` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `book_id` (`book_id`),
  KEY `user_id` (`user_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci AUTO_INCREMENT=5 ;


INSERT INTO `lend` (`id`, `book_id`, `user_id`, `date`) VALUES
(1, 1, 1, '2012-10-09 00:00:00'),
(2, 1, 2, '2012-10-09 00:00:00'),
(3, 1, 3, '2012-10-09 00:00:00'),
(4, 2, 1, '2012-10-09 00:00:00');
(5, 1, 1, '0000-00-00 00:00:00');


CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nick` varchar(50) COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci AUTO_INCREMENT=4 ;

INSERT INTO `user` (`id`, `nick`) VALUES
(1, 'ctenar1'),
(2, 'ctenar2'),
(3, 'ctenar3');


ALTER TABLE `lend`
  ADD CONSTRAINT `lend_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
  ADD CONSTRAINT `lend_ibfk_1` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`);

Výše uvedený dotaz, který mi byl doporučen ne počítá správně ( kolikrát jsem měl knihu vypůjčenou)

SELECT b.name, COUNT(l.id) AS contBook
FROM book b
LEFT JOIN lend l on b.id = l.book_id
LEFT JOIN users u on l.user_id
WHERE u.id = 1
GROUP BY b.id
ORDER BY l.date ASC

Tento dotaz dělá to co požaduji:
Vypíše názvy mých vypůjčených knih, počet mých výpůjček a počet všech výpůjček:

SELECT
   b.name,
   u.nick,
   ( SELECT COUNT( id ) FROM lend WHERE book_id = b.id and user_id = u.id) AS mujPocetPujceni,
   ( SELECT COUNT( id ) FROM lend WHERE book_id = b.id) AS celkovyPocetPujceni
FROM book b
LEFT JOIN lend l ON b.id = l.book_id
LEFT JOIN user u ON l.user_id = u.id
WHERE u.id = 1
GROUP BY b.name

Dokázal by někdo tento dotaz přepsat do NDB?

Díky

Model databáze: http://s8.postimage.org/…knihovna.png

Editoval motorcb (9. 10. 2012 19:16)

Caine
Člen | 216
+
0
-

Boze, je to spravne az na par chybicek..

$myBooks = $connection->table('book')->select('book.id, book.name, COUNT(lend:id) AS countbook')->where('user_id', 1)->group('book.id')->order('lend:date'); //dvojtecka musi byt vsude
$books = array();
foreach ($myBooks as $book) {
	$book['lendcount'] = $book->related('lend')->count('*');
	$books[] = $book;
}

Coz polozi dotazy

SELECT `book`.`id`, `name`, COUNT(`lend`.`id`) AS `countbook`
FROM `book`
LEFT JOIN `lend` ON `book`.`id` = `lend`.`book_id`
WHERE (`user_id` = ?)
GROUP BY `book`.`id`
ORDER BY `lend`.`date`

a

SELECT COUNT(*), `lend`.`book_id`
FROM `lend`
WHERE (`lend`.`book_id` IN (2, 1))
GROUP BY `lend`.`book_id`

a vrati presne to, co chces.

jtousek
Člen | 951
+
0
-

Tak dnešní test jsem snad zvládl takže už mám čas. :-) Cainovo řešení je správné – téměř přesně to, co jsem měl na mysli. Trochu více NDB way mi připadá rozložit to na 3 dotazy (níže). Kód mi také připadá o něco málo lépe srozumitelný, ale samozřejmě vše co píšu je pouze věc názoru.

$books = $connection->table('book')->where('lend:user_id', 1)->group('book.id')->order('lend:date');
foreach ($books as $book) {
	$book->related('lend')->count('*'); //počet půjčení celkem
	$book->related('lend')->where('user_id', 1)->count('*'); //počet mých půjčení
}
motorcb
Člen | 552
+
0
-

@**jtousek**:

Dík, a jak se v šabloně odkážu na počet půjčení celkem ( $book->related(‚lend‘)->count(‚‘); ) a počet mých výpůjček ($book->related(‚lend‘)->where(‚user_id‘, 1)->count(‚‘);) ?

enumag
Člen | 2118
+
0
-

Nejlépe tak, že si do šablony předáš $book a related voláš až tam. ;-)

EDIT: Myslel jsem $books.

Editoval enumag (16. 10. 2012 22:12)

motorcb
Člen | 552
+
0
-

Ještě další zdokonalení :)
Chtěl bych vypisovat kolik procent z celkové výpůjčky knihy tvoří mé výpůjčky:
Kniha byla půjčená 10×, já ji měl půjčenou 1× ⇒ 10%
Kniha byla půjčená 1×, já ji měl půjčenou 1× ⇒ 100%
Kniha byla půjčená 3×, já ji měl půjčenou 1× ⇒ 33,33%

A nevím kde mám počítat procenta. Není prasárna počítat procenta v šabloně?
Nebylo by elegantnější si připravit data v presenteru a v šabloně je zobrazit?