4 * Copyright © 2003-2024 The Galette Team
6 * This file is part of Galette (https://galette.eu).
8 * Galette is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * Galette is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
22 namespace Galette\Core
;
25 use Laminas\Db\Sql\Select
;
28 use Galette\Entity\Adherent
;
29 use Galette\Filters\MailingsList
;
30 use Laminas\Db\Sql\Expression
;
35 * @author Johan Cwiklinski <johan@x-tnd.be>
37 * @property MailingsList $filters
39 class MailingHistory
extends History
41 public const TABLE
= 'mailing_history';
42 public const PK
= 'mailing_id';
44 public const FILTER_DC_SENT
= 0;
45 public const FILTER_SENT
= 1;
46 public const FILTER_NOT_SENT
= 2;
48 private ?Mailing
$mailing = null;
51 private string $subject;
52 private string $message;
53 /** @var array<int, mixed> */
54 private array $recipients;
56 private ?
string $sender_name;
57 private ?
string $sender_address;
58 private bool $sent = false;
63 * @param Db $zdb Database
64 * @param Login $login Login
65 * @param Preferences $preferences Preferences
66 * @param MailingsList|null $filters Filtering
67 * @param Mailing|null $mailing Mailing
69 public function __construct(Db
$zdb, Login
$login, Preferences
$preferences, MailingsList
$filters = null, Mailing
$mailing = null)
71 parent
::__construct($zdb, $login, $preferences, $filters);
72 $this->mailing
= $mailing;
76 * Get the entire history list
78 * @return array<int, object>
80 public function getHistory(): array
83 $select = $this->zdb
->select($this->getTableName(), 'a');
85 array('b' => PREFIX_DB
. Adherent
::TABLE
),
86 'a.mailing_sender=b.' . Adherent
::PK
,
87 array('nom_adh', 'prenom_adh'),
90 $this->buildWhereClause($select);
91 $select->order($this->buildOrderClause());
92 $this->proceedCount($select);
93 //add limits to retrieve only relevant rows
94 $this->filters
->setLimits($select);
95 $results = $this->zdb
->execute($select);
98 foreach ($results as $r) {
99 if ($r['mailing_sender'] !== null && $r['mailing_sender_name'] === null) {
100 $r['mailing_sender_name']
101 = Adherent
::getSName($this->zdb
, $r['mailing_sender']);
104 $this->handleRecipients($r);
107 if (file_exists(GALETTE_ATTACHMENTS_PATH
. $r[self
::PK
])) {
108 $rdi = new \
RecursiveDirectoryIterator(
109 GALETTE_ATTACHMENTS_PATH
. $r[self
::PK
],
110 \FilesystemIterator
::SKIP_DOTS
112 $contents = new \
RecursiveIteratorIterator(
114 \RecursiveIteratorIterator
::CHILD_FIRST
116 foreach ($contents as $path) {
117 if ($path->isFile()) {
122 $r['attachments'] = $attachments;
126 } catch (Throwable
$e) {
128 'Unable to get history. | ' . $e->getMessage(),
136 * Builds the order clause
138 * @return array<int, string> SQL ORDER clauses
140 protected function buildOrderClause(): array
144 switch ($this->filters
->orderby
) {
145 case MailingsList
::ORDERBY_DATE
:
146 $order[] = 'mailing_date ' . $this->filters
->ordered
;
148 case MailingsList
::ORDERBY_SENDER
:
149 $order[] = 'mailing_sender ' . $this->filters
->ordered
;
151 case MailingsList
::ORDERBY_SUBJECT
:
152 $order[] = 'mailing_subject ' . $this->filters
->ordered
;
154 case MailingsList
::ORDERBY_SENT
:
155 $order[] = 'mailing_sent ' . $this->filters
->ordered
;
163 * Builds where clause, for filtering on simple list mode
165 * @param Select $select Original select
169 private function buildWhereClause(Select
$select): void
172 if ($this->filters
->start_date_filter
!= null) {
173 $d = new \
DateTime($this->filters
->raw_start_date_filter
);
174 $select->where
->greaterThanOrEqualTo(
180 if ($this->filters
->end_date_filter
!= null) {
181 $d = new \
DateTime($this->filters
->raw_end_date_filter
);
182 $select->where
->lessThanOrEqualTo(
188 if ($this->filters
->sender_filter
!= null && $this->filters
->sender_filter
!= '0') {
189 $sender = $this->filters
->sender_filter
;
190 if ($sender == '-1') {
191 $select->where('mailing_sender IS NULL');
193 $select->where
->equalTo(
200 switch ($this->filters
->sent_filter
) {
201 case self
::FILTER_SENT
:
202 $select->where('mailing_sent = true');
204 case self
::FILTER_NOT_SENT
:
205 $select->where('mailing_sent = false');
207 case self
::FILTER_DC_SENT
:
208 //nothing to do here.
213 if ($this->filters
->subject_filter
!= '') {
214 $token = $this->zdb
->platform
->quoteValue(
215 '%' . strtolower($this->filters
->subject_filter
) . '%'
219 'LOWER(mailing_subject) LIKE ' .
223 } catch (Throwable
$e) {
225 __METHOD__
. ' | ' . $e->getMessage(),
233 * Count history entries from the query
235 * @param Select $select Original select
239 private function proceedCount(Select
$select): void
242 $countSelect = clone $select;
243 $countSelect->reset($countSelect::COLUMNS
);
244 $countSelect->reset($countSelect::JOINS
);
245 $countSelect->reset($countSelect::ORDER
);
246 $countSelect->columns(
248 self
::PK
=> new Expression('COUNT(' . self
::PK
. ')')
252 $results = $this->zdb
->execute($countSelect);
253 $result = $results->current();
256 $this->count
= $result->$k;
257 $this->filters
->setCounter($this->count
);
258 } catch (Throwable
$e) {
260 'Cannot count history | ' . $e->getMessage(),
268 * Load mailing from an existing one
270 * @param Db $zdb Database instance
271 * @param integer $id Model identifier
272 * @param Mailing $mailing Mailing object
273 * @param boolean $new True if we create a 'new' mailing,
274 * false otherwise (from preview for example)
278 public static function loadFrom(Db
$zdb, int $id, Mailing
$mailing, bool $new = true): bool
281 $select = $zdb->select(self
::TABLE
);
282 $select->where(['mailing_id' => $id]);
284 $results = $zdb->execute($select);
285 /** @var ArrayObject<string, mixed> $result */
286 $result = $results->current();
288 return $mailing->loadFromHistory($result, $new);
289 } catch (Throwable
$e) {
291 'Unable to load mailing model #' . $id . ' | ' .
300 * Store a mailing in the history
302 * @param boolean $sent Defaults to false
306 public function storeMailing(bool $sent = false): bool
308 if ($this->mailing
instanceof Mailing
) {
309 if ($this->mailing
->sender_name
!= null) {
310 $this->sender_name
= $this->mailing
->getSenderName();
311 $this->sender_address
= $this->mailing
->getSenderAddress();
313 $this->sender
= $this->login
->id
;
314 $this->subject
= $this->mailing
->subject
;
315 $this->message
= $this->mailing
->message
;
316 $this->recipients
= $this->mailing
->recipients
;
318 $this->date
= date('Y-m-d H:i:s');
319 if (!$this->mailing
->existsInHistory()) {
321 $this->mailing
->id
= $this->id
;
322 $this->mailing
->moveAttachments($this->id
);
324 if ($this->mailing
->tmp_path
!== false) {
325 //attachments are still in a temporary path, move them
326 $this->mailing
->moveAttachments($this->id ??
$this->mailing
->history_id
);
328 //existing stored mailing. Just update row.
335 '] Mailing should be an instance of Mailing',
343 * Update in the database
347 public function update(): bool
350 $_recipients = array();
351 if ($this->recipients
!= null) {
352 foreach ($this->recipients
as $_r) {
353 $_recipients[$_r->id
] = $_r->sname
. ' <' . $_r->email
. '>';
357 $sender = ($this->sender
=== 0) ?
358 new Expression('NULL') : $this->sender
;
359 $sender_name = ($this->sender_name
=== null) ?
360 new Expression('NULL') : $this->sender_name
;
361 $sender_address = ($this->sender_address
=== null) ?
362 new Expression('NULL') : $this->sender_address
;
365 'mailing_sender' => $sender,
366 'mailing_sender_name' => $sender_name,
367 'mailing_sender_address' => $sender_address,
368 'mailing_subject' => $this->subject
,
369 'mailing_body' => $this->message
,
370 'mailing_date' => $this->date
,
371 'mailing_recipients' => Galette
::jsonEncode($_recipients),
372 'mailing_sent' => ($this->sent
) ?
374 ($this->zdb
->isPostgres() ?
'false' : 0)
377 $update = $this->zdb
->update(self
::TABLE
);
378 $update->set($values);
379 $update->where([self
::PK
=> $this->mailing
->history_id
]);
380 $this->zdb
->execute($update);
382 } catch (Throwable
$e) {
384 'An error occurend updating Mailing | ' . $e->getMessage(),
392 * Store in the database
396 public function store(): bool
399 $_recipients = array();
400 if ($this->recipients
!= null) {
401 foreach ($this->recipients
as $_r) {
402 $_recipients[$_r->id
] = $_r->sname
. ' <' . $_r->email
. '>';
407 if ($this->sender
=== 0) {
408 $sender = new Expression('NULL');
410 $sender = $this->sender
;
412 $sender_name = ($this->sender_name
=== null) ?
413 new Expression('NULL') : $this->sender_name
;
414 $sender_address = ($this->sender_address
=== null) ?
415 new Expression('NULL') : $this->sender_address
;
418 'mailing_sender' => $sender,
419 'mailing_sender_name' => $sender_name,
420 'mailing_sender_address' => $sender_address,
421 'mailing_subject' => $this->subject
,
422 'mailing_body' => $this->message
,
423 'mailing_date' => $this->date
,
424 'mailing_recipients' => Galette
::jsonEncode($_recipients),
425 'mailing_sent' => ($this->sent
) ?
427 ($this->zdb
->isPostgres() ?
'false' : 0)
430 $insert = $this->zdb
->insert(self
::TABLE
);
431 $insert->values($values);
432 $this->zdb
->execute($insert);
434 $this->id
= $this->zdb
->getLastGeneratedValue($this);
436 } catch (Throwable
$e) {
438 'An error occurred storing Mailing | ' . $e->getMessage(),
446 * Remove specified entries
448 * @param integer|array<int> $ids Mailing history entries identifiers
449 * @param History $hist History instance
453 public function removeEntries(int|
array $ids, History
$hist): bool
455 $list = is_array($ids) ?
$ids : [$ids];
458 foreach ($list as $id) {
459 $mailing = new Mailing($this->preferences
, [], $id);
460 $mailing->removeAttachments();
463 $this->zdb
->connection
->beginTransaction();
466 $delete = $this->zdb
->delete(self
::TABLE
);
467 $delete->where
->in(self
::PK
, $list);
468 $this->zdb
->execute($delete);
471 $this->zdb
->connection
->commit();
473 //add an history entry
475 _T("Delete mailing entries")
479 } catch (Throwable
$e) {
480 $this->zdb
->connection
->rollBack();
482 'Unable to delete selected mailing history entries |' .
493 * @param boolean $prefixed Whether table name should be prefixed
497 protected function getTableName(bool $prefixed = false): string
499 if ($prefixed === true) {
500 return PREFIX_DB
. self
::TABLE
;
511 protected function getPk(): string
517 * Get count for current query
521 public function getCount(): int
527 * Handle mailing recipients
529 * @param ArrayObject<string, string> $row ResultSet row
532 private function handleRecipients(ArrayObject
&$row): void
534 if ($row['mailing_recipients'] == null) {
540 if (Galette
::isSerialized($row['mailing_recipients'])) {
541 $recipients = unserialize($row['mailing_recipients']);
543 $recipients = Galette
::jsonDecode($row['mailing_recipients']);
545 } catch (\Throwable
$e) {
547 'Unable to retrieve recipients for mailing history ' . $row['mailing_id'],
551 $row['mailing_recipients'] = $recipients;