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
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Utils
  • none
  • Tracy
    • Bridges
      • Nette

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