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