Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • 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
    • Bridges
      • Nette

Classes

  • ActiveRow
  • GroupedSelection
  • Selection
  • SqlBuilder

Interfaces

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