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
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • ActiveRow
  • GroupedSelection
  • Selection
  • SqlBuilder

Interfaces

  • IRow
  • IRowContainer
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  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 static
 56:      */
 57:     public function setActive($active)
 58:     {
 59:         $this->active = $active;
 60:         return $this;
 61:     }
 62: 
 63: 
 64:     /**
 65:      * @return static
 66:      */
 67:     public function select($columns, ...$params)
 68:     {
 69:         if (!$this->sqlBuilder->getSelect()) {
 70:             $this->sqlBuilder->addSelect("$this->name.$this->column");
 71:         }
 72: 
 73:         return parent::select($columns, ...$params);
 74:     }
 75: 
 76: 
 77:     /**
 78:      * @return static
 79:      */
 80:     public function order($columns, ...$params)
 81:     {
 82:         if (!$this->sqlBuilder->getOrder()) {
 83:             // improve index utilization
 84:             $this->sqlBuilder->addOrder("$this->name.$this->column" . (preg_match('~\bDESC\z~i', $columns) ? ' DESC' : ''));
 85:         }
 86: 
 87:         return parent::order($columns, ...$params);
 88:     }
 89: 
 90: 
 91:     /********************* aggregations ****************d*g**/
 92: 
 93: 
 94:     public function aggregation($function)
 95:     {
 96:         $aggregation = &$this->getRefTable($refPath)->aggregation[$refPath . $function . $this->sqlBuilder->getSelectQueryHash($this->getPreviousAccessedColumns())];
 97: 
 98:         if ($aggregation === null) {
 99:             $aggregation = [];
100: 
101:             $selection = $this->createSelectionInstance();
102:             $selection->getSqlBuilder()->importConditions($this->getSqlBuilder());
103:             $selection->select($function);
104:             $selection->select("$this->name.$this->column");
105:             $selection->group("$this->name.$this->column");
106: 
107:             foreach ($selection as $row) {
108:                 $aggregation[$row[$this->column]] = $row;
109:             }
110:         }
111: 
112:         if (isset($aggregation[$this->active])) {
113:             foreach ($aggregation[$this->active] as $val) {
114:                 return $val;
115:             }
116:         }
117:     }
118: 
119: 
120:     /**
121:      * @return int
122:      */
123:     public function count($column = null)
124:     {
125:         $return = parent::count($column);
126:         return isset($return) ? $return : 0;
127:     }
128: 
129: 
130:     /********************* internal ****************d*g**/
131: 
132: 
133:     protected function execute()
134:     {
135:         if ($this->rows !== null) {
136:             $this->observeCache = $this;
137:             return;
138:         }
139: 
140:         $accessedColumns = $this->accessedColumns;
141:         $this->loadRefCache();
142: 
143:         if (!isset($this->refCacheCurrent['data'])) {
144:             // we have not fetched any data yet => init accessedColumns by cached accessedColumns
145:             $this->accessedColumns = $accessedColumns;
146: 
147:             $limit = $this->sqlBuilder->getLimit();
148:             $rows = count($this->refTable->rows);
149:             if ($limit && $rows > 1) {
150:                 $this->sqlBuilder->setLimit(null, null);
151:             }
152:             parent::execute();
153:             $this->sqlBuilder->setLimit($limit, null);
154:             $data = [];
155:             $offset = [];
156:             $this->accessColumn($this->column);
157:             foreach ((array) $this->rows as $key => $row) {
158:                 $ref = &$data[$row[$this->column]];
159:                 $skip = &$offset[$row[$this->column]];
160:                 if ($limit === null || $rows <= 1 || (count($ref ?: []) < $limit && $skip >= $this->sqlBuilder->getOffset())) {
161:                     $ref[$key] = $row;
162:                 } else {
163:                     unset($this->rows[$key]);
164:                 }
165:                 $skip++;
166:                 unset($ref, $skip);
167:             }
168: 
169:             $this->refCacheCurrent['data'] = $data;
170:             $this->data = &$this->refCacheCurrent['data'][$this->active];
171:         }
172: 
173:         $this->observeCache = $this;
174:         if ($this->data === null) {
175:             $this->data = [];
176:         } else {
177:             foreach ($this->data as $row) {
178:                 $row->setTable($this); // injects correct parent GroupedSelection
179:             }
180:             reset($this->data);
181:         }
182:     }
183: 
184: 
185:     /**
186:      * @return Selection
187:      */
188:     protected function getRefTable(&$refPath)
189:     {
190:         $refObj = $this->refTable;
191:         $refPath = $this->name . '.';
192:         while ($refObj instanceof self) {
193:             $refPath .= $refObj->name . '.';
194:             $refObj = $refObj->refTable;
195:         }
196: 
197:         return $refObj;
198:     }
199: 
200: 
201:     protected function loadRefCache()
202:     {
203:         $hash = $this->getSpecificCacheKey();
204:         $referencing = &$this->refCache['referencing'][$this->getGeneralCacheKey()];
205:         $this->observeCache = &$referencing['observeCache'];
206:         $this->refCacheCurrent = &$referencing[$hash];
207:         $this->accessedColumns = &$referencing[$hash]['accessed'];
208:         $this->specificCacheKey = &$referencing[$hash]['specificCacheKey'];
209:         $this->rows = &$referencing[$hash]['rows'];
210: 
211:         if (isset($referencing[$hash]['data'][$this->active])) {
212:             $this->data = &$referencing[$hash]['data'][$this->active];
213:         }
214:     }
215: 
216: 
217:     protected function emptyResultSet($saveCache = true, $deleteRererencedCache = true)
218:     {
219:         parent::emptyResultSet($saveCache, false);
220:     }
221: 
222: 
223:     /********************* manipulation ****************d*g**/
224: 
225: 
226:     public function insert($data)
227:     {
228:         if ($data instanceof \Traversable && !$data instanceof Selection) {
229:             $data = iterator_to_array($data);
230:         }
231: 
232:         if (Nette\Utils\Arrays::isList($data)) {
233:             foreach (array_keys($data) as $key) {
234:                 $data[$key][$this->column] = $this->active;
235:             }
236:         } else {
237:             $data[$this->column] = $this->active;
238:         }
239: 
240:         return parent::insert($data);
241:     }
242: 
243: 
244:     public function update($data)
245:     {
246:         $builder = $this->sqlBuilder;
247: 
248:         $this->sqlBuilder = clone $this->sqlBuilder;
249:         $this->where($this->column, $this->active);
250:         $return = parent::update($data);
251: 
252:         $this->sqlBuilder = $builder;
253:         return $return;
254:     }
255: 
256: 
257:     public function delete()
258:     {
259:         $builder = $this->sqlBuilder;
260: 
261:         $this->sqlBuilder = clone $this->sqlBuilder;
262:         $this->where($this->column, $this->active);
263:         $return = parent::delete();
264: 
265:         $this->sqlBuilder = $builder;
266:         return $return;
267:     }
268: }
269: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0