use Galette\IO\PdfContribution;
use Galette\Repository\PaymentTypes;
use Galette\Features\Dynamics;
+use Galette\Features\EntityHelper;
/**
* Contribution class for galette
{
use Dynamics;
use HasEvent;
+ use EntityHelper {
+ getFieldLabel as protected trait_getFieldLabel;
+ __isset as protected trait___isset;
+ }
public const TABLE = 'cotisations';
public const PK = 'id_cotis';
private bool $_is_cotis;
private ?int $_extension = null;
- //fields list and their translation
- /** @var array<string, array<string, string>> */
- private array $_fields;
-
/** @var Db */
private Db $zdb;
/** @var Login */
private Login $login;
/** @var array<string> */
- private array $errors = [];
+ protected array $errors = [];
private bool $sendmail = false;
+ /** @var string[] */
+ protected array $forbidden_fields = ['is_cotis'];
+
+ /** @var string[] */
+ protected array $virtual_fields = [
+ 'duration',
+ 'model',
+ 'raw_date',
+ 'raw_begin_date',
+ 'raw_end_date',
+ ];
+
/**
* Default constructor
*
$this->_payment_type = $preferences->pref_default_paymenttype;
$this
+ ->setFields()
->withAddEvent()
->withEditEvent()
->withoutDeleteEvent()
->activateEvents();
- /*
- * Fields configuration. Each field is an array and must reflect:
- * array(
- * (string)label,
- * (string) property name
- * )
- *
- * I'd prefer a static private variable for this...
- * But call to the _T function does not seem to be allowed there :/
- */
- $this->_fields = array(
+
+ if (is_int($args)) {
+ $this->load($args);
+ } elseif (is_array($args)) {
+ $this->_date = date("Y-m-d");
+ if (isset($args['adh']) && $args['adh'] != '') {
+ $this->_member = (int)$args['adh'];
+ }
+ if (isset($args['trans'])) {
+ $this->_transaction = new Transaction($this->zdb, $this->login, (int)$args['trans']);
+ if (!isset($this->_member)) {
+ $this->_member = $this->_transaction->member;
+ }
+ $this->_amount = $this->_transaction->getMissingAmount();
+ }
+ $this->setContributionType((int)$args['type']);
+ //calculate begin date for membership fee
+ $this->_begin_date = $this->_date;
+ if ($this->_is_cotis) {
+ $due_date = self::getDueDate($this->zdb, $this->_member);
+ if ($due_date != '') {
+ $now = new \DateTime();
+ $due_date = new \DateTime($due_date);
+ if ($due_date < $now) {
+ // Member didn't renew on time
+ $this->_begin_date = $now->format('Y-m-d');
+ } else {
+ // Caution : the next_begin_date is the day after the due_date.
+ $next_begin_date = clone $due_date;
+ $next_begin_date->add(new \DateInterval('P1D'));
+ $this->_begin_date = $next_begin_date->format('Y-m-d');
+ }
+ }
+ $this->retrieveEndDate();
+ }
+ if (isset($args['payment_type'])) {
+ $this->_payment_type = $args['payment_type'];
+ }
+ } elseif (is_object($args)) {
+ $this->loadFromRS($args);
+ }
+
+ $this->loadDynamicFields();
+ }
+
+ /**
+ * Set fields, must populate $this->fields
+ *
+ * @return self
+ */
+ protected function setFields(): self
+ {
+ $this->fields = array(
'id_cotis' => array(
'label' => _T('Contribution id'), //not a field in the form
'propname' => 'id'
'propname' => 'extension'
)
);
- if (is_int($args)) {
- $this->load($args);
- } elseif (is_array($args)) {
- $this->_date = date("Y-m-d");
- if (isset($args['adh']) && $args['adh'] != '') {
- $this->_member = (int)$args['adh'];
- }
- if (isset($args['trans'])) {
- $this->_transaction = new Transaction($this->zdb, $this->login, (int)$args['trans']);
- if (!isset($this->_member)) {
- $this->_member = $this->_transaction->member;
- }
- $this->_amount = $this->_transaction->getMissingAmount();
- }
- $this->setContributionType((int)$args['type']);
- //calculate begin date for membership fee
- $this->_begin_date = $this->_date;
- if ($this->_is_cotis) {
- $due_date = self::getDueDate($this->zdb, $this->_member);
- if ($due_date != '') {
- $now = new \DateTime();
- $due_date = new \DateTime($due_date);
- if ($due_date < $now) {
- // Member didn't renew on time
- $this->_begin_date = $now->format('Y-m-d');
- } else {
- // Caution : the next_begin_date is the day after the due_date.
- $next_begin_date = clone $due_date;
- $next_begin_date->add(new \DateInterval('P1D'));
- $this->_begin_date = $next_begin_date->format('Y-m-d');
- }
- }
- $this->retrieveEndDate();
- }
- if (isset($args['payment_type'])) {
- $this->_payment_type = $args['payment_type'];
- }
- } elseif (is_object($args)) {
- $this->loadFromRS($args);
- }
- $this->loadDynamicFields();
+ return $this;
}
+
/**
* Sets end contribution date
*
global $preferences;
$this->errors = array();
- $fields = array_keys($this->_fields);
+ $fields = array_keys($this->fields);
foreach ($fields as $key) {
//first, let's sanitize values
$key = strtolower($key);
- $prop = '_' . $this->_fields[$key]['propname'];
+ $prop = '_' . $this->fields[$key]['propname'];
if (isset($values[$key])) {
$value = trim($values[$key]);
case 'date_debut_cotis':
case 'date_fin_cotis':
if ($value != '') {
- try {
- $d = \DateTime::createFromFormat(__("Y-m-d"), $value);
- if ($d === false) {
- //try with non localized date
- $d = \DateTime::createFromFormat("Y-m-d", $value);
- if ($d === false) {
- throw new \Exception('Incorrect format');
- }
- }
- $this->$prop = $d->format('Y-m-d');
- } catch (Throwable $e) {
- Analog::log(
- 'Wrong date format. field: ' . $key .
- ', value: ' . $value . ', expected fmt: ' .
- __("Y-m-d") . ' | ' . $e->getMessage(),
- Analog::INFO
- );
- $this->errors[] = sprintf(
- //TRANS: %1$s is the date format, %2$s is the field name
- _T('- Wrong date format (%1$s) for %2$s!'),
- __("Y-m-d"),
- $this->_fields[$key]['label']
- );
- }
+ $this->setDate($key, $value);
}
break;
case Adherent::PK:
// missing required fields?
foreach ($required as $key => $val) {
if ($val === 1) {
- $prop = '_' . $this->_fields[$key]['propname'];
+ $prop = '_' . $this->fields[$key]['propname'];
if (
!isset($disabled[$key])
&& (!isset($this->$prop)
$values = array();
$fields = self::getDbFields($this->zdb);
foreach ($fields as $field) {
- $prop = '_' . $this->_fields[$field]['propname'];
+ $prop = '_' . $this->fields[$field]['propname'];
if (!isset($this->$prop)) {
continue;
}
* Get field label
*
* @param string $field Field name
+ * @param string $entry Array entry to use (defaults to "label")
*
* @return string
*/
- public function getFieldLabel(string $field): string
+ public function getFieldLabel(string $field, string $entry = 'label'): string
{
- $label = $this->_fields[$field]['label'];
if ($field == 'date_debut_cotis' && !empty($this->_is_cotis) && $this->isFee()) {
- $label = $this->_fields[$field]['cotlabel'];
+ $entry = 'cotlabel';
}
- //replace " "
- $label = str_replace(' ', ' ', $label);
- //remove trailing ':' and then trim
- $label = trim(trim($label, ':'));
- return $label;
+ return $this->trait_getFieldLabel($field, $entry);
}
/**
*/
public function __get(string $name)
{
-
- $forbidden = array('is_cotis');
- $virtuals = array('duration', 'model', 'raw_date',
- 'raw_begin_date', 'raw_end_date'
- );
-
$rname = '_' . $name;
- if (in_array($name, $forbidden)) {
+ if (in_array($name, $this->forbidden_fields)) {
Analog::log(
"Call to __get for '$name' is forbidden!",
Analog::WARNING
}
} elseif (
property_exists($this, $rname)
- || in_array($name, $virtuals)
+ || property_exists($this, $name)
+ || in_array($name, $this->virtual_fields)
) {
switch ($name) {
case 'raw_date':
case 'raw_begin_date':
case 'raw_end_date':
$rname = '_' . substr($name, 4);
- if ($this->$rname !== null && $this->$rname != '') {
- try {
- $d = new \DateTime($this->$rname);
- return $d;
- } catch (Throwable $e) {
- //oops, we've got a bad date :/
- Analog::log(
- 'Bad date (' . $this->$rname . ') | ' .
- $e->getMessage(),
- Analog::INFO
- );
- throw $e;
- }
- }
- break;
+ return $this->getDate($rname, false);
case 'date':
case 'begin_date':
case 'end_date':
- if ($this->$rname !== null && $this->$rname != '') {
- try {
- $d = new \DateTime($this->$rname);
- return $d->format(__("Y-m-d"));
- } catch (Throwable $e) {
- //oops, we've got a bad date :/
- Analog::log(
- 'Bad date (' . $this->$rname . ') | ' .
- $e->getMessage(),
- Analog::INFO
- );
- return $this->$rname;
- }
- }
- break;
+ return $this->getDate($rname);
case 'duration':
if (isset($this->_is_cotis)) {
// Caution : the end_date stored is actually the due date.
}
return ($this->isFee()) ?
PdfModel::INVOICE_MODEL : PdfModel::RECEIPT_MODEL;
+ case 'fields':
+ return $this->fields;
default:
if (property_exists($this, $rname)) {
if (isset($this->$rname)) {
*/
public function __isset(string $name): bool
{
- $forbidden = array('is_cotis');
- $virtuals = array('duration', 'model', 'raw_date',
- 'raw_begin_date', 'raw_end_date'
- );
-
- $rname = '_' . $name;
-
- if (in_array($name, $forbidden)) {
- switch ($name) {
- case 'is_cotis':
- return true;
- }
- } elseif (
- property_exists($this, $rname)
- || in_array($name, $virtuals)
- ) {
- return true;
- }
-
- return false;
+ return $this->trait___isset('_' . $name) || $this->trait___isset($name);
}
$this->setContributionType($value);
break;
case 'begin_date':
- try {
- $d = \DateTime::createFromFormat(__("Y-m-d"), $value);
- if ($d === false) {
- throw new \Exception('Incorrect format');
- }
- $this->_begin_date = $d->format('Y-m-d');
- } catch (Throwable $e) {
- Analog::log(
- 'Wrong date format. field: ' . $name .
- ', value: ' . $value . ', expected fmt: ' .
- __("Y-m-d") . ' | ' . $e->getMessage(),
- Analog::INFO
- );
- $this->errors[] = sprintf(
- //TRANS: %1$s is the date format, %2$s is the field name
- _T('- Wrong date format (%1$s) for %2$s!'),
- __("Y-m-d"),
- $this->_fields['date_debut_cotis']['label']
- );
- }
+ $this->setDate($rname, $value);
break;
case 'amount':
if (is_numeric($value) && $value > 0) {
use Galette\Core\History;
use Galette\Core\Login;
use Galette\Features\Dynamics;
+use Galette\Features\EntityHelper;
/**
* Transaction class for galette
* @author Johan Cwiklinski <johan@x-tnd.be>
*
* @property integer $id
- * @property date $date
+ * @property string $date
* @property integer $amount
* @property ?string $description
* @property ?integer $member
class Transaction
{
use Dynamics;
+ use EntityHelper;
public const TABLE = 'transactions';
public const PK = 'trans_id';
private ?int $_member = null;
private ?int $_payment_type = null;
- /**
- * fields list and their translation
- *
- * @var array<string, array<string, string>>
- */
- private array $_fields;
-
private Db $zdb;
private Login $login;
/** @var array<string> */
- private array $errors;
+ protected array $errors;
+ /** @var string[] */
+ protected array $forbidden_fields = [];
/**
* Default constructor
{
$this->zdb = $zdb;
$this->login = $login;
+ $this->setFields();
+
+ if ($args === null || is_int($args)) {
+ $this->_date = date("Y-m-d");
+
+ if (is_int($args) && $args > 0) {
+ $this->load($args);
+ }
+ } elseif ($args instanceof ArrayObject) {
+ $this->loadFromRS($args);
+ }
+
+ $this->loadDynamicFields();
+ }
- /*
- * Fields configuration. Each field is an array and must reflect:
- * array(
- * (string)label,
- * (string) propname
- * )
- *
- * I'd prefer a static private variable for this...
- * But call to the _T function does not seem to be allowed there :/
- */
- $this->_fields = array(
+
+ /**
+ * Set fields, must populate $this->fields
+ *
+ * @return self
+ */
+ protected function setFields(): self
+ {
+ $this->fields = array(
self::PK => array(
'label' => null, //not a field in the form
'propname' => 'id'
'propname' => 'payment_type'
)
);
- if ($args === null || is_int($args)) {
- $this->_date = date("Y-m-d");
-
- if (is_int($args) && $args > 0) {
- $this->load($args);
- }
- } elseif ($args instanceof ArrayObject) {
- $this->loadFromRS($args);
- }
-
- $this->loadDynamicFields();
+ return $this;
}
/**
global $preferences;
$this->errors = array();
- $fields = array_keys($this->_fields);
+ $fields = array_keys($this->fields);
foreach ($fields as $key) {
//first, let's sanitize values
$key = strtolower($key);
- $prop = '_' . $this->_fields[$key]['propname'];
+ $prop = '_' . $this->fields[$key]['propname'];
if (isset($values[$key])) {
$value = trim($values[$key]);
switch ($key) {
// dates
case 'trans_date':
- try {
- $d = \DateTime::createFromFormat(__("Y-m-d"), $value);
- if ($d === false) {
- //try with non localized date
- $d = \DateTime::createFromFormat("Y-m-d", $value);
- if ($d === false) {
- throw new \Exception('Incorrect format');
- }
- }
- $this->$prop = $d->format('Y-m-d');
- } catch (Throwable $e) {
- Analog::log(
- 'Wrong date format. field: ' . $key .
- ', value: ' . $value . ', expected fmt: ' .
- __("Y-m-d") . ' | ' . $e->getMessage(),
- Analog::INFO
- );
- $this->errors[] = sprintf(
- //TRANS: %1$s is the date format, %2$s is the field name
- _T('- Wrong date format (%1$s) for %2$s!'),
- __("Y-m-d"),
- $this->getFieldLabel($key)
- );
- }
+ $this->setDate($key, $value);
break;
case Adherent::PK:
$this->_member = (int)$value;
// missing required fields?
foreach ($required as $key => $val) {
if ($val === 1) {
- $prop = '_' . $this->_fields[$key]['propname'];
+ $prop = '_' . $this->fields[$key]['propname'];
if (!isset($disabled[$key]) && !isset($this->$prop)) {
$this->errors[] = str_replace(
'%field',
$fields = $this->getDbFields($this->zdb);
/** FIXME: quote? */
foreach ($fields as $field) {
- $prop = '_' . $this->_fields[$field]['propname'];
+ $prop = '_' . $this->fields[$field]['propname'];
if (isset($this->$prop)) {
$values[$field] = $this->$prop;
}
*/
public function __get(string $name)
{
- $forbidden = array();
-
$rname = '_' . $name;
- if (!in_array($name, $forbidden) && property_exists($this, $rname)) {
+ if (!in_array($name, $this->forbidden_fields) && (property_exists($this, $rname) || property_exists($this, $name))) {
switch ($name) {
case 'date':
- if ($this->$rname != '') {
- try {
- $d = new \DateTime($this->$rname);
- return $d->format(__("Y-m-d"));
- } catch (Throwable $e) {
- //oops, we've got a bad date :/
- Analog::log(
- 'Bad date (' . $this->$rname . ') | ' .
- $e->getMessage(),
- Analog::INFO
- );
- return $this->$rname;
- }
- }
- break;
+ return $this->getDate($rname);
case 'id':
if (isset($this->$rname) && $this->$rname !== null) {
return (int)$this->$rname;
return (double)$this->$rname;
}
return null;
+ case 'fields':
+ return $this->fields;
default:
return $this->$rname;
}
}
}
- /**
- * Global isset method
- * Required for twig to access properties via __get
- *
- * @param string $name name of the property we want to retrieve
- *
- * @return bool
- */
- public function __isset(string $name): bool
- {
- $forbidden = array();
-
- $rname = '_' . $name;
- if (!in_array($name, $forbidden) && property_exists($this, $rname)) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Get field label
- *
- * @param string $field Field name
- *
- * @return string
- */
- public function getFieldLabel(string $field): string
- {
- $label = $this->_fields[$field]['label'];
- //replace " "
- $label = str_replace(' ', ' ', $label);
- //remove trailing ':' and then trim
- $label = trim(trim($label, ':'));
- return $label;
- }
-
/**
* Handle files (dynamics files)
*
--- /dev/null
+<?php
+
+/**
+ * Copyright © 2003-2024 The Galette Team
+ *
+ * This file is part of Galette (https://galette.eu).
+ *
+ * Galette is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Galette is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Galette. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Galette\Features;
+
+use DateTime;
+use Galette\Entity\Adherent;
+use Galette\Repository\DynamicFieldsSet;
+use Throwable;
+use Analog\Analog;
+use Galette\DynamicFields\File;
+use Galette\DynamicFields\Date;
+use Galette\DynamicFields\Boolean;
+use Galette\Entity\DynamicFieldsHandle;
+
+/**
+ * Dynamics fields trait
+ *
+ * @author Johan Cwiklinski <johan@x-tnd.be>
+ */
+
+trait EntityHelper
+{
+ /**
+ * Fields configuration. Each field is an array and must reflect:
+ * array(
+ * (string)label,
+ * (string)propname
+ * )
+ *
+ * @var array<string, array<string, string>>
+ */
+ protected array $fields;
+
+ /** @var string[] */
+ //protected array $forbidden_fields = [];
+
+ /** @var string[] */
+ //protected array $virtual_fields = [];
+
+ /**
+ * Set fields, must populate $this->fields
+ *
+ * @return self
+ */
+ abstract protected function setFields(): self;
+
+ /**
+ * Global isset method
+ * Required for twig to access properties via __get
+ *
+ * @param string $name name of the property we want to retrieve
+ *
+ * @return bool
+ */
+ public function __isset(string $name): bool
+ {
+ if (in_array($name, ($this->forbidden_fields ?? []))) {
+ return false;
+ }
+
+ $virtual_fields = [];
+ if (isset($this->virtual_fields)) {
+ $virtual_fields = $this->virtual_fields;
+ }
+ return (in_array($name, $virtual_fields) || property_exists($this, $name));
+ }
+
+ /**
+ * Get field label
+ *
+ * @param string $field Field name
+ * @param string $entry Array entry to use (defaults to "label")
+ *
+ * @return string
+ */
+ public function getFieldLabel(string $field, string $entry = 'label'): string
+ {
+ $label = $this->fields[$field][$entry] ?? $field;
+ //replace " "
+ $label = str_replace(' ', ' ', $label);
+ //remove trailing ':' and then trim
+ $label = trim(trim($label, ':'));
+ return $label;
+ }
+
+ /**
+ * Set a Date
+ *
+ * @param string $field Field to store date
+ * @param string $value Date to store
+ *
+ * @return self
+ */
+ protected function setDate(string $field, string $value): self
+ {
+ try {
+ $date = \DateTime::createFromFormat(__("Y-m-d"), $value);
+ if ($date === false) {
+ //try with non localized date
+ $date = \DateTime::createFromFormat("Y-m-d", $value);
+ if ($date === false) {
+ throw new \Exception('Incorrect format');
+ }
+ }
+ if (isset($this->fields[$field]['propname'])) {
+ $propname = $this->fields[$field]['propname'];
+ } else {
+ $propname = $field;
+ }
+ $this->$propname = $date->format('Y-m-d');
+ } catch (Throwable $e) {
+ Analog::log(
+ 'Wrong date format. field: ' . $field .
+ ', value: ' . $field . ', expected fmt: ' .
+ __("Y-m-d") . ' | ' . $e->getMessage(),
+ Analog::INFO
+ );
+ $this->errors[] = sprintf(
+ //TRANS: %1$s is the date format, %2$s is the field name
+ _T('- Wrong date format (%1$s) for %2$s!'),
+ __("Y-m-d"),
+ $this->getFieldLabel($field)
+ );
+ }
+ return $this;
+ }
+
+ /**
+ * Get a date
+ *
+ * @param string $field Field name to retrieve
+ * @param bool $formatted Get formatted date, or DateTime object
+ * @param bool $translated Get translated or db value
+ *
+ * @return string|DateTime|null
+ */
+ public function getDate(string $field, bool $formatted = true, bool $translated = true): string|DateTime|null
+ {
+ if ($this->$field !== null && $this->$field != '') {
+ try {
+ $date = new \DateTime($this->$field);
+ if ($formatted === false) {
+ return $date;
+ }
+ if ($translated === false) {
+ return $date->format('Y-m-d');
+ }
+ return $date->format(__('Y-m-d'));
+ } catch (Throwable $e) {
+ //oops, we've got a bad date :/
+ Analog::log(
+ 'Bad date (' . $this->$field . ') | ' .
+ $e->getMessage(),
+ Analog::INFO
+ );
+ return $this->$field;
+ }
+ }
+ return null;
+ }
+}