]> git.agnieray.net Git - galette.git/commitdiff
Move trait to Features namespace
authorJohan Cwiklinski <johan@x-tnd.be>
Sun, 31 Oct 2021 14:44:44 +0000 (15:44 +0100)
committerJohan Cwiklinski <johan@x-tnd.be>
Sun, 31 Oct 2021 15:05:31 +0000 (16:05 +0100)
13 files changed:
galette/lib/Galette/DynamicFields/DynamicField.php
galette/lib/Galette/Entity/Adherent.php
galette/lib/Galette/Entity/Contribution.php
galette/lib/Galette/Entity/DynamicsTrait.php [deleted file]
galette/lib/Galette/Entity/Entitled.php
galette/lib/Galette/Entity/I18nTrait.php [deleted file]
galette/lib/Galette/Entity/PaymentType.php
galette/lib/Galette/Entity/Transaction.php
galette/lib/Galette/Entity/TranslatableTrait.php [deleted file]
galette/lib/Galette/Features/Dynamics.php [new file with mode: 0644]
galette/lib/Galette/Features/I18n.php [new file with mode: 0644]
galette/lib/Galette/Features/Replacements.php
galette/lib/Galette/Features/Translatable.php [new file with mode: 0644]

index 61292db25874a13a3e66b0f2870188a11e7c3c6b..775ed2c53443cba1631ffe701ee8063ab88a4c42 100644 (file)
@@ -7,7 +7,7 @@
  *
  * PHP version 5
  *
- * Copyright © 2012-2014 The Galette Team
+ * Copyright © 2012-2021 The Galette Team
  *
  * This file is part of Galette (http://galette.tuxfamily.org).
  *
@@ -28,7 +28,7 @@
  * @package   Galette
  *
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2012-2014 The Galette Team
+ * @copyright 2012-2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @link      http://galette.tuxfamily.org
  * @since     Available since 0.7.1dev - 2012-07-28
@@ -40,8 +40,8 @@ use Throwable;
 use Analog\Analog;
 use Galette\Core\Db;
 use Galette\Entity\DynamicFieldsHandle;
-use Galette\Entity\TranslatableTrait;
-use Galette\Entity\I18nTrait;
+use Galette\Features\Translatable;
+use Galette\Features\I18n;
 use Laminas\Db\Sql\Expression;
 use Laminas\Db\Sql\Predicate\Expression as PredicateExpression;
 
@@ -60,8 +60,8 @@ use Laminas\Db\Sql\Predicate\Expression as PredicateExpression;
 
 abstract class DynamicField
 {
-    use TranslatableTrait;
-    use I18nTrait;
+    use Translatable;
+    use I18n;
 
     public const TABLE = 'field_types';
     public const PK = 'field_id';
index 9bfcc25c78851ae859a3233cf171c68d0380586b..89dd0a57e1248653970b0a1e451736d18cdd9cbd 100644 (file)
@@ -48,6 +48,7 @@ use Galette\Core\History;
 use Galette\Repository\Groups;
 use Galette\Core\Login;
 use Galette\Repository\Members;
+use Galette\Features\Dynamics;
 
 /**
  * Member class for galette
@@ -122,7 +123,7 @@ use Galette\Repository\Members;
  */
 class Adherent
 {
-    use DynamicsTrait;
+    use Dynamics;
 
     public const TABLE = 'adherents';
     public const PK = 'id_adh';
index 5e8f830e87acfc819aa08f2816c63f76eca85315..5124e047bedefa410a0ee96e6d12099ac0ba5817 100644 (file)
@@ -45,6 +45,7 @@ use Galette\Core\Login;
 use Galette\IO\ExternalScript;
 use Galette\IO\PdfContribution;
 use Galette\Repository\PaymentTypes;
+use Galette\Features\Dynamics;
 
 /**
  * Contribution class for galette
@@ -80,7 +81,7 @@ use Galette\Repository\PaymentTypes;
  */
 class Contribution
 {
-    use DynamicsTrait;
+    use Dynamics;
 
     public const TABLE = 'cotisations';
     public const PK = 'id_cotis';
diff --git a/galette/lib/Galette/Entity/DynamicsTrait.php b/galette/lib/Galette/Entity/DynamicsTrait.php
deleted file mode 100644 (file)
index 8ba16c3..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-<?php
-
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Dynamics fields trait
- *
- * PHP version 5
- *
- * Copyright © 2017-2021 The Galette Team
- *
- * This file is part of Galette (http://galette.tuxfamily.org).
- *
- * 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/>.
- *
- * @category  Entity
- * @package   Galette
- *
- * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2017-2021 The Galette Team
- * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
- * @link      http://galette.tuxfamily.org
- * @since     Available since 0.9dev - 2017-05-26
- */
-
-namespace Galette\Entity;
-
-use Throwable;
-use Analog\Analog;
-use Galette\DynamicFields\File;
-use Galette\DynamicFields\Date;
-use Galette\DynamicFields\Boolean;
-
-/**
- * Dynamics fields trait
- *
- * @category  Entity
- * @name      DynamicsTrait
- * @package   Galette
- * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2017-2021 The Galette Team
- * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
- * @link      http://galette.tuxfamily.org
- * @since     Available since 0.9dev - 2017-05-26
- */
-
-trait DynamicsTrait
-{
-    /** @var string */
-    protected $name_pattern = 'info_field_';
-
-    /** @var DynamicFieldsHandle */
-    protected $dynamics;
-
-    /**
-     * Load dynamic fields for member
-     *
-     * @return void
-     */
-    private function loadDynamicFields()
-    {
-        if (!property_exists($this, 'login')) {
-            global $login;
-        } else {
-            $login = $this->login;
-        }
-        $this->dynamics = new DynamicFieldsHandle($this->zdb, $login, $this);
-    }
-
-    /**
-     * Get dynamic fields
-     *
-     * @return array
-     */
-    public function getDynamicFields()
-    {
-        if (null === $this->dynamics) {
-            $this->loadDynamicFields();
-        }
-        return $this->dynamics;
-    }
-
-    /**
-     * Extract posted values for dynamic fields
-     *
-     * @param array $post     Posted values
-     * @param array $required Array of required fields
-     * @param array $disabled Array of disabled fields
-     *
-     * @return boolean
-     */
-    protected function dynamicsCheck(array $post, array $required, array $disabled)
-    {
-        if ($this->dynamics === null) {
-            Analog::log(
-                'Dynamics fields have not been loaded, cannot be checked. (from: ' . __METHOD__ . ')',
-                Analog::WARNING
-            );
-            $this->loadDynamicFields();
-        }
-
-        if ($post != null) {
-            $valid = true;
-            $fields = $this->dynamics->getFields();
-
-            $dynamic_fields = [];
-            //posted fields
-            foreach ($post as $key => $value) {
-                // if the field is enabled, and match patterns check it
-                if (isset($disabled[$key]) || substr($key, 0, 11) != $this->name_pattern) {
-                    continue;
-                }
-
-                list($field_id, $val_index) = explode('_', str_replace($this->name_pattern, '', $key));
-                if (!is_numeric($field_id) || !is_numeric($val_index)) {
-                    continue;
-                }
-
-                $dynamic_fields[$key] = [
-                    'value'     => $value,
-                    'field_id'  => $field_id,
-                    'val_index' => $val_index
-                ];
-            }
-
-            //some fields may be mising in posted values (checkboxes)
-            foreach ($fields as $field) {
-                $pattern = '/' . $this->name_pattern . $field->getId() . '_(\d)/';
-                if ($field instanceof Boolean && !preg_grep($pattern, array_keys($dynamic_fields))) {
-                    $dynamic_fields[$this->name_pattern . $field->getId() . '_1'] = [
-                        'value'     => '',
-                        'field_id'  => $field->getId(),
-                        'val_index' => 1
-                    ];
-                }
-            }
-
-            foreach ($dynamic_fields as $key => $dfield_values) {
-                $field_id = $dfield_values['field_id'];
-                $value = $dfield_values['value'];
-                $val_index = $dfield_values['val_index'];
-
-                if ($fields[$field_id]->isRequired() && (trim($value) === '' || $value == null)) {
-                    $this->errors[] = str_replace(
-                        '%field',
-                        $fields[$field_id]->getName(),
-                        _T('Missing required field %field')
-                    );
-                } else {
-                    if ($fields[$field_id] instanceof File) {
-                        //delete checkbox
-                        $filename = sprintf(
-                            'member_%d_field_%d_value_%d',
-                            $this->id,
-                            $field_id,
-                            $val_index
-                        );
-                        if (file_exists(GALETTE_FILES_PATH . $filename)) {
-                            unlink(GALETTE_FILES_PATH . $filename);
-                        }
-                        $this->dynamics->setValue($this->id, $field_id, $val_index, '');
-                    } else {
-                        if ($fields[$field_id] instanceof Date && !empty(trim($value))) {
-                            //check date format
-                            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');
-                                    }
-                                }
-                            } catch (Throwable $e) {
-                                $valid = false;
-                                Analog::log(
-                                    'Wrong date format. field: ' . $field_id .
-                                    ', value: ' . $value . ', expected fmt: ' .
-                                    __("Y-m-d") . ' | ' . $e->getMessage(),
-                                    Analog::INFO
-                                );
-                                $this->errors[] = str_replace(
-                                    array(
-                                        '%date_format',
-                                        '%field'
-                                    ),
-                                    array(
-                                        __("Y-m-d"),
-                                        $fields[$field_id]->getName()
-                                    ),
-                                    _T("- Wrong date format (%date_format) for %field!")
-                                );
-                            }
-                        }
-                        //actual field value
-                        if ($value !== null && trim($value) !== '') {
-                            $this->dynamics->setValue($this->id, $field_id, $val_index, $value);
-                        } else {
-                            $this->dynamics->unsetValue($this->id, $field_id, $val_index);
-                        }
-                    }
-                }
-            }
-
-            return $valid;
-        }
-    }
-
-    /**
-     * Stores dynamic fields
-     *
-     * @param boolean $transaction True if a transaction already exists
-     *
-     * @return boolean
-     */
-    protected function dynamicsStore($transaction = false)
-    {
-        if ($this->dynamics === null) {
-            Analog::log(
-                'Dynamics fields have not been loaded, cannot be stored. (from: ' . __METHOD__ . ')',
-                Analog::WARNING
-            );
-            $this->loadDynamicFields();
-        }
-        $return = $this->dynamics->storeValues($this->id, $transaction);
-        if (method_exists($this, 'updateModificationDate') && $this->dynamics->hasChanged()) {
-            $this->updateModificationDate();
-        }
-        return $return;
-    }
-
-    /**
-     * Store dynamic Files
-     *
-     * @param array $files Posted files
-     *
-     * @return void
-     */
-    protected function dynamicsFiles($files)
-    {
-        $this->loadDynamicFields();
-        $fields = $this->dynamics->getFields();
-        $store = false;
-
-        foreach ($files as $key => $file) {
-            // if the field is disabled, skip it
-            if (isset($disabled[$key])) {
-                continue;
-            }
-
-            if (substr($key, 0, 11) != $this->name_pattern) {
-                continue;
-            }
-
-            list($field_id, $val_index) = explode('_', str_replace($this->name_pattern, '', $key));
-            if (!is_numeric($field_id) || !is_numeric($val_index)) {
-                continue;
-            }
-
-            if (
-                $file['error'] == UPLOAD_ERR_NO_FILE
-                && $file['name'] == ''
-                && $file['tmp_name'] == ''
-            ) {
-                //not upload atempt.
-                continue;
-            } elseif ($file['error'] !== UPLOAD_ERR_OK) {
-                Analog::log("file upload error", Analog::ERROR);
-                continue;
-            }
-
-            $tmp_filename = $file['tmp_name'];
-            if ($tmp_filename == '') {
-                Analog::log("empty temporary filename", Analog::ERROR);
-                continue;
-            }
-
-            if (!is_uploaded_file($tmp_filename)) {
-                Analog::log("not an uploaded file", Analog::ERROR);
-                continue;
-            }
-
-            $max_size =
-                $fields[$field_id]->getSize() ?
-                $fields[$field_id]->getSize() * 1024 : File::DEFAULT_MAX_FILE_SIZE * 1024;
-            if ($file['size'] > $max_size) {
-                Analog::log(
-                    "file too large: " . $file['size'] . " Ko, vs $max_size Ko allowed",
-                    Analog::ERROR
-                );
-                $this->errors[] = preg_replace(
-                    '|%d|',
-                    $max_size,
-                    _T("File is too big. Maximum allowed size is %dKo")
-                );
-                continue;
-            }
-
-            $new_filename = sprintf(
-                'member_%d_field_%d_value_%d',
-                $this->id,
-                $field_id,
-                $val_index
-            );
-            Analog::log("new file: $new_filename", Analog::DEBUG);
-
-            move_uploaded_file(
-                $tmp_filename,
-                GALETTE_FILES_PATH . $new_filename
-            );
-            $this->dynamics->setValue($this->id, $field_id, $val_index, $file['name']);
-            $store = true;
-        }
-
-        if ($store === true) {
-            $this->dynamicsStore();
-        }
-    }
-
-    /**
-     * Remove dynamic fields values
-     *
-     * @param boolean $transaction True if a transaction already exists
-     *
-     * @return boolean
-     */
-    protected function dynamicsRemove($transaction = false)
-    {
-        if ($this->dynamics === null) {
-            Analog::log(
-                'Dynamics fields have not been loaded, cannot be removed. (from: ' . __METHOD__ . ')',
-                Analog::WARNING
-            );
-            $this->loadDynamicFields();
-        }
-        $return = $this->dynamics->removeValues($this->id, $transaction);
-        return $return;
-    }
-
-
-
-    /**
-     * Get errors
-     *
-     * @return array
-     */
-    public function getErrors()
-    {
-        return $this->errors;
-    }
-
-    /**
-     * Validate data for dynamic fields
-     * Set valid data in current object, also resets errors list
-     *
-     * @param array  $values Dynamic fields values
-     * @param string $prefix Prefix to replace, default to 'dynfield_'
-     *
-     * @return void
-     */
-    public function dynamicsValidate($values, $prefix = 'dynfield_')
-    {
-        $dfields = [];
-        foreach ($values as $key => $value) {
-            $dfields[str_replace($prefix, $this->name_pattern, $key)] = $value;
-        }
-        return $this->dynamicsCheck($dfields, [], []);
-    }
-}
index ea9f6ad8b0c8955dea354feb2ef7499af81e060d..2d58b0930b0144e488639783be35fe693b0ba12c 100644 (file)
@@ -39,8 +39,8 @@ namespace Galette\Entity;
 use Throwable;
 use Analog\Analog;
 use Laminas\Db\Sql\Expression;
-use Laminas\Db\Adapter\Adapter;
 use Galette\Core\Db;
+use Galette\Features\I18n;
 
 /**
  * Entitled handling. Manage:
@@ -66,7 +66,7 @@ use Galette\Core\Db;
 
 abstract class Entitled
 {
-    use I18nTrait;
+    use I18n;
 
     public const ID_NOT_EXITS = -1;
 
diff --git a/galette/lib/Galette/Entity/I18nTrait.php b/galette/lib/Galette/Entity/I18nTrait.php
deleted file mode 100644 (file)
index e6bbe0b..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-<?php
-
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * I18n
- *
- * PHP version 5
- *
- * Copyright © 2018 The Galette Team
- *
- * This file is part of Galette (http://galette.tuxfamily.org).
- *
- * 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/>.
- *
- * @category  Entity
- * @package   Galette
- *
- * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2018 The Galette Team
- * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
- * @link      http://galette.tuxfamily.org
- * @since     Available since 0.9.1dev - 2018-03-10
- */
-
-namespace Galette\Entity;
-
-use Throwable;
-use Analog\Analog;
-use Galette\Core\L10n;
-use Laminas\Db\Sql\Expression;
-
-/**
- * Files
- *
- * @category  Entity
- * @name      I18nTrait
- * @package   Galette
- * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2018 The Galette Team
- * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
- * @link      http://galette.tuxfamily.org
- * @since     Available since 0.9.1dev - 2018-03-10
- */
-
-trait I18nTrait
-{
-    protected $warnings = [];
-
-    /**
-     * Add a translation stored in the database
-     *
-     * @param string $text_orig Text to translate
-     *
-     * @return boolean
-     */
-    protected function addTranslation($text_orig)
-    {
-        global $i18n;
-
-        try {
-            foreach ($i18n->getList() as $lang) {
-                //check if translation already exists
-                $select = $this->zdb->select(L10n::TABLE);
-                $select->columns(array('text_nref'))
-                    ->where(
-                        array(
-                            'text_orig'     => $text_orig,
-                            'text_locale'   => $lang->getLongID()
-                        )
-                    );
-
-                $results = $this->zdb->execute($select);
-                $result = $results->current();
-                $nref = 0;
-                if ($result) {
-                    $nref = $result->text_nref;
-                }
-
-                if (is_numeric($nref) && $nref > 0) {
-                    //already existing, update
-                    $values = array(
-                        'text_nref' => new Expression('text_nref+1')
-                    );
-                    Analog::log(
-                        'Entry for `' . $text_orig .
-                        '` dynamic translation already exists.',
-                        Analog::INFO
-                    );
-
-                    $owhere = $select->where;
-
-                    $update = $this->zdb->update(L10n::TABLE);
-                    $update->set($values)->where($owhere);
-                    $this->zdb->execute($update);
-                } else {
-                    //add new entry
-                    // User is supposed to use current language as original text.
-                    $text_trans = $text_orig;
-                    if ($lang->getLongID() != $i18n->getLongID()) {
-                        $text_trans = '';
-                    }
-                    $values = array(
-                        'text_orig' => $text_orig,
-                        'text_locale' => $lang->getLongID(),
-                        'text_trans' => $text_trans
-                    );
-
-                    $insert = $this->zdb->insert(L10n::TABLE);
-                    $insert->values($values);
-                    $this->zdb->execute($insert);
-                }
-            }
-            return true;
-        } catch (Throwable $e) {
-            Analog::log(
-                'An error occurred adding dynamic translation for `' .
-                $text_orig . '` | ' . $e->getMessage(),
-                Analog::ERROR
-            );
-
-            $this->warnings[] = str_replace(
-                '%field',
-                $text_orig,
-                _T('Unable to add dynamic translation for %field :(')
-            );
-
-            return false;
-        }
-    }
-
-    /**
-     * Update a translation stored in the database
-     *
-     * @param string $text_orig   Text to translate
-     * @param string $text_locale The locale
-     * @param string $text_trans  Translated text
-     *
-     * @return boolean
-     */
-    protected function updateTranslation($text_orig, $text_locale, $text_trans)
-    {
-        try {
-            //check if translation already exists
-            $select = $this->zdb->select(L10n::TABLE);
-            $select->columns(array('text_nref'))->where(
-                array(
-                    'text_orig'     => $text_orig,
-                    'text_locale'   => $text_locale
-                )
-            );
-
-            $results = $this->zdb->execute($select);
-            $result = $results->current();
-
-            $exists = false;
-            if ($result) {
-                $nref = $result->text_nref;
-                $exists = (is_numeric($nref) && $nref > 0);
-            }
-
-            $values = array(
-                'text_trans' => $text_trans
-            );
-
-            if ($exists) {
-                $owhere = $select->where;
-
-                $update = $this->zdb->update(L10n::TABLE);
-                $update->set($values)->where($owhere);
-                $this->zdb->execute($update);
-            } else {
-                $values['text_orig'] = $text_orig;
-                $values['text_locale'] = $text_locale;
-
-                $insert = $this->zdb->insert(L10n::TABLE);
-                $insert->values($values);
-                $this->zdb->execute($insert);
-            }
-            return true;
-        } catch (Throwable $e) {
-            Analog::log(
-                'An error occurred updating dynamic translation for `' .
-                $text_orig . '` | ' . $e->getMessage(),
-                Analog::ERROR
-            );
-
-            $this->warnings[] = str_replace(
-                '%field',
-                $text_orig,
-                _T('Unable to update dynamic translation for %field :(')
-            );
-
-            return false;
-        }
-    }
-
-    /**
-     * Delete a translation stored in the database
-     *
-     * @param string $text_orig Text to translate
-     *
-     * @return boolean
-     */
-    protected function deleteTranslation($text_orig)
-    {
-        try {
-            $delete = $this->zdb->delete(L10n::TABLE);
-            $delete->where(
-                array(
-                    'text_orig'     => $text_orig
-                )
-            );
-            $this->zdb->execute($delete);
-            return true;
-        } catch (Throwable $e) {
-            Analog::log(
-                'An error occurred deleting dynamic translation for `' .
-                $text_orig . ' | ' . $e->getMessage(),
-                Analog::ERROR
-            );
-
-            $this->warnings[] = str_replace(
-                '%field',
-                $text_orig,
-                _T('Unable to remove old dynamic translation for %field :(')
-            );
-
-            return false;
-        }
-    }
-
-    /**
-     * Get warnings
-     *
-     * @return array
-     */
-    public function getWarnings()
-    {
-        return $this->warnings;
-    }
-}
index de027c874e5012ce3f5062df9e68d39e80f09a05..1180f57197ef897f37de50fd2237ed272f198e6d 100644 (file)
@@ -7,7 +7,7 @@
  *
  * PHP version 5
  *
- * Copyright © 2018 The Galette Team
+ * Copyright © 2018-2021 The Galette Team
  *
  * This file is part of Galette (http://galette.tuxfamily.org).
  *
@@ -28,7 +28,7 @@
  * @package   Galette
  *
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2018 The Galette Team
+ * @copyright 2018-2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @link      http://galette.tuxfamily.org
  * @since     Available since 0.9.2dev - 2018-07-23
 namespace Galette\Entity;
 
 use Throwable;
-use Galette\Core;
 use Galette\Core\Db;
-use Galette\Repository\PaymentTypes;
 use Analog\Analog;
-use Laminas\Db\Sql\Expression;
+use Galette\Features\I18n;
+use Galette\Features\Translatable;
 
 /**
  * Payment type
@@ -50,7 +49,7 @@ use Laminas\Db\Sql\Expression;
  * @name      PaymentType
  * @package   Galette
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2018 The Galette Team
+ * @copyright 2018-2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @link      http://galette.tuxfamily.org
  * @since     Available since 0.9.2dev - 2018-07-23
@@ -58,8 +57,8 @@ use Laminas\Db\Sql\Expression;
 
 class PaymentType
 {
-    use TranslatableTrait;
-    use I18nTrait;
+    use Translatable;
+    use I18n;
 
     public const TABLE = 'paymenttypes';
     public const PK = 'type_id';
index 1a43651c8abedd874632ab0d4d88063438afc8ec..a98769193b8b9214c22c6da2fcc5962aeeaeda92 100644 (file)
@@ -43,6 +43,7 @@ use Galette\Repository\Contributions;
 use Galette\Core\Db;
 use Galette\Core\History;
 use Galette\Core\Login;
+use Galette\Features\Dynamics;
 
 /**
  * Transaction class for galette
@@ -64,7 +65,7 @@ use Galette\Core\Login;
  */
 class Transaction
 {
-    use DynamicsTrait;
+    use Dynamics;
 
     public const TABLE = 'transactions';
     public const PK = 'trans_id';
diff --git a/galette/lib/Galette/Entity/TranslatableTrait.php b/galette/lib/Galette/Entity/TranslatableTrait.php
deleted file mode 100644 (file)
index ca342b4..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Translatable objects trait
- *
- * PHP version 5
- *
- * Copyright © 2018 The Galette Team
- *
- * This file is part of Galette (http://galette.tuxfamily.org).
- *
- * 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/>.
- *
- * @category  Entity
- * @package   Galette
- *
- * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2018 The Galette Team
- * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
- * @link      http://galette.tuxfamily.org
- * @since     Available since 0.9dev - 2017-05-26
- */
-
-namespace Galette\Entity;
-
-use Analog\Analog;
-
-/**
- * Translatable objects trait
- *
- * @category  Entity
- * @name      TranslatableTrait
- * @package   Galette
- * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2017 The Galette Team
- * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
- * @link      http://galette.tuxfamily.org
- * @since     Available since 0.9dev - 2017-05-26
- */
-
-trait TranslatableTrait
-{
-    protected $old_name;
-    protected $name;
-
-    /**
-     * Get field name
-     *
-     * @param boolean $translated Get translated or raw name
-     *
-     * @return String
-     */
-    public function getName($translated = true)
-    {
-        if (empty($this->name)) {
-            return '';
-        } elseif ($translated === true) {
-            return _T(strip_tags($this->name));
-        } else {
-            return strip_tags($this->name);
-        }
-    }
-}
diff --git a/galette/lib/Galette/Features/Dynamics.php b/galette/lib/Galette/Features/Dynamics.php
new file mode 100644 (file)
index 0000000..3f59b1f
--- /dev/null
@@ -0,0 +1,381 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Dynamics fields trait
+ *
+ * PHP version 5
+ *
+ * Copyright © 2017-2021 The Galette Team
+ *
+ * This file is part of Galette (http://galette.tuxfamily.org).
+ *
+ * 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/>.
+ *
+ * @category  Features
+ * @package   Galette
+ *
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2017-2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9dev - 2017-05-26
+ */
+
+namespace Galette\Features;
+
+use Throwable;
+use Analog\Analog;
+use Galette\DynamicFields\File;
+use Galette\DynamicFields\Date;
+use Galette\DynamicFields\Boolean;
+use Galette\Entity\DynamicFieldsHandle;
+
+/**
+ * Dynamics fields trait
+ *
+ * @category  Features
+ * @name      Dynamics
+ * @package   Galette
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2017-2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9dev - 2017-05-26
+ */
+
+trait Dynamics
+{
+    /** @var string */
+    protected $name_pattern = 'info_field_';
+
+    /** @var DynamicFieldsHandle */
+    protected $dynamics;
+
+    /**
+     * Load dynamic fields for member
+     *
+     * @return void
+     */
+    private function loadDynamicFields()
+    {
+        if (!property_exists($this, 'login')) {
+            global $login;
+        } else {
+            $login = $this->login;
+        }
+        $this->dynamics = new DynamicFieldsHandle($this->zdb, $login, $this);
+    }
+
+    /**
+     * Get dynamic fields
+     *
+     * @return array
+     */
+    public function getDynamicFields()
+    {
+        if (null === $this->dynamics) {
+            $this->loadDynamicFields();
+        }
+        return $this->dynamics;
+    }
+
+    /**
+     * Extract posted values for dynamic fields
+     *
+     * @param array $post     Posted values
+     * @param array $required Array of required fields
+     * @param array $disabled Array of disabled fields
+     *
+     * @return boolean
+     */
+    protected function dynamicsCheck(array $post, array $required, array $disabled)
+    {
+        if ($this->dynamics === null) {
+            Analog::log(
+                'Dynamics fields have not been loaded, cannot be checked. (from: ' . __METHOD__ . ')',
+                Analog::WARNING
+            );
+            $this->loadDynamicFields();
+        }
+
+        if ($post != null) {
+            $valid = true;
+            $fields = $this->dynamics->getFields();
+
+            $dynamic_fields = [];
+            //posted fields
+            foreach ($post as $key => $value) {
+                // if the field is enabled, and match patterns check it
+                if (isset($disabled[$key]) || substr($key, 0, 11) != $this->name_pattern) {
+                    continue;
+                }
+
+                list($field_id, $val_index) = explode('_', str_replace($this->name_pattern, '', $key));
+                if (!is_numeric($field_id) || !is_numeric($val_index)) {
+                    continue;
+                }
+
+                $dynamic_fields[$key] = [
+                    'value'     => $value,
+                    'field_id'  => $field_id,
+                    'val_index' => $val_index
+                ];
+            }
+
+            //some fields may be mising in posted values (checkboxes)
+            foreach ($fields as $field) {
+                $pattern = '/' . $this->name_pattern . $field->getId() . '_(\d)/';
+                if ($field instanceof Boolean && !preg_grep($pattern, array_keys($dynamic_fields))) {
+                    $dynamic_fields[$this->name_pattern . $field->getId() . '_1'] = [
+                        'value'     => '',
+                        'field_id'  => $field->getId(),
+                        'val_index' => 1
+                    ];
+                }
+            }
+
+            foreach ($dynamic_fields as $key => $dfield_values) {
+                $field_id = $dfield_values['field_id'];
+                $value = $dfield_values['value'];
+                $val_index = $dfield_values['val_index'];
+
+                if ($fields[$field_id]->isRequired() && (trim($value) === '' || $value == null)) {
+                    $this->errors[] = str_replace(
+                        '%field',
+                        $fields[$field_id]->getName(),
+                        _T('Missing required field %field')
+                    );
+                } else {
+                    if ($fields[$field_id] instanceof File) {
+                        //delete checkbox
+                        $filename = sprintf(
+                            'member_%d_field_%d_value_%d',
+                            $this->id,
+                            $field_id,
+                            $val_index
+                        );
+                        if (file_exists(GALETTE_FILES_PATH . $filename)) {
+                            unlink(GALETTE_FILES_PATH . $filename);
+                        }
+                        $this->dynamics->setValue($this->id, $field_id, $val_index, '');
+                    } else {
+                        if ($fields[$field_id] instanceof Date && !empty(trim($value))) {
+                            //check date format
+                            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');
+                                    }
+                                }
+                            } catch (Throwable $e) {
+                                $valid = false;
+                                Analog::log(
+                                    'Wrong date format. field: ' . $field_id .
+                                    ', value: ' . $value . ', expected fmt: ' .
+                                    __("Y-m-d") . ' | ' . $e->getMessage(),
+                                    Analog::INFO
+                                );
+                                $this->errors[] = str_replace(
+                                    array(
+                                        '%date_format',
+                                        '%field'
+                                    ),
+                                    array(
+                                        __("Y-m-d"),
+                                        $fields[$field_id]->getName()
+                                    ),
+                                    _T("- Wrong date format (%date_format) for %field!")
+                                );
+                            }
+                        }
+                        //actual field value
+                        if ($value !== null && trim($value) !== '') {
+                            $this->dynamics->setValue($this->id, $field_id, $val_index, $value);
+                        } else {
+                            $this->dynamics->unsetValue($this->id, $field_id, $val_index);
+                        }
+                    }
+                }
+            }
+
+            return $valid;
+        }
+    }
+
+    /**
+     * Stores dynamic fields
+     *
+     * @param boolean $transaction True if a transaction already exists
+     *
+     * @return boolean
+     */
+    protected function dynamicsStore($transaction = false)
+    {
+        if ($this->dynamics === null) {
+            Analog::log(
+                'Dynamics fields have not been loaded, cannot be stored. (from: ' . __METHOD__ . ')',
+                Analog::WARNING
+            );
+            $this->loadDynamicFields();
+        }
+        $return = $this->dynamics->storeValues($this->id, $transaction);
+        if (method_exists($this, 'updateModificationDate') && $this->dynamics->hasChanged()) {
+            $this->updateModificationDate();
+        }
+        return $return;
+    }
+
+    /**
+     * Store dynamic Files
+     *
+     * @param array $files Posted files
+     *
+     * @return void
+     */
+    protected function dynamicsFiles($files)
+    {
+        $this->loadDynamicFields();
+        $fields = $this->dynamics->getFields();
+        $store = false;
+
+        foreach ($files as $key => $file) {
+            // if the field is disabled, skip it
+            if (isset($disabled[$key])) {
+                continue;
+            }
+
+            if (substr($key, 0, 11) != $this->name_pattern) {
+                continue;
+            }
+
+            list($field_id, $val_index) = explode('_', str_replace($this->name_pattern, '', $key));
+            if (!is_numeric($field_id) || !is_numeric($val_index)) {
+                continue;
+            }
+
+            if (
+                $file['error'] == UPLOAD_ERR_NO_FILE
+                && $file['name'] == ''
+                && $file['tmp_name'] == ''
+            ) {
+                //not upload atempt.
+                continue;
+            } elseif ($file['error'] !== UPLOAD_ERR_OK) {
+                Analog::log("file upload error", Analog::ERROR);
+                continue;
+            }
+
+            $tmp_filename = $file['tmp_name'];
+            if ($tmp_filename == '') {
+                Analog::log("empty temporary filename", Analog::ERROR);
+                continue;
+            }
+
+            if (!is_uploaded_file($tmp_filename)) {
+                Analog::log("not an uploaded file", Analog::ERROR);
+                continue;
+            }
+
+            $max_size =
+                $fields[$field_id]->getSize() ?
+                $fields[$field_id]->getSize() * 1024 : File::DEFAULT_MAX_FILE_SIZE * 1024;
+            if ($file['size'] > $max_size) {
+                Analog::log(
+                    "file too large: " . $file['size'] . " Ko, vs $max_size Ko allowed",
+                    Analog::ERROR
+                );
+                $this->errors[] = preg_replace(
+                    '|%d|',
+                    $max_size,
+                    _T("File is too big. Maximum allowed size is %dKo")
+                );
+                continue;
+            }
+
+            $new_filename = sprintf(
+                'member_%d_field_%d_value_%d',
+                $this->id,
+                $field_id,
+                $val_index
+            );
+            Analog::log("new file: $new_filename", Analog::DEBUG);
+
+            move_uploaded_file(
+                $tmp_filename,
+                GALETTE_FILES_PATH . $new_filename
+            );
+            $this->dynamics->setValue($this->id, $field_id, $val_index, $file['name']);
+            $store = true;
+        }
+
+        if ($store === true) {
+            $this->dynamicsStore();
+        }
+    }
+
+    /**
+     * Remove dynamic fields values
+     *
+     * @param boolean $transaction True if a transaction already exists
+     *
+     * @return boolean
+     */
+    protected function dynamicsRemove($transaction = false)
+    {
+        if ($this->dynamics === null) {
+            Analog::log(
+                'Dynamics fields have not been loaded, cannot be removed. (from: ' . __METHOD__ . ')',
+                Analog::WARNING
+            );
+            $this->loadDynamicFields();
+        }
+        $return = $this->dynamics->removeValues($this->id, $transaction);
+        return $return;
+    }
+
+
+
+    /**
+     * Get errors
+     *
+     * @return array
+     */
+    public function getErrors()
+    {
+        return $this->errors;
+    }
+
+    /**
+     * Validate data for dynamic fields
+     * Set valid data in current object, also resets errors list
+     *
+     * @param array  $values Dynamic fields values
+     * @param string $prefix Prefix to replace, default to 'dynfield_'
+     *
+     * @return void
+     */
+    public function dynamicsValidate($values, $prefix = 'dynfield_')
+    {
+        $dfields = [];
+        foreach ($values as $key => $value) {
+            $dfields[str_replace($prefix, $this->name_pattern, $key)] = $value;
+        }
+        return $this->dynamicsCheck($dfields, [], []);
+    }
+}
diff --git a/galette/lib/Galette/Features/I18n.php b/galette/lib/Galette/Features/I18n.php
new file mode 100644 (file)
index 0000000..d40ef16
--- /dev/null
@@ -0,0 +1,253 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * I18n
+ *
+ * PHP version 5
+ *
+ * Copyright © 2018-2021 The Galette Team
+ *
+ * This file is part of Galette (http://galette.tuxfamily.org).
+ *
+ * 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/>.
+ *
+ * @category  Features
+ * @package   Galette
+ *
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2018-2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9.1dev - 2018-03-10
+ */
+
+namespace Galette\Features;
+
+use Throwable;
+use Analog\Analog;
+use Galette\Core\L10n;
+use Laminas\Db\Sql\Expression;
+
+/**
+ * Files
+ *
+ * @category  Features
+ * @name      I18n
+ * @package   Galette
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2018-2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9.1dev - 2018-03-10
+ */
+
+trait I18n
+{
+    protected $warnings = [];
+
+    /**
+     * Add a translation stored in the database
+     *
+     * @param string $text_orig Text to translate
+     *
+     * @return boolean
+     */
+    protected function addTranslation($text_orig)
+    {
+        global $i18n;
+
+        try {
+            foreach ($i18n->getList() as $lang) {
+                //check if translation already exists
+                $select = $this->zdb->select(L10n::TABLE);
+                $select->columns(array('text_nref'))
+                    ->where(
+                        array(
+                            'text_orig'     => $text_orig,
+                            'text_locale'   => $lang->getLongID()
+                        )
+                    );
+
+                $results = $this->zdb->execute($select);
+                $result = $results->current();
+                $nref = 0;
+                if ($result) {
+                    $nref = $result->text_nref;
+                }
+
+                if (is_numeric($nref) && $nref > 0) {
+                    //already existing, update
+                    $values = array(
+                        'text_nref' => new Expression('text_nref+1')
+                    );
+                    Analog::log(
+                        'Entry for `' . $text_orig .
+                        '` dynamic translation already exists.',
+                        Analog::INFO
+                    );
+
+                    $owhere = $select->where;
+
+                    $update = $this->zdb->update(L10n::TABLE);
+                    $update->set($values)->where($owhere);
+                    $this->zdb->execute($update);
+                } else {
+                    //add new entry
+                    // User is supposed to use current language as original text.
+                    $text_trans = $text_orig;
+                    if ($lang->getLongID() != $i18n->getLongID()) {
+                        $text_trans = '';
+                    }
+                    $values = array(
+                        'text_orig' => $text_orig,
+                        'text_locale' => $lang->getLongID(),
+                        'text_trans' => $text_trans
+                    );
+
+                    $insert = $this->zdb->insert(L10n::TABLE);
+                    $insert->values($values);
+                    $this->zdb->execute($insert);
+                }
+            }
+            return true;
+        } catch (Throwable $e) {
+            Analog::log(
+                'An error occurred adding dynamic translation for `' .
+                $text_orig . '` | ' . $e->getMessage(),
+                Analog::ERROR
+            );
+
+            $this->warnings[] = str_replace(
+                '%field',
+                $text_orig,
+                _T('Unable to add dynamic translation for %field :(')
+            );
+
+            return false;
+        }
+    }
+
+    /**
+     * Update a translation stored in the database
+     *
+     * @param string $text_orig   Text to translate
+     * @param string $text_locale The locale
+     * @param string $text_trans  Translated text
+     *
+     * @return boolean
+     */
+    protected function updateTranslation($text_orig, $text_locale, $text_trans)
+    {
+        try {
+            //check if translation already exists
+            $select = $this->zdb->select(L10n::TABLE);
+            $select->columns(array('text_nref'))->where(
+                array(
+                    'text_orig'     => $text_orig,
+                    'text_locale'   => $text_locale
+                )
+            );
+
+            $results = $this->zdb->execute($select);
+            $result = $results->current();
+
+            $exists = false;
+            if ($result) {
+                $nref = $result->text_nref;
+                $exists = (is_numeric($nref) && $nref > 0);
+            }
+
+            $values = array(
+                'text_trans' => $text_trans
+            );
+
+            if ($exists) {
+                $owhere = $select->where;
+
+                $update = $this->zdb->update(L10n::TABLE);
+                $update->set($values)->where($owhere);
+                $this->zdb->execute($update);
+            } else {
+                $values['text_orig'] = $text_orig;
+                $values['text_locale'] = $text_locale;
+
+                $insert = $this->zdb->insert(L10n::TABLE);
+                $insert->values($values);
+                $this->zdb->execute($insert);
+            }
+            return true;
+        } catch (Throwable $e) {
+            Analog::log(
+                'An error occurred updating dynamic translation for `' .
+                $text_orig . '` | ' . $e->getMessage(),
+                Analog::ERROR
+            );
+
+            $this->warnings[] = str_replace(
+                '%field',
+                $text_orig,
+                _T('Unable to update dynamic translation for %field :(')
+            );
+
+            return false;
+        }
+    }
+
+    /**
+     * Delete a translation stored in the database
+     *
+     * @param string $text_orig Text to translate
+     *
+     * @return boolean
+     */
+    protected function deleteTranslation($text_orig)
+    {
+        try {
+            $delete = $this->zdb->delete(L10n::TABLE);
+            $delete->where(
+                array(
+                    'text_orig'     => $text_orig
+                )
+            );
+            $this->zdb->execute($delete);
+            return true;
+        } catch (Throwable $e) {
+            Analog::log(
+                'An error occurred deleting dynamic translation for `' .
+                $text_orig . ' | ' . $e->getMessage(),
+                Analog::ERROR
+            );
+
+            $this->warnings[] = str_replace(
+                '%field',
+                $text_orig,
+                _T('Unable to remove old dynamic translation for %field :(')
+            );
+
+            return false;
+        }
+    }
+
+    /**
+     * Get warnings
+     *
+     * @return array
+     */
+    public function getWarnings()
+    {
+        return $this->warnings;
+    }
+}
index b97563688ccdc1d5c94c22c4fd2b2dae0f984c31..e0e69c81924261fbc17e523c1e4e1e0c7f50a884 100644 (file)
@@ -24,7 +24,7 @@
  * You should have received a copy of the GNU General Public License
  * along with Galette. If not, see <http://www.gnu.org/licenses/>.
  *
- * @category  Entity
+ * @category  Features
  * @package   Galette
  *
  * @author    Johan Cwiklinski <johan@x-tnd.be>
diff --git a/galette/lib/Galette/Features/Translatable.php b/galette/lib/Galette/Features/Translatable.php
new file mode 100644 (file)
index 0000000..10d6d83
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Translatable objects trait
+ *
+ * PHP version 5
+ *
+ * Copyright © 2018-2021 The Galette Team
+ *
+ * This file is part of Galette (http://galette.tuxfamily.org).
+ *
+ * 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/>.
+ *
+ * @category  Features
+ * @package   Galette
+ *
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2018-2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9dev - 2017-05-26
+ */
+
+namespace Galette\Features;
+
+/**
+ * Translatable objects trait
+ *
+ * @category  Features
+ * @name      Translatable
+ * @package   Galette
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2018-2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9dev - 2017-05-26
+ */
+
+trait Translatable
+{
+    protected $old_name;
+    protected $name;
+
+    /**
+     * Get field name
+     *
+     * @param boolean $translated Get translated or raw name
+     *
+     * @return String
+     */
+    public function getName($translated = true)
+    {
+        if (empty($this->name)) {
+            return '';
+        } elseif ($translated === true) {
+            return _T(strip_tags($this->name));
+        } else {
+            return strip_tags($this->name);
+        }
+    }
+}