From: Johan Cwiklinski Date: Wed, 27 Mar 2024 10:46:52 +0000 (+0100) Subject: Add entity helper feature X-Git-Url: https://git.agnieray.net/?a=commitdiff_plain;h=b87c2a553e713f842a416a4ec7b478614ae71588;p=galette.git Add entity helper feature setDate getDate __isset getFieldLabel --- diff --git a/galette/lib/Galette/Entity/Contribution.php b/galette/lib/Galette/Entity/Contribution.php index 3adae2280..d8dde4db1 100644 --- a/galette/lib/Galette/Entity/Contribution.php +++ b/galette/lib/Galette/Entity/Contribution.php @@ -34,6 +34,7 @@ use Galette\IO\ExternalScript; use Galette\IO\PdfContribution; use Galette\Repository\PaymentTypes; use Galette\Features\Dynamics; +use Galette\Features\EntityHelper; /** * Contribution class for galette @@ -64,6 +65,10 @@ class Contribution { 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'; @@ -93,19 +98,27 @@ class Contribution private bool $_is_cotis; private ?int $_extension = null; - //fields list and their translation - /** @var array> */ - private array $_fields; - /** @var Db */ private Db $zdb; /** @var Login */ private Login $login; /** @var array */ - 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 * @@ -124,22 +137,65 @@ class Contribution $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' @@ -188,50 +244,11 @@ class Contribution '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 * @@ -401,11 +418,11 @@ class Contribution 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]); @@ -425,30 +442,7 @@ class Contribution 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: @@ -507,7 +501,7 @@ class Contribution // 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) @@ -637,7 +631,7 @@ class Contribution $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; } @@ -808,20 +802,16 @@ class Contribution * 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); } /** @@ -1149,15 +1139,9 @@ class Contribution */ 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 @@ -1171,46 +1155,19 @@ class Contribution } } 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. @@ -1230,6 +1187,8 @@ class Contribution } return ($this->isFee()) ? PdfModel::INVOICE_MODEL : PdfModel::RECEIPT_MODEL; + case 'fields': + return $this->fields; default: if (property_exists($this, $rname)) { if (isset($this->$rname)) { @@ -1258,26 +1217,7 @@ class Contribution */ 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); } @@ -1312,26 +1252,7 @@ class Contribution $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) { diff --git a/galette/lib/Galette/Entity/Transaction.php b/galette/lib/Galette/Entity/Transaction.php index 594e10d39..88b4a9f95 100644 --- a/galette/lib/Galette/Entity/Transaction.php +++ b/galette/lib/Galette/Entity/Transaction.php @@ -32,6 +32,7 @@ use Galette\Core\Db; use Galette\Core\History; use Galette\Core\Login; use Galette\Features\Dynamics; +use Galette\Features\EntityHelper; /** * Transaction class for galette @@ -39,7 +40,7 @@ use Galette\Features\Dynamics; * @author Johan Cwiklinski * * @property integer $id - * @property date $date + * @property string $date * @property integer $amount * @property ?string $description * @property ?integer $member @@ -48,6 +49,7 @@ use Galette\Features\Dynamics; class Transaction { use Dynamics; + use EntityHelper; public const TABLE = 'transactions'; public const PK = 'trans_id'; @@ -59,18 +61,13 @@ class Transaction private ?int $_member = null; private ?int $_payment_type = null; - /** - * fields list and their translation - * - * @var array> - */ - private array $_fields; - private Db $zdb; private Login $login; /** @var array */ - private array $errors; + protected array $errors; + /** @var string[] */ + protected array $forbidden_fields = []; /** * Default constructor @@ -85,18 +82,30 @@ class Transaction { $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' @@ -122,17 +131,7 @@ class Transaction '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; } /** @@ -296,11 +295,11 @@ class Transaction 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]); @@ -315,30 +314,7 @@ class Transaction 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; @@ -381,7 +357,7 @@ class Transaction // 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', @@ -436,7 +412,7 @@ class Transaction $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; } @@ -619,27 +595,11 @@ class Transaction */ 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; @@ -650,6 +610,8 @@ class Transaction return (double)$this->$rname; } return null; + case 'fields': + return $this->fields; default: return $this->$rname; } @@ -665,43 +627,6 @@ class Transaction } } - /** - * 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) * diff --git a/galette/lib/Galette/Features/EntityHelper.php b/galette/lib/Galette/Features/EntityHelper.php new file mode 100644 index 000000000..5bf1961ea --- /dev/null +++ b/galette/lib/Galette/Features/EntityHelper.php @@ -0,0 +1,180 @@ +. + */ + +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 + */ + +trait EntityHelper +{ + /** + * Fields configuration. Each field is an array and must reflect: + * array( + * (string)label, + * (string)propname + * ) + * + * @var array> + */ + 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; + } +}