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 $delimitedColumn;
35:
36:
37: protected $active;
38:
39:
40: protected $referencing;
41:
42:
43: protected $aggregation = array();
44:
45:
46:
47: public function __construct($name, Selection $refTable, $column)
48: {
49: parent::__construct($name, $refTable->connection);
50: $this->refTable = $refTable;
51: $this->column = $column;
52: $this->delimitedColumn = $this->connection->getSupplementalDriver()->delimite($this->column);
53: }
54:
55:
56:
57: 58: 59: 60: 61:
62: public function setActive($active)
63: {
64: $this->rows = NULL;
65: $this->active = $active;
66: $this->select = $this->where = $this->conditions = $this->parameters = $this->order = array();
67: $this->limit = $this->offset = NULL;
68: $this->group = $this->having = '';
69: return $this;
70: }
71:
72:
73:
74:
75: public function through($column)
76: {
77: trigger_error(__METHOD__ . '() is deprecated; use ' . __CLASS__ . '::related("' . $this->name . '", "' . $column . '") instead.', E_USER_WARNING);
78: $this->column = $column;
79: $this->delimitedColumn = $this->refTable->connection->getSupplementalDriver()->delimite($this->column);
80: return $this;
81: }
82:
83:
84:
85: public function select($columns)
86: {
87: if (!$this->select) {
88: $this->select[] = "$this->delimitedName.$this->delimitedColumn";
89: }
90: return parent::select($columns);
91: }
92:
93:
94:
95: public function order($columns)
96: {
97: if (!$this->order) {
98: $this->order[] = "$this->delimitedName.$this->delimitedColumn"
99: . (preg_match('~\\bDESC$~i', $columns) ? ' DESC' : '');
100: }
101: return parent::order($columns);
102: }
103:
104:
105:
106: public function aggregation($function)
107: {
108: $aggregation = & $this->aggregation[$function . implode('', $this->where) . implode('', $this->conditions)];
109: if ($aggregation === NULL) {
110: $aggregation = array();
111:
112: $selection = new Selection($this->name, $this->connection);
113: $selection->where = $this->where;
114: $selection->parameters = $this->parameters;
115: $selection->conditions = $this->conditions;
116:
117: $selection->select($function);
118: $selection->select("{$this->name}.{$this->column}");
119: $selection->group("{$this->name}.{$this->column}");
120:
121: foreach ($selection as $row) {
122: $aggregation[$row[$this->column]] = $row;
123: }
124: }
125:
126: if (isset($aggregation[$this->active])) {
127: foreach ($aggregation[$this->active] as $val) {
128: return $val;
129: }
130: }
131: }
132:
133:
134:
135: public function count($column = '')
136: {
137: $return = parent::count($column);
138: return isset($return) ? $return : 0;
139: }
140:
141:
142:
143: public function insert($data)
144: {
145: if ($data instanceof \Traversable && !$data instanceof Selection) {
146: $data = iterator_to_array($data);
147: }
148:
149: if (Nette\Utils\Validators::isList($data)) {
150: foreach (array_keys($data) as $key) {
151: $data[$key][$this->column] = $this->active;
152: }
153: } else {
154: $data[$this->column] = $this->active;
155: }
156:
157: return parent::insert($data);
158: }
159:
160:
161:
162: public function update($data)
163: {
164: $condition = array($this->where, $this->parameters);
165:
166: $this->where[0] = "$this->delimitedColumn = ?";
167: $this->parameters[0] = $this->active;
168: $return = parent::update($data);
169:
170: list($this->where, $this->parameters) = $condition;
171: return $return;
172: }
173:
174:
175:
176: public function delete()
177: {
178: $condition = array($this->where, $this->parameters);
179:
180: $this->where[0] = "$this->delimitedColumn = ?";
181: $this->parameters[0] = $this->active;
182: $return = parent::delete();
183:
184: list($this->where, $this->parameters) = $condition;
185: return $return;
186: }
187:
188:
189:
190: protected function execute()
191: {
192: if ($this->rows !== NULL) {
193: return;
194: }
195:
196: $hash = md5($this->getSql() . json_encode($this->parameters));
197: $referencing = & $this->referencing[$hash];
198: if ($referencing === NULL) {
199: $limit = $this->limit;
200: $rows = count($this->refTable->rows);
201: if ($this->limit && $rows > 1) {
202: $this->limit = NULL;
203: }
204: parent::execute();
205: $this->limit = $limit;
206: $referencing = array();
207: $offset = array();
208: foreach ($this->rows as $key => $row) {
209: $ref = & $referencing[$row[$this->column]];
210: $skip = & $offset[$row[$this->column]];
211: if ($limit === NULL || $rows <= 1 || (count($ref) < $limit && $skip >= $this->offset)) {
212: $ref[$key] = $row;
213: } else {
214: unset($this->rows[$key]);
215: }
216: $skip++;
217: unset($ref, $skip);
218: }
219: }
220:
221: $this->data = & $referencing[$this->active];
222: if ($this->data === NULL) {
223: $this->data = array();
224: } else {
225: reset($this->data);
226: }
227: }
228:
229: }
230: