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