1 <?php
2
3 namespace Balance\Model\Persistence\Db;
4
5 use Balance\Model\ModelException;
6 use Balance\Model\Persistence\PersistenceInterface;
7 use Exception;
8 use IntlDateFormatter;
9 use NumberFormatter;
10 use Zend\Db\Sql\Expression;
11 use Zend\Db\Sql\Select;
12 use Zend\Paginator;
13 use Zend\ServiceManager\ServiceLocatorAwareInterface;
14 use Zend\ServiceManager\ServiceLocatorAwareTrait;
15 use Zend\Stdlib\Parameters;
16
17 18 19
20 class Postings implements ServiceLocatorAwareInterface, PersistenceInterface
21 {
22 use ServiceLocatorAwareTrait;
23
24 25 26 27 28
29 protected function buildDateFormatter()
30 {
31 return new IntlDateFormatter(null, IntlDateFormatter::MEDIUM, IntlDateFormatter::MEDIUM);
32 }
33
34 35 36
37 public function fetch(Parameters $params)
38 {
39
40 $db = $this->getServiceLocator()->get('db');
41
42 $select = (new Select())
43 ->from(array('p' => 'postings'))
44 ->columns(array('id', 'datetime', 'description'))
45 ->order(array('p.datetime DESC'));
46
47 if ($params['keywords']) {
48
49 $select->where(function ($where) use ($params) {
50
51 $language = locale_get_display_language(null, 'en');
52
53 $document = new Expression(
54 'TO_TSVECTOR(\'' . $language . '\', STRING_AGG("a"."name", \' \'))'
55 . ' || TO_TSVECTOR(\'' . $language . '\', STRING_AGG("p"."description", \' \'))'
56 );
57
58 $search = (new Select())
59 ->from(array('p' => 'postings'))
60 ->columns(array('posting_id' => 'id', 'document' => $document))
61 ->join(array('e' => 'entries'), 'p.id = e.posting_id', array())
62 ->join(array('a' => 'accounts'), 'a.id = e.account_id', array())
63 ->group(array('p.id'));
64
65 $subselect = (new Select())
66 ->from(array('search' => $search))
67 ->columns(array('posting_id'))
68 ->where(function ($where) use ($params, $language) {
69 $where->expression(
70 '"search"."document" @@ TO_TSQUERY(\'' . $language . '\', ?)',
71 sprintf("'%s'", addslashes($params['keywords']))
72 );
73 });
74
75 $where->in('p.id', $subselect);
76 });
77 }
78
79 if ($params['account_id']) {
80
81 $subselect = (new Select())
82 ->from(array('e' => 'entries'))
83 ->columns(array('posting_id'))
84 ->where(function ($where) use ($params) {
85 $where->equalTo('e.account_id', $params['account_id']);
86 });
87
88 $select->where(function ($where) use ($subselect) {
89 $where->in('p.id', $subselect);
90 });
91 }
92
93 $formatter = $this->buildDateFormatter();
94
95 if ($params['datetime_begin']) {
96
97 $datetime = date('c', $formatter->parse($params['datetime_begin']));
98
99 $select->where(function ($where) use ($datetime) {
100 $where->greaterThanOrEqualTo('p.datetime', $datetime);
101 });
102 }
103
104 if ($params['datetime_end']) {
105
106 $datetime = date('c', $formatter->parse($params['datetime_end']));
107
108 $select->where(function ($where) use ($datetime) {
109 $where->lessThanOrEqualTo('p.datetime', $datetime);
110 });
111 }
112
113 $result = new Paginator\Paginator(new Paginator\Adapter\DbSelect($select, $db));
114
115 if ($params['page']) {
116
117 $result->setCurrentPageNumber($params['page']);
118 }
119
120 return $result;
121 }
122
123 124 125
126 public function find(Parameters $params)
127 {
128
129 if (! $params['id']) {
130 throw new ModelException('Unknown Primary Key');
131 }
132
133 $db = $this->getServiceLocator()->get('db');
134
135 $select = (new Select())
136 ->from(array('p' => 'postings'))
137 ->columns(array('id', 'datetime', 'description'))
138 ->where(function ($where) use ($params) {
139 $where->equalTo('p.id', (int) $params['id']);
140 });
141
142 $row = $db->query($select->getSqlString($db->getPlatform()))->execute()->current();
143
144 if (! $row) {
145 throw new ModelException('Unknown Element');
146 }
147
148 $formatter = $this->buildDateFormatter();
149
150 $element = array(
151 'id' => (int) $row['id'],
152 'datetime' => $formatter->format(strtotime($row['datetime'])),
153 'description' => $row['description'],
154 'entries' => array(),
155 );
156
157
158 $select = (new Select())
159 ->from(array('e' => 'entries'))
160 ->columns(array('type', 'account_id', 'value'))
161 ->where(function ($where) use ($element) {
162 $where->equalTo('e.posting_id', $element['id']);
163 })
164 ->order(array('e.position'));
165
166 $rowset = $db->query($select->getSqlString($db->getPlatform()))->execute();
167
168 $formatter = new NumberFormatter(null, NumberFormatter::DECIMAL);
169
170 $formatter->setSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL, '');
171
172 $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
173
174 foreach ($rowset as $row) {
175 $element['entries'][] = array(
176 'type' => $row['type'],
177 'account_id' => $row['account_id'],
178 'value' => $formatter->format($row['value']),
179 );
180 }
181
182 return $element;
183 }
184
185 186 187
188 public function save(Parameters $data)
189 {
190
191 $connection = $this->getServiceLocator()->get('db')->getDriver()->getConnection();
192 $tbPostings = $this->getServiceLocator()->get('Balance\Db\TableGateway\Postings');
193 $tbEntries = $this->getServiceLocator()->get('Balance\Db\TableGateway\Entries');
194
195 $formatter = $this->buildDateFormatter();
196 $datetime = date('c', $formatter->parse($data['datetime']));
197
198
199 try {
200
201 $connection->beginTransaction();
202
203 if ($data['id']) {
204
205 $count = $tbPostings->update(array(
206 'datetime' => $datetime,
207 'description' => $data['description'],
208 ), function ($where) use ($data) {
209 $where->equalTo('id', $data['id']);
210 });
211
212 if ($count !== 1) {
213 throw new ModelException('Unknown Element');
214 }
215 } else {
216
217 $tbPostings->insert(array(
218 'datetime' => $datetime,
219 'description' => $data['description'],
220 ));
221
222 $data['id'] = (int) $tbPostings->getLastInsertValue();
223 }
224
225 $tbEntries->delete(function ($delete) use ($data) {
226 $delete->where(function ($where) use ($data) {
227 $where->equalTo('posting_id', $data['id']);
228 });
229 });
230
231 $formatter = new NumberFormatter(null, NumberFormatter::CURRENCY);
232
233 $formatter->setSymbol(NumberFormatter::CURRENCY_SYMBOL, '');
234
235 $position = 0;
236
237 foreach ($data['entries'] as $subdata) {
238
239 $tbEntries->insert(array(
240 'posting_id' => $data['id'],
241 'account_id' => $subdata['account_id'],
242 'type' => $subdata['type'],
243 'value' => $formatter->parseCurrency($subdata['value'], $currency),
244 'position' => $position++,
245 ));
246
247 unset($currency);
248 }
249
250 $connection->commit();
251 } catch (Exception $e) {
252
253 $connection->rollback();
254
255 throw new ModelException('Database Error', null, $e);
256 }
257
258 return $this;
259 }
260
261 262 263
264 public function remove(Parameters $params)
265 {
266
267 if (! $params['id']) {
268 throw new ModelException('Unknown Primary Key');
269 }
270
271 $tbPostings = $this->getServiceLocator()->get('Balance\Db\TableGateway\Postings');
272
273 $count = $tbPostings->delete(function ($delete) use ($params) {
274 $delete->where(function ($where) use ($params) {
275 $where->equalTo('id', $params['id']);
276 });
277 });
278
279 if ($count !== 1) {
280 throw new ModelException('Unknown Element');
281 }
282
283 return $this;
284 }
285 }
286