*
* PHP version 5
*
- * Copyright © 2009-2022 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-2022 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 - 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;
* @name Adherent
* @package Galette
* @author Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2009-2022 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 $company_name
* @property string $name
- * @property string $surname
+ * @property ?string $surname
* @property string $nickname
* @property string $birthdate Localized birthdate
* @property string $rbirthdate Raw birthdate
* @property string $sname
* @property string $saddress
* @property string $contribstatus State of member contributions
- * @property string $days_remaining
+ * @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 Dynamics;
use Socials;
+ use HasEvent;
public const TABLE = 'adherents';
public const PK = 'id_adh';
private $_groups = [];
private $_managed_groups = [];
private $_parent;
- private $_children;
+ private $_children = [];
private $_duplicate = false;
private $_socials;
private $_number;
private $_row_classes;
private $_self_adh = false;
- private $_deps = array(
- 'picture' => true,
- 'groups' => true,
- 'dues' => true,
- 'parent' => false,
- 'children' => false,
- 'dynamics' => false,
- 'socials' => false
- );
private $zdb;
private $preferences;
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 should be an array, ' . gettype($deps) . ' given!',
}
}
+ $this
+ ->withAddEvent()
+ ->withEditEvent()
+ ->withoutDeleteEvent()
+ ->activateEvents();
+
if ($args == null || is_int($args)) {
if (is_int($args) && $args > 0) {
$this->load($args);
return false;
}
- $this->loadFromRS($results->current());
+ /** @var ArrayObject $result */
+ $result = $results->current();
+ $this->loadFromRS($result);
return true;
} catch (Throwable $e) {
Analog::log(
}
$results = $this->zdb->execute($select);
- $result = $results->current();
- if ($result) {
+ if ($results->count() > 0) {
+ /** @var ArrayObject $result */
+ $result = $results->current();
$this->loadFromRS($result);
}
return true;
/**
* Populate object from a resultset row
*
- * @param ResultSet $r the resultset row
+ * @param ArrayObject $r the resultset row
*
* @return void
*/
- private function loadFromRS($r): void
+ private function loadFromRS(ArrayObject $r): void
{
$this->_self_adh = false;
$this->_id = $r->id_adh;
*/
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);
}
*/
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;
}
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;
$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(
*/
private function getFieldLabel(string $field): string
{
- $label = $this->fields[$field]['label'];
+ $label = $this->fields[$field]['label'] ?? '';
//replace " "
$label = str_replace(' ', ' ', $label);
//remove trailing ':' and then trim
- $label = trim(trim($label ?? '', ':'));
+ $label = trim(trim($label, ':'));
return $label;
}
if (isset($values[$key])) {
$value = $values[$key];
if ($value !== true && $value !== false) {
+ //@phpstan-ignore-next-line
$value = trim($value ?? '');
}
} elseif (empty($this->_id)) {
$this->_parent = null;
}
- if ($login->isGroupManager() && !$login->isAdmin() && !$login->isStaff()) {
+ 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)) {
- $this->errors[] = _T('You have to select a group you own!');
+ if ($login->isGroupManager($gid)) {
+ $owned_group = true;
}
}
+ if ($owned_group === false) {
+ $this->errors[] = _T('You have to select a group you own!');
+ }
}
}
$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 (!empty($this->_id)) {
- $select->where->notEqualTo(
- 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 (Throwable $e) {
- Analog::log(
- 'An error occurred checking member email uniqueness.',
- 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.");
}
+
+ $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':
}
}
- $success = false;
if (empty($this->_id)) {
//we're inserting a new member
unset($values[self::PK]);
$this->sname
);
}
- $success = true;
- $event = 'member.add';
+ $event = $this->getAddEventName();
} else {
$hist->add(_T("Fail to add new member."));
throw new \Exception(
$this->sname
);
}
- $success = true;
- $event = 'member.edit';
+ $event = $this->getEditEventName();
}
//dynamic fields
- if ($success) {
- $success = $this->dynamicsStore();
- $this->storeSocials($this->id);
- }
+ $this->dynamicsStore();
+ $this->storeSocials($this->id);
//send event at the end of process, once all has been stored
- if ($event !== null) {
- $emitter->emit($event, $this);
+ if ($event !== null && $this->areEventsEnabled()) {
+ $emitter->dispatch(new GaletteEvent($event, $this));
}
- return $success;
+ return true;
} catch (Throwable $e) {
Analog::log(
'Something went wrong :\'( | ' . $e->getMessage() . "\n" .
array('date_modif_adh' => $modif_date)
)->where([self::PK => $this->_id]);
- $edit = $this->zdb->execute($update);
+ $this->zdb->execute($update);
$this->_modification_date = $modif_date;
} catch (Throwable $e) {
Analog::log(
}
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"));
- break;
case 'sactive':
- return (($this->$real) ? _T("Active") : _T("Inactive"));
- break;
+ return (($this->isActive()) ? _T("Active") : _T("Inactive"));
case 'stitle':
if (isset($this->_title) && $this->_title instanceof Title) {
return $this->_title->tshort;
} else {
return null;
}
- break;
case 'sstatus':
$status = new Status($this->zdb);
return $status->getLabel($this->_status);
}
}
+ /**
+ * 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);
+ }
+ }
+
/**
* Get member email
* If member does not have an email address, but is attached to
public function getEmail(): string
{
$email = $this->_email;
- if (empty($email)) {
+ if (empty($email) && $this->hasParent()) {
$this->loadParent();
$email = $this->parent->email;
}
/**
* 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(array $files)
+ public function handleFiles(array $files, array $cropping = null)
{
$this->errors = [];
// picture upload
if ($files['photo']['error'] === UPLOAD_ERR_OK) {
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);
}
/**
- * Reset dependencies to load
- *
- * @return $this
- */
- public function disableAllDeps(): self
- {
- foreach ($this->_deps as &$dep) {
- $dep = false;
- }
- return $this;
- }
-
- /**
- * Enable all dependencies to load
- *
- * @return $this
- */
- public function enableAllDeps(): self
- {
- foreach ($this->_deps as &$dep) {
- $dep = true;
- }
- return $this;
- }
-
- /**
- * Enable a load dependency
- *
- * @param string $name Dependency name
- *
- * @return $this
- */
- public function enableDep(string $name): self
- {
- if (!isset($this->_deps[$name])) {
- Analog::log(
- 'dependency ' . $name . ' does not exists!',
- Analog::WARNING
- );
- } else {
- $this->_deps[$name] = true;
- }
-
- return $this;
- }
-
- /**
- * Enable a load dependency
+ * Get prefix for events
*
- * @param string $name Dependency name
- *
- * @return $this
- */
- public function disableDep(string $name): self
- {
- if (!isset($this->_deps[$name])) {
- Analog::log(
- 'dependency ' . $name . ' does not exists!',
- Analog::WARNING
- );
- } else {
- $this->_deps[$name] = false;
- }
-
- return $this;
- }
-
- /**
- * Is load dependency enabled?
- *
- * @param string $name Dependency name
- *
- * @return boolean
+ * @return string
*/
- protected function isDepEnabled(string $name): bool
+ protected function getEventsPrefix(): string
{
- return $this->_deps[$name];
+ return 'member';
}
}