Packages

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • NGroupedTableSelection
  • NTableRow
  • NTableSelection
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  * @package Nette\Database\Table
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * Filtered table representation.
 17:  * Selection is based on the great library NotORM http://www.notorm.com written by Jakub Vrana.
 18:  *
 19:  * @author     Jakub Vrana
 20:  *
 21:  * @property-read string $sql
 22:  * @package Nette\Database\Table
 23:  */
 24: class NTableSelection extends NObject implements Iterator, ArrayAccess, Countable
 25: {
 26:     /** @var NConnection */
 27:     protected $connection;
 28: 
 29:     /** @var string table name */
 30:     protected $name;
 31: 
 32:     /** @var string primary key field name */
 33:     protected $primary;
 34: 
 35:     /** @var array of [primary key => TableRow] read from database */
 36:     protected $rows;
 37: 
 38:     /** @var array of [primary key => TableRow] modifiable */
 39:     protected $data;
 40: 
 41:     /** @var array of column to select */
 42:     protected $select = array();
 43: 
 44:     /** @var array of where conditions */
 45:     protected $where = array();
 46: 
 47:     /** @var array of where conditions for caching */
 48:     protected $conditions = array();
 49: 
 50:     /** @var array of parameters passed to where conditions */
 51:     protected $parameters = array();
 52: 
 53:     /** @var array or columns to order by */
 54:     protected $order = array();
 55: 
 56:     /** @var int number of rows to fetch */
 57:     protected $limit = NULL;
 58: 
 59:     /** @var int first row to fetch */
 60:     protected $offset = NULL;
 61: 
 62:     /** @var string columns to grouping */
 63:     protected $group = '';
 64: 
 65:     /** @var string grouping condition */
 66:     protected $having = '';
 67: 
 68:     /** @var bool recheck referencing keys */
 69:     protected $checkReferenceNewKeys = FALSE;
 70: 
 71:     /** @var array of referenced TableSelection */
 72:     protected $referenced = array();
 73: 
 74:     /** @var array of [sql+parameters => [column => [key => TableRow]]] used by GroupedTableSelection */
 75:     protected $referencing = array();
 76: 
 77:     /** @var array of [conditions => [key => TableRow]] used by GroupedTableSelection */
 78:     protected $aggregation = array();
 79: 
 80:     /** @var array of touched columns */
 81:     protected $accessed;
 82: 
 83:     /** @var array of earlier touched columns */
 84:     protected $prevAccessed;
 85: 
 86:     /** @var array of primary key values */
 87:     protected $keys = array();
 88: 
 89:     /** @var string */
 90:     protected $delimitedName;
 91: 
 92:     /** @var string */
 93:     protected $delimitedPrimary;
 94: 
 95: 
 96: 
 97:     /**
 98:      * @param  string
 99:      * @param
100:      */
101:     public function __construct($table, NConnection $connection)
102:     {
103:         $this->name = $table;
104:         $this->connection = $connection;
105:         $this->primary = $connection->getDatabaseReflection()->getPrimary($table);
106:         $this->delimitedName = $this->tryDelimite($this->name);
107:         $this->delimitedPrimary = $connection->getSupplementalDriver()->delimite($this->primary);
108:     }
109: 
110: 
111: 
112:     /**
113:      * Saves data to cache and empty result.
114:      */
115:     public function __destruct()
116:     {
117:         $cache = $this->connection->getCache();
118:         if ($cache && !$this->select && $this->rows !== NULL) {
119:             $cache->save(array(__CLASS__, $this->name, $this->conditions), $this->accessed);
120:         }
121:         $this->rows = NULL;
122:     }
123: 
124: 
125: 
126:     /**
127:      * @return NConnection
128:      */
129:     public function getConnection()
130:     {
131:         return $this->connection;
132:     }
133: 
134: 
135: 
136:     /**
137:      * @return string
138:      */
139:     public function getName()
140:     {
141:         return $this->name;
142:     }
143: 
144: 
145: 
146:     /**
147:      * @return string
148:      */
149:     public function getPrimary()
150:     {
151:         return $this->primary;
152:     }
153: 
154: 
155: 
156:     /**
157:      * Returns row specified by primary key.
158:      * @param  mixed
159:      * @return NTableRow or FALSE if there is no such row
160:      */
161:     public function get($key)
162:     {
163:         // can also use array_pop($this->where) instead of clone to save memory
164:         $clone = clone $this;
165:         $clone->where($this->delimitedPrimary, $key);
166:         return $clone->fetch();
167:     }
168: 
169: 
170: 
171:     /**
172:      * Adds select clause, more calls appends to the end.
173:      * @param  string for example "column, MD5(column) AS column_md5"
174:      * @return NTableSelection provides a fluent interface
175:      */
176:     public function select($columns)
177:     {
178:         $this->__destruct();
179:         $this->select[] = $columns;
180:         return $this;
181:     }
182: 
183: 
184: 
185:     /**
186:      * Selects by primary key.
187:      * @param  mixed
188:      * @return NTableSelection provides a fluent interface
189:      */
190:     public function find($key)
191:     {
192:         return $this->where($this->delimitedPrimary, $key);
193:     }
194: 
195: 
196: 
197:     /**
198:      * Adds where condition, more calls appends with AND.
199:      * @param  string condition possibly containing ?
200:      * @param  mixed
201:      * @param  mixed ...
202:      * @return NTableSelection provides a fluent interface
203:      */
204:     public function where($condition, $parameters = array())
205:     {
206:         if (is_array($condition)) { // where(array('column1' => 1, 'column2 > ?' => 2))
207:             foreach ($condition as $key => $val) {
208:                 if (is_int($key)) {
209:                     $this->where($val); // where('full condition')
210:                 } else {
211:                     $this->where($key, $val);   // where('column', 1)
212:                 }
213:             }
214:             return $this;
215:         }
216: 
217:         $hash = md5(json_encode(func_get_args()));
218:         if (isset($this->conditions[$hash])) {
219:             return $this;
220:         }
221: 
222:         $this->__destruct();
223: 
224:         $this->conditions[$hash] = $condition;
225:         $condition = $this->removeExtraTables($condition);
226:         $condition = $this->tryDelimite($condition);
227: 
228:         $args = func_num_args();
229:         if ($args !== 2 || strpbrk($condition, '?:')) { // where('column < ? OR column > ?', array(1, 2))
230:             if ($args !== 2 || !is_array($parameters)) { // where('column < ? OR column > ?', 1, 2)
231:                 $parameters = func_get_args();
232:                 array_shift($parameters);
233:             }
234:             $this->parameters = array_merge($this->parameters, $parameters);
235: 
236:         } elseif ($parameters === NULL) { // where('column', NULL)
237:             $condition .= ' IS NULL';
238: 
239:         } elseif ($parameters instanceof NTableSelection) { // where('column', $db->$table())
240:             $clone = clone $parameters;
241:             if (!$clone->select) {
242:                 $clone->select = array($clone->primary);
243:             }
244:             if ($this->connection->getAttribute(PDO::ATTR_DRIVER_NAME) !== 'mysql') {
245:                 $condition .= ' IN (' . $clone->getSql() . ')';
246:             } else {
247:                 $in = array();
248:                 foreach ($clone as $row) {
249:                     $this->parameters[] = array_values(iterator_to_array($row));
250:                     $in[] = (count($row) === 1 ? '?' : '(?)');
251:                 }
252:                 $condition .= ' IN (' . ($in ? implode(', ', $in) : 'NULL') . ')';
253:             }
254: 
255:         } elseif (!is_array($parameters)) { // where('column', 'x')
256:             $condition .= ' = ?';
257:             $this->parameters[] = $parameters;
258: 
259:         } else { // where('column', array(1, 2))
260:             if ($parameters) {
261:                 $condition .= " IN (?)";
262:                 $this->parameters[] = $parameters;
263:             } else {
264:                 $condition .= " IN (NULL)";
265:             }
266:         }
267: 
268:         $this->where[] = $condition;
269:         return $this;
270:     }
271: 
272: 
273: 
274:     /**
275:      * Adds order clause, more calls appends to the end.
276:      * @param  string for example 'column1, column2 DESC'
277:      * @return NTableSelection provides a fluent interface
278:      */
279:     public function order($columns)
280:     {
281:         $this->rows = NULL;
282:         $this->order[] = $columns;
283:         return $this;
284:     }
285: 
286: 
287: 
288:     /**
289:      * Sets limit clause, more calls rewrite old values.
290:      * @param  int
291:      * @param  int
292:      * @return NTableSelection provides a fluent interface
293:      */
294:     public function limit($limit, $offset = NULL)
295:     {
296:         $this->rows = NULL;
297:         $this->limit = $limit;
298:         $this->offset = $offset;
299:         return $this;
300:     }
301: 
302: 
303: 
304:     /**
305:      * Sets offset using page number, more calls rewrite old values.
306:      * @param  int
307:      * @param  int
308:      * @return NTableSelection provides a fluent interface
309:      */
310:     public function page($page, $itemsPerPage)
311:     {
312:         $this->rows = NULL;
313:         $this->limit = $itemsPerPage;
314:         $this->offset = ($page - 1) * $itemsPerPage;
315:         return $this;
316:     }
317: 
318: 
319: 
320:     /**
321:      * Sets group clause, more calls rewrite old values.
322:      * @param  string
323:      * @param  string
324:      * @return NTableSelection provides a fluent interface
325:      */
326:     public function group($columns, $having = '')
327:     {
328:         $this->__destruct();
329:         $this->group = $columns;
330:         $this->having = $having;
331:         return $this;
332:     }
333: 
334: 
335: 
336:     /**
337:      * Executes aggregation function.
338:      * @param  string
339:      * @return string
340:      */
341:     public function aggregation($function)
342:     {
343:         $selection = new NTableSelection($this->name, $this->connection);
344:         $selection->where = $this->where;
345:         $selection->parameters = $this->parameters;
346:         $selection->conditions = $this->conditions;
347: 
348:         $selection->select($function);
349: 
350:         foreach ($selection->fetch() as $val) {
351:             return $val;
352:         }
353:     }
354: 
355: 
356: 
357:     /**
358:      * Counts number of rows.
359:      * @param  string
360:      * @return int
361:      */
362:     public function count($column = '')
363:     {
364:         if (!$column) {
365:             $this->execute();
366:             return count($this->data);
367:         }
368:         return $this->aggregation("COUNT($column)");
369:     }
370: 
371: 
372: 
373:     /**
374:      * Returns minimum value from a column.
375:      * @param  string
376:      * @return int
377:      */
378:     public function min($column)
379:     {
380:         return $this->aggregation("MIN($column)");
381:     }
382: 
383: 
384: 
385:     /**
386:      * Returns maximum value from a column.
387:      * @param  string
388:      * @return int
389:      */
390:     public function max($column)
391:     {
392:         return $this->aggregation("MAX($column)");
393:     }
394: 
395: 
396: 
397:     /**
398:      * Returns sum of values in a column.
399:      * @param  string
400:      * @return int
401:      */
402:     public function sum($column)
403:     {
404:         return $this->aggregation("SUM($column)");
405:     }
406: 
407: 
408: 
409:     /**
410:      * Returns SQL query.
411:      * @return string
412:      */
413:     public function getSql()
414:     {
415:         $join = $this->createJoins(implode(',', $this->conditions), TRUE)
416:             + $this->createJoins(implode(',', $this->select) . ",$this->group,$this->having," . implode(',', $this->order));
417: 
418:         $cache = $this->connection->getCache();
419:         if ($this->rows === NULL && $cache && !is_string($this->prevAccessed)) {
420:             $this->accessed = $this->prevAccessed = $cache->load(array(__CLASS__, $this->name, $this->conditions));
421:         }
422: 
423:         $prefix = $join ? "$this->delimitedName." : '';
424:         if ($this->select) {
425:             $cols = $this->tryDelimite($this->removeExtraTables(implode(', ', $this->select)));
426: 
427:         } elseif ($this->prevAccessed) {
428:             $cols = array_map(array($this->connection->getSupplementalDriver(), 'delimite'), array_keys(array_filter($this->prevAccessed)));
429:             $cols = $prefix . implode(', ' . $prefix, $cols);
430: 
431:         } else {
432:             $cols = $prefix . '*';
433:         }
434: 
435:         return "SELECT{$this->topString()} $cols FROM $this->delimitedName" . implode($join) . $this->whereString();
436:     }
437: 
438: 
439: 
440:     protected function createJoins($val, $inner = FALSE)
441:     {
442:         $driver = $this->connection->getSupplementalDriver();
443:         $reflection = $this->connection->getDatabaseReflection();
444:         $joins = array();
445:         preg_match_all('~\\b([a-z][\\w.:]*[.:])([a-z]\\w*|\*)(\\s+IS\\b|\\s*<=>)?~i', $val, $matches);
446:         foreach ($matches[1] as $names) {
447:             $parent = $this->name;
448:             if ($names !== "$parent.") { // case-sensitive
449:                 preg_match_all('~\\b([a-z][\\w]*|\*)([.:])~i', $names, $matches, PREG_SET_ORDER);
450:                 foreach ($matches as $match) {
451:                     list(, $name, $delimiter) = $match;
452: 
453:                     if ($delimiter === ':') {
454:                         list($table, $primary) = $reflection->getHasManyReference($parent, $name);
455:                         $column = $reflection->getPrimary($parent);
456:                     } else {
457:                         list($table, $column) = $reflection->getBelongsToReference($parent, $name);
458:                         $primary = $reflection->getPrimary($table);
459:                     }
460: 
461:                     $joins[$name] = ' '
462:                         . (!isset($joins[$name]) && $inner && !isset($match[3]) ? 'INNER' : 'LEFT')
463:                         . ' JOIN ' . $driver->delimite($table) . ($table !== $name ? ' AS ' . $driver->delimite($name) : '')
464:                         . ' ON ' . $driver->delimite($parent) . '.' . $driver->delimite($column)
465:                         . ' = ' . $driver->delimite($name) . '.' . $driver->delimite($primary);
466: 
467:                     $parent = $name;
468:                 }
469:             }
470:         }
471:         return $joins;
472:     }
473: 
474: 
475: 
476:     /**
477:      * Executes built query.
478:      * @return NULL
479:      */
480:     protected function execute()
481:     {
482:         if ($this->rows !== NULL) {
483:             return;
484:         }
485: 
486:         try {
487:             $result = $this->query($this->getSql());
488: 
489:         } catch (PDOException $exception) {
490:             if (!$this->select && $this->prevAccessed) {
491:                 $this->prevAccessed = '';
492:                 $this->accessed = array();
493:                 $result = $this->query($this->getSql());
494:             } else {
495:                 throw $exception;
496:             }
497:         }
498: 
499:         $this->rows = array();
500:         $result->setFetchMode(PDO::FETCH_ASSOC);
501:         foreach ($result as $key => $row) {
502:             $row = $result->normalizeRow($row);
503:             $this->rows[isset($row[$this->primary]) ? $row[$this->primary] : $key] = new NTableRow($row, $this);
504:         }
505:         $this->data = $this->rows;
506: 
507:         if (isset($row[$this->primary]) && !is_string($this->accessed)) {
508:             $this->accessed[$this->primary] = TRUE;
509:         }
510:     }
511: 
512: 
513: 
514:     protected function whereString()
515:     {
516:         $return = '';
517:         $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME);
518:         $where = $this->where;
519:         if ($this->limit !== NULL && $driver === 'oci') {
520:             $where[] = ($this->offset ? "rownum > $this->offset AND " : '') . 'rownum <= ' . ($this->limit + $this->offset);
521:         }
522:         if ($where) {
523:             $return .= ' WHERE (' . implode(') AND (', $where) . ')';
524:         }
525:         if ($this->group) {
526:             $return .= ' GROUP BY '. $this->tryDelimite($this->removeExtraTables($this->group));
527:         }
528:         if ($this->having) {
529:             $return .= ' HAVING '. $this->tryDelimite($this->removeExtraTables($this->having));
530:         }
531:         if ($this->order) {
532:             $return .= ' ORDER BY ' . $this->tryDelimite($this->removeExtraTables(implode(', ', $this->order)));
533:         }
534:         if ($this->limit !== NULL && $driver !== 'oci' && $driver !== 'dblib') {
535:             $return .= " LIMIT $this->limit";
536:             if ($this->offset !== NULL) {
537:                 $return .= " OFFSET $this->offset";
538:             }
539:         }
540:         return $return;
541:     }
542: 
543: 
544: 
545:     protected function topString()
546:     {
547:         if ($this->limit !== NULL && $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME) === 'dblib') {
548:             return " TOP ($this->limit)"; //! offset is not supported
549:         }
550:         return '';
551:     }
552: 
553: 
554: 
555:     protected function tryDelimite($s)
556:     {
557:         $driver = $this->connection->getSupplementalDriver();
558:         return preg_replace_callback('#(?<=[^\w`"\[]|^)[a-z_][a-z0-9_]*(?=[^\w`"(\]]|$)#i', create_function('$m', 'extract(NCFix::$vars['.NCFix::uses(array('driver'=>$driver)).'], EXTR_REFS);
559:             return strtoupper($m[0]) === $m[0] ? $m[0] : $driver->delimite($m[0]);
560:         '), $s);
561:     }
562: 
563: 
564: 
565:     protected function removeExtraTables($expression)
566:     {
567:         return preg_replace('~(?:\\b[a-z_][a-z0-9_.:]*[.:])?([a-z_][a-z0-9_]*)[.:]([a-z_*])~i', '\\1.\\2', $expression); // rewrite tab1.tab2.col
568:     }
569: 
570: 
571: 
572:     protected function query($query)
573:     {
574:         return $this->connection->queryArgs($query, $this->parameters);
575:     }
576: 
577: 
578: 
579:     /**
580:      * @internal
581:      * @param  string        column name
582:      * @param  bool|NULL     TRUE - cache, FALSE - don't cache, NULL - remove
583:      * @return bool
584:      */
585:     public function access($key, $cache = TRUE)
586:     {
587:         if ($cache === NULL) {
588:             if (is_array($this->accessed)) {
589:                 $this->accessed[$key] = FALSE;
590:             }
591:             return FALSE;
592:         }
593: 
594:         if ($key === NULL) {
595:             $this->accessed = '';
596: 
597:         } elseif (!is_string($this->accessed)) {
598:             $this->accessed[$key] = $cache;
599:         }
600: 
601:         if ($cache && !$this->select && $this->prevAccessed && ($key === NULL || !isset($this->prevAccessed[$key]))) {
602:             $this->prevAccessed = '';
603:             $this->rows = NULL;
604:             return TRUE;
605:         }
606:         return FALSE;
607:     }
608: 
609: 
610: 
611:     /********************* manipulation ****************d*g**/
612: 
613: 
614: 
615:     /**
616:      * Inserts row in a table.
617:      * @param  mixed array($column => $value)|Traversable for single row insert or Selection|string for INSERT ... SELECT
618:      * @return NTableRow or FALSE in case of an error or number of affected rows for INSERT ... SELECT
619:      */
620:     public function insert($data)
621:     {
622:         if ($data instanceof NTableSelection) {
623:             $data = $data->getSql();
624: 
625:         } elseif ($data instanceof Traversable) {
626:             $data = iterator_to_array($data);
627:         }
628: 
629:         $return = $this->connection->query("INSERT INTO $this->delimitedName", $data);
630: 
631:         if (!is_array($data)) {
632:             return $return->rowCount();
633:         }
634: 
635:         $this->checkReferenceNewKeys = TRUE;
636: 
637:         if (!isset($data[$this->primary]) && ($id = $this->connection->lastInsertId())) {
638:             $data[$this->primary] = $id;
639:             return $this->rows[$id] = new NTableRow($data, $this);
640: 
641:         } else {
642:             return new NTableRow($data, $this);
643: 
644:         }
645:     }
646: 
647: 
648: 
649:     /**
650:      * Updates all rows in result set.
651:      * @param  array|Traversable ($column => $value)
652:      * @return int number of affected rows or FALSE in case of an error
653:      */
654:     public function update($data)
655:     {
656:         if ($data instanceof Traversable) {
657:             $data = iterator_to_array($data);
658: 
659:         } elseif (!is_array($data)) {
660:             throw new InvalidArgumentException;
661:         }
662: 
663:         if (!$data) {
664:             return 0;
665:         }
666:         // joins in UPDATE are supported only in MySQL
667:         return $this->connection->queryArgs(
668:             'UPDATE' . $this->topString() . " $this->delimitedName SET ?" . $this->whereString(),
669:             array_merge(array($data), $this->parameters)
670:         )->rowCount();
671:     }
672: 
673: 
674: 
675:     /**
676:      * Deletes all rows in result set.
677:      * @return int number of affected rows or FALSE in case of an error
678:      */
679:     public function delete()
680:     {
681:         return $this->query(
682:             'DELETE' . $this->topString() . " FROM $this->delimitedName" . $this->whereString()
683:         )->rowCount();
684:     }
685: 
686: 
687: 
688:     /********************* references ****************d*g**/
689: 
690: 
691: 
692:     /**
693:      * Returns referenced row.
694:      * @param  string
695:      * @param  string
696:      * @param  bool  checks if rows contains the same primary value relations
697:      * @return NTableRow or NULL if the row does not exist
698:      */
699:     public function getReferencedTable($table, $column, $checkReferenceNewKeys = FALSE)
700:     {
701:         $referenced = & $this->referenced[$table][$column];
702:         if ($referenced === NULL || $checkReferenceNewKeys || $this->checkReferenceNewKeys) {
703:             $keys = array();
704:             foreach ($this->rows as $row) {
705:                 if ($row[$column] === NULL)
706:                     continue;
707: 
708:                 $key = $row[$column] instanceof NTableRow ? $row[$column]->getPrimary() : $row[$column];
709:                 $keys[$key] = TRUE;
710:             }
711: 
712:             if ($referenced !== NULL && $keys === array_keys($this->rows)) {
713:                 $this->checkReferenceNewKeys = FALSE;
714:                 return $referenced;
715:             }
716: 
717:             if ($keys) {
718:                 $referenced = new NTableSelection($table, $this->connection);
719:                 $referenced->where($table . '.' . $referenced->primary, array_keys($keys));
720:             } else {
721:                 $referenced = array();
722:             }
723:         }
724: 
725:         return $referenced;
726:     }
727: 
728: 
729: 
730:     /**
731:      * Returns referencing rows.
732:      * @param  string
733:      * @param  string
734:      * @return NGroupedTableSelection
735:      */
736:     public function getReferencingTable($table, $column, $active = NULL)
737:     {
738:         $referencing = new NGroupedTableSelection($table, $this, $column, $active);
739:         $referencing->where("$table.$column", array_keys((array) $this->rows)); // (array) - is NULL after insert
740:         return $referencing;
741:     }
742: 
743: 
744: 
745:     /********************* interface Iterator ****************d*g**/
746: 
747: 
748: 
749:     public function rewind()
750:     {
751:         $this->execute();
752:         $this->keys = array_keys($this->data);
753:         reset($this->keys);
754:     }
755: 
756: 
757: 
758:     /** @return NTableRow */
759:     public function current()
760:     {
761:         return $this->data[current($this->keys)];
762:     }
763: 
764: 
765: 
766:     /**
767:      * @return string row ID
768:      */
769:     public function key()
770:     {
771:         return current($this->keys);
772:     }
773: 
774: 
775: 
776:     public function next()
777:     {
778:         next($this->keys);
779:     }
780: 
781: 
782: 
783:     public function valid()
784:     {
785:         return current($this->keys) !== FALSE;
786:     }
787: 
788: 
789: 
790:     /********************* interface ArrayAccess ****************d*g**/
791: 
792: 
793: 
794:     /**
795:      * Mimic row.
796:      * @param  string row ID
797:      * @param  NTableRow
798:      * @return NULL
799:      */
800:     public function offsetSet($key, $value)
801:     {
802:         $this->execute();
803:         $this->data[$key] = $value;
804:     }
805: 
806: 
807: 
808:     /**
809:      * Returns specified row.
810:      * @param  string row ID
811:      * @return NTableRow or NULL if there is no such row
812:      */
813:     public function offsetGet($key)
814:     {
815:         $this->execute();
816:         return $this->data[$key];
817:     }
818: 
819: 
820: 
821:     /**
822:      * Tests if row exists.
823:      * @param  string row ID
824:      * @return bool
825:      */
826:     public function offsetExists($key)
827:     {
828:         $this->execute();
829:         return isset($this->data[$key]);
830:     }
831: 
832: 
833: 
834:     /**
835:      * Removes row from result set.
836:      * @param  string row ID
837:      * @return NULL
838:      */
839:     public function offsetUnset($key)
840:     {
841:         $this->execute();
842:         unset($this->data[$key]);
843:     }
844: 
845: 
846: 
847:     /**
848:      * Returns next row of result.
849:      * @return NTableRow or FALSE if there is no row
850:      */
851:     public function fetch()
852:     {
853:         $this->execute();
854:         $return = current($this->data);
855:         next($this->data);
856:         return $return;
857:     }
858: 
859: 
860: 
861:     /**
862:      * Returns all rows as associative array.
863:      * @param  string
864:      * @param  string column name used for an array value or an empty string for the whole row
865:      * @return array
866:      */
867:     public function fetchPairs($key, $value = '')
868:     {
869:         $return = array();
870:         // no $clone->select = array($key, $value) to allow efficient caching with repetitive calls with different parameters
871:         foreach ($this as $row) {
872:             $return[$row[$key]] = ($value !== '' ? $row[$value] : $row);
873:         }
874:         return $return;
875:     }
876: 
877: }
878: 
Nette Framework 2.0.1 (for PHP 5.2, prefixed) API API documentation generated by ApiGen 2.7.0