*
* PHP version 5
*
- * Copyright © 2009-2014 The Galette Team
+ * Copyright © 2009-2023 The Galette Team
*
* This file is part of Galette (http://galette.tuxfamily.org).
*
* @package Galette
*
* @author Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2009-2014 The Galette Team
+ * @copyright 2009-2023 The Galette Team
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
- * @version SVN: $Id$
* @link http://galette.tuxfamily.org
* @since Available since 0.7dev - 2009-06-02
*/
namespace Galette\Entity;
+use ArrayObject;
+use Galette\Events\GaletteEvent;
+use Galette\Features\HasEvent;
+use Galette\Features\Socials;
+use Throwable;
use Analog\Analog;
use Laminas\Db\Sql\Expression;
use Galette\Core\Db;
use Galette\Core\Preferences;
use Galette\Core\History;
use Galette\Repository\Groups;
+use Galette\Core\Login;
use Galette\Repository\Members;
+use Galette\Features\Dynamics;
/**
* Member class for galette
* @name Adherent
* @package Galette
* @author Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2009-2014 The Galette Team
+ * @copyright 2009-2023 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.7dev - 02-06-2009
+ *
+ * @property integer $id
+ * @property integer|Title $title Either a title id or an instance of Title
+ * @property string $stitle Title label
+ * @property string $company_name
+ * @property string $name
+ * @property ?string $surname
+ * @property string $nickname
+ * @property string $birthdate Localized birthdate
+ * @property string $rbirthdate Raw birthdate
+ * @property string $birth_place
+ * @property integer $gender
+ * @property string $sgender Gender label
+ * @property string $job
+ * @property string $language
+ * @property integer $status
+ * @property string $sstatus Status label
+ * @property string $address
+ * @property string $zipcode
+ * @property string $town
+ * @property string $country
+ * @property string $phone
+ * @property string $gsm
+ * @property string $email
+ * @property string $gnupgid
+ * @property string $fingerprint
+ * @property string $login
+ * @property string $creation_date Localized creation date
+ * @property string $modification_date Localized modification date
+ * @property string $due_date Localized due date
+ * @property string $others_infos
+ * @property string $others_infos_admin
+ * @property Picture $picture
+ * @property array $groups
+ * @property array $managed_groups
+ * @property integer|Adherent $parent Parent id if parent dep is not loaded, Adherent instance otherwise
+ * @property array $children
+ * @property boolean $admin better to rely on isAdmin()
+ * @property boolean $staff better to rely on isStaff()
+ * @property boolean $due_free better to rely on isDueFree()
+ * @property boolean $appears_in_list better to rely on appearsInMembersList()
+ * @property boolean $active better to rely on isActive()
+ * @property boolean $duplicate better to rely on isDuplicate()
+ * @property string $sadmin yes/no
+ * @property string $sstaff yes/no
+ * @property string $sdue_free yes/no
+ * @property string $sappears_in_list yes/no
+ * @property string $sactive yes/no
+ * @property string $sfullname
+ * @property string $sname
+ * @property string $saddress
+ * @property string $contribstatus State of member contributions
+ * @property integer $days_remaining
+ * @property-read integer $parent_id
+ * @property Social $social Social networks/Contact
+ * @property string $number Member number
+ * @property-read bool $self_adh
*/
class Adherent
{
- use DynamicsTrait;
+ use Dynamics;
+ use Socials;
+ use HasEvent;
- const TABLE = 'adherents';
- const PK = 'id_adh';
+ public const TABLE = 'adherents';
+ public const PK = 'id_adh';
- const NC = 0;
- const MAN = 1;
- const WOMAN = 2;
+ public const NC = 0;
+ public const MAN = 1;
+ public const WOMAN = 2;
- const AFTER_ADD_DEFAULT = 0;
- const AFTER_ADD_TRANS = 1;
- const AFTER_ADD_NEW = 2;
- const AFTER_ADD_SHOW = 3;
- const AFTER_ADD_LIST = 4;
- const AFTER_ADD_HOME = 5;
+ public const AFTER_ADD_DEFAULT = 0;
+ public const AFTER_ADD_TRANS = 1;
+ public const AFTER_ADD_NEW = 2;
+ public const AFTER_ADD_SHOW = 3;
+ public const AFTER_ADD_LIST = 4;
+ public const AFTER_ADD_HOME = 5;
private $_id;
//Identity
private $_status;
//Contact information
private $_address;
- private $_address_continuation; /** TODO: remove */
private $_zipcode;
private $_town;
private $_country;
private $_phone;
private $_gsm;
private $_email;
- private $_website;
- private $_msn; /** TODO: remove */
- private $_icq; /** TODO: remove */
- private $_jabber; /** TODO: remove */
- private $_gnupgid; /** TODO: remove */
- private $_fingerprint; /** TODO: remove */
+ private $_gnupgid;
+ private $_fingerprint;
//Galette relative information
private $_appears_in_list;
private $_admin;
- private $_staff;
+ private $_staff = false;
private $_due_free;
private $_login;
private $_password;
private $_picture;
private $_oldness;
private $_days_remaining;
- private $_groups;
- private $_managed_groups;
+ private $_groups = [];
+ private $_managed_groups = [];
private $_parent;
- private $_children;
- //
+ private $_children = [];
+ private $_duplicate = false;
+ private $_socials;
+ private $_number;
+
private $_row_classes;
- //fields list and their translation
+
private $_self_adh = false;
- private $_deps = array(
- 'picture' => true,
- 'groups' => true,
- 'dues' => true,
- 'parent' => false,
- 'children' => false,
- 'dynamics' => false
- );
private $zdb;
private $preferences;
private $parent_fields = [
'adresse_adh',
- 'adresse2_adh',
'cp_adh',
'ville_adh',
'email_adh'
private $errors = [];
+ private $sendmail = false;
+
/**
* Default constructor
*
- * @param Db $zdb Database instance
- * @param mixed $args Either a ResultSet row, its id or its
- * login or its email for to load s specific
- * member, or null to just instanciate object
- * @param boolean $deps Dependencies configuration, see Adherent::$_deps
+ * @param Db $zdb Database instance
+ * @param mixed $args Either a ResultSet row, its id or its
+ * login or its email for to load s specific
+ * member, or null to just instantiate object
+ * @param false|array|null $deps Dependencies configuration, see Adherent::$_deps
*/
public function __construct(Db $zdb, $args = null, $deps = null)
{
if ($deps !== null) {
if (is_array($deps)) {
- $this->_deps = array_merge(
- $this->_deps,
- $deps
- );
+ $this->setDeps($deps);
} elseif ($deps === false) {
//no dependencies
- $this->deps = array_fill_keys(
- array_keys($this->deps),
- false
- );
+ $this->disableAllDeps();
} else {
Analog::log(
- '$deps shoud be an array, ' . gettype($deps) . ' given!',
+ '$deps should be an array, ' . gettype($deps) . ' given!',
Analog::WARNING
);
}
}
+ $this
+ ->withAddEvent()
+ ->withEditEvent()
+ ->withoutDeleteEvent()
+ ->activateEvents();
+
if ($args == null || is_int($args)) {
if (is_int($args) && $args > 0) {
$this->load($args);
/**
* Loads a member from its id
*
- * @param int $id the identifiant for the member to load
+ * @param int $id the identifier for the member to load
*
* @return bool true if query succeed, false otherwise
*/
- public function load($id)
+ public function load(int $id): bool
{
try {
$select = $this->zdb->select(self::TABLE, 'a');
return false;
}
- $this->loadFromRS($results->current());
+ /** @var ArrayObject $result */
+ $result = $results->current();
+ $this->loadFromRS($result);
return true;
- } catch (\Exception $e) {
+ } catch (Throwable $e) {
Analog::log(
'Cannot load member form id `' . $id . '` | ' . $e->getMessage(),
Analog::WARNING
);
- return false;
+ throw $e;
}
}
*
* @param string $login login for the member to load
*
- * @return bool true if query succeed, false otherwise
+ * @return boolean
*/
- public function loadFromLoginOrMail($login)
+ public function loadFromLoginOrMail(string $login): bool
{
try {
$select = $this->zdb->select(self::TABLE);
}
$results = $this->zdb->execute($select);
- $result = $results->current();
- if ($result) {
+ if ($results->count() > 0) {
+ /** @var ArrayObject $result */
+ $result = $results->current();
$this->loadFromRS($result);
}
- } catch (\Exception $e) {
+ return true;
+ } catch (Throwable $e) {
Analog::log(
'Cannot load member form login `' . $login . '` | ' .
$e->getMessage(),
Analog::WARNING
);
- return false;
+ throw $e;
}
}
/**
* Populate object from a resultset row
*
- * @param ResultSet $r the resultset row
+ * @param ArrayObject $r the resultset row
*
* @return void
*/
- private function loadFromRS($r)
+ private function loadFromRS(ArrayObject $r): void
{
$this->_self_adh = false;
$this->_id = $r->id_adh;
$this->_gender = (int)$r->sexe_adh;
$this->_job = $r->prof_adh;
$this->_language = $r->pref_lang;
- $this->_active = ($r->activite_adh == 1) ? true : false;
+ $this->_active = $r->activite_adh == 1;
$this->_status = (int)$r->id_statut;
//Contact information
$this->_address = $r->adresse_adh;
- /** TODO: remove and merge with address */
- $this->_address_continuation = $r->adresse2_adh;
$this->_zipcode = $r->cp_adh;
$this->_town = $r->ville_adh;
$this->_country = $r->pays_adh;
$this->_phone = $r->tel_adh;
$this->_gsm = $r->gsm_adh;
$this->_email = $r->email_adh;
- $this->_website = $r->url_adh;
- /** TODO: remove */
- $this->_msn = $r->msn_adh;
- /** TODO: remove */
- $this->_icq = $r->icq_adh;
- /** TODO: remove */
- $this->_jabber = $r->jabber_adh;
- /** TODO: remove */
$this->_gnupgid = $r->gpgid;
- /** TODO: remove */
$this->_fingerprint = $r->fingerprint;
//Galette relative information
- $this->_appears_in_list = ($r->bool_display_info == 1) ? true : false;
- $this->_admin = ($r->bool_admin_adh == 1) ? true : false;
- if (isset($r->priorite_statut)
+ $this->_appears_in_list = $r->bool_display_info == 1;
+ $this->_admin = $r->bool_admin_adh == 1;
+ if (
+ isset($r->priorite_statut)
&& $r->priorite_statut < Members::NON_STAFF_MEMBERS
) {
$this->_staff = true;
}
- $this->_due_free = ($r->bool_exempt_adh == 1) ? true : false;
+ $this->_due_free = $r->bool_exempt_adh == 1;
$this->_login = $r->login_adh;
$this->_password = $r->mdp_adh;
$this->_creation_date = $r->date_crea_adh;
$this->_due_date = $r->date_echeance;
$this->_others_infos = $r->info_public_adh;
$this->_others_infos_admin = $r->info_adh;
+ $this->_number = $r->num_adh;
if ($r->parent_id !== null) {
- $this->_parent = $r->parent_id;
+ $this->_parent = (int)$r->parent_id;
if ($this->_deps['parent'] === true) {
- $this->loadParent($r->parent_id);
+ $this->loadParent();
}
}
if ($this->_deps['dynamics'] === true) {
$this->loadDynamicFields();
}
+
+ if ($this->_deps['socials'] === true) {
+ $this->loadSocials();
+ }
}
/**
*
* @return void
*/
- private function loadParent()
+ private function loadParent(): void
{
- if (!$this->_parent instanceof Adherent) {
+ if ($this->_parent !== null && !$this->_parent instanceof Adherent) {
$deps = array_fill_keys(array_keys($this->_deps), false);
$this->_parent = new Adherent($this->zdb, (int)$this->_parent, $deps);
}
*
* @return void
*/
- private function loadChildren()
+ private function loadChildren(): void
{
$this->_children = array();
try {
$select = $this->zdb->select(self::TABLE);
$select->columns(
array($id)
- )->where(
- 'parent_id = ' . $this->_id
- );
+ )->where(['parent_id' => $this->_id]);
$results = $this->zdb->execute($select);
- if ($results->count() > 0) {
+ if ($results->count() > 0) {
foreach ($results as $row) {
$deps = $this->_deps;
$deps['children'] = false;
$this->_children[] = new Adherent($this->zdb, (int)$row->$id, $deps);
}
}
- } catch (\Exception $e) {
+ } catch (Throwable $e) {
Analog::log(
'Cannot load children for member #' . $this->_id . ' | ' .
$e->getMessage(),
Analog::WARNING
);
- return false;
+ throw $e;
}
}
*
* @return void
*/
- public function loadGroups()
+ public function loadGroups(): void
{
$this->_groups = Groups::loadGroups($this->_id);
$this->_managed_groups = Groups::loadManagedGroups($this->_id);
}
+ /**
+ * Load member social network/contact information
+ *
+ * @return void
+ */
+ public function loadSocials(): void
+ {
+ $this->_socials = Social::getListForMember($this->_id);
+ }
+
/**
* Retrieve status from preferences
*
- * @return pref_statut
+ * @return integer
*
*/
- private function getDefaultStatus()
+ private function getDefaultStatus(): int
{
global $preferences;
if ($preferences->pref_statut != '') {
*
* @return void
*/
- private function checkDues()
+ private function checkDues(): void
{
//how many days since our beloved member has been created
- $date_now = new \DateTime();
- $this->_oldness = $date_now->diff(
+ $now = new \DateTime();
+ $this->_oldness = $now->diff(
new \DateTime($this->_creation_date)
)->days;
if ($this->_due_date == '') {
$this->_row_classes .= ' cotis-never';
} else {
- $date_end = new \DateTime($this->_due_date);
- $date_diff = $date_now->diff($date_end);
- $this->_days_remaining = ( $date_diff->invert == 1 )
- ? $date_diff->days * -1
- : $date_diff->days;
-
- if ($this->_days_remaining == 0) {
- $this->_row_classes .= ' cotis-lastday';
- } elseif ($this->_days_remaining < 0) {
- $this->_row_classes .= ' cotis-late';
- } elseif ($this->_days_remaining < 30) {
- $this->_row_classes .= ' cotis-soon';
- } else {
- $this->_row_classes .= ' cotis-ok';
+ // To count the days remaining, the next begin date is required.
+ $due_date = new \DateTime($this->_due_date);
+ $next_begin_date = clone $due_date;
+ $next_begin_date->add(new \DateInterval('P1D'));
+ $date_diff = $now->diff($next_begin_date);
+ $this->_days_remaining = $date_diff->days;
+ // Active
+ if ($date_diff->invert == 0 && $date_diff->days >= 0) {
+ $this->_days_remaining = $date_diff->days;
+ if ($this->_days_remaining <= 30) {
+ if ($date_diff->days == 0) {
+ $this->_row_classes .= ' cotis-lastday';
+ }
+ $this->_row_classes .= ' cotis-soon';
+ } else {
+ $this->_row_classes .= ' cotis-ok';
+ }
+ // Expired
+ } elseif ($date_diff->invert == 1 && $date_diff->days >= 0) {
+ $this->_days_remaining = $date_diff->days;
+ //check if member is still active
+ $this->_row_classes .= $this->isActive() ? ' cotis-late' : ' cotis-old';
}
}
}
*
* @return bool
*/
- public function isAdmin()
+ public function isAdmin(): bool
{
return $this->_admin;
}
*
* @return bool
*/
- public function isStaff()
+ public function isStaff(): bool
{
return $this->_staff;
}
*
* @return bool
*/
- public function isDueFree()
+ public function isDueFree(): bool
{
return $this->_due_free;
}
*
* @return boolean
*/
- public function isGroupMember($group_name)
+ public function isGroupMember(string $group_name): bool
{
- if (is_array($this->_groups)) {
- foreach ($this->_groups as $g) {
- if ($g->getName() == $group_name) {
- return true;
- break;
- }
+ if (!$this->isDepEnabled('groups')) {
+ $this->loadGroups();
+ }
+
+ foreach ($this->_groups as $g) {
+ if ($g->getName() == $group_name) {
+ return true;
}
- } else {
- Analog::log(
- 'Calling ' . __METHOD__ . ' without groups loaded!',
- Analog::ERROR
- );
- return false;
}
+ return false;
}
/**
*
* @return boolean
*/
- public function isGroupManager($group_name)
+ public function isGroupManager(string $group_name): bool
{
- if (is_array($this->_managed_groups)) {
- foreach ($this->_managed_groups as $mg) {
- if ($mg->getName() == $group_name) {
- return true;
- break;
- }
+ if (!$this->isDepEnabled('groups')) {
+ $this->loadGroups();
+ }
+
+ foreach ($this->_managed_groups as $mg) {
+ if ($mg->getName() == $group_name) {
+ return true;
}
- } else {
- Analog::log(
- 'Calling ' . __METHOD__ . ' without groups loaded!',
- Analog::ERROR
- );
- return false;
}
+ return false;
}
/**
*
* @return boolean
*/
- public function isCompany()
+ public function isCompany(): bool
{
- return trim($this->_company_name) != '';
+ return trim($this->_company_name ?? '') != '';
}
/**
*
* @return boolean
*/
- public function isMan()
+ public function isMan(): bool
{
return (int)$this->_gender === self::MAN;
}
*
* @return boolean
*/
- public function isWoman()
+ public function isWoman(): bool
{
return (int)$this->_gender === self::WOMAN;
}
*
* @return bool
*/
- public function appearsInMembersList()
+ public function appearsInMembersList(): bool
{
return $this->_appears_in_list;
}
*
* @return bool
*/
- public function isActive()
+ public function isActive(): bool
{
return $this->_active;
}
*
* @return bool
*/
- public function hasPicture()
+ public function hasPicture(): bool
{
return $this->_picture->hasPicture();
}
*
* @return bool
*/
- public function hasParent()
+ public function hasParent(): bool
{
- return $this->_parent !== null;
+ return !empty($this->_parent);
}
/**
*
* @return bool
*/
- public function hasChildren()
+ public function hasChildren(): bool
{
if ($this->_children === null) {
- Analog::log(
- 'Children has not been loaded!',
- Analog::WARNING
- );
+ if ($this->id) {
+ Analog::log(
+ 'Children has not been loaded!',
+ Analog::WARNING
+ );
+ }
return false;
} else {
return count($this->_children) > 0;
*
* @return string the class to apply
*/
- public function getRowClass($public = false)
+ public function getRowClass(bool $public = false): string
{
- $strclass = ($this->isActive()) ? 'active' : 'inactive';
+ $strclass = ($this->isActive()) ? 'active-account' : 'inactive-account';
if ($public === false) {
$strclass .= $this->_row_classes;
}
*
* @return string i18n string representing state of due
*/
- public function getDues()
+ public function getDues(): string
{
$ret = '';
+ $never_contributed = false;
+ $now = new \DateTime();
+ // To count the days remaining, the next begin date is required.
+ if ($this->_due_date === null) {
+ $this->_due_date = $now->format('Y-m-d');
+ $never_contributed = true;
+ }
+ $due_date = new \DateTime($this->_due_date);
+ $next_begin_date = clone $due_date;
+ $next_begin_date->add(new \DateInterval('P1D'));
+ $date_diff = $now->diff($next_begin_date);
if ($this->isDueFree()) {
$ret = _T("Freed of dues");
- } elseif ($this->_due_date == '') {
+ } elseif ($never_contributed === true) {
$patterns = array('/%days/', '/%date/');
$cdate = new \DateTime($this->_creation_date);
$replace = array(
} else {
$ret = _T("Never contributed");
}
+ // Last active or first expired day
} elseif ($this->_days_remaining == 0) {
- $ret = _T("Last day!");
- } elseif ($this->_days_remaining < 0) {
- $patterns = array('/%days/', '/%date/');
- $ddate = new \DateTime($this->_due_date);
- $replace = array(
- $this->_days_remaining *-1,
- $ddate->format(__("Y-m-d"))
- );
- if ($this->_active) {
- $ret = preg_replace(
- $patterns,
- $replace,
- _T("Late of %days days (since %date)")
- );
+ if ($date_diff->invert == 0) {
+ $ret = _T("Last day!");
} else {
- $ret = _T("Late");
+ $ret = _T("Late since today!");
}
- } else {
+ // Active
+ } elseif ($date_diff->invert == 0 && $this->_days_remaining > 0) {
$patterns = array('/%days/', '/%date/');
- $ddate = new \DateTime($this->_due_date);
$replace = array(
$this->_days_remaining,
- $ddate->format(__("Y-m-d"))
+ $due_date->format(__("Y-m-d"))
);
$ret = preg_replace(
$patterns,
$replace,
_T("%days days remaining (ending on %date)")
);
+ // Expired
+ } elseif ($date_diff->invert == 1 && $this->_days_remaining > 0) {
+ $patterns = array('/%days/', '/%date/');
+ $replace = array(
+ // We need the number of days expired, not the number of days remaining.
+ $this->_days_remaining + 1,
+ $due_date->format(__("Y-m-d"))
+ );
+ if ($this->_active) {
+ $ret = preg_replace(
+ $patterns,
+ $replace,
+ _T("Late of %days days (since %date)")
+ );
+ } else {
+ $ret = _T("No longer member");
+ }
}
return $ret;
}
*
* @return string formatted Name and Surname
*/
- public static function getSName($zdb, $id, $wid = false, $wnick = false)
+ public static function getSName(Db $zdb, int $id, bool $wid = false, bool $wnick = false): string
{
try {
$select = $zdb->select(self::TABLE);
- $select->where(self::PK . ' = ' . $id);
+ $select->where([self::PK => $id]);
$results = $zdb->execute($select);
$row = $results->current();
($wid === true ? $row->id_adh : false),
($wnick === true ? $row->pseudo_adh : false)
);
- } catch (\Exception $e) {
+ } catch (Throwable $e) {
Analog::log(
'Cannot get formatted name for member form id `' . $id . '` | ' .
$e->getMessage(),
Analog::WARNING
);
- return false;
+ throw $e;
}
}
* Get member name with correct case
*
* @param string $name Member name
- * @param string $surname Mmeber surname
+ * @param string $surname Member surname
* @param false|Title $title Member title to show or false
* @param false|integer $id Member id to display or false
* @param false|string $nick Member nickname to display or false
*
* @return string
*/
- public static function getNameWithCase($name, $surname, $title = false, $id = false, $nick = false)
- {
+ public static function getNameWithCase(
+ ?string $name,
+ ?string $surname,
+ $title = false,
+ $id = false,
+ $nick = false
+ ): string {
$str = '';
- if ($title !== false && $title instanceof Title) {
+ if ($title instanceof Title) {
$str .= $title->tshort . ' ';
}
- $str .= mb_strtoupper($name, 'UTF-8') . ' ' .
- ucwords(mb_strtolower($surname, 'UTF-8'), " \t\r\n\f\v-_|");
+ $str .= mb_strtoupper($name ?? '', 'UTF-8') . ' ' .
+ ucwords(mb_strtolower($surname ?? '', 'UTF-8'), " \t\r\n\f\v-_|");
- if ($id !== false || $nick !== false) {
+ if ($id !== false || !empty($nick)) {
$str .= ' (';
}
- if ($nick !== false) {
+ if (!empty($nick)) {
$str .= $nick;
}
if ($id !== false) {
- if ($nick !== false && !empty($nick)) {
+ if (!empty($nick)) {
$str .= ', ';
}
$str .= $id;
}
- if ($id !== false || $nick !== false) {
+ if ($id !== false || !empty($nick)) {
$str .= ')';
}
- return $str;
+ return strip_tags($str);
}
/**
* Change password for a given user
*
- * @param Db $zdb Database instance
- * @param string $id_adh Member identifier
- * @param string $pass New password
+ * @param Db $zdb Database instance
+ * @param integer $id_adh Member identifier
+ * @param string $pass New password
*
* @return boolean
*/
- public static function updatePassword(Db $zdb, $id_adh, $pass)
+ public static function updatePassword(Db $zdb, int $id_adh, string $pass): bool
{
try {
$cpass = password_hash($pass, PASSWORD_BCRYPT);
$update = $zdb->update(self::TABLE);
$update->set(
array('mdp_adh' => $cpass)
- )->where(self::PK . ' = ' . $id_adh);
+ )->where([self::PK => $id_adh]);
$zdb->execute($update);
Analog::log(
'Password for `' . $id_adh . '` has been updated.',
Analog::DEBUG
);
return true;
- } catch (\Exception $e) {
+ } catch (Throwable $e) {
Analog::log(
'An error occurred while updating password for `' . $id_adh .
'` | ' . $e->getMessage(),
Analog::ERROR
);
- return false;
+ throw $e;
}
}
*
* @return string
*/
- private function getFieldLabel($field)
+ private function getFieldLabel(string $field): string
{
- $label = $this->fields[$field]['label'];
- //remove trailing ':' and then nbsp (for french at least)
- $label = trim(trim($label, ':'), ' ');
+ $label = $this->fields[$field]['label'] ?? '';
+ //replace " "
+ $label = str_replace(' ', ' ', $label);
+ //remove trailing ':' and then trim
+ $label = trim(trim($label, ':'));
return $label;
}
*
* @return array
*/
- public static function getDbFields(Db $zdb)
+ public static function getDbFields(Db $zdb): array
{
$columns = $zdb->getColumns(self::TABLE);
$fields = array();
*
* @return void
*/
- public function setSelfMembership()
+ public function setSelfMembership(): void
{
$this->_self_adh = true;
}
*
* @return boolean
*/
- public function isUp2Date()
+ public function isUp2Date(): bool
{
- if ($this->_deps['dues']) {
- if ($this->isDueFree()) {
- //member is due free, he's up to date.
- return true;
+ if (!$this->isDepEnabled('dues')) {
+ $this->checkDues();
+ }
+
+ if ($this->isDueFree()) {
+ //member is due free, he's up to date.
+ return true;
+ } else {
+ //let's check from due date, if present
+ if ($this->_due_date == null) {
+ return false;
} else {
- //let's check from end date, if present
- if ($this->_due_date == null) {
- return false;
- } else {
- $ech = new \DateTime($this->_due_date);
- $now = new \DateTime();
- $now->setTime(0, 0, 0);
- return $ech >= $now;
- }
+ $due_date = new \DateTime($this->_due_date);
+ $now = new \DateTime();
+ $now->setTime(0, 0, 0);
+ return $due_date >= $now;
}
- } else {
- throw new \RuntimeException(
- 'Cannot check if member is up to date, dues deps is disabled!'
- );
}
}
*
* @return true|array
*/
- public function check($values, $required, $disabled)
+ public function check(array $values, array $required, array $disabled)
{
+ global $login;
+
$this->errors = array();
+ //Sanitize
+ foreach ($values as &$rawvalue) {
+ if (is_string($rawvalue)) {
+ $rawvalue = strip_tags($rawvalue);
+ }
+ }
+
$fields = self::getDbFields($this->zdb);
- //reset company name if needeed
+ //reset company name if needed
if (!isset($values['is_company'])) {
unset($values['is_company']);
$values['societe_adh'] = '';
}
//no parent if checkbox was unchecked
- if (!isset($values['attach'])
+ if (
+ !isset($values['attach'])
&& empty($this->_id)
&& isset($values['parent_id'])
) {
unset($values['parent_id']);
}
+ if (isset($values['duplicate'])) {
+ //if we're duplicating, keep a trace (if an error occurs)
+ $this->_duplicate = true;
+ }
+
foreach ($fields as $key) {
- //first of all, let's sanitize values
+ //first, let's sanitize values
$key = strtolower($key);
$prop = '_' . $this->fields[$key]['propname'];
if (isset($values[$key])) {
$value = $values[$key];
if ($value !== true && $value !== false) {
- $value = trim($value);
+ //@phpstan-ignore-next-line
+ $value = trim($value ?? '');
}
- } elseif ($this->_id == '' || $this->_id == null) {
+ } elseif (empty($this->_id)) {
switch ($key) {
case 'bool_admin_adh':
case 'bool_exempt_adh':
$value = 0;
break;
case 'activite_adh':
- //values that are setted at object instanciation
+ //values that are set at object instantiation
$value = true;
break;
case 'date_crea_adh':
case 'id_statut':
case 'pref_lang':
case 'parent_id':
- //values that are setted at object instanciation
+ //values that are set at object instantiation
$value = $this->$prop;
break;
+ case self::PK:
+ $value = null;
+ break;
default:
$value = '';
+ break;
}
} else {
//keep stored value on update
// now, check validity
if ($value !== null && $value != '') {
- $this->validate($key, $value, $values);
- } elseif (($key == 'login_adh' && !isset($required['login_adh']))
- || ($key == 'mdp_adh' && !isset($required['mdp_adh']))
- && !isset($this->_id)
- ) {
- $p = new Password($this->zdb);
- $this->$prop = $p->makeRandomPassword(15);
+ if ($key !== 'mdp_adh') {
+ $this->validate($key, $value, $values);
+ }
+ } elseif (empty($this->_id)) {
+ //ensure login and password are not empty
+ if (($key == 'login_adh' || $key == 'mdp_adh') && !isset($required[$key])) {
+ $p = new Password($this->zdb);
+ $generated_value = $p->makeRandomPassword(15);
+ if ($key == 'login_adh') {
+ //'@' is not permitted in logins
+ $this->$prop = str_replace('@', 'a', $generated_value);
+ } else {
+ $this->$prop = $generated_value;
+ }
+ }
}
}
}
+ //password checks need data to be previously set
+ if (isset($values['mdp_adh'])) {
+ $this->validate('mdp_adh', $values['mdp_adh'], $values);
+ }
+
// missing required fields?
foreach ($required as $key => $val) {
$prop = '_' . $this->fields[$key]['propname'];
if ($mandatory_missing === true) {
$this->errors[] = str_replace(
'%field',
- '<a href="#' . $key . '">' . $this->getFieldLabel($key) .'</a>',
+ '<a href="#' . $key . '">' . $this->getFieldLabel($key) . '</a>',
_T("- Mandatory field %field empty.")
);
}
$this->_parent = null;
}
- $this->dynamicsCheck($values);
+ if ($login->isGroupManager() && !$login->isAdmin() && !$login->isStaff() && $this->parent_id !== $login->id) {
+ if (!isset($values['groups_adh'])) {
+ $this->errors[] = _T('You have to select a group you own!');
+ } else {
+ $owned_group = false;
+ foreach ($values['groups_adh'] as $group) {
+ list($gid) = explode('|', $group);
+ if ($login->isGroupManager($gid)) {
+ $owned_group = true;
+ }
+ }
+ if ($owned_group === false) {
+ $this->errors[] = _T('You have to select a group you own!');
+ }
+ }
+ }
+
+ $this->dynamicsCheck($values, $required, $disabled);
+ $this->checkSocials($values);
if (count($this->errors) > 0) {
Analog::log(
- 'Some errors has been throwed attempting to edit/store a member' . "\n" .
+ 'Some errors has been thew attempting to edit/store a member' . "\n" .
print_r($this->errors, true),
Analog::ERROR
);
*
* @return void
*/
- public function validate($field, $value, $values)
+ public function validate(string $field, $value, array $values): void
{
global $preferences;
$prop = '_' . $this->fields[$field]['propname'];
+ if ($value === null || (is_string($value) && trim($value) == '')) {
+ //empty values are OK
+ $this->$prop = $value;
+ return;
+ }
+
switch ($field) {
// dates
case 'date_crea_adh':
$d->setTime(0, 0, 0);
$diff = $now->diff($d);
- $days = (integer)$diff->format('%R%a');
+ $days = (int)$diff->format('%R%a');
if ($days >= 0) {
- $this->errors[] =_T('- Birthdate must be set in the past!');
+ $this->errors[] = _T('- Birthdate must be set in the past!');
}
- $years = (integer)$diff->format('%R%Y');
+ $years = (int)$diff->format('%R%Y');
if ($years <= -200) {
$this->errors[] = str_replace(
'%years',
}
}
$this->$prop = $d->format('Y-m-d');
- } catch (\Exception $e) {
+ } catch (Throwable $e) {
Analog::log(
'Wrong date format. field: ' . $field .
', value: ' . $value . ', expected fmt: ' .
}
break;
case 'email_adh':
- case 'msn_adh':
if (!GaletteMail::isValidEmail($value)) {
$this->errors[] = _T("- Non-valid E-Mail address!") .
' (' . $this->getFieldLabel($field) . ')';
}
- if ($field == 'email_adh') {
- try {
- $select = $this->zdb->select(self::TABLE);
- $select->columns(
- array(self::PK)
- )->where(array('email_adh' => $value));
- if ($this->_id != '' && $this->_id != null) {
- $select->where(
- self::PK . ' != ' . $this->_id
- );
- }
- $results = $this->zdb->execute($select);
- if ($results->count() !== 0) {
- $this->errors[] = _T("- This E-Mail address is already used by another member!");
- }
- } catch (\Exception $e) {
- Analog::log(
- 'An error occurred checking member email unicity.',
- Analog::ERROR
+ try {
+ $select = $this->zdb->select(self::TABLE);
+ $select->columns(
+ array(self::PK)
+ )->where(array('email_adh' => $value));
+ if (!empty($this->_id)) {
+ $select->where->notEqualTo(
+ self::PK,
+ $this->_id
);
- $this->errors[] = _T("An error has occurred while looking if login already exists.");
}
- }
- break;
- case 'url_adh':
- if ($value == 'http://') {
- $this->$prop = '';
- } elseif (!isValidWebUrl($value)) {
- $this->errors[] = _T("- Non-valid Website address! Maybe you've skipped the http://?");
+
+ $results = $this->zdb->execute($select);
+ if ($results->count() !== 0) {
+ $this->errors[] = _T("- This E-Mail address is already used by another member!");
+ }
+ } catch (Throwable $e) {
+ Analog::log(
+ 'An error occurred checking member email uniqueness.',
+ Analog::ERROR
+ );
+ $this->errors[] = _T("An error has occurred while looking if login already exists.");
}
break;
case 'login_adh':
- /** FIXME: add a preference for login lenght */
+ /** FIXME: add a preference for login length */
if (strlen($value) < 2) {
$this->errors[] = str_replace(
'%i',
$select->columns(
array(self::PK)
)->where(array('login_adh' => $value));
- if ($this->_id != '' && $this->_id != null) {
- $select->where(
- self::PK . ' != ' . $this->_id
+ if (!empty($this->_id)) {
+ $select->where->notEqualTo(
+ self::PK,
+ $this->_id
);
}
$results = $this->zdb->execute($select);
- if ($results->count() !== 0
+ if (
+ $results->count() !== 0
|| $value == $preferences->pref_admin_login
) {
$this->errors[] = _T("- This username is already in use, please choose another one!");
}
- } catch (\Exception $e) {
+ } catch (Throwable $e) {
Analog::log(
- 'An error occurred checking member login unicity.',
+ 'An error occurred checking member login uniqueness.',
Analog::ERROR
);
$this->errors[] = _T("An error has occurred while looking if login already exists.");
}
break;
case 'mdp_adh':
- /** TODO: check password complexity, set by a preference */
- /** TODO: add a preference for password lenght */
- if (strlen($value) < 6) {
- $this->errors[] = str_replace(
- '%i',
- 6,
- _T("- The password must be of at least %i characters!")
- );
- } elseif ($this->_self_adh !== true
+ if (
+ $this->_self_adh !== true
&& (!isset($values['mdp_adh2'])
|| $values['mdp_adh2'] != $value)
) {
$this->errors[] = _T("- The passwords don't match!");
- } elseif ($this->_self_adh === true
- && !crypt($value, $values['mdp_crypt'])==$values['mdp_crypt']
+ } elseif (
+ $this->_self_adh === true
+ && !crypt($value, $values['mdp_crypt']) == $values['mdp_crypt']
) {
$this->errors[] = _T("Password misrepeated: ");
} else {
- $this->$prop = password_hash(
- $value,
- PASSWORD_BCRYPT
- );
+ $pinfos = password_get_info($value);
+ //check if value is already a hash
+ if ($pinfos['algo'] == 0) {
+ $this->$prop = password_hash(
+ $value,
+ PASSWORD_BCRYPT
+ );
+
+ $pwcheck = new \Galette\Util\Password($preferences);
+ $pwcheck->setAdherent($this);
+ if (!$pwcheck->isValid($value)) {
+ $this->errors = array_merge(
+ $this->errors,
+ $pwcheck->getErrors()
+ );
+ }
+ }
}
break;
case 'id_statut':
$this->$prop = (int)$value;
//check if status exists
$select = $this->zdb->select(Status::TABLE);
- $select->where(Status::PK . '= ' . $value);
+ $select->where([Status::PK => $value]);
$results = $this->zdb->execute($select);
$result = $results->current();
);
break;
}
- } catch (\Exception $e) {
+ } catch (Throwable $e) {
Analog::log(
- 'An error occurred checking status existance: ' . $e->getMessage(),
+ 'An error occurred checking status existence: ' . $e->getMessage(),
Analog::ERROR
);
$this->errors[] = _T("An error has occurred while looking if status does exists.");
$this->errors[] = _T("Gender %gender does not exists!");
}
break;
+ case 'parent_id':
+ $this->$prop = ($value instanceof Adherent) ? (int)$value->id : (int)$value;
+ $this->loadParent();
+ break;
}
}
*
* @return boolean
*/
- public function store()
+ public function store(): bool
{
- global $hist, $emitter;
+ global $hist, $emitter, $login;
+ $event = null;
+
+ if (!$login->isAdmin() && !$login->isStaff() && !$login->isGroupManager() && $this->id == '') {
+ if ($this->preferences->pref_bool_create_member) {
+ $this->_parent = $login->id;
+ }
+ }
try {
$values = array();
$fields = self::getDbFields($this->zdb);
foreach ($fields as $field) {
- if ($field !== 'date_modif_adh'
- || !isset($this->_id)
- || $this->_id == ''
+ if (
+ $field !== 'date_modif_adh'
+ || empty($this->_id)
) {
$prop = '_' . $this->fields[$field]['propname'];
- if (($field === 'bool_admin_adh'
+ if (
+ ($field === 'bool_admin_adh'
|| $field === 'bool_exempt_adh'
|| $field === 'bool_display_info'
|| $field === 'activite_adh')
$values['parent_id'] = new Expression('NULL');
}
+ if (!$this->_number) {
+ $values['num_adh'] = new Expression('NULL');
+ }
+
//fields that cannot be null
$notnull = [
'_surname' => 'prenom_adh',
}
}
- $success = false;
- if (!isset($this->_id) || $this->_id == '') {
+ if (empty($this->_id)) {
//we're inserting a new member
unset($values[self::PK]);
//set modification date
$insert->values($values);
$add = $this->zdb->execute($insert);
if ($add->count() > 0) {
- if ($this->zdb->isPostgres()) {
- $this->_id = $this->zdb->driver->getLastGeneratedValue(
- PREFIX_DB . 'adherents_id_seq'
- );
- } else {
- $this->_id = $this->zdb->driver->getLastGeneratedValue();
- }
+ $this->_id = $this->zdb->getLastGeneratedValue($this);
$this->_picture = new Picture($this->_id);
// logging
if ($this->_self_adh) {
$this->sname
);
}
- $success = true;
- $emitter->emit('member.add', $this);
+ $event = $this->getAddEventName();
} else {
$hist->add(_T("Fail to add new member."));
throw new \Exception(
$update = $this->zdb->update(self::TABLE);
$update->set($values);
- $update->where(
- self::PK . '=' . $this->_id
- );
+ $update->where([self::PK => $this->_id]);
$edit = $this->zdb->execute($update);
$this->sname
);
}
- $success = true;
-
- $emitter->emit('member.edit', $this);
+ $event = $this->getEditEventName();
}
//dynamic fields
- if ($success) {
- $success = $this->dynamicsStore();
- }
+ $this->dynamicsStore();
+ $this->storeSocials($this->id);
- return $success;
- } catch (\Exception $e) {
+ //send event at the end of process, once all has been stored
+ if ($event !== null && $this->areEventsEnabled()) {
+ $emitter->dispatch(new GaletteEvent($event, $this));
+ }
+ return true;
+ } catch (Throwable $e) {
Analog::log(
'Something went wrong :\'( | ' . $e->getMessage() . "\n" .
$e->getTraceAsString(),
Analog::ERROR
);
- return false;
+ throw $e;
}
}
*
* @return void
*/
- private function updateModificationDate()
+ private function updateModificationDate(): void
{
try {
$modif_date = date('Y-m-d');
$update = $this->zdb->update(self::TABLE);
$update->set(
array('date_modif_adh' => $modif_date)
- )->where(self::PK . '=' . $this->_id);
+ )->where([self::PK => $this->_id]);
- $edit = $this->zdb->execute($update);
+ $this->zdb->execute($update);
$this->_modification_date = $modif_date;
- } catch (\Exception $e) {
+ } catch (Throwable $e) {
Analog::log(
'Something went wrong updating modif date :\'( | ' .
$e->getMessage() . "\n" . $e->getTraceAsString(),
Analog::ERROR
);
+ throw $e;
}
}
/**
* Global getter method
*
- * @param string $name name of the property we want to retrive
+ * @param string $name name of the property we want to retrieve
*
- * @return false|object the called property
+ * @return mixed
*/
- public function __get($name)
+ public function __get(string $name)
{
$forbidden = array(
'admin', 'staff', 'due_free', 'appears_in_list', 'active',
- 'row_classes'
+ 'row_classes', 'oldness', 'duplicate', 'groups', 'managed_groups'
);
+ if (!defined('GALETTE_TESTS')) {
+ $forbidden[] = 'password'; //keep that for tests only
+ }
$virtuals = array(
'sadmin', 'sstaff', 'sdue_free', 'sappears_in_list', 'sactive',
- 'stitle', 'sstatus', 'sfullname', 'sname', 'rowclass', 'saddress'
+ 'stitle', 'sstatus', 'sfullname', 'sname', 'saddress',
+ 'rbirthdate', 'sgender', 'contribstatus',
);
+ $socials = array('website', 'msn', 'jabber', 'icq');
+
if (in_array($name, $forbidden)) {
Analog::log(
- "Call to __get for '$name' is forbidden!",
+ 'Calling property "' . $name . '" directly is discouraged.',
Analog::WARNING
);
switch ($name) {
case 'admin':
return $this->isAdmin();
- break;
case 'staff':
return $this->isStaff();
- break;
case 'due_free':
return $this->isDueFree();
- break;
case 'appears_in_list':
return $this->appearsInMembersList();
- break;
case 'active':
return $this->isActive();
- break;
+ case 'duplicate':
+ return $this->isDuplicate();
+ case 'groups':
+ return $this->getGroups();
+ case 'managed_groups':
+ return $this->getManagedGroups();
default:
throw new \RuntimeException("Call to __get for '$name' is forbidden!");
}
+ }
+
+ if (in_array($name, $virtuals)) {
+ if (substr($name, 0, 1) !== '_') {
+ $real = '_' . substr($name, 1);
+ } else {
+ $real = $name;
+ }
+ switch ($name) {
+ case 'sadmin':
+ return (($this->isAdmin()) ? _T("Yes") : _T("No"));
+ case 'sdue_free':
+ return (($this->isDueFree()) ? _T("Yes") : _T("No"));
+ case 'sappears_in_list':
+ return (($this->appearsInMembersList()) ? _T("Yes") : _T("No"));
+ case 'sstaff':
+ return (($this->$real) ? _T("Yes") : _T("No"));
+ case 'sactive':
+ return (($this->isActive()) ? _T("Active") : _T("Inactive"));
+ case 'stitle':
+ if (isset($this->_title) && $this->_title instanceof Title) {
+ return $this->_title->tshort;
+ } else {
+ return null;
+ }
+ case 'sstatus':
+ $status = new Status($this->zdb);
+ return $status->getLabel($this->_status);
+ case 'sfullname':
+ return $this->getNameWithCase(
+ $this->_name,
+ $this->_surname,
+ (isset($this->_title) ? $this->title : false)
+ );
+ case 'saddress':
+ $address = $this->_address;
+ return $address;
+ case 'sname':
+ return $this->getNameWithCase($this->_name, $this->_surname);
+ case 'rbirthdate':
+ return $this->_birthdate;
+ case 'sgender':
+ switch ($this->gender) {
+ case self::MAN:
+ return _T('Man');
+ case self::WOMAN:
+ return _T('Woman');
+ default:
+ return _T('Unspecified');
+ }
+ case 'contribstatus':
+ return $this->getDues();
+ }
+ }
+
+ //for backward compatibility
+ if (in_array($name, $socials)) {
+ $values = Social::getListForMember($this->_id, $name);
+ return $values[0] ?? null;
+ }
+
+ if (substr($name, 0, 1) !== '_') {
+ $rname = '_' . $name;
} else {
- if (in_array($name, $virtuals)) {
- if (substr($name, 0, 1) !== '_') {
- $real = '_' . substr($name, 1);
+ $rname = $name;
+ }
+
+ switch ($name) {
+ case 'id':
+ case 'id_statut':
+ if ($this->$rname !== null) {
+ return (int)$this->$rname;
} else {
- $real = $name;
+ return null;
}
- switch ($name) {
- case 'sadmin':
- case 'sdue_free':
- case 'sappears_in_list':
- case 'sstaff':
- return (($this->$real) ? _T("Yes") : _T("No"));
- break;
- case 'sactive':
- return (($this->$real) ? _T("Active") : _T("Inactive"));
- break;
- case 'stitle':
- if (isset($this->_title)) {
- return $this->_title->tshort;
- } else {
- return null;
- }
- break;
- case 'sstatus':
- $status = new Status($this->zdb);
- return $status->getLabel($this->_status);
- break;
- case 'sfullname':
- return $this->getNameWithCase(
- $this->_name,
- $this->_surname,
- (isset($this->_title) ? $this->title : false)
+ case 'address':
+ return $this->$rname ?? '';
+ case 'birthdate':
+ case 'creation_date':
+ case 'modification_date':
+ case 'due_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
);
- break;
- case 'saddress':
- $address = $this->_address;
- if ($this->_address_continuation !== '' && $this->_address_continuation !== null) {
- $address .= "\n" . $this->_address_continuation;
- }
- return $address;
- break;
- case 'sname':
- return $this->getNameWithCase($this->_name, $this->_surname);
- break;
+ return $this->$rname;
+ }
}
- } else {
- if (substr($name, 0, 1) !== '_') {
- $rname = '_' . $name;
+ break;
+ case 'parent_id':
+ return ($this->_parent instanceof Adherent) ? (int)$this->_parent->id : (int)$this->_parent;
+ default:
+ if (!property_exists($this, $rname)) {
+ Analog::log(
+ "Unknown property '$rname'",
+ Analog::WARNING
+ );
+ return null;
} else {
- $rname = $name;
+ return $this->$rname;
}
+ }
+ }
- switch ($name) {
- case 'id':
- case 'id_statut':
- return (int)$this->$rname;
- break;
- case 'birthdate':
- case 'creation_date':
- case 'modification_date':
- case 'due_date':
- if ($this->$rname != '') {
- try {
- $d = new \DateTime($this->$rname);
- return $d->format(__("Y-m-d"));
- } catch (\Exception $e) {
- //oops, we've got a bad date :/
- Analog::log(
- 'Bad date (' . $this->$rname . ') | ' .
- $e->getMessage(),
- Analog::INFO
- );
- return $this->$rname;
- }
- }
- break;
- default:
- if (!property_exists($this, $rname)) {
- Analog::log(
- "Unknown property '$rname'",
- Analog::WARNING
- );
- return null;
- } else {
- return $this->$rname;
- }
- break;
- }
+ /**
+ * 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)
+ {
+ $forbidden = array(
+ 'admin', 'staff', 'due_free', 'appears_in_list', 'active',
+ 'row_classes', 'oldness', 'duplicate', 'groups', 'managed_groups'
+ );
+ if (!defined('GALETTE_TESTS')) {
+ $forbidden[] = 'password'; //keep that for tests only
+ }
+
+ $virtuals = array(
+ 'sadmin', 'sstaff', 'sdue_free', 'sappears_in_list', 'sactive',
+ 'stitle', 'sstatus', 'sfullname', 'sname', 'saddress',
+ 'rbirthdate', 'sgender', 'contribstatus',
+ );
+
+ $socials = array('website', 'msn', 'jabber', 'icq');
+
+ if (in_array($name, $forbidden)) {
+ Analog::log(
+ 'Calling property "' . $name . '" directly is discouraged.',
+ Analog::WARNING
+ );
+ switch ($name) {
+ case 'admin':
+ case 'staff':
+ case 'due_free':
+ case 'appears_in_list':
+ case 'active':
+ case 'duplicate':
+ case 'groups':
+ case 'managed_groups':
+ return true;
}
+
+ return false;
+ }
+
+ if (in_array($name, $virtuals)) {
+ return true;
+ }
+
+ //for backward compatibility
+ if (in_array($name, $socials)) {
+ return true;
+ }
+
+ if (substr($name, 0, 1) !== '_') {
+ $rname = '_' . $name;
+ } else {
+ $rname = $name;
+ }
+
+ switch ($name) {
+ case 'id':
+ case 'id_statut':
+ case 'address':
+ case 'birthdate':
+ case 'creation_date':
+ case 'modification_date':
+ case 'due_date':
+ case 'parent_id':
+ return true;
+ default:
+ return property_exists($this, $rname);
}
}
*
* @return string
*/
- public function getEmail()
+ public function getEmail(): string
{
$email = $this->_email;
- if (empty($email)) {
+ if (empty($email) && $this->hasParent()) {
$this->loadParent();
$email = $this->parent->email;
}
- return $email;
+ return $email ?? '';
}
/**
*
* @return string
*/
- public function getAddress()
+ public function getAddress(): string
{
$address = $this->_address;
if (empty($address) && $this->hasParent()) {
$address = $this->parent->address;
}
- return $address;
- }
-
- /**
- * Get member address continuation.
- * If member does not have an address, but is attached to another member, we'll take information from its parent.
- *
- * @return string
- */
- public function getAddressContinuation()
- {
- $address = $this->_address;
- $address_continuation = $this->_address_continuation;
- if (empty($address) && $this->hasParent()) {
- $this->loadParent();
- $address_continuation = $this->parent->address_continuation;
- }
-
- return $address_continuation;
+ return $address ?? '';
}
/**
*
* @return string
*/
- public function getZipcode()
+ public function getZipcode(): string
{
$address = $this->_address;
$zip = $this->_zipcode;
$zip = $this->parent->zipcode;
}
- return $zip;
+ return $zip ?? '';
}
/**
*
* @return string
*/
- public function getTown()
+ public function getTown(): string
{
$address = $this->_address;
$town = $this->_town;
$town = $this->parent->town;
}
- return $town;
+ return $town ?? '';
}
/**
*
* @return string
*/
- public function getCountry()
+ public function getCountry(): string
{
$address = $this->_address;
$country = $this->_country;
$country = $this->parent->country;
}
- return $country;
+ return $country ?? '';
}
/**
*
* @return string
*/
- public function getAge()
+ public function getAge(): string
{
if ($this->_birthdate == null) {
return '';
'Invalid birthdate: ' . $this->_birthdate,
Analog::ERROR
);
- return;
+ return '';
}
return str_replace(
*
* @return array
*/
- public function getParentFields()
+ public function getParentFields(): array
{
return $this->parent_fields;
}
/**
- * Handle files (phot and dynamics files
+ * Handle files (photo and dynamics files)
*
- * @param array $files Files sent
+ * @param array $files Files sent
+ * @param array $cropping Cropping properties
*
* @return array|true
*/
- public function handleFiles($files)
+ public function handleFiles(array $files, array $cropping = null)
{
$this->errors = [];
// picture upload
if (isset($files['photo'])) {
if ($files['photo']['error'] === UPLOAD_ERR_OK) {
- if ($files['photo']['tmp_name'] !='') {
+ if ($files['photo']['tmp_name'] != '') {
if (is_uploaded_file($files['photo']['tmp_name'])) {
- $res = $this->picture->store($files['photo']);
+ if ($this->preferences->pref_force_picture_ratio == 1 && isset($cropping)) {
+ $res = $this->picture->store($files['photo'], false, $cropping);
+ } else {
+ $res = $this->picture->store($files['photo']);
+ }
if ($res < 0) {
$this->errors[]
= $this->picture->getErrorMessage($res);
);
}
}
- $this->dynamicsFiles($_FILES);
+ $this->dynamicsFiles($files);
if (count($this->errors) > 0) {
Analog::log(
- 'Some errors has been throwed attempting to edit/store a member files' . "\n" .
+ 'Some errors has been thew attempting to edit/store a member files' . "\n" .
print_r($this->errors, true),
Analog::ERROR
);
*
* @return void
*/
- public function setDuplicate()
+ public function setDuplicate(): void
{
//mark as duplicated
+ $this->_duplicate = true;
$infos = $this->_others_infos_admin;
$this->_others_infos_admin = str_replace(
['%name', '%id'],
$this->_id = null;
//drop email, must be unique
$this->_email = null;
+ //drop creation date
+ $this->_creation_date = date("Y-m-d");
+ //drop login
+ $this->_login = null;
+ //reset picture
+ $this->_picture = new Picture();
+ //remove birthdate
+ $this->_birthdate = null;
+ //remove surname
+ $this->_surname = null;
+ //not admin
+ $this->_admin = false;
+ //not due free
+ $this->_due_free = false;
}
/**
*
* @return array
*/
- public function getErrors()
+ public function getErrors(): array
{
return $this->errors;
}
+
+ /**
+ * Get user groups
+ *
+ * @return array
+ */
+ public function getGroups(): array
+ {
+ if (!$this->isDepEnabled('groups')) {
+ $this->loadGroups();
+ }
+ return $this->_groups;
+ }
+
+ /**
+ * Get user managed groups
+ *
+ * @return array
+ */
+ public function getManagedGroups(): array
+ {
+ if (!$this->isDepEnabled('groups')) {
+ $this->loadGroups();
+ }
+ return $this->_managed_groups;
+ }
+
+ /**
+ * Can current logged-in user create member
+ *
+ * @param Login $login Login instance
+ *
+ * @return boolean
+ */
+ public function canCreate(Login $login): bool
+ {
+ global $preferences;
+
+ if ($this->id && $login->id == $this->id || $login->isAdmin() || $login->isStaff()) {
+ return true;
+ }
+
+ if ($preferences->pref_bool_groupsmanagers_create_member && $login->isGroupManager()) {
+ return true;
+ }
+
+ if ($preferences->pref_bool_create_member && $login->isLogged()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Can current logged-in user edit member
+ *
+ * @param Login $login Login instance
+ *
+ * @return boolean
+ */
+ public function canEdit(Login $login): bool
+ {
+ global $preferences;
+
+ //admin and staff users can edit, as well as member itself
+ if ($this->id && $login->id == $this->id || $login->isAdmin() || $login->isStaff()) {
+ return true;
+ }
+
+ //parent can edit their child cards
+ if ($this->hasParent() && $this->parent_id === $login->id) {
+ return true;
+ }
+
+ //group managers can edit members of groups they manage when pref is on
+ if ($preferences->pref_bool_groupsmanagers_edit_member && $login->isGroupManager()) {
+ foreach ($this->getGroups() as $g) {
+ if ($login->isGroupManager($g->getId())) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Can current logged-in user display member
+ *
+ * @param Login $login Login instance
+ *
+ * @return boolean
+ */
+ public function canShow(Login $login): bool
+ {
+ //group managers can show members of groups they manage
+ if ($login->isGroupManager()) {
+ foreach ($this->getGroups() as $g) {
+ if ($login->isGroupManager($g->getId())) {
+ return true;
+ }
+ }
+ }
+
+ return $this->canEdit($login);
+ }
+
+ /**
+ * Are we currently duplicated a member?
+ *
+ * @return boolean
+ */
+ public function isDuplicate(): bool
+ {
+ return $this->_duplicate;
+ }
+
+ /**
+ * Flag creation mail sending
+ *
+ * @param boolean $send True (default) to send creation email
+ *
+ * @return Adherent
+ */
+ public function setSendmail(bool $send = true): self
+ {
+ $this->sendmail = $send;
+ return $this;
+ }
+
+ /**
+ * Should we send administrative emails to member?
+ *
+ * @return boolean
+ */
+ public function sendEMail(): bool
+ {
+ return $this->sendmail;
+ }
+
+ /**
+ * Set member parent
+ *
+ * @param integer $id Parent identifier
+ *
+ * @return $this
+ */
+ public function setParent(int $id): self
+ {
+ $this->_parent = $id;
+ $this->loadParent();
+ return $this;
+ }
+
+ /**
+ * Get prefix for events
+ *
+ * @return string
+ */
+ protected function getEventsPrefix(): string
+ {
+ return 'member';
+ }
}