1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Database\Table;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17: 18: 19:
20: class GroupedSelection extends Selection
21: {
22:
23: protected $refTable;
24:
25:
26: protected $column;
27:
28:
29: protected $active;
30:
31:
32: 33: 34: 35: 36: 37:
38: public function __construct(Selection $refTable, $table, $column)
39: {
40: parent::__construct($table, $refTable->connection);
41: $this->refTable = $refTable;
42: $this->column = $column;
43: }
44:
45:
46: 47: 48: 49: 50: 51:
52: public function setActive($active)
53: {
54: $this->active = $active;
55: return $this;
56: }
57:
58:
59:
60: public function through($column)
61: {
62: trigger_error(__METHOD__ . '() is deprecated; use ' . __CLASS__ . '::related("' . $this->name . '", "' . $column . '") instead.', E_USER_WARNING);
63: $this->column = $column;
64: $this->delimitedColumn = $this->refTable->connection->getSupplementalDriver()->delimite($this->column);
65: return $this;
66: }
67:
68:
69: public function select($columns)
70: {
71: if (!$this->sqlBuilder->getSelect()) {
72: $this->sqlBuilder->addSelect("$this->name.$this->column");
73: }
74:
75: return parent::select($columns);
76: }
77:
78:
79: public function order($columns)
80: {
81: if (!$this->sqlBuilder->getOrder()) {
82:
83: $this->sqlBuilder->addOrder("$this->name.$this->column" . (preg_match('~\bDESC\z~i', $columns) ? ' DESC' : ''));
84: }
85:
86: return parent::order($columns);
87: }
88:
89:
90:
91:
92:
93: public function aggregation($function)
94: {
95: $aggregation = & $this->getRefTable($refPath)->aggregation[$refPath . $function . $this->getSql() . json_encode($this->sqlBuilder->getParameters())];
96:
97: if ($aggregation === NULL) {
98: $aggregation = array();
99:
100: $selection = $this->createSelectionInstance();
101: $selection->getSqlBuilder()->importConditions($this->getSqlBuilder());
102: $selection->select($function);
103: $selection->select("$this->name.$this->column");
104: $selection->group("$this->name.$this->column");
105:
106: foreach ($selection as $row) {
107: $aggregation[$row[$this->column]] = $row;
108: }
109: }
110:
111: if (isset($aggregation[$this->active])) {
112: foreach ($aggregation[$this->active] as $val) {
113: return $val;
114: }
115: }
116: }
117:
118:
119: public function count($column = NULL)
120: {
121: $return = parent::count($column);
122: return isset($return) ? $return : 0;
123: }
124:
125:
126:
127:
128:
129: protected function execute()
130: {
131: if ($this->rows !== NULL) {
132: $this->observeCache = $this;
133: return;
134: }
135:
136: $hash = md5($this->getSql() . json_encode($this->sqlBuilder->getParameters()));
137: $accessedColumns = $this->accessedColumns;
138:
139: $referencingBase = & $this->getRefTable($refPath)->referencing[$this->getCacheKey()];
140: $referencing = & $referencingBase[$refPath . $hash];
141: $this->rows = & $referencing['rows'];
142: $this->referenced = & $referencing['refs'];
143: $this->accessedColumns = & $referencing['accessed'];
144: $this->observeCache = & $referencingBase['observeCache'];
145: $refData = & $referencing['data'];
146:
147: if ($refData === NULL) {
148:
149: $this->accessedColumns = $accessedColumns;
150:
151: $limit = $this->sqlBuilder->getLimit();
152: $rows = count($this->refTable->rows);
153: if ($limit && $rows > 1) {
154: $this->sqlBuilder->setLimit(NULL, NULL);
155: }
156: parent::execute();
157: $this->sqlBuilder->setLimit($limit, NULL);
158: $refData = array();
159: $offset = array();
160: $this->accessColumn($this->column);
161: foreach ((array) $this->rows as $key => $row) {
162: $ref = & $refData[$row[$this->column]];
163: $skip = & $offset[$row[$this->column]];
164: if ($limit === NULL || $rows <= 1 || (count($ref) < $limit && $skip >= $this->sqlBuilder->getOffset())) {
165: $ref[$key] = $row;
166: } else {
167: unset($this->rows[$key]);
168: }
169: $skip++;
170: unset($ref, $skip);
171: }
172: }
173:
174: $this->observeCache = $this;
175: $this->data = & $refData[$this->active];
176: if ($this->data === NULL) {
177: $this->data = array();
178: } else {
179: foreach ($this->data as $row) {
180: $row->setTable($this);
181: }
182: reset($this->data);
183: $this->checkReferenced = TRUE;
184: }
185: }
186:
187:
188: protected function getRefTable(& $refPath)
189: {
190: $refObj = $this->refTable;
191: $refPath = $this->name . '.';
192: while ($refObj instanceof GroupedSelection) {
193: $refPath .= $refObj->name . '.';
194: $refObj = $refObj->refTable;
195: }
196:
197: return $refObj;
198: }
199:
200:
201:
202:
203:
204: public function insert($data)
205: {
206: if ($data instanceof \Traversable && !$data instanceof Selection) {
207: $data = iterator_to_array($data);
208: }
209:
210: if (Nette\Utils\Validators::isList($data)) {
211: foreach (array_keys($data) as $key) {
212: $data[$key][$this->column] = $this->active;
213: }
214: } else {
215: $data[$this->column] = $this->active;
216: }
217:
218: return parent::insert($data);
219: }
220:
221:
222: public function update($data)
223: {
224: $builder = $this->sqlBuilder;
225:
226: $this->sqlBuilder = clone $this->sqlBuilder;
227: $this->where($this->column, $this->active);
228: $return = parent::update($data);
229:
230: $this->sqlBuilder = $builder;
231: return $return;
232: }
233:
234:
235: public function delete()
236: {
237: $builder = $this->sqlBuilder;
238:
239: $this->sqlBuilder = clone $this->sqlBuilder;
240: $this->where($this->column, $this->active);
241: $return = parent::delete();
242:
243: $this->sqlBuilder = $builder;
244: return $return;
245: }
246:
247: }
248: