]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Entity/PdfModel.php
phpdoc
[galette.git] / galette / lib / Galette / Entity / PdfModel.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * PDF Model
7 *
8 * PHP version 5
9 *
10 * Copyright © 2013-2020 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Entity
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2013-2020 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @link http://galette.tuxfamily.org
34 * @since Available since 0.7.5dev - 2013-02-19
35 */
36
37 namespace Galette\Entity;
38
39 use Throwable;
40 use Galette\Core\Db;
41 use Galette\Core\Preferences;
42 use Galette\Features\Replacements;
43 use Galette\Repository\PdfModels;
44 use Analog\Analog;
45 use Laminas\Db\Sql\Expression;
46
47 /**
48 * PDF Model
49 *
50 * @category Entity
51 * @name PdfModel
52 * @package Galette
53 * @author Johan Cwiklinski <johan@x-tnd.be>
54 * @copyright 2013-2020 The Galette Team
55 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
56 * @link http://galette.tuxfamily.org
57 * @since Available since 0.7.5dev - 2013-02-19
58 *
59 * @property integer $id
60 * @property string $name
61 * @property integer $type
62 * @property string $header
63 * @property string $footer
64 * @property string $title
65 * @property string $subtitle
66 * @property string $body
67 * @property string $styles
68 * @property PdfMain $parent
69 */
70
71 abstract class PdfModel
72 {
73 use Replacements;
74
75 public const TABLE = 'pdfmodels';
76 public const PK = 'model_id';
77
78 public const MAIN_MODEL = 1;
79 public const INVOICE_MODEL = 2;
80 public const RECEIPT_MODEL = 3;
81 public const ADHESION_FORM_MODEL = 4;
82
83 private $id;
84 private $name;
85 private $type;
86 private $header;
87 private $footer;
88 private $title;
89 private $subtitle;
90 private $body;
91 private $styles;
92 private $parent;
93
94 /**
95 * Main constructor
96 *
97 * @param Db $zdb Database instance
98 * @param Preferences $preferences Galette preferences
99 * @param int $type Model type
100 * @param mixed $args Arguments
101 */
102 public function __construct(Db $zdb, Preferences $preferences, $type, $args = null)
103 {
104 global $container, $login;
105 $this->router = $container->get('router');
106 $this->preferences = $preferences;
107 $this
108 ->setDb($zdb)
109 ->setLogin($login);
110 $this->type = $type;
111
112 if (is_int($args)) {
113 $this->load($args);
114 } elseif ($args !== null && is_object($args)) {
115 $this->loadFromRs($args);
116 } else {
117 $this->load($type);
118 }
119
120 $this->setPatterns($this->getMainPatterns());
121 $this->setMain();
122 }
123
124 /**
125 * Load a Model from its identifier
126 *
127 * @param int $id Identifier
128 * @param boolean $init Init data if required model is missing
129 *
130 * @return void
131 */
132 protected function load($id, $init = true)
133 {
134 global $login;
135
136 try {
137 $select = $this->zdb->select(self::TABLE);
138 $select->limit(1)
139 ->where(self::PK . ' = ' . $id);
140
141 $results = $this->zdb->execute($select);
142
143 $count = $results->count();
144 if ($count === 0) {
145 if ($init === true) {
146 $models = new PdfModels($this->zdb, $this->preferences, $login);
147 $models->installInit();
148 $this->load($id, false);
149 } else {
150 throw new \RuntimeException('Model not found!');
151 }
152 } else {
153 $this->loadFromRs($results->current());
154 }
155 } catch (Throwable $e) {
156 Analog::log(
157 'An error occurred loading model #' . $id . "Message:\n" .
158 $e->getMessage(),
159 Analog::ERROR
160 );
161 throw $e;
162 }
163 }
164
165 /**
166 * Load model from a db ResultSet
167 *
168 * @param ResultSet $rs ResultSet
169 *
170 * @return void
171 */
172 protected function loadFromRs($rs)
173 {
174 $pk = self::PK;
175 $this->id = (int)$rs->$pk;
176
177 $callback = function ($matches) {
178 return _T($matches[1]);
179 };
180 $this->name = preg_replace_callback(
181 '/_T\("([^\"]+)"\)/',
182 $callback,
183 $rs->model_name
184 );
185
186 $this->title = $rs->model_title;
187 $this->subtitle = $rs->model_subtitle;
188 $this->header = $rs->model_header;
189 $this->footer = $rs->model_footer;
190 $this->body = $rs->model_body;
191 $this->styles .= $rs->model_styles;
192
193 if ($this->id > self::MAIN_MODEL) {
194 //FIXME: for now, parent will always be a PdfMain
195 $this->parent = new PdfMain(
196 $this->zdb,
197 $this->preferences,
198 (int)$rs->model_parent
199 );
200 }
201 }
202
203 /**
204 * Store model in database
205 *
206 * @return boolean
207 */
208 public function store()
209 {
210 $title = $this->title;
211 if (trim($title) === '') {
212 $title = new Expression('NULL');
213 }
214
215 $subtitle = $this->subtitle;
216 if (trim($subtitle) === '') {
217 $subtitle = new Expression('NULL');
218 }
219
220 $data = array(
221 'model_header' => $this->header,
222 'model_footer' => $this->footer,
223 'model_type' => $this->type,
224 'model_title' => $title,
225 'model_subtitle' => $subtitle,
226 'model_body' => $this->body,
227 'model_styles' => $this->styles
228 );
229
230 try {
231 if ($this->id !== null) {
232 $update = $this->zdb->update(self::TABLE);
233 $update->set($data)->where(
234 self::PK . '=' . $this->id
235 );
236 $this->zdb->execute($update);
237 } else {
238 $data['model_name'] = $this->name;
239 $insert = $this->zdb->insert(self::TABLE);
240 $insert->values($data);
241 $add = $this->zdb->execute($insert);
242 if (!($add->count() > 0)) {
243 Analog::log('Not stored!', Analog::ERROR);
244 return false;
245 }
246 }
247 return true;
248 } catch (Throwable $e) {
249 Analog::log(
250 'An error occurred storing model: ' . $e->getMessage() .
251 "\n" . print_r($data, true),
252 Analog::ERROR
253 );
254 return false;
255 }
256 }
257
258 /**
259 * Get object class for specified type
260 *
261 * @param int $type Type
262 *
263 * @return string
264 */
265 public static function getTypeClass(int $type)
266 {
267 $class = null;
268 switch ($type) {
269 case self::INVOICE_MODEL:
270 $class = 'PdfInvoice';
271 break;
272 case self::RECEIPT_MODEL:
273 $class = 'PdfReceipt';
274 break;
275 case self::ADHESION_FORM_MODEL:
276 $class = 'PdfAdhesionFormModel';
277 break;
278 default:
279 $class = 'PdfMain';
280 break;
281 }
282 $class = 'Galette\\Entity\\' . $class;
283 return $class;
284 }
285
286 /**
287 * Check length
288 *
289 * @param string $value The value
290 * @param int $chars Length
291 * @param string $field Field name
292 * @param boolean $empty Can value be empty
293 *
294 * @return void
295 */
296 protected function checkChars($value, $chars, $field, $empty = false)
297 {
298 if ($value !== null && trim($value) !== '') {
299 if (mb_strlen($value) > $chars) {
300 throw new \LengthException(
301 str_replace(
302 array('%field', '%chars'),
303 array($field, $chars),
304 _T("%field should be less than %chars characters long.")
305 )
306 );
307 }
308 } else {
309 if ($empty === false) {
310 throw new \UnexpectedValueException(
311 str_replace(
312 '%field',
313 $field,
314 _T("%field should not be empty!")
315 )
316 );
317 }
318 }
319 }
320
321 /**
322 * Getter
323 *
324 * @param string $name Property name
325 *
326 * @return mixed
327 */
328 public function __get($name)
329 {
330 global $lang;
331
332 switch ($name) {
333 case 'name':
334 case 'id':
335 case 'header':
336 case 'footer':
337 case 'body':
338 case 'title':
339 case 'subtitle':
340 case 'type':
341 case 'styles':
342 case 'patterns':
343 case 'replaces':
344 return $this->$name;
345 break;
346 case 'hstyles':
347 $value = null;
348
349 //get header and footer from parent if not defined in current model
350 if (
351 $this->id > self::MAIN_MODEL
352 && $this->parent !== null
353 ) {
354 $value = $this->parent->styles;
355 }
356
357 $value .= $this->styles;
358 return $value;
359 break;
360 case 'hheader':
361 case 'hfooter':
362 case 'htitle':
363 case 'hsubtitle':
364 case 'hbody':
365 $pname = substr($name, 1);
366 $prop_value = $this->$pname ?? '';
367
368 //get header and footer from parent if not defined in current model
369 if (
370 $this->id > self::MAIN_MODEL
371 && $this->parent !== null
372 && ($pname === 'footer'
373 || $pname === 'header')
374 && trim($prop_value) === ''
375 ) {
376 $prop_value = $this->parent->$pname;
377 }
378
379 $value = $this->proceedReplacements($prop_value);
380 return $value;
381 break;
382 default:
383 Analog::log(
384 'Unable to get PdfModel property ' . $name,
385 Analog::WARNING
386 );
387 break;
388 }
389 }
390
391 /**
392 * Setter
393 *
394 * @param string $name Property name
395 * @param mixed $value Property value
396 *
397 * @return void
398 */
399 public function __set($name, $value)
400 {
401 switch ($name) {
402 case 'type':
403 if (
404 $value === self::MAIN_MODEL
405 || $value === self::INVOICE_MODEL
406 || $value === self::RECEIPT_MODEL
407 || $value === self::ADHESION_FORM_MODEL
408 ) {
409 $this->$name = $value;
410 } else {
411 throw new \UnexpectedValueException(
412 str_replace(
413 '%type',
414 $value,
415 _T("Unknown type %type!")
416 )
417 );
418 }
419 break;
420 case 'name':
421 try {
422 $this->checkChars($value, 50, _T("Name"));
423 $this->$name = $value;
424 } catch (Throwable $e) {
425 throw $e;
426 }
427 break;
428 case 'title':
429 case 'subtitle':
430 if ($name == 'title') {
431 $field = _T("Title");
432 } else {
433 $field = _T("Subtitle");
434 }
435 try {
436 $this->checkChars($value, 100, $field, true);
437 $this->$name = $value;
438 } catch (Throwable $e) {
439 throw $e;
440 }
441 break;
442 case 'header':
443 case 'footer':
444 case 'body':
445 if ($value === null || trim($value) === '') {
446 if ($name !== 'body' && get_class($this) === 'PdfMain') {
447 throw new \UnexpectedValueException(
448 _T("header and footer should not be empty!")
449 );
450 } elseif ($name === 'body' && get_class($this) !== 'PdfMain') {
451 throw new \UnexpectedValueException(
452 _T("body should not be empty!")
453 );
454 }
455 }
456
457 $this->$name = $value;
458 break;
459 case 'styles':
460 $this->styles = $value;
461 break;
462 default:
463 Analog::log(
464 'Unable to set PdfModel property ' . $name,
465 Analog::WARNING
466 );
467 break;
468 }
469 }
470 }