diff --git a/ajax/memberships/lock.php b/ajax/memberships/lock.php index 5d34bd279a3095ca8974859765496865a5b5c871..8fa7d307c4316b3ef772b6979c01293f4213900d 100644 --- a/ajax/memberships/lock.php +++ b/ajax/memberships/lock.php @@ -16,22 +16,23 @@ function ($id) { try { $Memberships = MembershipsHandler::getInstance(); - /** @var \QUI\Memberships\Membership $Membership */ $Membership = $Memberships->getChild((int)$id); if ($Membership->isLocked()) { $Membership->unlock(); - Watcher::addString( - QUI::getLocale()->get( - 'quiqqer/memberships', - 'watcher.membership.force.edit', - [ - 'id' => $id - ] - ), - 'package_quiqqer_memberships_ajax_memberships_lock' - ); + if (class_exists('QUI\Watcher')) { + Watcher::addString( + QUI::getLocale()->get( + 'quiqqer/memberships', + 'watcher.membership.force.edit', + [ + 'id' => $id + ] + ), + 'package_quiqqer_memberships_ajax_memberships_lock' + ); + } } $Membership->lock(); diff --git a/ajax/memberships/products/getMembershipProducts.php b/ajax/memberships/products/getMembershipProducts.php index bad7953b57ef887f0c83ad1e6ebdba68cbe6ed98..f913064c9c003957c5ab59caf0a03cc413eb64d2 100644 --- a/ajax/memberships/products/getMembershipProducts.php +++ b/ajax/memberships/products/getMembershipProducts.php @@ -17,7 +17,13 @@ function ($membershipId) { $Membership = $Memberships->getChild((int)$membershipId); $productData = []; - /** @var \QUI\ERP\Products\Product\Product $Product */ + if ( + !class_exists('QUI\ERP\Products\Product\Product') + || !class_exists('QUI\ERP\Products\Handler\Fields') + ) { + return $productData; + } + foreach ($Membership->getProducts() as $Product) { $productData[] = [ 'id' => $Product->getId(), diff --git a/ajax/memberships/unlock.php b/ajax/memberships/unlock.php index f9d97931e21f39e7750a64f08d14f5684cff2e95..95531b72248153e34479895231953b1c4e21ddc9 100644 --- a/ajax/memberships/unlock.php +++ b/ajax/memberships/unlock.php @@ -17,28 +17,29 @@ function ($id) { try { $Memberships = MembershipsHandler::getInstance(); - /** @var \QUI\Memberships\Membership $Membership */ $Membership = $Memberships->getChild((int)$id); if ($Membership->isLocked()) { $Membership->unlock(); - Watcher::addString( - QUI::getLocale()->get( - 'quiqqer/memberships', - 'watcher.location.force.edit', - [ - 'id' => $Membership->getId() - ] - ), - 'package_quiqqer_memberships_ajax_memberships_lock' - ); + if (class_exists('QUI\Watcher')) { + Watcher::addString( + QUI::getLocale()->get( + 'quiqqer/memberships', + 'watcher.location.force.edit', + [ + 'id' => $Membership->getId() + ] + ), + 'package_quiqqer_memberships_ajax_memberships_lock' + ); + } } else { $Membership->unlock(); } - } catch (\QUI\Permissions\Exception $Exception) { + } catch (\QUI\Permissions\Exception) { return true; - } catch (\Exception $Exception) { + } catch (Exception $Exception) { QUI\System\Log::addError( 'AJAX :: package_quiqqer_memberships_ajax_memberships_lock -> ' . $Exception->getMessage() ); diff --git a/ajax/memberships/users/getList.php b/ajax/memberships/users/getList.php index 61b696a18b35dabd7983399658f3abf4b1334bf1..2609dc3e5071aeef32ade6067f91f27f4612cc5c 100644 --- a/ajax/memberships/users/getList.php +++ b/ajax/memberships/users/getList.php @@ -10,7 +10,6 @@ use QUI\Memberships\Handler as MembershipsHandler; use QUI\Memberships\Users\Handler as MembershipUsersHandler; -use QUI\Memberships\Users\MembershipUser; use QUI\Utils\Grid; use QUI\Utils\Security\Orthos; @@ -24,7 +23,6 @@ function ($membershipId, $searchParams) { $membershipUsers = []; foreach ($Membership->searchUsers($searchParams) as $membershipUserId) { - /** @var MembershipUser $MembershipUser */ $MembershipUser = $MembershipUsers->getChild($membershipUserId); $membershipUsers[] = $MembershipUser->getBackendViewData(); } diff --git a/composer.json b/composer.json index 87ead11936b4f710da8913f5fb2d758eb18dcd07..a0a5713d4a50810e3b104da44cb9c0c312f3a183 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "quiqqer\/memberships", + "name": "quiqqer/memberships", "type": "quiqqer-module", "description": "Create and manage memberships for your users. With memberships you can grant your users permissions for set periods of time in your system. In conjunction with the QUIQQER ERP system, this module also enables automated linking of memberships with products, so that you can offer memberships for sale.", "license": [ @@ -10,21 +10,22 @@ { "name": "Patrick M\u00fcller", "email": "info@pcsg.de", - "homepage": "https:\/\/www.pcsg.de", + "homepage": "https://www.pcsg.de", "role": "Developer" } ], "support": { "email": "support@pcsg.de", - "url": "http:\/\/www.pcsg.de" + "url": "https://www.pcsg.de" }, "require": { - "quiqqer\/core": "^2", - "quiqqer\/verification": "^3" + "quiqqer/core": "^2", + "quiqqer/erp": "^3", + "quiqqer/verification": "^3" }, "autoload": { "psr-4": { - "QUI\\Memberships\\": "src\/QUI\/Memberships" + "QUI\\Memberships\\": "src/QUI/Memberships" } } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 7275517f87ad09dcdc7cd4f6f79e2ed27d04cc5b..6f3a93ed7c883b4529a7b0838484fb4c741ead7f 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,391 +1,5 @@ parameters: - ignoreErrors: - - - message: "#^Parameter \\#2 \\$User of static method QUI\\\\Permissions\\\\Permission\\:\\:hasPermission\\(\\) expects bool\\|QUI\\\\Users\\\\User, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#" - count: 1 - path: ajax/memberships/canUnlock.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getUniqueGroupIds\\(\\)\\.$#" - count: 1 - path: ajax/memberships/get.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getBackendViewData\\(\\)\\.$#" - count: 1 - path: ajax/memberships/getView.php - - - - message: "#^Call to static method addString\\(\\) on an unknown class QUI\\\\Watcher\\.$#" - count: 1 - path: ajax/memberships/lock.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:createProduct\\(\\)\\.$#" - count: 1 - path: ajax/memberships/products/createMembershipProducts.php - - - - message: "#^Access to constant FIELD_PRODUCT_NO on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#" - count: 1 - path: ajax/memberships/products/getMembershipProducts.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getProducts\\(\\)\\.$#" - count: 1 - path: ajax/memberships/products/getMembershipProducts.php - - - - message: "#^Call to method getFieldValue\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: ajax/memberships/products/getMembershipProducts.php - - - - message: "#^Call to method getId\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: ajax/memberships/products/getMembershipProducts.php - - - - message: "#^Call to method getTitle\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: ajax/memberships/products/getMembershipProducts.php - - - - message: "#^PHPDoc tag @var for variable \\$Product contains unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: ajax/memberships/products/getMembershipProducts.php - - - - message: "#^Call to static method addString\\(\\) on an unknown class QUI\\\\Watcher\\.$#" - count: 1 - path: ajax/memberships/unlock.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getTitle\\(\\)\\.$#" - count: 1 - path: ajax/memberships/users/create.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:searchUsers\\(\\)\\.$#" - count: 2 - path: ajax/memberships/users/getArchiveList.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:searchUsers\\(\\)\\.$#" - count: 2 - path: ajax/memberships/users/getList.php - - - - message: "#^Parameter \\#2 \\$value of method QUI\\\\Users\\\\User\\:\\:setAttribute\\(\\) expects array\\|int\\|string, true given\\.$#" - count: 1 - path: src/QUI/Memberships/Cron.php - - - - message: "#^Call to static method getCategory\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Categories\\.$#" - count: 1 - path: src/QUI/Memberships/Handler.php - - - - message: "#^Call to static method getField\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#" - count: 2 - path: src/QUI/Memberships/Handler.php - - - - message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:getDefaultMembership\\(\\) should return QUI\\\\Memberships\\\\Membership\\|false but returns QUI\\\\CRUD\\\\Child\\.$#" - count: 1 - path: src/QUI/Memberships/Handler.php - - - - message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:getProductCategory\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Interfaces\\\\CategoryInterface\\.$#" - count: 1 - path: src/QUI/Memberships/Handler.php - - - - message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:getProductMembershipField\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#" - count: 1 - path: src/QUI/Memberships/Handler.php - - - - message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:getProductMembershipFlagField\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#" - count: 1 - path: src/QUI/Memberships/Handler.php - - - - message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:search\\(\\) should return array but returns int\\.$#" - count: 1 - path: src/QUI/Memberships/Handler.php - - - - message: "#^Variable \\$whereOr in empty\\(\\) always exists and is not falsy\\.$#" - count: 1 - path: src/QUI/Memberships/Handler.php - - - - message: "#^Access to constant FIELD_AUTO_EXTEND on an unknown class QUI\\\\ERP\\\\Plans\\\\Handler\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Access to constant FIELD_DURATION on an unknown class QUI\\\\ERP\\\\Plans\\\\Handler\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Access to constant FIELD_INVOICE_INTERVAL on an unknown class QUI\\\\ERP\\\\Plans\\\\Handler\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Access to constant FIELD_MIN_DURATION on an unknown class QUI\\\\ERP\\\\Plans\\\\Handler\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Access to constant FIELD_SHORT_DESC on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Access to constant FIELD_TITLE on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getGroupIds\\(\\)\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to method deactivate\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to method getField\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to method getId\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to method save\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to method search\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Search\\\\BackendSearch\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to method setOwnFieldStatus\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#" - count: 2 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to method setValue\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#" - count: 2 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to static method createProduct\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Products\\.$#" - count: 2 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to static method getField\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#" - count: 2 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to static method getProduct\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Products\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Cannot call method getId\\(\\) on QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\|false\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Class QUI\\\\ERP\\\\Plans\\\\PlanProduct not found\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Instantiated class QUI\\\\ERP\\\\Products\\\\Search\\\\BackendSearch not found\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:addUser\\(\\) should return QUI\\\\Memberships\\\\Users\\\\MembershipUser but returns QUI\\\\CRUD\\\\Child\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:createProduct\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:getGroupIds\\(\\) should return array\\<int\\> but returns array\\<int, string\\>\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:getMembershipUser\\(\\) should return QUI\\\\Memberships\\\\Users\\\\MembershipUser but returns QUI\\\\CRUD\\\\Child\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:getProducts\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^PHPDoc tag @var for variable \\$Product contains unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Parameter \\#2 \\$PermissionUser of method QUI\\\\Memberships\\\\Users\\\\Handler\\:\\:createChild\\(\\) expects QUI\\\\Users\\\\User\\|null, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Parameter \\#2 \\$User of static method QUI\\\\Permissions\\\\Permission\\:\\:checkPermission\\(\\) expects bool\\|QUI\\\\Users\\\\User\\|null, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#" - count: 2 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Ternary operator condition is always true\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Variable \\$where in empty\\(\\) always exists and is not falsy\\.$#" - count: 1 - path: src/QUI/Memberships/Membership.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:calcEndDate\\(\\)\\.$#" - count: 1 - path: src/QUI/Memberships/Users/Handler.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getMembershipUser\\(\\)\\.$#" - count: 1 - path: src/QUI/Memberships/Users/Handler.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:hasMembershipUserId\\(\\)\\.$#" - count: 1 - path: src/QUI/Memberships/Users/Handler.php - - - - message: "#^Method QUI\\\\Memberships\\\\Users\\\\Handler\\:\\:getMembershipUsersByUserId\\(\\) should return array\\<QUI\\\\Memberships\\\\Users\\\\MembershipUser\\> but returns array\\<int\\<0, max\\>, QUI\\\\CRUD\\\\Child\\>\\.$#" - count: 1 - path: src/QUI/Memberships/Users/Handler.php - - - - message: "#^Parameter \\#2 \\$User of static method QUI\\\\Permissions\\\\Permission\\:\\:checkPermission\\(\\) expects bool\\|QUI\\\\Users\\\\User\\|null, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#" - count: 1 - path: src/QUI/Memberships/Users/Handler.php - - - - message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:hasMembershipUserId\\(\\)\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Call to function is_array\\(\\) with string will always evaluate to false\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Call to method getCurrentCancelTerminationDate\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Call to method getCycleEndDate\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#" - count: 2 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Call to method getNextCycleEndDate\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Call to method getPeriodOfNoticeInterval\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#" - count: 2 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Call to method isInPeriodOfNotice\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#" - count: 2 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Handler\\.$#" - count: 3 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Call to static method getProduct\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Products\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^If condition is always true\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Method QUI\\\\Memberships\\\\Users\\\\MembershipUser\\:\\:getContract\\(\\) has invalid return type QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^PHPDoc tag @param references unknown parameter\\: \\$withPermission$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Parameter \\#2 \\$User of static method QUI\\\\Permissions\\\\Permission\\:\\:checkPermission\\(\\) expects bool\\|QUI\\\\Users\\\\User\\|null, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#" - count: 2 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Parameter \\#2 \\$msg of method QUI\\\\Memberships\\\\Users\\\\MembershipUser\\:\\:addHistoryEntry\\(\\) expects string, array\\<string, string\\> given\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Parameter \\#2 \\$val of method QUI\\\\QDOM\\:\\:setAttribute\\(\\) expects array\\|bool\\|object\\|string, int given\\.$#" - count: 2 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Parameter \\#2 \\$val of method QUI\\\\QDOM\\:\\:setAttribute\\(\\) expects array\\|bool\\|object\\|string, null given\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Unreachable statement \\- code above always terminates\\.$#" - count: 1 - path: src/QUI/Memberships/Users/MembershipUser.php - - - - message: "#^Call to function is_string\\(\\) with int will always evaluate to false\\.$#" - count: 1 - path: src/QUI/Memberships/Utils.php - - - - message: "#^Result of && is always false\\.$#" - count: 1 - path: src/QUI/Memberships/Utils.php + ignoreErrors: + - + message: "#^Method QUI\\\\Memberships\\\\Users\\\\MembershipUser::getContract\\(\\) has invalid return type QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#" + path: src/QUI/Memberships/Users/MembershipUser.php \ No newline at end of file diff --git a/src/QUI/Memberships/Controls/Profile/Memberships.php b/src/QUI/Memberships/Controls/Profile/Memberships.php index 8bab61d0a9d62b7320b31e738e9a21b65c2ee1a5..332c345bb8e56a7cc622076d67912c7473a53941 100644 --- a/src/QUI/Memberships/Controls/Profile/Memberships.php +++ b/src/QUI/Memberships/Controls/Profile/Memberships.php @@ -23,7 +23,6 @@ public function __construct(array $attributes = []) * Can be overwritten * * @return string - * @throws \QUI\Exception */ public function getBody(): string { @@ -34,7 +33,7 @@ public function getBody(): string /** * Method is called, when on save is triggered * - * @return mixed|void + * @return void */ public function onSave(): void { @@ -43,8 +42,7 @@ public function onSave(): void /** * Validate the send data * - * @return mixed|void - * @throws \Exception + * @return void */ public function validate(): void { diff --git a/src/QUI/Memberships/Cron.php b/src/QUI/Memberships/Cron.php index dcb5c9a0a0ec8419e797e7e77256a92e1f1e7e4e..70763fe96ce28b8092eabdacc1abe150fabbf30d 100644 --- a/src/QUI/Memberships/Cron.php +++ b/src/QUI/Memberships/Cron.php @@ -2,10 +2,13 @@ namespace QUI\Memberships; +use DateInterval; use QUI; use QUI\Memberships\Users\Handler as MembershipUsersHandler; use QUI\Memberships\Users\MembershipUser; +use function date_create; + /** * Class Cron * @@ -13,7 +16,7 @@ */ class Cron { - public static function checkMembershipUsers() + public static function checkMembershipUsers(): void { $MembershipUsers = MembershipUsersHandler::getInstance(); @@ -57,10 +60,10 @@ public static function checkMembershipUsers() 'cancelStatus' ) === MembershipUsersHandler::CANCEL_STATUS_CANCEL_CONFIRM_PENDING ) { - $CancelDate = \date_create($MembershipUser->getAttribute('cancelDate')); + $CancelDate = date_create($MembershipUser->getAttribute('cancelDate')); if ($CancelDate) { - $RemindDate = $CancelDate->add(new \DateInterval('P' . $cancelConfirmReminderAfterDays . 'D')); + $RemindDate = $CancelDate->add(new DateInterval('P' . $cancelConfirmReminderAfterDays . 'D')); $User = $MembershipUser->getUser(); if ( diff --git a/src/QUI/Memberships/Events.php b/src/QUI/Memberships/Events.php index 4d91eec1165dc5c91cb5714f6c098aa612c07039..a861a0b0d7b36f68a8c6029384f7d3ebdb12a59a 100644 --- a/src/QUI/Memberships/Events.php +++ b/src/QUI/Memberships/Events.php @@ -2,18 +2,25 @@ namespace QUI\Memberships; +use DateTime; use QUI; +use QUI\Database\Exception; use QUI\ERP\Accounting\Contracts\Contract; +use QUI\ERP\Order\AbstractOrder; use QUI\ERP\Products\Field\Field as ProductField; use QUI\ERP\Products\Handler\Categories as ProductCategories; use QUI\ERP\Products\Handler\Fields as ProductFields; use QUI\ERP\Products\Handler\Products as ProductsHandler; use QUI\ERP\Products\Handler\Search as ProductSearchHandler; use QUI\ERP\Products\Product\Product; +use QUI\ExceptionStack; use QUI\Memberships\Handler as MembershipsHandler; use QUI\Memberships\Products\MembershipField; use QUI\Memberships\Users\Handler as MembershipUsersHandler; use QUI\Package\Package; +use QUI\Users\User; + +use function date_interval_create_from_date_string; /** * Class Events @@ -28,7 +35,7 @@ class Events * @param Package $Package * @return void */ - public static function onPackageSetup(Package $Package) + public static function onPackageSetup(Package $Package): void { if ($Package->getName() !== 'quiqqer/memberships') { return; @@ -59,8 +66,9 @@ public static function onPackageSetup(Package $Package) * * @param Product $Product * @return void + * @throws Exception */ - public static function onQuiqqerProductsProductDelete(Product $Product) + public static function onQuiqqerProductsProductDelete(Product $Product): void { $membershipFieldId = Handler::getProductMembershipField()->getId(); @@ -102,8 +110,9 @@ public static function onQuiqqerProductsProductDelete(Product $Product) * * @param QUI\Users\User $User * @return void + * @throws QUI\Exception */ - public static function onUserSave(QUI\Users\User $User) + public static function onUserSave(QUI\Users\User $User): void { $DefaultMembership = MembershipsHandler::getDefaultMembership(); @@ -127,8 +136,11 @@ public static function onUserSave(QUI\Users\User $User) * * Delete user from alle memberships * - * @param QUI\Users\User $User + * @param User $User * @return void + * @throws QUI\Exception + * @throws ExceptionStack + * @throws QUI\Permissions\Exception */ public static function onUserDelete(QUI\Users\User $User): void { @@ -145,9 +157,9 @@ public static function onUserDelete(QUI\Users\User $User): void * Create necessary membership product fields and save their IDs to the config * * @return void - * @throws \QUI\Exception + * @throws QUI\Exception */ - protected static function createProductFields() + protected static function createProductFields(): void { $L = new QUI\Locale(); $Conf = QUI::getPackage('quiqqer/memberships')->getConfig(); @@ -242,10 +254,10 @@ protected static function createProductFields() * * Add user to a membership if he ordered a product that contains one * - * @param QUI\ERP\Order\Order|QUI\ERP\Order\OrderInProcess $Order + * @param AbstractOrder $Order * @return void */ - public static function onQuiqqerOrderSuccessful($Order) + public static function onQuiqqerOrderSuccessful(AbstractOrder $Order): void { $MembershipField = Handler::getProductMembershipField(); @@ -286,7 +298,6 @@ public static function onQuiqqerOrderSuccessful($Order) $SystemUser = QUI::getUsers()->getSystemUser(); - /** @var QUI\ERP\Accounting\Article $Article */ foreach ($Order->getArticles()->getArticles() as $Article) { try { $Product = ProductsHandler::getProduct($Article->getId()); @@ -309,7 +320,7 @@ public static function onQuiqqerOrderSuccessful($Order) ); $MembershipUser->update(); - } catch (\QUI\ERP\Products\Product\Exception $Exception) { + } catch (QUI\ERP\Products\Product\Exception $Exception) { // nothing, this can happen if the $Product does not have a membership field assigned QUI\System\Log::writeDebugException($Exception); } catch (\Exception $Exception) { @@ -324,10 +335,10 @@ public static function onQuiqqerOrderSuccessful($Order) * Automatically extend all MembershipUsers associated with the contract that is extended * * @param Contract $Contract - * @param \DateTime $EndDate - * @param \DateTime $NewEndDate + * @param DateTime $EndDate + * @param DateTime $NewEndDate */ - public static function onQuiqqerContractsExtend(Contract $Contract, \DateTime $EndDate, \DateTime $NewEndDate) + public static function onQuiqqerContractsExtend(Contract $Contract, DateTime $EndDate, DateTime $NewEndDate): void { try { $Conf = QUI::getPackage('quiqqer/memberships')->getConfig(); @@ -362,7 +373,7 @@ public static function onQuiqqerContractsExtend(Contract $Contract, \DateTime $E // Calculate new cylce begin date $NextBeginDate = clone $EndDate; - $NextBeginDate->add(\date_interval_create_from_date_string('1 day')); + $NextBeginDate->add(date_interval_create_from_date_string('1 day')); $NextBeginDate->setTime(0, 0, 0); $MembershipUser->extend(true, $NextBeginDate, $NewEndDate); @@ -378,10 +389,10 @@ public static function onQuiqqerContractsExtend(Contract $Contract, \DateTime $E * If a contract is created from an order, check if the Order also contains a Membership product * * @param Contract $Contract - * @param QUI\ERP\Order\OrderInProcess $Order + * @param AbstractOrder $Order * @return void */ - public static function onQuiqqerContractsCreateFromOrder(Contract $Contract, $Order) + public static function onQuiqqerContractsCreateFromOrder(Contract $Contract, AbstractOrder $Order): void { try { $Conf = QUI::getPackage('quiqqer/memberships')->getConfig(); @@ -423,7 +434,7 @@ public static function onQuiqqerContractsCreateFromOrder(Contract $Contract, $Or $MembershipUser->linkToContract($Contract->getCleanId()); break; - } catch (\QUI\ERP\Products\Product\Exception $Exception) { + } catch (QUI\ERP\Products\Product\Exception $Exception) { QUI\System\Log::writeDebugException($Exception); // nothing, this can happen if the $Product does not have a membership field assigned } catch (\Exception $Exception) { @@ -478,7 +489,7 @@ public static function onQuiqqerContractsCreateFromOrder(Contract $Contract, $Or * @param Contract $Contract * @throws QUI\Database\Exception */ - public static function onQuiqqerContractsDelete(Contract $Contract) + public static function onQuiqqerContractsDelete(Contract $Contract): void { $MembershipUsers = MembershipUsersHandler::getInstance(); @@ -509,9 +520,8 @@ public static function onQuiqqerContractsDelete(Contract $Contract) * Cancel MembershipUser of associated contract * * @param Contract $Contract - * @throws QUI\Database\Exception */ - public static function onQuiqqerContractsCancel(Contract $Contract) + public static function onQuiqqerContractsCancel(Contract $Contract): void { try { $Conf = QUI::getPackage('quiqqer/memberships')->getConfig(); @@ -543,7 +553,7 @@ public static function onQuiqqerContractsCancel(Contract $Contract) * @param ProductField $Field * @throws Exception */ - public static function onQuiqqerProductsFieldDeleteBefore(ProductField $Field) + public static function onQuiqqerProductsFieldDeleteBefore(ProductField $Field): void { $MembershipField = Handler::getProductMembershipField(); @@ -572,10 +582,9 @@ public static function onQuiqqerProductsFieldDeleteBefore(ProductField $Field) * @param int $membershipUserId * @return void */ - public static function onQuiqqerVerificationDeleteUnverified($membershipUserId) + public static function onQuiqqerVerificationDeleteUnverified(int $membershipUserId): void { try { - /** @var QUI\Memberships\Users\MembershipUser $MembershipUser */ $MembershipUser = MembershipUsersHandler::getInstance()->getChild($membershipUserId); } catch (\Exception $Exception) { QUI\System\Log::writeDebugException($Exception); @@ -602,8 +611,10 @@ public static function onQuiqqerVerificationDeleteUnverified($membershipUserId) * Create a product category for memberships * * @return void + * @throws Exception + * @throws QUI\Exception */ - protected static function createProductCategory() + protected static function createProductCategory(): void { $Category = MembershipsHandler::getProductCategory(); diff --git a/src/QUI/Memberships/Handler.php b/src/QUI/Memberships/Handler.php index 2923efbc4581a4800a792bde1248cc45176ce207..ae4f1347e265230f4c67f4de72017e046c1b4878 100644 --- a/src/QUI/Memberships/Handler.php +++ b/src/QUI/Memberships/Handler.php @@ -2,10 +2,12 @@ namespace QUI\Memberships; +use PDO; use QUI; use QUI\CRUD\Factory; use QUI\ERP\Products\Handler\Categories as ProductCategories; use QUI\ERP\Products\Handler\Fields as ProductFields; +use QUI\Exception; use QUI\Memberships\Users\Handler as MembershipUsersHandler; use QUI\Permissions\Permission; use QUI\Utils\Grid; @@ -21,6 +23,15 @@ class Handler extends Factory const PERMISSION_DELETE = 'quiqqer.memberships.delete'; const PERMISSION_FORCE_EDIT = 'quiqqer.memberships.force_edit'; + public function getChild(int | string $id): Membership + { + /* @var $Membership Membership */ + $Membership = parent::getChild($id); + + // @phpstan-ignore-next-line + return $Membership; + } + /** * @inheritdoc * @throws QUI\Memberships\Exception @@ -84,7 +95,6 @@ public function createChild($data = []): QUI\CRUD\Child } /** - * @inheritdoc * @return string */ public function getDataBaseTableName(): string @@ -93,7 +103,6 @@ public function getDataBaseTableName(): string } /** - * @inheritdoc * @return string */ public function getChildClass(): string @@ -102,7 +111,6 @@ public function getChildClass(): string } /** - * @inheritdoc * @return array */ public function getChildAttributes(): array @@ -131,9 +139,10 @@ public function getChildAttributes(): array * * @param array $searchParams * @param bool $countOnly (optional) - get count for search result only [default: false] - * @return array - membership IDs + * @return array|int - membership IDs + * @throws Exception */ - public function search($searchParams, $countOnly = false) + public function search(array $searchParams, bool $countOnly = false): array | int { $memberships = []; $Grid = new Grid($searchParams); @@ -157,7 +166,6 @@ public function search($searchParams, $countOnly = false) $membershipIds = []; - /** @var QUI\Memberships\Users\MembershipUser $MembershipUser */ foreach ($memberhsipUsers as $MembershipUser) { $membershipIds[] = $MembershipUser->getMembership()->getId(); } @@ -180,14 +188,11 @@ public function search($searchParams, $countOnly = false) $whereOr[] = '`' . $searchColumn . '` LIKE :search'; } - if (!empty($whereOr)) { - $where[] = '(' . implode(' OR ', $whereOr) . ')'; - - $binds['search'] = [ - 'value' => '%' . $searchParams['search'] . '%', - 'type' => \PDO::PARAM_STR - ]; - } + $where[] = '(' . implode(' OR ', $whereOr) . ')'; + $binds['search'] = [ + 'value' => '%' . $searchParams['search'] . '%', + 'type' => PDO::PARAM_STR + ]; } // build WHERE query string @@ -214,7 +219,7 @@ public function search($searchParams, $countOnly = false) $sql .= " LIMIT " . $gridParams['limit']; } else { if (!$countOnly) { - $sql .= " LIMIT " . (int)20; + $sql .= " LIMIT " . 20; } } @@ -227,7 +232,7 @@ public function search($searchParams, $countOnly = false) try { $Stmt->execute(); - $result = $Stmt->fetchAll(\PDO::FETCH_ASSOC); + $result = $Stmt->fetchAll(PDO::FETCH_ASSOC); } catch (\Exception $Exception) { QUI\System\Log::addError( self::class . ' :: searchUsers() -> ' . $Exception->getMessage() @@ -253,7 +258,7 @@ public function search($searchParams, $countOnly = false) * @param array $groupIds * @return int[] */ - public function getMembershipIdsByGroupIds($groupIds) + public function getMembershipIdsByGroupIds(array $groupIds): array { $ids = []; @@ -272,7 +277,7 @@ public function getMembershipIdsByGroupIds($groupIds) $whereOr[] = '`groupIds` LIKE :' . $bindParam; $binds[$bindParam] = [ 'value' => '%,' . $groupId . ',%', - 'type' => \PDO::PARAM_STR + 'type' => PDO::PARAM_STR ]; } @@ -288,7 +293,7 @@ public function getMembershipIdsByGroupIds($groupIds) try { $Stmt->execute(); - $result = $Stmt->fetchAll(\PDO::FETCH_ASSOC); + $result = $Stmt->fetchAll(PDO::FETCH_ASSOC); } catch (\Exception $Exception) { QUI\System\Log::writeException($Exception); return []; @@ -307,7 +312,7 @@ public function getMembershipIdsByGroupIds($groupIds) * @param string $key * @return mixed */ - public static function getSetting($key) + public static function getSetting(string $key): mixed { $Config = QUI::getPackage('quiqqer/memberships')->getConfig(); return $Config->get('memberships', $key); @@ -319,8 +324,9 @@ public static function getSetting($key) * Get Memberships product category * * @return QUI\ERP\Products\Interfaces\CategoryInterface|false + * @throws Exception */ - public static function getProductCategory() + public static function getProductCategory(): bool | QUI\ERP\Products\Interfaces\CategoryInterface { $Conf = QUI::getPackage('quiqqer/memberships')->getConfig(); $categoryId = $Conf->get('products', 'categoryId'); @@ -329,6 +335,10 @@ public static function getProductCategory() return false; } + if (!class_exists('QUI\ERP\Products\Handler\Categories')) { + return false; + } + try { return ProductCategories::getCategory((int)$categoryId); } catch (\Exception $Exception) { @@ -348,12 +358,16 @@ public static function getProductCategory() * * @return QUI\ERP\Products\Field\Field|false */ - public static function getProductMembershipField() + public static function getProductMembershipField(): bool | QUI\ERP\Products\Field\Field { if (!Utils::isQuiqqerProductsInstalled()) { return false; } + if (!class_exists('QUI\ERP\Products\Handler\Fields')) { + return false; + } + try { $Conf = QUI::getPackage('quiqqer/memberships')->getConfig(); $fieldId = $Conf->get('products', 'membershipFieldId'); @@ -376,12 +390,16 @@ public static function getProductMembershipField() * * @return QUI\ERP\Products\Field\Field|false */ - public static function getProductMembershipFlagField() + public static function getProductMembershipFlagField(): bool | QUI\ERP\Products\Field\Field { if (!Utils::isQuiqqerProductsInstalled()) { return false; } + if (!class_exists('QUI\ERP\Products\Handler\Fields')) { + return false; + } + try { $Conf = QUI::getPackage('quiqqer/memberships')->getConfig(); $fieldId = $Conf->get('products', 'membershipFlagFieldId'); @@ -401,8 +419,9 @@ public static function getProductMembershipFlagField() * Get the default membership * * @return Membership|false - Membership or false if none set + * @throws Exception */ - public static function getDefaultMembership() + public static function getDefaultMembership(): Membership | bool { $membershipId = self::getSetting('defaultMembershipId'); @@ -418,7 +437,7 @@ public static function getDefaultMembership() * * @return bool */ - public static function isLinkedToContracts() + public static function isLinkedToContracts(): bool { try { $Conf = QUI::getPackage('quiqqer/memberships')->getConfig(); diff --git a/src/QUI/Memberships/Membership.php b/src/QUI/Memberships/Membership.php index 93f0178a6897641c997b14c43d70d35f9f6a49ea..13d09d9dcee2879e9c59dc18df5771a953902b8a 100644 --- a/src/QUI/Memberships/Membership.php +++ b/src/QUI/Memberships/Membership.php @@ -2,16 +2,20 @@ namespace QUI\Memberships; +use PDO; use QUI; use QUI\CRUD\Child; use QUI\ERP\Plans\Handler as ErpPlansHandler; use QUI\ERP\Products\Handler\Fields as ProductFields; use QUI\ERP\Products\Handler\Products as ProductsHandler; use QUI\ERP\Products\Search\BackendSearch; +use QUI\ExceptionStack; use QUI\Interfaces\Users\User as QUIUserInterface; use QUI\Locale; use QUI\Lock\Locker; use QUI\Memberships\Users\Handler as MembershipUsersHandler; +use QUI\Memberships\Users\MembershipUser; +use QUI\Permissions\Exception; use QUI\Permissions\Permission; use QUI\Utils\Security\Orthos; @@ -20,16 +24,16 @@ class Membership extends Child /** * User that is editing this Membership in this runtime * - * @var QUIUserInterface + * @var ?QUIUserInterface */ - protected $EditUser = null; + protected ?QUIUserInterface $EditUser = null; /** * Set User that is editing this Membership in this runtime * * @param QUIUserInterface $EditUser */ - public function setEditUser(QUIUserInterface $EditUser) + public function setEditUser(QUIUserInterface $EditUser): void { $this->EditUser = $EditUser; } @@ -37,21 +41,24 @@ public function setEditUser(QUIUserInterface $EditUser) /** * Get IDs of all QUIQQER Groups * - * @return int[] + * @return int[]|string[] */ - public function getGroupIds() + public function getGroupIds(): array { $groupIds = $this->getAttribute('groupIds'); - return explode(",", trim($groupIds, ",")); + $groupIds = trim($groupIds, ","); + $groupIds = explode(",", $groupIds); + + return $groupIds; } /** * Get membership title * - * @param Locale $Locale (optional) + * @param Locale|null $Locale (optional) * @return string - localized title */ - public function getTitle($Locale = null) + public function getTitle(null | Locale $Locale = null): string { if (is_null($Locale)) { $Locale = QUI::getLocale(); @@ -69,10 +76,10 @@ public function getTitle($Locale = null) /** * Get membership description * - * @param Locale $Locale (optional) + * @param Locale|null $Locale (optional) * @return string - localized description */ - public function getDescription($Locale = null) + public function getDescription(null | Locale $Locale = null): string { if (is_null($Locale)) { $Locale = QUI::getLocale(); @@ -90,10 +97,10 @@ public function getDescription($Locale = null) /** * Get membership content * - * @param Locale $Locale (optional) + * @param Locale|null $Locale (optional) * @return string - localized content */ - public function getContent($Locale = null) + public function getContent(null | Locale $Locale = null): string { if (is_null($Locale)) { $Locale = QUI::getLocale(); @@ -115,12 +122,14 @@ public function getContent($Locale = null) */ public function isAutoExtend(): bool { - return $this->getAttribute('autoExtend') ? true : false; + return (bool)$this->getAttribute('autoExtend'); } /** - * @inheritdoc - * @throws QUI\Memberships\Exception + * @throws Exception + * @throws QUI\Exception + * @throws ExceptionStack + * @throws Exception */ public function update(): void { @@ -163,7 +172,7 @@ public function update(): void if (empty($attributes['autoExtend'])) { $attributes['autoExtend'] = 0; } else { - $attributes['autoExtend'] = $attributes['autoExtend'] ? 1 : 0; + $attributes['autoExtend'] = 1; } $this->setAttributes($attributes); @@ -177,9 +186,9 @@ public function update(): void * Only possible if membership has no users in it! * * @return void - * @throws \QUI\Memberships\Exception - * @throws \QUI\Permissions\Exception - * @throws \QUI\Exception + * @throws QUI\Memberships\Exception + * @throws QUI\Permissions\Exception + * @throws QUI\Exception */ public function delete(): void { @@ -201,8 +210,7 @@ public function delete(): void } // remove from products - if (Utils::isQuiqqerProductsInstalled()) { - /** @var QUI\ERP\Products\Product\Product $Product */ + if (Utils::isQuiqqerProductsInstalled() && class_exists('QUI\ERP\Products\Handler\Products')) { foreach ($this->getProducts() as $Product) { $MembershipField = $Product->getField( Handler::getProductMembershipField()->getId() @@ -226,11 +234,14 @@ public function delete(): void /** * Get a user of this membership (non-archived) * - * @param int $userId - QUIQQER User ID - * @return QUI\Memberships\Users\MembershipUser - * @throws QUI\Memberships\Exception + * @param int|string $userId - QUIQQER User ID + * @return MembershipUser + * + * @throws Exception + * @throws QUI\Database\Exception + * @throws QUI\Exception */ - public function getMembershipUser($userId) + public function getMembershipUser(int | string $userId): Users\MembershipUser { $result = QUI::getDataBase()->fetch([ 'select' => [ @@ -263,7 +274,7 @@ public function getMembershipUser($userId) * @param bool $includeArchived (optional) - Include archived MembershipUsers * @return int[] */ - public function getMembershipUserIds($includeArchived = false) + public function getMembershipUserIds(bool $includeArchived = false): array { $membershipUserIds = []; @@ -298,8 +309,9 @@ public function getMembershipUserIds($includeArchived = false) * Get IDs of all QUIQQER Groups that are UNIQUE to this membership * * @return int[] + * @throws QUI\Exception */ - public function getUniqueGroupIds() + public function getUniqueGroupIds(): array { $Memberships = Handler::getInstance(); $groupIds = $this->getGroupIds(); @@ -312,6 +324,10 @@ public function getUniqueGroupIds() $Membership = $Memberships->getChild($membershipId); + if (!method_exists($Membership, 'getGroupIds')) { + continue; + } + foreach ($Membership->getGroupIds() as $groupId) { if (in_array($groupId, $groupIds)) { $k = array_search($groupId, $uniqueGroupIds); @@ -329,10 +345,11 @@ public function getUniqueGroupIds() /** * Checks if this membership has an (active, non-archived) user assigned * - * @param int $userId + * @param int|string $userId * @return bool + * @throws QUI\Database\Exception */ - public function hasMembershipUserId($userId) + public function hasMembershipUserId(int | string $userId): bool { $result = QUI::getDataBase()->fetch([ 'count' => 1, @@ -357,8 +374,9 @@ public function hasMembershipUserId($userId) * @param bool $archivedOnly (optional) - search archived users only [default: false] * @param bool $countOnly (optional) - get count for search result only [default: false] * @return int[]|int - membership user IDs or count + * @throws QUI\Exception */ - public function searchUsers($searchParams, $archivedOnly = false, $countOnly = false) + public function searchUsers(array $searchParams, bool $archivedOnly = false, bool $countOnly = false): array | int { $membershipUserIds = []; $Grid = new QUI\Utils\Grid($searchParams); @@ -399,7 +417,7 @@ public function searchUsers($searchParams, $archivedOnly = false, $countOnly = f $whereOR[] = $column . ' LIKE :search'; $binds['search'] = [ 'value' => '%' . $searchParams['search'] . '%', - 'type' => \PDO::PARAM_STR + 'type' => PDO::PARAM_STR ]; } @@ -410,14 +428,12 @@ public function searchUsers($searchParams, $archivedOnly = false, $countOnly = f $where[] = '`musers`.productId = :productId'; $binds['productId'] = [ 'value' => (int)$searchParams['productId'], - 'type' => \PDO::PARAM_INT + 'type' => PDO::PARAM_INT ]; } // build WHERE query string - if (!empty($where)) { - $sql .= " WHERE " . implode(" AND ", $where); - } + $sql .= " WHERE " . implode(" AND ", $where); // ORDER if (!empty($searchParams['sortOn'])) { @@ -469,7 +485,7 @@ public function searchUsers($searchParams, $archivedOnly = false, $countOnly = f try { $Stmt->execute(); - $result = $Stmt->fetchAll(\PDO::FETCH_ASSOC); + $result = $Stmt->fetchAll(PDO::FETCH_ASSOC); } catch (\Exception $Exception) { QUI\System\Log::addError( self::class . ' :: searchUsers() -> ' . $Exception->getMessage() @@ -492,10 +508,10 @@ public function searchUsers($searchParams, $archivedOnly = false, $countOnly = f /** * Calculate the end date for this membership based on a given time * - * @param int $start (optional) - UNIX timestamp; if omitted use time() + * @param int|null $start (optional) - UNIX timestamp; if omitted use time() * @return string|null - formatted timestamp */ - public function calcEndDate($start = null) + public function calcEndDate(null | int $start = null): ?string { if ($this->isInfinite()) { return null; @@ -534,12 +550,20 @@ public function calcEndDate($start = null) * * @return QUI\ERP\Products\Product\Product[] */ - public function getProducts() + public function getProducts(): array { if (!Utils::isQuiqqerProductsInstalled()) { return []; } + if ( + !class_exists('QUI\ERP\Products\Search\BackendSearch') + || !class_exists('QUI\ERP\Products\Handler\Products') + || !class_exists('QUI\ERP\Products\Field\Field') + ) { + return []; + } + try { $Search = new BackendSearch(); $MembershipField = Handler::getProductMembershipField(); @@ -580,14 +604,22 @@ public function getProducts() * of previous calls! * * @return QUI\ERP\Products\Product\Product|false - * @throws \QUI\Exception + * @throws QUI\Exception */ - public function createProduct() + public function createProduct(): QUI\ERP\Products\Product\Product | bool { if (!Utils::isQuiqqerProductsInstalled()) { return false; } + if ( + !class_exists('QUI\ERP\Products\Handler\Products') + || !class_exists('QUI\ERP\Products\Handler\Fields') + || !class_exists('QUI\ERP\Products\Field\Field') + ) { + return false; + } + $categories = []; $fields = []; @@ -629,7 +661,12 @@ public function createProduct() $fields[] = $DescField; } - if ($this->isAutoExtend() && Utils::isQuiqqerErpPlansInstalled()) { + if ( + $this->isAutoExtend() + && Utils::isQuiqqerErpPlansInstalled() + && class_exists('QUI\ERP\Plans\Handler') + && class_exists('QUI\ERP\Plans\PlanProduct') + ) { $Product = ProductsHandler::createProduct($categories, $fields, QUI\ERP\Plans\PlanProduct::class); $Product->getField(ErpPlansHandler::FIELD_DURATION)->setValue($this->getAttribute('duration')); @@ -655,10 +692,10 @@ public function createProduct() * Locks editing of this membership for the current session user * * @return void - * @throws \QUI\Lock\Exception - * @throws \QUI\Exception + * @throws QUI\Lock\Exception + * @throws QUI\Exception */ - public function lock() + public function lock(): void { Locker::lock(QUI::getPackage('quiqqer/memberships'), $this->getLockKey()); } @@ -667,11 +704,11 @@ public function lock() * Unlock membership (requires permission!) * * @return void - * @throws \QUI\Permissions\Exception - * @throws \QUI\Lock\Exception - * @throws \QUI\Exception + * @throws QUI\Permissions\Exception + * @throws QUI\Lock\Exception + * @throws QUI\Exception */ - public function unlock() + public function unlock(): void { Locker::unlockWithPermissions( QUI::getPackage('quiqqer/memberships'), @@ -684,9 +721,9 @@ public function unlock() * Check if this membership is currently locked * * @return bool - * @throws \QUI\Exception + * @throws QUI\Exception */ - public function isLocked() + public function isLocked(): bool { return Locker::isLocked(QUI::getPackage('quiqqer/memberships'), $this->getLockKey()); } @@ -696,7 +733,7 @@ public function isLocked() * * @return string */ - protected function getLockKey() + protected function getLockKey(): string { return 'membership_' . $this->id; } @@ -706,7 +743,7 @@ protected function getLockKey() * * @return array */ - public function getBackendViewData() + public function getBackendViewData(): array { return [ 'id' => $this->getId(), @@ -721,7 +758,7 @@ public function getBackendViewData() * * @return bool */ - public function isInfinite() + public function isInfinite(): bool { return $this->getAttribute('duration') === 'infinite'; } @@ -731,7 +768,7 @@ public function isInfinite() * * @return bool */ - public function isDefault() + public function isDefault(): bool { $DefaultMembership = Handler::getDefaultMembership(); @@ -747,13 +784,17 @@ public function isDefault() * * @param QUI\Users\User $User * @return QUI\Memberships\Users\MembershipUser - * @throws \QUI\Exception + * @throws QUI\Exception */ - public function addUser(QUI\Users\User $User) + public function addUser(QUI\Users\User $User): QUI\Memberships\Users\MembershipUser { - return MembershipUsersHandler::getInstance()->createChild([ + $MembershipUser = MembershipUsersHandler::getInstance()->createChild([ 'userId' => $User->getId(), 'membershipId' => $this->id ], $this->EditUser); + + /* @var $MembershipUser QUI\Memberships\Users\MembershipUser */ + // @phpstan-ignore-next-line + return $MembershipUser; } } diff --git a/src/QUI/Memberships/Products/MembershipField.php b/src/QUI/Memberships/Products/MembershipField.php index 98d78def805c042b5bb73de240116512c8074d9e..d698f5a17486850de101f530a5bcf780121e9c3e 100644 --- a/src/QUI/Memberships/Products/MembershipField.php +++ b/src/QUI/Memberships/Products/MembershipField.php @@ -7,6 +7,7 @@ namespace QUI\Memberships\Products; use QUI\ERP\Products; +use QUI\ERP\Products\Field\Exception; use QUI\Memberships\Handler as MembershipsHandler; /** @@ -41,7 +42,7 @@ class MembershipField extends Products\Field\Field * @param mixed $value * @return int */ - public function cleanup($value): mixed + public function cleanup(mixed $value): int { return (int)$value; } @@ -51,9 +52,9 @@ public function cleanup($value): mixed * is the value valid for the field type? * * @param mixed $value - * @throws \QUI\ERP\Products\Field\Exception + * @throws Exception */ - public function validate($value): void + public function validate(mixed $value): void { if (empty($value)) { return; @@ -63,8 +64,8 @@ public function validate($value): void try { MembershipsHandler::getInstance()->getChild($value); - } catch (\Exception $Exception) { - throw new Products\Field\Exception([ + } catch (\Exception) { + throw new Exception([ 'quiqqer/products', 'exception.field.invalid', [ diff --git a/src/QUI/Memberships/Users/AbortCancelVerification.php b/src/QUI/Memberships/Users/AbortCancelVerification.php index 56c94217e41d86370f3acbb9be0d045654f1ea0f..e9d15a3c6367449598e49e00e0e32bc6b089fa98 100644 --- a/src/QUI/Memberships/Users/AbortCancelVerification.php +++ b/src/QUI/Memberships/Users/AbortCancelVerification.php @@ -6,7 +6,6 @@ use QUI\Verification\Entity\AbstractVerification; use QUI\Verification\Entity\LinkVerification; use QUI\Verification\Enum\VerificationErrorReason; -use quiqqer\memberships\src\QUI\Memberships\Users\AbstractMembershipUserLinkVerificationHandler; /** * Class CancelVerification diff --git a/src/QUI/Memberships/Users/AbstractMembershipUserLinkVerificationHandler.php b/src/QUI/Memberships/Users/AbstractMembershipUserLinkVerificationHandler.php index a4f5451ecd955b7458933be4031cdf7d41cd4389..b57fb29e81e90d511979b673736207862507e4b7 100644 --- a/src/QUI/Memberships/Users/AbstractMembershipUserLinkVerificationHandler.php +++ b/src/QUI/Memberships/Users/AbstractMembershipUserLinkVerificationHandler.php @@ -2,8 +2,8 @@ namespace QUI\Memberships\Users; +use QUI\Exception; use QUI\Memberships\Users\Handler as MembershipUsersHandler; -use QUI\Memberships\Users\MembershipUser; use QUI\Verification\AbstractLinkVerificationHandler; use QUI\Verification\Entity\LinkVerification; use QUI\Verification\Enum\VerificationErrorReason; @@ -21,7 +21,7 @@ public function __construct(protected ?MembershipUsersHandler $membershipUsersHa * @param LinkVerification $verification * @return MembershipUser * - * @throws \QUI\Exception + * @throws Exception */ protected function getMembershipUser(LinkVerification $verification): MembershipUser { diff --git a/src/QUI/Memberships/Users/CancelVerification.php b/src/QUI/Memberships/Users/CancelVerification.php index 6b0907dadefc73b9b40f84a79cacdfe09fa1a092..aca9cfd52a58884428f5766f595ff51c4af6cd0a 100644 --- a/src/QUI/Memberships/Users/CancelVerification.php +++ b/src/QUI/Memberships/Users/CancelVerification.php @@ -7,7 +7,6 @@ use QUI\Verification\Entity\AbstractVerification; use QUI\Verification\Entity\LinkVerification; use QUI\Verification\Enum\VerificationErrorReason; -use quiqqer\memberships\src\QUI\Memberships\Users\AbstractMembershipUserLinkVerificationHandler; /** * Class CancelVerification diff --git a/src/QUI/Memberships/Users/Handler.php b/src/QUI/Memberships/Users/Handler.php index 4d66349faa09a32af61b3b112a2fb1ad6c4a197d..8217bf631cd186939c9c3bffd2d5f188bc12095d 100644 --- a/src/QUI/Memberships/Users/Handler.php +++ b/src/QUI/Memberships/Users/Handler.php @@ -77,6 +77,15 @@ class Handler extends Factory */ const PERMISSION_EDIT_USERS = 'quiqqer.memberships.edit_users'; + public function getChild(int | string $id): MembershipUser + { + /* @var $MembershipUser MembershipUser */ + $MembershipUser = parent::getChild($id); + + // @phpstan-ignore-next-line + return $MembershipUser; + } + /** * @param array $data * @param User|null $PermissionUser @@ -88,8 +97,10 @@ class Handler extends Factory * @throws QUI\Memberships\Exception * @throws QUI\Permissions\Exception */ - public function createChild(array $data = [], QUI\Interfaces\Users\User $PermissionUser = null): QUI\CRUD\Child - { + public function createChild( + array $data = [], + null | QUI\Interfaces\Users\User $PermissionUser = null + ): QUI\CRUD\Child { if (is_null($PermissionUser)) { $PermissionUser = QUI::getUserBySession(); } @@ -117,6 +128,13 @@ public function createChild(array $data = [], QUI\Interfaces\Users\User $Permiss $Membership = MembershipsHandler::getInstance()->getChild($data['membershipId']); $User = QUI::getUsers()->get($data['userId']); + if (!($Membership instanceof QUI\Memberships\Membership)) { + throw new QUI\Memberships\Exception([ + 'quiqqer/memberships', + 'exception.users.handler.no.membership' + ]); + } + // if the user is already in the membership -> extend runtime if ($Membership->hasMembershipUserId($User->getId())) { $MembershipUser = $Membership->getMembershipUser($User->getId()); @@ -202,7 +220,7 @@ public function getIdsByMembershipId(int $membershipId, bool $includeArchived = * @param bool $includeArchived (optional) - include archived MembershipUsers * @return MembershipUser[] */ - public function getMembershipUsersByUserId(int|string $userId, bool $includeArchived = false): array + public function getMembershipUsersByUserId(int | string $userId, bool $includeArchived = false): array { if (is_int($userId)) { try { @@ -251,7 +269,7 @@ public function getMembershipUsersByUserId(int|string $userId, bool $includeArch * @param int $contractId * @return MembershipUser|false */ - public function getMembershipUserByContractId(int $contractId): bool|MembershipUser + public function getMembershipUserByContractId(int $contractId): bool | MembershipUser { try { $result = QUI::getDataBase()->fetch([ @@ -369,7 +387,7 @@ public function getChildAttributes(): array * * @throws QUI\Exception */ - public static function getSetting(string $key): array|string + public static function getSetting(string $key): array | string { $Config = QUI::getPackage('quiqqer/memberships')->getConfig(); return $Config->get('membershipusers', $key); diff --git a/src/QUI/Memberships/Users/MembershipUser.php b/src/QUI/Memberships/Users/MembershipUser.php index 85516360bf3c4fa63ebf63f139cc8d2ff30a9da6..ec77f026d0b5b4c44a27b414b1334f3faa081e06 100644 --- a/src/QUI/Memberships/Users/MembershipUser.php +++ b/src/QUI/Memberships/Users/MembershipUser.php @@ -2,17 +2,31 @@ namespace QUI\Memberships\Users; +use DateInterval; +use DateTime; use QUI; use QUI\CRUD\Child; +use QUI\CRUD\Factory; use QUI\ERP\Accounting\Contracts\Handler as ContractsHandler; use QUI\ERP\Products\Handler\Products as ProductsHandler; +use QUI\Exception; +use QUI\ExceptionStack; use QUI\Interfaces\Users\User as QUIUserInterface; use QUI\Mail\Mailer; use QUI\Memberships\Handler as MembershipsHandler; use QUI\Memberships\Users\Handler as MembershipUsersHandler; use QUI\Memberships\Utils; use QUI\Permissions\Permission; +use QUI\Verification\Interface\VerificationFactoryInterface; +use QUI\Verification\VerificationFactory; use QUI\Verification\Verifier; +use QUI\Verification\Entity\LinkVerification; +use QUI\Verification\Interface\VerificationRepositoryInterface; +use QUI\Verification\VerificationRepository; + +use function date_create; +use function date_interval_create_from_date_string; +use function is_null; /** * Class MembershipUser @@ -26,31 +40,44 @@ class MembershipUser extends Child /** * The Membership this MembershipUser is assigned to * - * @var QUI\Memberships\Membership + * @var ?QUI\Memberships\Membership */ - protected $Membership = null; + protected ?QUI\Memberships\Membership $Membership = null; /** * User that is editing this MembershipUser in the current runtime * - * @var QUIUserInterface + * @var ?QUIUserInterface */ - protected $EditUser = null; + protected ?QUIUserInterface $EditUser = null; + + public function __construct( + int | string $id, + Factory $Factory, + private ?VerificationFactoryInterface $verificationFactory = null, + private ?VerificationRepositoryInterface $verificationRepository = null + ) { + parent::__construct($id, $Factory); + + if (is_null($this->verificationFactory)) { + $this->verificationFactory = new VerificationFactory(); + } + + if (is_null($this->verificationRepository)) { + $this->verificationRepository = new VerificationRepository(); + } + } /** * Set User that is editing this MembershipUser in the current runtime * * @param QUIUserInterface $EditUser */ - public function setEditUser(QUIUserInterface $EditUser) + public function setEditUser(QUIUserInterface $EditUser): void { $this->EditUser = $EditUser; } - /** - * @inheritdoc - * @param bool $withPermission - check permissions on update [default: true] - */ public function update(): void { Permission::checkPermission(MembershipUsersHandler::PERMISSION_EDIT_USERS, $this->EditUser); @@ -113,13 +140,17 @@ public function update(): void * * @param bool $auto (optional) - Used if the membership is automatically extended. * If set to false, the setting membershipusers.extendMode is used [default: true] - * @param \DateTime $NextBeginDate (optional) - New cycle begin date - * @param \DateTime $NextEndDate (optional) - New cycle end date + * @param DateTime|null $NextBeginDate (optional) - New cycle begin date + * @param DateTime|null $NextEndDate (optional) - New cycle end date * @return void - * @throws QUI\Exception + * @throws Exception + * @throws ExceptionStack */ - public function extend($auto = true, \DateTime $NextBeginDate = null, \DateTime $NextEndDate = null) - { + public function extend( + bool $auto = true, + null | DateTime $NextBeginDate = null, + null | DateTime $NextEndDate = null + ): void { // Calculate new start and/or end time if (empty($NextBeginDate)) { if (MembershipUsersHandler::getExtendMode() === MembershipUsersHandler::EXTEND_MODE_PROLONG) { @@ -167,22 +198,27 @@ public function extend($auto = true, \DateTime $NextBeginDate = null, \DateTime /** * Calculate the end date of the current cycle based on a start date * - * @param \DateTime $Start (optional) - Calculate based on this start date [default: now] - * @return \DateTime + * @param DateTime|null $Start (optional) - Calculate based on this start date [default: now] + * @return DateTime + * @throws Exception */ - public function calcEndDate($Start = null) + public function calcEndDate(null | DateTime $Start = null): DateTime { if (empty($Start)) { - $Start = \date_create(); + $Start = date_create(); } $contractId = $this->getContractId(); - $NewEndDate = \date_create($this->getMembership()->calcEndDate($Start->getTimestamp())); + $NewEndDate = date_create($this->getMembership()->calcEndDate($Start->getTimestamp())); if (empty($contractId)) { return $NewEndDate; } + if (!class_exists('QUI\ERP\Accounting\Contracts\Handler')) { + return $NewEndDate; + } + try { $Contract = ContractsHandler::getInstance()->getContract($contractId); $ContractExtensionInterval = $Contract->getExtensionInterval(); @@ -197,11 +233,9 @@ public function calcEndDate($Start = null) $NewEndDate = $Start->add($ContractExtensionInterval); - switch (MembershipUsersHandler::getDurationMode()) { - case MembershipUsersHandler::DURATION_MODE_DAY: - $NewEndDate->add(new \DateInterval('P1D')); - $NewEndDate->setTime(23, 59, 59); - break; + if (MembershipUsersHandler::getDurationMode() == MembershipUsersHandler::DURATION_MODE_DAY) { + $NewEndDate->add(new DateInterval('P1D')); + $NewEndDate->setTime(23, 59, 59); } return $NewEndDate; @@ -211,8 +245,9 @@ public function calcEndDate($Start = null) * Send mail to the user if the membership is extended automatically * * @return void + * @throws Exception */ - protected function sendAutoExtendMail() + protected function sendAutoExtendMail(): void { $sendMail = MembershipUsersHandler::getSetting('sendAutoExtendMail'); @@ -235,12 +270,13 @@ protected function sendAutoExtendMail() /** * Send mail to the user if the membership is extended manually * - * Manually = Either by admin edit or if the user is re-added to the membership + * Manually = Either by admin edit or if the user is re-added to the membership, * although he already is a member * * @return void + * @throws Exception */ - public function sendManualExtendMail() + public function sendManualExtendMail(): void { $sendMail = MembershipUsersHandler::getSetting('sendManualExtendMail'); @@ -264,9 +300,9 @@ public function sendManualExtendMail() * Expires this memberships user * * @return void - * @throws \QUI\Exception + * @throws Exception */ - public function expire() + public function expire(): void { $this->addHistoryEntry(MembershipUsersHandler::HISTORY_TYPE_EXPIRED); $this->archive(MembershipUsersHandler::ARCHIVE_REASON_EXPIRED); @@ -287,9 +323,9 @@ public function expire() * * @throws QUI\Memberships\Exception * @throws QUI\Verification\Exception - * @throws QUI\Exception + * @throws Exception */ - public function startManualCancel() + public function startManualCancel(): void { // check cancel permission if ((int)QUI::getUserBySession()->getId() !== (int)$this->getUserId()) { @@ -324,7 +360,8 @@ public function startManualCancel() ]); } - $cancelUrl = Verifier::startVerification($this->getCancelVerification(), true); + $cancelVerification = $this->createCancelVerification(); + $cancelUrl = $cancelVerification->getVerificationUrl(); $cancelDate = Utils::getFormattedTimestamp(); $CancelEndDate = $this->getCurrentCancelEndDate(); @@ -365,7 +402,7 @@ public function startManualCancel() * @return void * @throws \Exception */ - public function autoCancel() + public function autoCancel(): void { if ($this->isCancelled()) { return; @@ -410,9 +447,9 @@ public function autoCancel() * @return void * @throws QUI\Memberships\Exception * @throws QUI\Verification\Exception - * @throws QUI\Exception + * @throws Exception */ - public function startAbortCancel() + public function startAbortCancel(): void { // check cancel permission if ((int)QUI::getUserBySession()->getId() !== (int)$this->getUserId()) { @@ -448,7 +485,8 @@ public function startAbortCancel() ]); } - $abortCancelUrl = Verifier::startVerification($this->getAbortCancelVerification(), true); + $verification = $this->createAbortCancelVerification(); + $abortCancelUrl = $verification->getVerificationUrl(); $this->setAttributes([ 'cancelStatus' => MembershipUsersHandler::CANCEL_STATUS_ABORT_CANCEL_CONFIRM_PENDING, @@ -473,7 +511,7 @@ public function startAbortCancel() * * @return void */ - public function confirmAbortCancel() + public function confirmAbortCancel(): void { $this->setAttributes([ 'cancelDate' => null, @@ -483,7 +521,11 @@ public function confirmAbortCancel() ]); try { - Verifier::removeVerification($this->getAbortCancelVerification()); + $verification = $this->getAbortCancelVerification(); + + if ($verification) { + $this->verificationRepository->delete($verification); + } } catch (\Exception $Exception) { QUI\System\Log::writeException($Exception); } @@ -504,9 +546,9 @@ public function confirmAbortCancel() * * @return void * @throws QUI\Memberships\Exception - * @throws QUI\ExceptionStack|QUI\Exception + * @throws QUI\ExceptionStack|Exception */ - public function confirmManualCancel() + public function confirmManualCancel(): void { if ($this->isCancelled()) { return; @@ -532,7 +574,7 @@ public function confirmManualCancel() * * @return void */ - public function sendConfirmCancelMail() + public function sendConfirmCancelMail(): void { try { $subject = $this->getUser()->getLocale()->get( @@ -551,7 +593,7 @@ public function sendConfirmCancelMail() * * @return bool - success */ - public function sendConfirmCancelReminderMail() + public function sendConfirmCancelReminderMail(): bool { try { $subject = $this->getUser()->getLocale()->get( @@ -559,16 +601,22 @@ public function sendConfirmCancelReminderMail() 'templates.mail.confirmcancel_reminder.subject' ); + $cancelVerification = $this->getCancelVerification(); + + if (!$cancelVerification) { + return false; + } + $this->sendMail( $subject, dirname(__FILE__, 5) . '/templates/mail_confirmcancel_reminder.html', [ - 'cancelUrl' => Verifier::getVerificationUrl($this->getCancelVerification()) + 'cancelUrl' => $cancelVerification->getVerificationUrl() ] ); $this->addHistoryEntry( - \QUI\Memberships\Users\Handler::HISTORY_TYPE_MISC, + Handler::HISTORY_TYPE_MISC, QUI::getLocale()->get( 'quiqqer/memberships', 'history.MembershipUser.cancel_confirm_reminder_sent' @@ -589,9 +637,9 @@ public function sendConfirmCancelReminderMail() * Cancel membership * * @return void - * @throws \QUI\Exception + * @throws Exception */ - public function cancel() + public function cancel(): void { $this->archive(MembershipUsersHandler::ARCHIVE_REASON_CANCELLED); @@ -605,9 +653,9 @@ public function cancel() /** * Check if this user has cancelled his membership * - * @return mixed + * @return bool */ - public function isCancelled() + public function isCancelled(): bool { return boolval($this->getAttribute('cancelled')); } @@ -618,6 +666,7 @@ public function isCancelled() * A deleted membership user is not removed from the database but set to "archived". * * @return void + * @throws QUI\Permissions\Exception|ExceptionStack|Exception */ public function delete(): void { @@ -635,8 +684,9 @@ public function delete(): void * Set User to all membership QUIQQER groups * * @return void + * @throws Exception */ - public function addToGroups() + public function addToGroups(): void { $groupIds = $this->getMembership()->getGroupIds(); $User = $this->getUser(); @@ -653,9 +703,9 @@ public function addToGroups() * his membership) * * @return void - * @throws QUI\Exception + * @throws Exception */ - protected function removeFromGroups() + protected function removeFromGroups(): void { /** * Check if the user exists first. If he does NOT, then he does not need to be removed @@ -679,7 +729,9 @@ protected function removeFromGroups() // remove user from unique group ids foreach ($Membership->getUniqueGroupIds() as $groupId) { - $Groups->get($groupId)->removeUser($User); + if ($User instanceof QUI\Users\User) { + $Groups->get($groupId)->removeUser($User); + } $k = array_search($groupId, $membershipGroupIds); @@ -694,7 +746,10 @@ protected function removeFromGroups() foreach ($Memberships->getMembershipIdsByGroupIds([$groupId]) as $membershipId) { $OtherMembership = $Memberships->getChild($membershipId); - if (!$OtherMembership->hasMembershipUserId($User->getId())) { + if ( + method_exists($OtherMembership, 'hasMembershipUserId') + && !$OtherMembership->hasMembershipUserId($User->getId()) + ) { $User->removeGroup($groupId); } } @@ -708,13 +763,12 @@ protected function removeFromGroups() * * @param string $reason - The reason why this user is archived * @return void + * @throws Exception */ - public function archive($reason) + public function archive(string $reason): void { $this->removeFromGroups(); - $this->addHistoryEntry(MembershipUsersHandler::HISTORY_TYPE_ARCHIVED, [ - 'reason' => $reason - ]); + $this->addHistoryEntry(MembershipUsersHandler::HISTORY_TYPE_ARCHIVED, $reason); $this->setAttributes([ 'archived' => 1, 'archiveDate' => Utils::getFormattedTimestamp(), @@ -728,7 +782,7 @@ public function archive($reason) * * @retun bool */ - public function isArchived() + public function isArchived(): bool { return boolval($this->getAttribute('archived')); } @@ -737,6 +791,7 @@ public function isArchived() * Get the Membership this membership user is assigned to * * @return QUI\Memberships\Membership|null + * @throws Exception */ public function getMembership(): ?QUI\Memberships\Membership { @@ -756,7 +811,7 @@ public function getMembership(): ?QUI\Memberships\Membership * * @return int|string */ - public function getUserId(): int|string + public function getUserId(): int | string { return $this->getAttribute('userId'); } @@ -782,7 +837,7 @@ public function getUser(): ?QUIUserInterface * * @return int|false */ - public function getContractId(): false|int + public function getContractId(): false | int { $contractId = $this->getAttribute('contractId'); @@ -798,7 +853,7 @@ public function getContractId(): false|int * * @return false|QUI\ERP\Accounting\Contracts\Contract */ - public function getContract() + public function getContract(): QUI\ERP\Accounting\Contracts\Contract | bool { $contractId = $this->getContractId(); @@ -806,6 +861,10 @@ public function getContract() return false; } + if (!class_exists('QUI\ERP\Accounting\Contracts\Handler')) { + return false; + } + try { return QUI\ERP\Accounting\Contracts\Handler::getInstance()->get($contractId); } catch (\Exception $Exception) { @@ -821,10 +880,15 @@ public function getContract() * * @param int $contractId * @return void - * @throws QUI\Exception + * @throws Exception */ - public function linkToContract($contractId) + public function linkToContract(int $contractId): void { + if (!class_exists('QUI\ERP\Accounting\Contracts\Handler')) { + QUI\System\Log::addError('quiqqer/contracts is not installed'); + return; + } + try { $Contract = ContractsHandler::getInstance()->getContract($contractId); $ContractCycleEndDate = $Contract->getCycleEndDate(); @@ -848,20 +912,15 @@ public function linkToContract($contractId) * @param string $type - History entry type (see \QUI\Memberships\Users\Handler) * @param string $msg (optional) - additional custom message */ - public function addHistoryEntry($type, $msg = "") + public function addHistoryEntry(string $type, string $msg = ""): void { $history = $this->getHistory(); + $User = QUI::getUserBySession(); if (empty($msg)) { $msg = ""; } - if (is_array($msg)) { - $msg = json_encode($msg); - } - - $User = QUI::getUserBySession(); - $history[] = [ 'type' => $type, 'time' => Utils::getFormattedTimestamp(), @@ -877,7 +936,7 @@ public function addHistoryEntry($type, $msg = "") * * @return array */ - public function getHistory() + public function getHistory(): array { $history = $this->getAttribute('history'); @@ -893,15 +952,15 @@ public function getHistory() /** * Format date based on User Locale and duration mode * - * @param string|\DateTime $date - Formatted date YYYY-MM-DD HH:MM:SS or \DateTime object + * @param DateTime|string $date - Formatted date YYYY-MM-DD HH:MM:SS or \DateTime object * @return string|false - formatted date or false on error - * @throws \QUI\Exception + * @throws Exception */ - protected function formatDate($date) + protected function formatDate(DateTime | string $date): bool | string { if (empty($date) || $date === '0000-00-00 00:00:00') { return false; - } elseif ($date instanceof \DateTime) { + } elseif ($date instanceof DateTime) { $date = $date->format('Y-m-d H:i:s'); } @@ -931,14 +990,10 @@ protected function formatDate($date) if (QUI::getPackageManager()->isInstalled('quiqqer/erp')) { $dateFormat = QUI\ERP\Defaults::getTimestampFormat($lang); } else { - switch ($lang) { - case 'de': - $dateFormat = 'dd.MM.yyyy HH:mm:ss'; - break; - - default: - $dateFormat = 'MMM dd, yyyy, HH:mm:ss'; - } + $dateFormat = match ($lang) { + 'de' => 'dd.MM.yyyy HH:mm:ss', + default => 'MMM dd, yyyy, HH:mm:ss', + }; } } } @@ -950,8 +1005,9 @@ protected function formatDate($date) * Get membership data for frontend view/edit purposes with correctly formatted dates * * @return array + * @throws Exception */ - public function getFrontendViewData() + public function getFrontendViewData(): array { $QuiqqerUser = $this->getUser(); $Membership = $this->getMembership(); @@ -965,6 +1021,7 @@ public function getFrontendViewData() $viewDataMode === 'product' && !empty($productId) && Utils::isQuiqqerProductsInstalled() + && class_exists('QUI\ERP\Products\Handler\Products') ) { $Product = ProductsHandler::getProduct($productId); $title = $Product->getTitle($Locale); @@ -981,7 +1038,11 @@ public function getFrontendViewData() $cancelAllowed = !$this->isCancelled(); $Contract = $this->getContract(); - if (!$this->isCancelled() && $Contract) { + if ( + class_exists('QUI\ERP\Accounting\Contracts\Contract') + && !$this->isCancelled() + && $Contract + ) { try { if (!$Contract->isInPeriodOfNotice()) { $cancelAllowed = false; @@ -989,8 +1050,8 @@ public function getFrontendViewData() $PeriodOfNoticeInterval = $Contract->getPeriodOfNoticeInterval(); $EndBaseDate = clone $CurrentCancelEndDate; - $EndBaseDate->setTime(0, 0, 0); - $EndBaseDate->sub(\date_interval_create_from_date_string('1 second')); + $EndBaseDate->setTime(0, 0); + $EndBaseDate->sub(date_interval_create_from_date_string('1 second')); $CancelUntilDate = clone $EndBaseDate; @@ -1010,7 +1071,7 @@ public function getFrontendViewData() $nextCycleEndDate = $NextCycleEndDate ? $this->formatDate($NextCycleEndDate) : '-'; // Determine cancel info text - if ($Contract) { + if (class_exists('QUI\ERP\Accounting\Contracts\Contract') && $Contract) { if ($Contract->getPeriodOfNoticeInterval()) { if ($Contract->isInPeriodOfNotice()) { $cancelInfoText = QUI::getLocale()->get( @@ -1094,8 +1155,9 @@ public function getFrontendViewData() * Get membership data for backend view/edit purposes * * @return array + * @throws Exception */ - public function getBackendViewData() + public function getBackendViewData(): array { $QuiqqerUser = $this->getUser(); $Membership = $this->getMembership(); @@ -1125,34 +1187,76 @@ public function getBackendViewData() /** * Get Verification object for MembershipUser cancellation * - * @return CancelVerification + * @return LinkVerification|null */ - protected function getCancelVerification() + protected function getCancelVerification(): ?LinkVerification { - return new CancelVerification($this->id); + $verification = $this->verificationRepository->findByIdentifier( + 'quiqqer-memberships-users-cancel-' . $this->id, + ); + + return $verification instanceof LinkVerification ? $verification : null; + } + + /** + * Get Verification object for MembershipUser cancellation + * + * @return LinkVerification + */ + protected function createCancelVerification(): LinkVerification + { + return $this->verificationFactory->createLinkVerification( + 'quiqqer-memberships-users-cancel-' . $this->id, + new CancelVerification(), + [ + 'membershipUserId' => $this->id + ], + true + ); + } + + /** + * Get Verification object for MembershipUser cancel abort + * + * @return LinkVerification + */ + protected function createAbortCancelVerification(): LinkVerification + { + return $this->verificationFactory->createLinkVerification( + 'quiqqer-memberships-users-cancel-abort-' . $this->id, + new CancelVerification(), + [ + 'membershipUserId' => $this->id + ], + true + ); } /** * Get Verification object for MembershipUser cancel abort * - * @return AbortCancelVerification + * @return LinkVerification|null */ - protected function getAbortCancelVerification() + protected function getAbortCancelVerification(): ?LinkVerification { - return new AbortCancelVerification($this->id); + $verification = $this->verificationRepository->findByIdentifier( + 'quiqqer-memberships-users-cancel-abort-' . $this->id, + ); + + return $verification instanceof LinkVerification ? $verification : null; } /** - * Send an email to the membership user + * Email the membership user * * @param string $subject - mail subject * @param string $templateFile * @param array $templateVars (optional) - additional template variables (besides $this) * @return void * - * @throws \QUI\Exception + * @throws Exception */ - public function sendMail($subject, $templateFile, $templateVars = []) + public function sendMail(string $subject, string $templateFile, array $templateVars = []): void { $User = $this->getUser(); $email = $User->getAttribute('email'); @@ -1186,7 +1290,12 @@ public function sendMail($subject, $templateFile, $templateVars = []) $Mailer->addRecipient($email, $User->getName()); $Mailer->setSubject($subject); $Mailer->setBody($template); - $Mailer->send(); + + try { + $Mailer->send(); + } catch (\PHPMailer\PHPMailer\Exception $e) { + QUI\System\Log::addError($e->getMessage()); + } } /** @@ -1197,7 +1306,7 @@ public function sendMail($subject, $templateFile, $templateVars = []) * @param string $key * @param string $value */ - public function setExtraData($key, $value) + public function setExtraData(string $key, string $value): void { $extraData = $this->getExtraData(); @@ -1222,10 +1331,10 @@ public function setExtraData($key, $value) /** * Get extra data of this MembershipUser * - * @param string $key (optional) - If omitted return all extra data + * @param string|null $key (optional) - If omitted return all extra data * @return array|string|false */ - public function getExtraData($key = null) + public function getExtraData(null | string $key = null): bool | array | string { $extraData = $this->getAttribute('extraData'); @@ -1249,20 +1358,25 @@ public function getExtraData($key = null) /** * Get begin Date of the current cycle * - * @return \DateTime + * @return DateTime */ - public function getCycleBeginDate() + public function getCycleBeginDate(): DateTime { - return \date_create($this->getAttribute('beginDate')); + return date_create($this->getAttribute('beginDate')); } /** * Get end Date of the current cycle * - * @return \DateTime|false - DateTime of the cycle end or false if Membership has no cycle end (i.e. is infinite) + * @return DateTime|false - DateTime of the cycle end or false if Membership has no cycle end (i.e. is infinite) + * @throws Exception */ - public function getCycleEndDate() + public function getCycleEndDate(): DateTime | bool { + if (!class_exists('QUI\ERP\Accounting\Contracts\Contract')) { + return false; + } + $Contract = $this->getContract(); if ($Contract) { @@ -1273,23 +1387,28 @@ public function getCycleEndDate() return false; } - return \date_create($this->getAttribute('endDate')); + return date_create($this->getAttribute('endDate')); } /** * Get begin date of the (hypothetical) next cycle * - * @return \DateTime|false - DateTime of the cycle end or false if Membership has no next cycle (i.e. is infinite) + * @return DateTime|false - DateTime of the cycle end or false if Membership has no next cycle (i.e. is infinite) + * @throws Exception */ - public function getNextCycleBeginDate() + public function getNextCycleBeginDate(): DateTime | bool { + if (!class_exists('QUI\ERP\Accounting\Contracts\Contract')) { + return false; + } + $Contract = $this->getContract(); if ($Contract) { $EndDate = $Contract->getCycleEndDate(); $NextBeginDate = clone $EndDate; - $NextBeginDate->add(\date_interval_create_from_date_string('1 day')); - $NextBeginDate->setTime(0, 0, 0); + $NextBeginDate->add(date_interval_create_from_date_string('1 day')); + $NextBeginDate->setTime(0, 0); return $NextBeginDate; } @@ -1308,12 +1427,12 @@ public function getNextCycleBeginDate() switch (MembershipUsersHandler::getDurationMode()) { case MembershipUsersHandler::DURATION_MODE_EXACT: - $NextBeginDate->add(\date_interval_create_from_date_string('1 second')); + $NextBeginDate->add(date_interval_create_from_date_string('1 second')); break; default: - $NextBeginDate->add(\date_interval_create_from_date_string('1 day')); - $NextBeginDate->setTime(0, 0, 0); + $NextBeginDate->add(date_interval_create_from_date_string('1 day')); + $NextBeginDate->setTime(0, 0); } return $NextBeginDate; @@ -1322,10 +1441,15 @@ public function getNextCycleBeginDate() /** * Get the end Date of the (hypothetical) next cycle * - * @return \DateTime|false - DateTime of the next cycle end or false if Membership has no next cycle end (i.e. is infinite) + * @return DateTime|false - DateTime of the next cycle end or false if Membership has no next cycle end (i.e. is infinite) + * @throws Exception */ - public function getNextCycleEndDate() + public function getNextCycleEndDate(): DateTime | bool { + if (!class_exists('QUI\ERP\Accounting\Contracts\Contract')) { + return false; + } + $Contract = $this->getContract(); if ($Contract) { @@ -1360,17 +1484,22 @@ public function getNextCycleEndDate() $end = strtotime($start . ' +' . $durationCount . ' ' . $durationScope); } - return \date_create('@' . $end); + return date_create('@' . $end); } /** * Calculates the date the membership for this user would end * if it was cancelled NOW * - * @return \DateTime + * @return DateTime|bool + * @throws Exception */ - public function getCurrentCancelEndDate() + public function getCurrentCancelEndDate(): DateTime | bool { + if (!class_exists('QUI\ERP\Accounting\Contracts\Contract')) { + return $this->getCycleEndDate(); + } + /** * If a contract is connected to this MembershipUser * the contract cancel termination date has priority! diff --git a/src/QUI/Memberships/Utils.php b/src/QUI/Memberships/Utils.php index 903f059c3e13470b548d0606392aefe2dfc7dc6a..f806fbcb5ab22315011a6ee5a1078a8ee6c25fe8 100644 --- a/src/QUI/Memberships/Utils.php +++ b/src/QUI/Memberships/Utils.php @@ -2,9 +2,16 @@ namespace QUI\Memberships; +use DateInterval; +use DateTime; use QUI; use QUI\Utils\Security\Orthos; +use function explode; +use function is_numeric; +use function is_string; +use function strtotime; + class Utils { /** @@ -13,15 +20,13 @@ class Utils * @param string $str - JSON string * @return string - cleared JSON string */ - public static function clearJSONString($str) + public static function clearJSONString(string $str): string { $str = Orthos::removeHTML($str); $str = Orthos::clearPath($str); // $str = Orthos::clearFormRequest($str); - $str = htmlspecialchars($str, ENT_NOQUOTES); - - return $str; + return htmlspecialchars($str, ENT_NOQUOTES); } /** @@ -30,12 +35,8 @@ public static function clearJSONString($str) * @param array $array * @return array - cleared array */ - public static function clearArrayWithJSON(array $array) + public static function clearArrayWithJSON(array $array): array { - if (!is_array($array)) { - return []; - } - foreach ($array as $k => $v) { if (is_array($v)) { $array[$k] = self::clearArrayWithJSON($v); @@ -54,7 +55,7 @@ public static function clearArrayWithJSON(array $array) * @param array $localeData * @return string */ - public static function getLocaleFromArray($localeData) + public static function getLocaleFromArray(array $localeData): string { return QUI::getLocale()->get($localeData['group'], $localeData['var']); } @@ -62,21 +63,21 @@ public static function getLocaleFromArray($localeData) /** * Get formatted timestamp for a given UNIX timestamp * - * @param int|\DateTime $time (optional) - Timestamp or \DateTime object [default: now] + * @param string|DateTime|int|null $time (optional) - Timestamp or \DateTime object [default: now] * @return string */ - public static function getFormattedTimestamp($time = null) + public static function getFormattedTimestamp(null | string | DateTime | int $time = null): string { if (is_null($time)) { $time = time(); } - if ($time instanceof \DateTime) { + if ($time instanceof DateTime) { return $time->format('Y-m-d H:i:s'); } - if (\is_string($time) && !\is_numeric($time)) { - $time = \strtotime($time); + if (is_string($time) && !is_numeric($time)) { + $time = strtotime($time); } return date('Y-m-d H:i:s', $time); @@ -88,7 +89,7 @@ public static function getFormattedTimestamp($time = null) * * @return array */ - public static function getInstalledMembershipPackages() + public static function getInstalledMembershipPackages(): array { $packages = []; $relevantPackages = [ @@ -101,7 +102,7 @@ public static function getInstalledMembershipPackages() try { QUI::getPackage($package); $packages[] = $package; - } catch (\Exception $Exception) { + } catch (\Exception) { // ignore (package is probably not installed) } } @@ -113,38 +114,26 @@ public static function getInstalledMembershipPackages() * Parse a DateInterval from a contract duration setting * * @param string $duration - * @return \DateInterval|false + * @return DateInterval|false * @throws \Exception */ - public static function parseIntervalFromDuration($duration) + public static function parseIntervalFromDuration(string $duration): DateInterval | bool { if (empty($duration)) { return false; } - $duration = \explode('-', $duration); + $duration = explode('-', $duration); $intervalNumber = $duration[0]; - switch ($duration[1]) { - case 'week': - $intervalPeriod = 'W'; - break; - - case 'month': - $intervalPeriod = 'M'; - break; - - case 'year': - $intervalPeriod = 'Y'; - break; - - case 'day': - default: - $intervalPeriod = 'D'; - break; - } + $intervalPeriod = match ($duration[1]) { + 'week' => 'W', + 'month' => 'M', + 'year' => 'Y', + default => 'D', + }; - return new \DateInterval('P' . $intervalNumber . $intervalPeriod); + return new DateInterval('P' . $intervalNumber . $intervalPeriod); } /** @@ -152,7 +141,7 @@ public static function parseIntervalFromDuration($duration) * * @return bool */ - public static function isQuiqqerProductsInstalled() + public static function isQuiqqerProductsInstalled(): bool { return QUI::getPackageManager()->isInstalled('quiqqer/products'); } @@ -162,7 +151,7 @@ public static function isQuiqqerProductsInstalled() * * @return bool */ - public static function isQuiqqerErpPlansInstalled() + public static function isQuiqqerErpPlansInstalled(): bool { return QUI::getPackageManager()->isInstalled('quiqqer/erp-plans'); } @@ -172,7 +161,7 @@ public static function isQuiqqerErpPlansInstalled() * * @return bool */ - public static function isQuiqqerContractsInstalled() + public static function isQuiqqerContractsInstalled(): bool { return QUI::getPackageManager()->isInstalled('quiqqer/contracts'); }