Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationLatte
      • ApplicationTracy
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsLatte
      • Framework
      • HttpTracy
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Templating
    • Utils
  • NetteModule
  • none
  • Tracy

Classes

  • ActiveRow
  • GroupedSelection
  • Selection
  • SqlBuilder

Interfaces

  • IRow
  • IRowContainer
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Database\Table;
  9: 
 10: use Nette;
 11: 
 12: 
 13: /**
 14:  * Representation of filtered table grouped by some column.
 15:  * GroupedSelection is based on the great library NotORM http://www.notorm.com written by Jakub Vrana.
 16:  *
 17:  * @author     Jakub Vrana
 18:  * @author     Jan Skrasek
 19:  */
 20: class GroupedSelection extends Selection
 21: {
 22:     /** @var Selection referenced table */
 23:     protected $refTable;
 24: 
 25:     /** @var  mixed current assigned referencing array */
 26:     protected $refCacheCurrent;
 27: 
 28:     /** @var string grouping column name */
 29:     protected $column;
 30: 
 31:     /** @var int primary key */
 32:     protected $active;
 33: 
 34: 
 35:     /**
 36:      * Creates filtered and grouped table representation.
 37:      * @param  Selection  $refTable
 38:      * @param  string  database table name
 39:      * @param  string  joining column
 40:      */
 41:     public function __construct(Selection $refTable, $table, $column)
 42:     {
 43:         $this->refTable = $refTable;
 44:         $this->column = $column;
 45:         parent::__construct($refTable->connection, $table, $refTable->reflection, $refTable->cache ? $refTable->cache->getStorage() : NULL);
 46:     }
 47: 
 48: 
 49:     /**
 50:      * Sets active group.
 51:      * @internal
 52:      * @param  int  primary key of grouped rows
 53:      * @return GroupedSelection
 54:      */
 55:     public function setActive($active)
 56:     {
 57:         $this->active = $active;
 58:         return $this;
 59:     }
 60: 
 61: 
 62:     public function select($columns)
 63:     {
 64:         if (!$this->sqlBuilder->getSelect()) {
 65:             $this->sqlBuilder->addSelect("$this->name.$this->column");
 66:         }
 67: 
 68:         return call_user_func_array('parent::select', func_get_args());
 69:     }
 70: 
 71: 
 72:     public function order($columns)
 73:     {
 74:         if (!$this->sqlBuilder->getOrder()) {
 75:             // improve index utilization
 76:             $this->sqlBuilder->addOrder("$this->name.$this->column" . (preg_match('~\bDESC\z~i', $columns) ? ' DESC' : ''));
 77:         }
 78: 
 79:         return call_user_func_array('parent::order', func_get_args());
 80:     }
 81: 
 82: 
 83:     /********************* aggregations ****************d*g**/
 84: 
 85: 
 86:     public function aggregation($function)
 87:     {
 88:         $aggregation = & $this->getRefTable($refPath)->aggregation[$refPath . $function . $this->getSql() . json_encode($this->sqlBuilder->getParameters())];
 89: 
 90:         if ($aggregation === NULL) {
 91:             $aggregation = array();
 92: 
 93:             $selection = $this->createSelectionInstance();
 94:             $selection->getSqlBuilder()->importConditions($this->getSqlBuilder());
 95:             $selection->select($function);
 96:             $selection->select("$this->name.$this->column");
 97:             $selection->group("$this->name.$this->column");
 98: 
 99:             foreach ($selection as $row) {
100:                 $aggregation[$row[$this->column]] = $row;
101:             }
102:         }
103: 
104:         if (isset($aggregation[$this->active])) {
105:             foreach ($aggregation[$this->active] as $val) {
106:                 return $val;
107:             }
108:         }
109:     }
110: 
111: 
112:     public function count($column = NULL)
113:     {
114:         $return = parent::count($column);
115:         return isset($return) ? $return : 0;
116:     }
117: 
118: 
119:     /********************* internal ****************d*g**/
120: 
121: 
122:     protected function execute()
123:     {
124:         if ($this->rows !== NULL) {
125:             $this->observeCache = $this;
126:             return;
127:         }
128: 
129:         $accessedColumns = $this->accessedColumns;
130:         $this->loadRefCache();
131: 
132:         if (!isset($this->refCacheCurrent['data'])) {
133:             // we have not fetched any data yet => init accessedColumns by cached accessedColumns
134:             $this->accessedColumns = $accessedColumns;
135: 
136:             $limit = $this->sqlBuilder->getLimit();
137:             $rows = count($this->refTable->rows);
138:             if ($limit && $rows > 1) {
139:                 $this->sqlBuilder->setLimit(NULL, NULL);
140:             }
141:             parent::execute();
142:             $this->sqlBuilder->setLimit($limit, NULL);
143:             $data = array();
144:             $offset = array();
145:             $this->accessColumn($this->column);
146:             foreach ((array) $this->rows as $key => $row) {
147:                 $ref = & $data[$row[$this->column]];
148:                 $skip = & $offset[$row[$this->column]];
149:                 if ($limit === NULL || $rows <= 1 || (count($ref) < $limit && $skip >= $this->sqlBuilder->getOffset())) {
150:                     $ref[$key] = $row;
151:                 } else {
152:                     unset($this->rows[$key]);
153:                 }
154:                 $skip++;
155:                 unset($ref, $skip);
156:             }
157: 
158:             $this->refCacheCurrent['data'] = $data;
159:             $this->data = & $this->refCacheCurrent['data'][$this->active];
160:         }
161: 
162:         $this->observeCache = $this;
163:         if ($this->data === NULL) {
164:             $this->data = array();
165:         } else {
166:             foreach ($this->data as $row) {
167:                 $row->setTable($this); // injects correct parent GroupedSelection
168:             }
169:             reset($this->data);
170:         }
171:     }
172: 
173: 
174:     protected function getRefTable(& $refPath)
175:     {
176:         $refObj = $this->refTable;
177:         $refPath = $this->name . '.';
178:         while ($refObj instanceof self) {
179:             $refPath .= $refObj->name . '.';
180:             $refObj = $refObj->refTable;
181:         }
182: 
183:         return $refObj;
184:     }
185: 
186: 
187:     protected function loadRefCache()
188:     {
189:         $hash = $this->getSpecificCacheKey();
190:         $referencing = & $this->refCache['referencing'][$this->getGeneralCacheKey()];
191:         $this->observeCache      = & $referencing['observeCache'];
192:         $this->refCacheCurrent   = & $referencing[$hash];
193:         $this->accessedColumns   = & $referencing[$hash]['accessed'];
194:         $this->specificCacheKey  = & $referencing[$hash]['specificCacheKey'];
195:         $this->rows              = & $referencing[$hash]['rows'];
196: 
197:         if (isset($referencing[$hash]['data'][$this->active])) {
198:             $this->data = & $referencing[$hash]['data'][$this->active];
199:         }
200:     }
201: 
202: 
203:     /********************* manipulation ****************d*g**/
204: 
205: 
206:     public function insert($data)
207:     {
208:         if ($data instanceof \Traversable && !$data instanceof Selection) {
209:             $data = iterator_to_array($data);
210:         }
211: 
212:         if (Nette\Utils\Arrays::isList($data)) {
213:             foreach (array_keys($data) as $key) {
214:                 $data[$key][$this->column] = $this->active;
215:             }
216:         } else {
217:             $data[$this->column] = $this->active;
218:         }
219: 
220:         return parent::insert($data);
221:     }
222: 
223: 
224:     public function update($data)
225:     {
226:         $builder = $this->sqlBuilder;
227: 
228:         $this->sqlBuilder = clone $this->sqlBuilder;
229:         $this->where($this->column, $this->active);
230:         $return = parent::update($data);
231: 
232:         $this->sqlBuilder = $builder;
233:         return $return;
234:     }
235: 
236: 
237:     public function delete()
238:     {
239:         $builder = $this->sqlBuilder;
240: 
241:         $this->sqlBuilder = clone $this->sqlBuilder;
242:         $this->where($this->column, $this->active);
243:         $return = parent::delete();
244: 
245:         $this->sqlBuilder = $builder;
246:         return $return;
247:     }
248: 
249: }
250: 
Nette 2.2 API documentation generated by ApiGen 2.8.0