diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 05179692..a31199b3 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -4,7 +4,6 @@ on: push: branches: - master - pull_request: permissions: contents: read diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 52d79e6a..e3cc1285 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -1,13 +1,13 @@ exclude('*/vendor/*') - ->in(__DIR__.'/files/'); + ->in(__DIR__ . '/files/'); return (new PhpCsFixer\Config()) ->setRiskyAllowed(true) ->setRules([ - '@PER-CS2.0' => true, - 'single_line_empty_body' => false, + '@PSR1' => true, + '@PSR2' => true, 'array_push' => true, 'backtick_to_shell_exec' => true, @@ -25,18 +25,23 @@ 'non_printable_character' => ['use_escape_sequences_in_strings' => true], + 'lowercase_static_reference' => true, 'magic_constant_casing' => true, 'magic_method_casing' => true, 'native_function_casing' => true, 'native_function_type_declaration_casing' => true, 'cast_spaces' => ['space' => 'none'], + 'lowercase_cast' => true, 'no_unset_cast' => true, + 'short_scalar_cast' => true, 'class_attributes_separation' => true, + 'no_blank_lines_after_class_opening' => true, 'no_null_property_initialization' => true, 'self_accessor' => true, 'single_class_element_per_statement' => true, + 'single_trait_insert_per_statement' => true, 'no_empty_comment' => true, 'single_line_comment_style' => ['comment_types' => ['hash']], @@ -55,12 +60,15 @@ 'native_function_invocation' => ['include' => ['@internal']], 'no_unreachable_default_argument_value' => true, 'nullable_type_declaration_for_default_null_value' => true, + 'return_type_declaration' => true, 'static_lambda' => true, 'fully_qualified_strict_types' => ['leading_backslash_in_global_namespace' => true], + 'no_leading_import_slash' => true, 'no_unused_imports' => true, 'ordered_imports' => true, + 'declare_equal_normalize' => true, 'dir_constant' => true, 'explicit_indirect_variable' => true, 'function_to_constant' => true, @@ -71,6 +79,7 @@ 'clean_namespace' => true, 'no_leading_namespace_whitespace' => true, + 'single_blank_line_before_namespace' => true, 'no_homoglyph_names' => true, @@ -82,6 +91,7 @@ 'operator_linebreak' => true, 'standardize_increment' => true, 'standardize_not_equals' => true, + 'ternary_operator_spaces' => true, 'ternary_to_elvis_operator' => true, 'ternary_to_null_coalescing' => true, 'unary_operator_spaces' => true, @@ -102,6 +112,7 @@ 'array_indentation' => true, 'blank_line_before_statement' => ['statements' => ['return', 'exit']], + 'compact_nullable_typehint' => true, 'method_chaining_indentation' => true, 'no_extra_blank_lines' => ['tokens' => ['case', 'continue', 'curly_brace_block', 'default', 'extra', 'parenthesis_brace_block', 'square_brace_block', 'switch', 'throw', 'use']], 'no_spaces_around_offset' => true, diff --git a/.phpcs.xml b/.phpcs.xml index c721282f..fa15c659 100644 --- a/.phpcs.xml +++ b/.phpcs.xml @@ -9,5 +9,7 @@ - + + + diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..60267d03 --- /dev/null +++ b/composer.json @@ -0,0 +1,8 @@ +{ + "name": "woltlab/com.woltlab.wcf.conversation", + "type": "project", + "require-dev": { + "phpstan/phpstan": "^2.1" + }, + "require": {} +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..4703f643 --- /dev/null +++ b/composer.lock @@ -0,0 +1,77 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "069580d97420a2a4f15021f8f35e0fc4", + "packages": [], + "packages-dev": [ + { + "name": "phpstan/phpstan", + "version": "2.1.8", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "f9adff3b87c03b12cc7e46a30a524648e497758f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f9adff3b87c03b12cc7e46a30a524648e497758f", + "reference": "f9adff3b87c03b12cc7e46a30a524648e497758f", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-03-09T09:30:48+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/files/lib/action/ConversationLabelFormAction.class.php b/files/lib/action/ConversationLabelFormAction.class.php index bfd1b497..735bcfc0 100644 --- a/files/lib/action/ConversationLabelFormAction.class.php +++ b/files/lib/action/ConversationLabelFormAction.class.php @@ -74,7 +74,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface } $data = $form->getData()['data']; - $deleteLabel = $label && $data['deleteLabel'] ?? false; + $deleteLabel = $label && ($data['deleteLabel'] ?? false); unset($data['deleteLabel']); if ($deleteLabel) { diff --git a/files/lib/data/conversation/Conversation.class.php b/files/lib/data/conversation/Conversation.class.php index 6d674cbd..75ce0b41 100644 --- a/files/lib/data/conversation/Conversation.class.php +++ b/files/lib/data/conversation/Conversation.class.php @@ -141,11 +141,9 @@ public function canReply(): bool /** * Overrides the last message data, used when `leftAt < lastPostTime`. * - * @param int $userID - * @param string $username - * @param int $time + * @return void */ - public function setLastMessage($userID, $username, $time) + public function setLastMessage(?int $userID, string $username, int $time) { $this->data['lastPostTime'] = $time; $this->data['lastPosterID'] = $userID; @@ -156,9 +154,9 @@ public function setLastMessage($userID, $username, $time) * Loads participation data for given user id (default: current user) on runtime. * You should use Conversation::getUserConversation() instead if possible. * - * @param int $userID + * @return void */ - public function loadUserParticipation($userID = null) + public function loadUserParticipation(?int $userID = null) { if ($userID === null) { $userID = WCF::getUser()->userID; @@ -179,11 +177,9 @@ public function loadUserParticipation($userID = null) /** * Returns a specific user conversation. * - * @param int $conversationID - * @param int $userID - * @return null|Conversation + * @return ?Conversation */ - public static function getUserConversation($conversationID, $userID) + public static function getUserConversation(int $conversationID, int $userID) { $sql = "SELECT conversation_to_user.*, conversation.* FROM wcf1_conversation conversation @@ -205,10 +201,9 @@ public static function getUserConversation($conversationID, $userID) * Returns a list of user conversations. * * @param int[] $conversationIDs - * @param int $userID - * @return Conversation[] + * @return Conversation[] */ - public static function getUserConversations(array $conversationIDs, $userID) + public static function getUserConversations(array $conversationIDs, int $userID) { $conditionBuilder = new PreparedStatementConditionBuilder(); $conditionBuilder->add('conversation.conversationID IN (?)', [$conversationIDs]); @@ -316,10 +311,9 @@ public function getFirstMessage(): ?ConversationMessage /** * Returns a list of the ids of all participants. * - * @param bool $excludeLeftParticipants - * @return int[] + * @return int[] */ - public function getParticipantIDs($excludeLeftParticipants = false) + public function getParticipantIDs(bool $excludeLeftParticipants = false) { $conditions = new PreparedStatementConditionBuilder(); $conditions->add("conversationID = ?", [$this->conversationID]); @@ -340,11 +334,9 @@ public function getParticipantIDs($excludeLeftParticipants = false) /** * Returns a list of the usernames of all participants. * - * @param bool $excludeSelf - * @param bool $leftByOwnChoice - * @return string[] + * @return string[] */ - public function getParticipantNames($excludeSelf = false, $leftByOwnChoice = false, bool $isAuthor = false) + public function getParticipantNames(bool $excludeSelf = false, bool $leftByOwnChoice = false, bool $isAuthor = false) { $conditions = new PreparedStatementConditionBuilder(); $conditions->add("conversationID = ?", [$this->conversationID]); @@ -422,9 +414,8 @@ public function getPopoverLinkClass(): string * of all given conversation ids. * * @param int[] $conversationIDs - * @param int $userID */ - public static function isParticipant(array $conversationIDs, $userID = null): bool + public static function isParticipant(array $conversationIDs, ?int $userID = null): bool { if ($userID === null) { $userID = WCF::getUser()->userID; @@ -473,15 +464,14 @@ public static function isParticipant(array $conversationIDs, $userID = null): bo /** * Validates the participants. * - * @param mixed $participants - * @param string $field + * @param string[]|string $participants * @param int[] $existingParticipants - * @return array $result - * @throws UserInputException + * @return list + * @throws UserInputException */ public static function validateParticipants( - $participants, - $field = 'participants', + array|string $participants, + string $field = 'participants', array $existingParticipants = [] ) { $result = []; @@ -534,14 +524,13 @@ public static function validateParticipants( /** * Validates the group participants. * - * @param mixed $participants - * @param string $field + * @param string[]|string $participants * @param int[] $existingParticipants - * @return array $result + * @return list */ public static function validateGroupParticipants( - $participants, - $field = 'participants', + array|string $participants, + string $field = 'participants', array $existingParticipants = [] ) { $groupIDs = \is_array($participants) ? $participants : ArrayUtil::toIntegerArray(\explode(',', $participants)); @@ -550,7 +539,7 @@ public static function validateGroupParticipants( foreach ($groupIDs as $groupID) { $group = UserGroup::getGroupByID($groupID); - /** @noinspection PhpUndefinedFieldInspection */ + // @phpstan-ignore property.notFound if ($group !== null && $group->canBeAddedAsConversationParticipant) { $validGroupIDs[] = $groupID; } @@ -599,11 +588,10 @@ public static function validateGroupParticipants( /** * Validates the given participant. * - * @param UserProfile $user - * @param string $field - * @throws UserInputException + * @return void + * @throws UserInputException */ - public static function validateParticipant(UserProfile $user, $field = 'participants') + public static function validateParticipant(UserProfile $user, string $field = 'participants') { // check participant's settings and permissions if (!$user->getPermission('user.conversation.canUseConversation')) { diff --git a/files/lib/data/conversation/ConversationAction.class.php b/files/lib/data/conversation/ConversationAction.class.php index d64d0544..3786c4d4 100644 --- a/files/lib/data/conversation/ConversationAction.class.php +++ b/files/lib/data/conversation/ConversationAction.class.php @@ -34,8 +34,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationEditor[] getObjects() - * @method ConversationEditor getSingleObject() + * @extends AbstractDatabaseObjectAction */ class ConversationAction extends AbstractDatabaseObjectAction implements IClipboardAction, @@ -60,7 +59,6 @@ class ConversationAction extends AbstractDatabaseObjectAction implements /** * @inheritDoc - * @return Conversation */ public function create() { @@ -74,7 +72,7 @@ public function create() $data['participants'] = \count($this->parameters['participants']); } // count attachments - if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) { + if (isset($this->parameters['attachmentHandler'])) { $data['attachments'] = \count($this->parameters['attachmentHandler']); } $conversation = \call_user_func([$this->className, 'create'], $data); @@ -178,7 +176,7 @@ public function delete() } // delete conversations - parent::delete(); + $count = parent::delete(); if (!empty($this->objectIDs)) { // delete notifications @@ -193,6 +191,8 @@ public function delete() UserStorageHandler::getInstance()->reset($participantIDs, 'unreadConversationCount'); } } + + return $count; } /** @@ -354,6 +354,7 @@ public function markAsRead() $returnValues['markAsRead'] = \reset($conversationIDs); } + // @phpstan-ignore return.void return $returnValues; } @@ -394,6 +395,8 @@ public function validateMarkAsRead() /** * Marks all conversations as read. + * + * @return array{markAllAsRead: bool} */ public function markAllAsRead() { @@ -428,6 +431,8 @@ public function markAllAsRead() /** * Validates the markAllAsRead action. + * + * @return void */ public function validateMarkAllAsRead() { @@ -437,8 +442,9 @@ public function validateMarkAllAsRead() /** * Validates parameters to close conversations. * - * @throws PermissionDeniedException - * @throws UserInputException + * @return void + * @throws PermissionDeniedException + * @throws UserInputException */ public function validateClose() { @@ -481,8 +487,9 @@ public function close() /** * Validates parameters to open conversations. * - * @throws PermissionDeniedException - * @throws UserInputException + * @return void + * @throws PermissionDeniedException + * @throws UserInputException */ public function validateOpen() { @@ -525,8 +532,9 @@ public function open() /** * Validates parameters to hide conversations. * - * @throws PermissionDeniedException - * @throws UserInputException + * @return void + * @throws PermissionDeniedException + * @throws UserInputException */ public function validateHideConversation() { @@ -554,7 +562,7 @@ public function validateHideConversation() /** * Hides or restores conversations. * - * @return string[] + * @return array{actionName: string, redirectURL: string} */ public function hideConversation() { @@ -581,6 +589,18 @@ public function validateGetConversations(): void } /** + * @return array{ + * items: array, + * totalCount: int, + * } * @since 5.5 */ public function getConversations(): array @@ -682,6 +702,8 @@ public function getConversations(): array /** * Validates the 'unmarkAll' action. + * + * @return void */ public function validateUnmarkAll() { @@ -690,6 +712,8 @@ public function validateUnmarkAll() /** * Unmarks all conversations. + * + * @return void */ public function unmarkAll() { @@ -701,7 +725,8 @@ public function unmarkAll() /** * Validates parameters to display the 'add participants' form. * - * @throws PermissionDeniedException + * @return void + * @throws PermissionDeniedException */ public function validateGetAddParticipantsForm() { @@ -717,12 +742,19 @@ public function validateGetAddParticipantsForm() /** * Shows the 'add participants' form. * - * @return array + * @return array{ + * excludedSearchValues: string[], + * maxItems: int, + * canAddGroupParticipants: int, + * template: string, + * restrictUserGroupIDs: list, + * } */ public function getAddParticipantsForm() { $restrictUserGroupIDs = []; foreach (UserGroup::getAllGroups() as $group) { + // @phpstan-ignore property.notFound if ($group->canBeAddedAsConversationParticipant) { $restrictUserGroupIDs[] = $group->groupID; } @@ -747,6 +779,8 @@ public function getAddParticipantsForm() /** * Validates parameters to add new participants. + * + * @return void */ public function validateAddParticipants() { @@ -771,7 +805,13 @@ public function validateAddParticipants() /** * Adds new participants. * - * @return array + * @return array{ + * count: int, + * successMessage: string, + * }|array{ + * actionName: 'addParticipants', + * errorMessage: string, + * } */ public function addParticipants() { @@ -873,8 +913,9 @@ public function addParticipants() /** * Validates parameters to remove a participant from a conversation. * - * @throws PermissionDeniedException - * @throws UserInputException + * @return void + * @throws PermissionDeniedException + * @throws UserInputException */ public function validateRemoveParticipant() { @@ -910,6 +951,8 @@ public function validateRemoveParticipant() /** * Removes a participant from a conversation. + * + * @return array{userID: int} */ public function removeParticipant() { @@ -936,6 +979,8 @@ public function removeParticipant() /** * Rebuilds the conversation data of the relevant conversations. + * + * @return void */ public function rebuild() { @@ -982,7 +1027,8 @@ public function rebuild() /** * Validates the parameters to edit a conversation's subject. * - * @throws PermissionDeniedException + * @return void + * @throws PermissionDeniedException */ public function validateEditSubject() { @@ -997,7 +1043,7 @@ public function validateEditSubject() /** * Edits a conversation's subject. * - * @return string[] + * @return array{subject: string} */ public function editSubject() { @@ -1027,11 +1073,9 @@ public function editSubject() /** * Adds conversation modification data. * - * @param Conversation $conversation - * @param string $key - * @param mixed $value + * @return void */ - protected function addConversationData(Conversation $conversation, $key, $value) + protected function addConversationData(Conversation $conversation, string $key, mixed $value) { if (!isset($this->conversationData[$conversation->conversationID])) { $this->conversationData[$conversation->conversationID] = []; @@ -1043,7 +1087,7 @@ protected function addConversationData(Conversation $conversation, $key, $value) /** * Returns conversation data. * - * @return mixed[][] + * @return mixed[][] */ protected function getConversationData() { @@ -1056,6 +1100,7 @@ protected function getConversationData() * Unmarks conversations. * * @param int[] $conversationIDs + * @return void */ protected function unmarkItems(array $conversationIDs = []) { diff --git a/files/lib/data/conversation/ConversationEditor.class.php b/files/lib/data/conversation/ConversationEditor.class.php index dea31864..a088b53f 100644 --- a/files/lib/data/conversation/ConversationEditor.class.php +++ b/files/lib/data/conversation/ConversationEditor.class.php @@ -14,9 +14,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method static Conversation create(array $parameters = []) - * @method Conversation getDecoratedObject() - * @mixin Conversation + * @mixin Conversation + * @extends DatabaseObjectEditor */ class ConversationEditor extends DatabaseObjectEditor { @@ -28,7 +27,7 @@ class ConversationEditor extends DatabaseObjectEditor /** * Adds a new message to this conversation. * - * @param ConversationMessage $message + * @return void */ public function addMessage(ConversationMessage $message) { @@ -43,6 +42,8 @@ public function addMessage(ConversationMessage $message) /** * Resets the participants of this conversation. + * + * @return void */ public function resetParticipants() { @@ -58,9 +59,9 @@ public function resetParticipants() * * @param int[] $participantIDs * @param int[] $invisibleParticipantIDs - * @param string $visibility + * @return void */ - public function updateParticipants(array $participantIDs, array $invisibleParticipantIDs = [], $visibility = 'all') + public function updateParticipants(array $participantIDs, array $invisibleParticipantIDs = [], string $visibility = 'all') { $usernames = []; if (!empty($participantIDs) || !empty($invisibleParticipantIDs)) { @@ -124,6 +125,8 @@ public function updateParticipants(array $participantIDs, array $invisiblePartic /** * Updates participant count. + * + * @return void */ public function updateParticipantCount() { @@ -148,6 +151,8 @@ public function updateParticipantCount() /** * Updates the participant summary of this conversation. + * + * @return void */ public function updateParticipantSummary() { @@ -166,9 +171,9 @@ public function updateParticipantSummary() /** * Removes a participant from this conversation. * - * @param int $userID + * @return void */ - public function removeParticipant($userID) + public function removeParticipant(int $userID) { $sql = "SELECT joinedAt, isInvisible FROM wcf1_conversation_to_user @@ -217,6 +222,8 @@ public function removeParticipant($userID) /** * Updates the first message of this conversation. + * + * @return void */ public function updateFirstMessage() { @@ -236,6 +243,8 @@ public function updateFirstMessage() /** * Updates the last message of this conversation. + * + * @return void */ public function updateLastMessage() { @@ -260,6 +269,7 @@ public function updateLastMessage() * Updates the participant summary of the given conversations. * * @param int[] $conversationIDs + * @return void */ public static function updateParticipantSummaries(array $conversationIDs) { @@ -277,6 +287,7 @@ public static function updateParticipantSummaries(array $conversationIDs) * Updates the participant counts of the given conversations. * * @param int[] $conversationIDs + * @return void */ public static function updateParticipantCounts(array $conversationIDs) { diff --git a/files/lib/data/conversation/ConversationList.class.php b/files/lib/data/conversation/ConversationList.class.php index 8118d6a1..b8783056 100644 --- a/files/lib/data/conversation/ConversationList.class.php +++ b/files/lib/data/conversation/ConversationList.class.php @@ -2,6 +2,7 @@ namespace wcf\data\conversation; +use wcf\data\DatabaseObjectDecorator; use wcf\data\DatabaseObjectList; /** @@ -11,11 +12,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method Conversation current() - * @method Conversation[] getObjects() - * @method Conversation|null getSingleObject() - * @method Conversation|null search($objectID) - * @property Conversation[] $objects + * @template TDatabaseObject of Conversation|DatabaseObjectDecorator = Conversation + * @extends DatabaseObjectList */ class ConversationList extends DatabaseObjectList { diff --git a/files/lib/data/conversation/ConversationParticipantList.class.php b/files/lib/data/conversation/ConversationParticipantList.class.php index f43944d0..f2d44e79 100644 --- a/files/lib/data/conversation/ConversationParticipantList.class.php +++ b/files/lib/data/conversation/ConversationParticipantList.class.php @@ -29,11 +29,9 @@ class ConversationParticipantList extends UserProfileList /** * Creates a new ConversationParticipantList object. * - * @param int $conversationID - * @param int $userID * @param bool $isAuthor true if given user is the author of this conversation */ - public function __construct($conversationID, $userID = 0, $isAuthor = false) + public function __construct(int $conversationID, int $userID = 0, bool $isAuthor = false) { parent::__construct(); diff --git a/files/lib/data/conversation/FeedConversation.class.php b/files/lib/data/conversation/FeedConversation.class.php index fc7b097a..5f43ee66 100644 --- a/files/lib/data/conversation/FeedConversation.class.php +++ b/files/lib/data/conversation/FeedConversation.class.php @@ -13,8 +13,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method Conversation getDecoratedObject() - * @mixin Conversation + * @mixin Conversation + * @extends DatabaseObjectDecorator * @deprecated 6.1 */ class FeedConversation extends DatabaseObjectDecorator implements IFeedEntry diff --git a/files/lib/data/conversation/FeedConversationList.class.php b/files/lib/data/conversation/FeedConversationList.class.php index 63e280c8..e90b60df 100644 --- a/files/lib/data/conversation/FeedConversationList.class.php +++ b/files/lib/data/conversation/FeedConversationList.class.php @@ -11,11 +11,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method FeedConversation current() - * @method FeedConversation[] getObjects() - * @method FeedConversation|null getSingleObject() - * @method FeedConversation|null search($objectID) - * @property FeedConversation[] $objects + * @extends ConversationList * @deprecated 6.1 */ class FeedConversationList extends ConversationList diff --git a/files/lib/data/conversation/UserConversationList.class.php b/files/lib/data/conversation/UserConversationList.class.php index 331805aa..f4e0fc20 100644 --- a/files/lib/data/conversation/UserConversationList.class.php +++ b/files/lib/data/conversation/UserConversationList.class.php @@ -16,11 +16,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ViewableConversation current() - * @method ViewableConversation[] getObjects() - * @method ViewableConversation|null getSingleObject() - * @method ViewableConversation|null search($objectID) - * @property ViewableConversation[] $objects + * @extends ConversationList */ class UserConversationList extends ConversationList { @@ -119,7 +115,7 @@ public function __construct($userID, $filter = '', $labelID = 0) /** * Sets the label list of the user the conversations belong to. * - * @param ConversationLabelList $labelList + * @return void */ public function setLabelList(ConversationLabelList $labelList) { diff --git a/files/lib/data/conversation/ViewableConversation.class.php b/files/lib/data/conversation/ViewableConversation.class.php index 6a7126ea..75b27a90 100644 --- a/files/lib/data/conversation/ViewableConversation.class.php +++ b/files/lib/data/conversation/ViewableConversation.class.php @@ -18,34 +18,34 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method Conversation getDecoratedObject() - * @mixin Conversation - * @property-read int|null $otherParticipantID - * @property-read string|null $otherParticipant + * @mixin Conversation + * @property-read ?int $otherParticipantID + * @property-read ?string $otherParticipant + * @extends DatabaseObjectDecorator */ class ViewableConversation extends DatabaseObjectDecorator { /** * participant summary - * @var string + * @var User[]|null */ protected $__participantSummary; /** * user profile object - * @var UserProfile + * @var ?UserProfile */ protected $userProfile; /** * last poster's profile - * @var UserProfile + * @var ?UserProfile */ protected $lastPosterProfile; /** * other participant's profile - * @var UserProfile + * @var ?UserProfile */ protected $otherParticipantProfile; @@ -63,7 +63,7 @@ class ViewableConversation extends DatabaseObjectDecorator /** * Returns the user profile object. * - * @return UserProfile + * @return UserProfile */ public function getUserProfile() { @@ -81,7 +81,7 @@ public function getUserProfile() /** * Returns the last poster's profile object. * - * @return UserProfile + * @return UserProfile */ public function getLastPosterProfile() { @@ -99,7 +99,7 @@ public function getLastPosterProfile() /** * Returns the number of pages in this conversation. * - * @return int + * @return int */ public function getPages() { @@ -111,13 +111,13 @@ public function getPages() $messagesPerPage = CONVERSATION_MESSAGES_PER_PAGE; } - return \intval(\ceil(($this->replies + 1) / $messagesPerPage)); + return (int)\ceil(($this->replies + 1) / $messagesPerPage); } /** * Returns a summary of the participants. * - * @return User[] + * @return User[] */ public function getParticipantSummary() { @@ -144,7 +144,7 @@ public function getParticipantSummary() /** * Returns the other participant's profile object. * - * @return UserProfile + * @return UserProfile */ public function getOtherParticipantProfile() { @@ -163,7 +163,7 @@ public function getOtherParticipantProfile() /** * Assigns a label. * - * @param ConversationLabel $label + * @return void */ public function assignLabel(ConversationLabel $label) { @@ -173,7 +173,7 @@ public function assignLabel(ConversationLabel $label) /** * Returns a list of assigned labels. * - * @return ConversationLabel[] + * @return ConversationLabel[] */ public function getAssignedLabels() { @@ -183,9 +183,7 @@ public function getAssignedLabels() /** * Converts a conversation into a viewable conversation. * - * @param Conversation $conversation - * @param ConversationLabelList $labelList - * @return ViewableConversation + * @return ViewableConversation */ public static function getViewableConversation(Conversation $conversation, ?ConversationLabelList $labelList = null) { diff --git a/files/lib/data/conversation/label/ConversationLabel.class.php b/files/lib/data/conversation/label/ConversationLabel.class.php index e3b9a87e..f81ee91c 100644 --- a/files/lib/data/conversation/label/ConversationLabel.class.php +++ b/files/lib/data/conversation/label/ConversationLabel.class.php @@ -40,10 +40,9 @@ class ConversationLabel extends DatabaseObject /** * Returns a list of conversation labels for given user id. * - * @param int $userID - * @return ConversationLabelList + * @return ConversationLabelList */ - public static function getLabelsByUser($userID = null) + public static function getLabelsByUser(?int $userID = null) { if ($userID === null) { $userID = WCF::getUser()->userID; @@ -59,7 +58,7 @@ public static function getLabelsByUser($userID = null) /** * Returns a list of available CSS class names. * - * @return string[] + * @return string[] */ public static function getLabelCssClassNames() { diff --git a/files/lib/data/conversation/label/ConversationLabelAction.class.php b/files/lib/data/conversation/label/ConversationLabelAction.class.php index ac4a3c3e..8aa9f91f 100644 --- a/files/lib/data/conversation/label/ConversationLabelAction.class.php +++ b/files/lib/data/conversation/label/ConversationLabelAction.class.php @@ -13,9 +13,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationLabel create() - * @method ConversationLabelEditor[] getObjects() - * @method ConversationLabelEditor getSingleObject() + * @extends AbstractDatabaseObjectAction */ class ConversationLabelAction extends AbstractDatabaseObjectAction { diff --git a/files/lib/data/conversation/label/ConversationLabelEditor.class.php b/files/lib/data/conversation/label/ConversationLabelEditor.class.php index 9b1d3af0..735918ac 100644 --- a/files/lib/data/conversation/label/ConversationLabelEditor.class.php +++ b/files/lib/data/conversation/label/ConversationLabelEditor.class.php @@ -11,9 +11,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method static ConversationLabel create(array $parameters = []) - * @method ConversationLabel getDecoratedObject() - * @mixin ConversationLabel + * @mixin ConversationLabel + * @extends DatabaseObjectEditor */ class ConversationLabelEditor extends DatabaseObjectEditor { diff --git a/files/lib/data/conversation/label/ConversationLabelList.class.php b/files/lib/data/conversation/label/ConversationLabelList.class.php index b99786e1..5d7fd5f8 100644 --- a/files/lib/data/conversation/label/ConversationLabelList.class.php +++ b/files/lib/data/conversation/label/ConversationLabelList.class.php @@ -11,11 +11,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationLabel current() - * @method ConversationLabel[] getObjects() - * @method ConversationLabel|null getSingleObject() - * @method ConversationLabel|null search($objectID) - * @property ConversationLabel[] $objects + * @extends DatabaseObjectList */ class ConversationLabelList extends DatabaseObjectList { diff --git a/files/lib/data/conversation/message/ConversationMessage.class.php b/files/lib/data/conversation/message/ConversationMessage.class.php index 96f13a58..214fdfcc 100644 --- a/files/lib/data/conversation/message/ConversationMessage.class.php +++ b/files/lib/data/conversation/message/ConversationMessage.class.php @@ -41,7 +41,7 @@ class ConversationMessage extends DatabaseObject implements IMessage, IEmbeddedM /** * conversation object - * @var Conversation + * @var ?Conversation */ protected $conversation; @@ -71,10 +71,9 @@ public function getSimplifiedFormattedMessage(): string /** * Assigns and returns the embedded attachments. * - * @param bool $ignoreCache - * @return null|GroupedAttachmentList + * @return ?GroupedAttachmentList */ - public function getAttachments($ignoreCache = false) + public function getAttachments(bool $ignoreCache = false) { if ($this->attachments || $ignoreCache) { $attachmentList = new GroupedAttachmentList('com.woltlab.wcf.conversation.message'); @@ -108,7 +107,7 @@ public function getExcerpt($maxLength = 255): string * * @param string $mimeType Either 'text/plain' or 'text/html' */ - public function getMailText($mimeType = 'text/plain'): string + public function getMailText(string $mimeType = 'text/plain'): string { if ($this->hasEmbeddedObjects) { MessageEmbeddedObjectManager::getInstance()->loadObjects( @@ -134,7 +133,7 @@ public function getMailText($mimeType = 'text/plain'): string /** * Returns the conversation of this message. * - * @return Conversation + * @return ?Conversation */ public function getConversation() { @@ -148,7 +147,7 @@ public function getConversation() /** * Sets the conversation of this message. * - * @param Conversation $conversation + * @return void */ public function setConversation(Conversation $conversation) { diff --git a/files/lib/data/conversation/message/ConversationMessageAction.class.php b/files/lib/data/conversation/message/ConversationMessageAction.class.php index f7617e88..d0655c4d 100644 --- a/files/lib/data/conversation/message/ConversationMessageAction.class.php +++ b/files/lib/data/conversation/message/ConversationMessageAction.class.php @@ -41,8 +41,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationMessageEditor[] getObjects() - * @method ConversationMessageEditor getSingleObject() + * @extends AbstractDatabaseObjectAction + * @implements IAttachmentMessageQuickReplyAction */ class ConversationMessageAction extends AbstractDatabaseObjectAction implements IAttachmentMessageQuickReplyAction, @@ -72,7 +72,6 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements /** * @inheritDoc - * @return ConversationMessage */ public function create() { @@ -81,7 +80,7 @@ public function create() } // count attachments - if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) { + if (isset($this->parameters['attachmentHandler'])) { $this->parameters['data']['attachments'] = \count($this->parameters['attachmentHandler']); } @@ -103,7 +102,6 @@ public function create() } // create message - /** @var ConversationMessage $message */ $message = parent::create(); $messageEditor = new ConversationMessageEditor($message); @@ -157,7 +155,7 @@ public function create() ); // update attachments - if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) { + if (isset($this->parameters['attachmentHandler'])) { /** @noinspection PhpUndefinedMethodInspection */ $this->parameters['attachmentHandler']->updateObjectID($message->messageID); } @@ -202,7 +200,7 @@ public function create() public function update() { // count attachments - if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) { + if (isset($this->parameters['attachmentHandler'])) { $this->parameters['data']['attachments'] = \count($this->parameters['attachmentHandler']); } @@ -318,6 +316,7 @@ public function quickReply() $returnValues = QuickReplyManager::getInstance()->createMessage( $this, $this->parameters, + // @phpstan-ignore argument.type ConversationAction::class, CONVERSATION_LIST_DEFAULT_SORT_ORDER, 'conversationMessageList' @@ -490,8 +489,6 @@ public function save() */ public function validateContainer(DatabaseObject $container) { - /** @var Conversation $container */ - if (!$container->conversationID) { throw new UserInputException('objectID'); } @@ -547,10 +544,8 @@ public function validateMessage(DatabaseObject $container, HtmlInputProcessor $h /** * @inheritDoc */ - public function getMessageList(DatabaseObject $container, $lastMessageTime) + public function getMessageList(DatabaseObject $container, int $lastMessageTime) { - /** @var Conversation $container */ - $messageList = new ViewableConversationMessageList(); $messageList->setConversation($container); $messageList->getConditionBuilder() @@ -568,8 +563,6 @@ public function getMessageList(DatabaseObject $container, $lastMessageTime) */ public function getPageNo(DatabaseObject $container) { - /** @var Conversation $container */ - $sql = "SELECT COUNT(*) AS count FROM wcf1_conversation_message WHERE conversationID = ?"; @@ -585,7 +578,6 @@ public function getPageNo(DatabaseObject $container) */ public function getRedirectUrl(DatabaseObject $container, DatabaseObject $message) { - /** @var ConversationMessage $message */ return $message->getLink(); } @@ -600,7 +592,7 @@ public function getAttachmentHandler(DatabaseObject $container) /** * @inheritDoc */ - public function getHtmlInputProcessor($message = null, $objectID = 0) + public function getHtmlInputProcessor(?string $message = null, int $objectID = 0) { if ($message === null) { return $this->htmlInputProcessor; diff --git a/files/lib/data/conversation/message/ConversationMessageEditor.class.php b/files/lib/data/conversation/message/ConversationMessageEditor.class.php index 4d0c62cb..c684752f 100644 --- a/files/lib/data/conversation/message/ConversationMessageEditor.class.php +++ b/files/lib/data/conversation/message/ConversationMessageEditor.class.php @@ -11,9 +11,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method static ConversationMessage create(array $parameters = []) - * @method ConversationMessage getDecoratedObject() - * @mixin ConversationMessage + * @mixin ConversationMessage + * @extends DatabaseObjectEditor */ class ConversationMessageEditor extends DatabaseObjectEditor { diff --git a/files/lib/data/conversation/message/ConversationMessageList.class.php b/files/lib/data/conversation/message/ConversationMessageList.class.php index 20b1990e..331f4793 100644 --- a/files/lib/data/conversation/message/ConversationMessageList.class.php +++ b/files/lib/data/conversation/message/ConversationMessageList.class.php @@ -2,6 +2,7 @@ namespace wcf\data\conversation\message; +use wcf\data\DatabaseObjectDecorator; use wcf\data\DatabaseObjectList; /** @@ -11,11 +12,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationMessage current() - * @method ConversationMessage[] getObjects() - * @method ConversationMessage|null getSingleObject() - * @method ConversationMessage|null search($objectID) - * @property ConversationMessage[] $objects + * @template TDatabaseObject of ConversationMessage|DatabaseObjectDecorator = ConversationMessage + * @extends DatabaseObjectList */ class ConversationMessageList extends DatabaseObjectList { diff --git a/files/lib/data/conversation/message/SearchResultConversationMessage.class.php b/files/lib/data/conversation/message/SearchResultConversationMessage.class.php index 342e4dee..58494c43 100644 --- a/files/lib/data/conversation/message/SearchResultConversationMessage.class.php +++ b/files/lib/data/conversation/message/SearchResultConversationMessage.class.php @@ -14,7 +14,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @property-read string|null $subject + * @property-read ?string $subject */ class SearchResultConversationMessage extends ViewableConversationMessage implements ISearchResultObject { diff --git a/files/lib/data/conversation/message/SearchResultConversationMessageList.class.php b/files/lib/data/conversation/message/SearchResultConversationMessageList.class.php index 365dc8f3..3b915798 100644 --- a/files/lib/data/conversation/message/SearchResultConversationMessageList.class.php +++ b/files/lib/data/conversation/message/SearchResultConversationMessageList.class.php @@ -9,11 +9,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method SearchResultConversationMessage current() - * @method SearchResultConversationMessage[] getObjects() - * @method SearchResultConversationMessage|null getSingleObject() - * @method SearchResultConversationMessage|null search($objectID) - * @property SearchResultConversationMessage[] $objects + * @extends SimplifiedViewableConversationMessageList */ class SearchResultConversationMessageList extends SimplifiedViewableConversationMessageList { diff --git a/files/lib/data/conversation/message/SimplifiedViewableConversationMessageList.class.php b/files/lib/data/conversation/message/SimplifiedViewableConversationMessageList.class.php index 3edaf7a4..06350305 100644 --- a/files/lib/data/conversation/message/SimplifiedViewableConversationMessageList.class.php +++ b/files/lib/data/conversation/message/SimplifiedViewableConversationMessageList.class.php @@ -9,6 +9,9 @@ * @author Marcel Werk * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License + * + * @template TDatabaseObject of ViewableConversationMessage = ViewableConversationMessage + * @extends ViewableConversationMessageList */ class SimplifiedViewableConversationMessageList extends ViewableConversationMessageList { diff --git a/files/lib/data/conversation/message/ViewableConversationMessage.class.php b/files/lib/data/conversation/message/ViewableConversationMessage.class.php index a030ba70..5db50c28 100644 --- a/files/lib/data/conversation/message/ViewableConversationMessage.class.php +++ b/files/lib/data/conversation/message/ViewableConversationMessage.class.php @@ -13,8 +13,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationMessage getDecoratedObject() - * @mixin ConversationMessage + * @mixin ConversationMessage + * @extends DatabaseObjectDecorator */ class ViewableConversationMessage extends DatabaseObjectDecorator { diff --git a/files/lib/data/conversation/message/ViewableConversationMessageList.class.php b/files/lib/data/conversation/message/ViewableConversationMessageList.class.php index 34c02ee3..d690e870 100644 --- a/files/lib/data/conversation/message/ViewableConversationMessageList.class.php +++ b/files/lib/data/conversation/message/ViewableConversationMessageList.class.php @@ -15,11 +15,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ViewableConversationMessage current() - * @method ViewableConversationMessage[] getObjects() - * @method ViewableConversationMessage|null getSingleObject() - * @method ViewableConversationMessage|null search($objectID) - * @property ViewableConversationMessage[] $objects + * @template TDatabaseObject of ViewableConversationMessage = ViewableConversationMessage + * @extends ConversationMessageList */ class ViewableConversationMessageList extends ConversationMessageList { @@ -47,7 +44,7 @@ class ViewableConversationMessageList extends ConversationMessageList /** * attachment list - * @var GroupedAttachmentList + * @var ?GroupedAttachmentList */ protected $attachmentList; @@ -121,6 +118,8 @@ public function readObjects() /** * Reads the embedded objects of the messages in the list. + * + * @return void */ public function readEmbeddedObjects() { @@ -139,6 +138,8 @@ public function readEmbeddedObjects() /** * Reads the list of attachments. + * + * @return void */ public function readAttachments() { @@ -153,7 +154,7 @@ public function readAttachments() /** * Returns the max post time. * - * @return int + * @return int */ public function getMaxPostTime() { @@ -163,7 +164,7 @@ public function getMaxPostTime() /** * Returns the list of attachments. * - * @return GroupedAttachmentList + * @return ?GroupedAttachmentList */ public function getAttachmentList() { @@ -173,9 +174,9 @@ public function getAttachmentList() /** * Enables/disables the loading of attachments. * - * @param bool $enable + * @return void */ - public function enableAttachmentLoading($enable = true) + public function enableAttachmentLoading(bool $enable = true) { $this->attachmentLoading = $enable; } @@ -183,9 +184,9 @@ public function enableAttachmentLoading($enable = true) /** * Enables/disables the loading of embedded objects. * - * @param bool $enable + * @return void */ - public function enableEmbeddedObjectLoading($enable = true) + public function enableEmbeddedObjectLoading(bool $enable = true) { $this->embeddedObjectLoading = $enable; } @@ -193,7 +194,7 @@ public function enableEmbeddedObjectLoading($enable = true) /** * Sets active conversation. * - * @param Conversation $conversation + * @return void */ public function setConversation(Conversation $conversation) { diff --git a/files/lib/data/modification/log/ConversationLogModificationLogList.class.php b/files/lib/data/modification/log/ConversationLogModificationLogList.class.php index c4ac1811..dc09772c 100644 --- a/files/lib/data/modification/log/ConversationLogModificationLogList.class.php +++ b/files/lib/data/modification/log/ConversationLogModificationLogList.class.php @@ -2,6 +2,7 @@ namespace wcf\data\modification\log; +use wcf\data\DatabaseObject; use wcf\system\cache\runtime\UserProfileRuntimeCache; use wcf\system\log\modification\ConversationModificationLogHandler; use wcf\system\WCF; @@ -13,18 +14,14 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ViewableConversationModificationLog current() - * @method ViewableConversationModificationLog[] getObjects() - * @method ViewableConversationModificationLog|null getSingleObject() - * @method ViewableConversationModificationLog|null search($objectID) - * @property ViewableConversationModificationLog[] $objects + * @extends ModificationLogList */ class ConversationLogModificationLogList extends ModificationLogList { /** * @inheritDoc */ - public function __construct($conversationID) + public function __construct(int $conversationID) { parent::__construct(); @@ -50,11 +47,13 @@ public function readObjects() " . (!empty($this->sqlOrderBy) ? "ORDER BY " . $this->sqlOrderBy : ''); $statement = WCF::getDB()->prepare($sql, $this->sqlLimit, $this->sqlOffset); $statement->execute($this->getConditionBuilder()->getParameters()); + // @phpstan-ignore assign.propertyType, argument.templateType $this->objects = $statement->fetchObjects(($this->objectClassName ?: $this->className)); // use table index as array index $objects = $userIDs = []; foreach ($this->objects as $object) { + /** @var ModificationLog $object */ $objectID = $object->{$this->getDatabaseTableIndexName()}; $objects[$objectID] = $object; @@ -64,17 +63,16 @@ public function readObjects() $userIDs[] = $object->userID; } } - $this->objectIDs = $this->indexToObject; - $this->objects = $objects; - if (!empty($userIDs)) { + if ($userIDs !== []) { UserProfileRuntimeCache::getInstance()->cacheObjectIDs($userIDs); } - foreach ($this->objects as &$object) { - $object = new ViewableConversationModificationLog($object); - } - unset($object); + $this->objectIDs = $this->indexToObject; + $this->objects = \array_map( + static fn(DatabaseObject $object) => new ViewableConversationModificationLog($object), + $objects + ); } /** diff --git a/files/lib/data/modification/log/ViewableConversationModificationLog.class.php b/files/lib/data/modification/log/ViewableConversationModificationLog.class.php index ce4bbf01..d9f86f70 100644 --- a/files/lib/data/modification/log/ViewableConversationModificationLog.class.php +++ b/files/lib/data/modification/log/ViewableConversationModificationLog.class.php @@ -14,8 +14,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ModificationLog getDecoratedObject() - * @mixin ModificationLog + * @mixin ModificationLog + * @extends DatabaseObjectDecorator */ class ViewableConversationModificationLog extends DatabaseObjectDecorator { @@ -26,7 +26,7 @@ class ViewableConversationModificationLog extends DatabaseObjectDecorator /** * user profile object - * @var UserProfile + * @var ?UserProfile */ protected $userProfile; @@ -46,7 +46,7 @@ public function __toString() /** * Returns the profile object of the user who created the modification entry. * - * @return UserProfile + * @return UserProfile */ public function getUserProfile() { diff --git a/files/lib/form/ConversationAddForm.class.php b/files/lib/form/ConversationAddForm.class.php index f4723f5f..9dfa97db 100644 --- a/files/lib/form/ConversationAddForm.class.php +++ b/files/lib/form/ConversationAddForm.class.php @@ -80,15 +80,15 @@ class ConversationAddForm extends MessageForm /** * draft status - * @var int + * @var bool */ - public $draft = 0; + public $draft = false; /** * true, if participants can add new participants - * @var int + * @var bool */ - public $participantCanInvite = 0; + public $participantCanInvite = false; /** * participants (user ids) @@ -276,7 +276,7 @@ public function save() 'userID' => WCF::getUser()->userID, 'username' => WCF::getUser()->username, 'isDraft' => $this->draft ? 1 : 0, - 'participantCanInvite' => $this->participantCanInvite, + 'participantCanInvite' => $this->participantCanInvite ? 1 : 0, ]); if ($this->draft) { $data['draftData'] = \serialize([ @@ -343,7 +343,7 @@ public function assignVariables() } WCF::getTPL()->assign([ - 'participantCanInvite' => $this->participantCanInvite, + 'participantCanInvite' => $this->participantCanInvite ? 1 : 0, 'participants' => $this->participants, 'participantsData' => $this->getParticipantsData(), 'invisibleParticipants' => $this->invisibleParticipants, @@ -365,7 +365,14 @@ public function show() parent::show(); } - private function getParticipantsData($invisible = false) + /** + * @return list + */ + private function getParticipantsData(bool $invisible = false): array { $result = []; $participants = ArrayUtil::trim(\explode( diff --git a/files/lib/form/ConversationDraftEditForm.class.php b/files/lib/form/ConversationDraftEditForm.class.php index c72b4808..72ba10b3 100644 --- a/files/lib/form/ConversationDraftEditForm.class.php +++ b/files/lib/form/ConversationDraftEditForm.class.php @@ -149,7 +149,7 @@ public function readData() if (empty($_POST)) { $this->text = $this->conversation->getFirstMessage()->message; - $this->participantCanInvite = $this->conversation->participantCanInvite; + $this->participantCanInvite = (bool)$this->conversation->participantCanInvite; $this->subject = $this->conversation->subject; if ($this->conversation->draftData) { diff --git a/files/lib/page/ConversationFeedPage.class.php b/files/lib/page/ConversationFeedPage.class.php index e7dfe701..80ff60a6 100644 --- a/files/lib/page/ConversationFeedPage.class.php +++ b/files/lib/page/ConversationFeedPage.class.php @@ -11,6 +11,8 @@ * @author Alexander Ebert * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License + * + * @extends AbstractFeedPage * @deprecated 6.1 use `ConversationRssFeedPage` instead */ class ConversationFeedPage extends AbstractFeedPage diff --git a/files/lib/page/ConversationListPage.class.php b/files/lib/page/ConversationListPage.class.php index b7e4095f..69c0ac1f 100644 --- a/files/lib/page/ConversationListPage.class.php +++ b/files/lib/page/ConversationListPage.class.php @@ -21,7 +21,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @property UserConversationList $objectList + * @extends SortablePage */ class ConversationListPage extends SortablePage { diff --git a/files/lib/page/ConversationPage.class.php b/files/lib/page/ConversationPage.class.php index 0d58f2bc..931be5f3 100644 --- a/files/lib/page/ConversationPage.class.php +++ b/files/lib/page/ConversationPage.class.php @@ -32,7 +32,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @property ViewableConversationMessageList $objectList + * @extends MultipleLinkPage */ class ConversationPage extends MultipleLinkPage { @@ -365,6 +365,8 @@ public function assignVariables() /** * Calculates the position of a specific post in this conversation. + * + * @return void */ protected function goToPost() { @@ -382,6 +384,8 @@ protected function goToPost() /** * Gets the id of the last post in this conversation and forwards the user to this post. + * + * @return void */ protected function goToLastPost() { @@ -412,6 +416,8 @@ protected function goToLastPost() /** * Forwards the user to the first new message in this conversation. + * + * @return void */ protected function goToFirstNewPost() { diff --git a/files/lib/system/attachment/ConversationMessageAttachmentObjectType.class.php b/files/lib/system/attachment/ConversationMessageAttachmentObjectType.class.php index c6964c20..f4cdfc60 100644 --- a/files/lib/system/attachment/ConversationMessageAttachmentObjectType.class.php +++ b/files/lib/system/attachment/ConversationMessageAttachmentObjectType.class.php @@ -15,7 +15,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationMessage getObject($objectID) + * @extends AbstractAttachmentObjectType */ class ConversationMessageAttachmentObjectType extends AbstractAttachmentObjectType { @@ -142,7 +142,7 @@ public function setPermissions(array $attachments) } } - if (!empty($messageIDs)) { + if ($messageIDs !== []) { $this->cacheObjects($messageIDs); } diff --git a/files/lib/system/cache/runtime/ConversationMessageRuntimeCache.class.php b/files/lib/system/cache/runtime/ConversationMessageRuntimeCache.class.php index 82a1c363..303ae745 100644 --- a/files/lib/system/cache/runtime/ConversationMessageRuntimeCache.class.php +++ b/files/lib/system/cache/runtime/ConversationMessageRuntimeCache.class.php @@ -13,9 +13,7 @@ * @license GNU Lesser General Public License * @since 6.1 * - * @method ConversationMessage[] getCachedObjects() - * @method ConversationMessage getObject($objectID) - * @method ConversationMessage[] getObjects(array $objectIDs) + * @extends AbstractRuntimeCache */ class ConversationMessageRuntimeCache extends AbstractRuntimeCache { diff --git a/files/lib/system/cache/runtime/ConversationRuntimeCache.class.php b/files/lib/system/cache/runtime/ConversationRuntimeCache.class.php index 8f5f9a2c..c430ec80 100644 --- a/files/lib/system/cache/runtime/ConversationRuntimeCache.class.php +++ b/files/lib/system/cache/runtime/ConversationRuntimeCache.class.php @@ -13,9 +13,7 @@ * @license GNU Lesser General Public License * @since 3.0 * - * @method Conversation[] getCachedObjects() - * @method Conversation getObject($objectID) - * @method Conversation[] getObjects(array $objectIDs) + * @extends AbstractRuntimeCache */ class ConversationRuntimeCache extends AbstractRuntimeCache { diff --git a/files/lib/system/cache/runtime/UserConversationRuntimeCache.class.php b/files/lib/system/cache/runtime/UserConversationRuntimeCache.class.php index df671b46..34e6ed2c 100644 --- a/files/lib/system/cache/runtime/UserConversationRuntimeCache.class.php +++ b/files/lib/system/cache/runtime/UserConversationRuntimeCache.class.php @@ -14,9 +14,7 @@ * @license GNU Lesser General Public License * @since 3.0 * - * @method Conversation[] getCachedObjects() - * @method Conversation getObject($objectID) - * @method Conversation[] getObjects(array $objectIDs) + * @extends AbstractRuntimeCache */ class UserConversationRuntimeCache extends AbstractRuntimeCache { diff --git a/files/lib/system/clipboard/action/ConversationClipboardAction.class.php b/files/lib/system/clipboard/action/ConversationClipboardAction.class.php index 76268da0..d5add99b 100644 --- a/files/lib/system/clipboard/action/ConversationClipboardAction.class.php +++ b/files/lib/system/clipboard/action/ConversationClipboardAction.class.php @@ -14,6 +14,8 @@ * @author Alexander Ebert * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License + * + * @extends AbstractClipboardAction */ class ConversationClipboardAction extends AbstractClipboardAction { @@ -136,6 +138,7 @@ public function getTypeName() * Returns a list of conversations with user participation. * * @param Conversation[] $conversations + * @return void */ protected function validateParticipation(array $conversations) { diff --git a/files/lib/system/conversation/command/DeleteEmptyConversations.class.php b/files/lib/system/conversation/command/DeleteEmptyConversations.class.php index a0502f23..8c18db1c 100644 --- a/files/lib/system/conversation/command/DeleteEmptyConversations.class.php +++ b/files/lib/system/conversation/command/DeleteEmptyConversations.class.php @@ -18,12 +18,15 @@ */ final class DeleteEmptyConversations { + /** + * @param int[] $conversationIDs + */ public function __construct( public readonly array $conversationIDs, ) { } - public function __invoke() + public function __invoke(): void { // update participants count and participant summary ConversationEditor::updateParticipantCounts($this->conversationIDs); diff --git a/files/lib/system/conversation/command/LeaveConversation.class.php b/files/lib/system/conversation/command/LeaveConversation.class.php index 75db785f..385a6a9b 100644 --- a/files/lib/system/conversation/command/LeaveConversation.class.php +++ b/files/lib/system/conversation/command/LeaveConversation.class.php @@ -19,6 +19,9 @@ */ final class LeaveConversation { + /** + * @param int[] $conversationIDs + */ public function __construct( public readonly array $conversationIDs, public readonly int $hideConversation @@ -33,7 +36,7 @@ public function __construct( } } - public function __invoke() + public function __invoke(): void { $sql = "UPDATE wcf1_conversation_to_user SET hideConversation = ? diff --git a/files/lib/system/endpoint/controller/core/conversations/AssignConversationLabels.class.php b/files/lib/system/endpoint/controller/core/conversations/AssignConversationLabels.class.php index 15b3bba9..f983ad67 100644 --- a/files/lib/system/endpoint/controller/core/conversations/AssignConversationLabels.class.php +++ b/files/lib/system/endpoint/controller/core/conversations/AssignConversationLabels.class.php @@ -65,6 +65,9 @@ public function __invoke(ServerRequestInterface $request, array $variables): Res return new JsonResponse([]); } + /** + * @param int[] $conversationIDs + */ private function removeOldLabels(ConversationLabelList $labelList, array $conversationIDs): void { // remove previous labels (if any) @@ -83,6 +86,10 @@ private function removeOldLabels(ConversationLabelList $labelList, array $conver $statement->execute($conditions->getParameters()); } + /** + * @param int[] $conversationIDs + * @param int[] $labelIDs + */ private function assignLabels(array $conversationIDs, array $labelIDs): void { if ($labelIDs === []) { diff --git a/files/lib/system/endpoint/controller/core/conversations/GetConversationLabels.class.php b/files/lib/system/endpoint/controller/core/conversations/GetConversationLabels.class.php index b9ff88f0..1fbd2e6a 100644 --- a/files/lib/system/endpoint/controller/core/conversations/GetConversationLabels.class.php +++ b/files/lib/system/endpoint/controller/core/conversations/GetConversationLabels.class.php @@ -85,6 +85,10 @@ private function getForm(string $id, ConversationLabelList $labelList, ?int $con ->build(); } + /** + * @param int[] $labelIDs + * @return int[] + */ private function getAssignedLabelIDs(array $labelIDs, ?int $conversationID): array { if ($conversationID === null) { diff --git a/files/lib/system/event/listener/UserGroupAddCanBeAddedAsConversationParticipantListener.class.php b/files/lib/system/event/listener/UserGroupAddCanBeAddedAsConversationParticipantListener.class.php index 752df02f..13af1347 100644 --- a/files/lib/system/event/listener/UserGroupAddCanBeAddedAsConversationParticipantListener.class.php +++ b/files/lib/system/event/listener/UserGroupAddCanBeAddedAsConversationParticipantListener.class.php @@ -24,7 +24,7 @@ class UserGroupAddCanBeAddedAsConversationParticipantListener implements IParame /** * true if group can be added as participant - * @var bool + * @var int */ protected $canBeAddedAsConversationParticipant = 0; @@ -35,7 +35,7 @@ public function execute($eventObj, $className, $eventName, array &$parameters) { $this->eventObj = $eventObj; - if ($this->eventObj instanceof UserGroupEditForm && \is_object($this->eventObj->group)) { + if ($this->eventObj instanceof UserGroupEditForm && $this->eventObj->group !== null) { switch ($this->eventObj->group->groupType) { case UserGroup::EVERYONE: case UserGroup::GUESTS: @@ -49,6 +49,8 @@ public function execute($eventObj, $className, $eventName, array &$parameters) /** * Handles the assignVariables event. + * + * @return void */ protected function assignVariables() { @@ -59,17 +61,23 @@ protected function assignVariables() /** * Handles the readData event. - * This is only called in UserGroupEditForm. + * + * @return void */ protected function readData() { - if (empty($_POST)) { + \assert($this->eventObj instanceof UserGroupEditForm); + + if ($_POST === []) { + // @phpstan-ignore property.notFound $this->canBeAddedAsConversationParticipant = $this->eventObj->group->canBeAddedAsConversationParticipant; } } /** * Handles the readFormParameters event. + * + * @return void */ protected function readFormParameters() { @@ -80,6 +88,8 @@ protected function readFormParameters() /** * Handles the save event. + * + * @return void */ protected function save() { diff --git a/files/lib/system/log/modification/ConversationModificationLogHandler.class.php b/files/lib/system/log/modification/ConversationModificationLogHandler.class.php index 334b1d78..12cd45d5 100644 --- a/files/lib/system/log/modification/ConversationModificationLogHandler.class.php +++ b/files/lib/system/log/modification/ConversationModificationLogHandler.class.php @@ -23,8 +23,8 @@ class ConversationModificationLogHandler extends VoidExtendedModificationLogHand /** * Adds a log entry for newly added conversation participants. * - * @param Conversation $conversation * @param int[] $participantIDs + * @return void */ public function addParticipants(Conversation $conversation, array $participantIDs) { @@ -47,7 +47,7 @@ public function addParticipants(Conversation $conversation, array $participantID /** * Adds a log entry for conversation close. * - * @param Conversation $conversation + * @return void */ public function close(Conversation $conversation) { @@ -57,7 +57,7 @@ public function close(Conversation $conversation) /** * Adds a log entry for conversation open. * - * @param Conversation $conversation + * @return void */ public function open(Conversation $conversation) { @@ -67,7 +67,7 @@ public function open(Conversation $conversation) /** * Adds a log entry for conversation leave. * - * @param Conversation $conversation + * @return void */ public function leave(Conversation $conversation) { @@ -77,10 +77,9 @@ public function leave(Conversation $conversation) /** * Adds a log entry for a removed participant. * - * @param Conversation $conversation - * @param int $userID + * @return void */ - public function removeParticipant(Conversation $conversation, $userID) + public function removeParticipant(Conversation $conversation, int $userID) { $user = new User($userID); $this->add($conversation, 'removeParticipant', [ @@ -92,11 +91,10 @@ public function removeParticipant(Conversation $conversation, $userID) /** * Adds a conversation modification log entry. * - * @param Conversation $conversation - * @param string $action - * @param array $additionalData + * @param mixed[] $additionalData + * @return void */ - public function add(Conversation $conversation, $action, array $additionalData = []) + public function add(Conversation $conversation, string $action, array $additionalData = []) { $this->createLog($action, $conversation->conversationID, null, $additionalData); } @@ -106,6 +104,7 @@ public function add(Conversation $conversation, $action, array $additionalData = * ids. * * @param int[] $objectIDs + * @return void * @deprecated 3.0, use deleteLogs() */ public function remove(array $objectIDs) diff --git a/files/lib/system/moderation/queue/report/ConversationMessageModerationQueueReportHandler.class.php b/files/lib/system/moderation/queue/report/ConversationMessageModerationQueueReportHandler.class.php index 71e05d5c..375260c0 100644 --- a/files/lib/system/moderation/queue/report/ConversationMessageModerationQueueReportHandler.class.php +++ b/files/lib/system/moderation/queue/report/ConversationMessageModerationQueueReportHandler.class.php @@ -41,7 +41,7 @@ class ConversationMessageModerationQueueReportHandler extends AbstractModeration /** * list of conversation message - * @var ConversationMessage[] + * @var array */ protected static $messages = []; @@ -129,10 +129,9 @@ public function isValid($objectID) /** * Returns a conversation message object by message id or null if message id is invalid. * - * @param int $objectID - * @return ConversationMessage + * @return ?ConversationMessage */ - protected function getMessage($objectID) + protected function getMessage(int $objectID) { if (!\array_key_exists($objectID, self::$messages)) { self::$messages[$objectID] = new ConversationMessage($objectID); diff --git a/files/lib/system/search/ConversationMessageSearch.class.php b/files/lib/system/search/ConversationMessageSearch.class.php index f9aab10e..cab3fa87 100644 --- a/files/lib/system/search/ConversationMessageSearch.class.php +++ b/files/lib/system/search/ConversationMessageSearch.class.php @@ -18,21 +18,17 @@ */ final class ConversationMessageSearch extends AbstractSearchProvider { - /** - * @var int - */ - private $conversationID = 0; + private int $conversationID = 0; /** * searched conversation - * @var Conversation */ - private $conversation; + private Conversation $conversation; /** * @var SearchResultConversationMessage[] */ - private $messageCache = []; + private array $messageCache = []; /** * @inheritDoc @@ -50,7 +46,7 @@ public function cacheObjects(array $objectIDs, ?array $additionalData = null): v /** * @inheritDoc */ - public function getAdditionalData(): ?array + public function getAdditionalData(): array { return [ 'conversationID' => $this->conversationID, @@ -104,7 +100,7 @@ public function getSubjectFieldName(): string /** * @inheritDoc */ - public function getConditionBuilder(array $parameters): ?PreparedStatementConditionBuilder + public function getConditionBuilder(array $parameters): PreparedStatementConditionBuilder { $this->readParameters($parameters); @@ -137,7 +133,7 @@ public function isAccessible(): bool */ public function getFormTemplateName(): string { - if ($this->conversation) { + if (isset($this->conversation)) { return 'searchConversationMessage'; } @@ -159,7 +155,7 @@ public function assignVariables(): void } /** - * @inheritDoc + * @param array $parameters */ private function readParameters(array $parameters): void { diff --git a/files/lib/system/user/content/provider/ConversationMessageUserContentProvider.class.php b/files/lib/system/user/content/provider/ConversationMessageUserContentProvider.class.php index dcdf06f1..03fffdb6 100644 --- a/files/lib/system/user/content/provider/ConversationMessageUserContentProvider.class.php +++ b/files/lib/system/user/content/provider/ConversationMessageUserContentProvider.class.php @@ -3,6 +3,7 @@ namespace wcf\system\user\content\provider; use wcf\data\conversation\message\ConversationMessage; +use wcf\data\conversation\message\ConversationMessageList; /** * User content provider for conversation messages. @@ -11,6 +12,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * @since 5.2 + * + * @extends AbstractDatabaseUserContentProvider */ class ConversationMessageUserContentProvider extends AbstractDatabaseUserContentProvider { diff --git a/files/lib/system/user/content/provider/ConversationUserContentProvider.class.php b/files/lib/system/user/content/provider/ConversationUserContentProvider.class.php index 1145d864..980e8758 100644 --- a/files/lib/system/user/content/provider/ConversationUserContentProvider.class.php +++ b/files/lib/system/user/content/provider/ConversationUserContentProvider.class.php @@ -3,6 +3,7 @@ namespace wcf\system\user\content\provider; use wcf\data\conversation\Conversation; +use wcf\data\conversation\ConversationList; /** * User content provider for conversations. @@ -11,6 +12,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * @since 5.2 + * + * @extends AbstractDatabaseUserContentProvider */ class ConversationUserContentProvider extends AbstractDatabaseUserContentProvider { diff --git a/files/lib/system/user/notification/object/ConversationMessageUserNotificationObject.class.php b/files/lib/system/user/notification/object/ConversationMessageUserNotificationObject.class.php index 3ca8b361..fbcd4319 100644 --- a/files/lib/system/user/notification/object/ConversationMessageUserNotificationObject.class.php +++ b/files/lib/system/user/notification/object/ConversationMessageUserNotificationObject.class.php @@ -12,8 +12,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationMessage getDecoratedObject() - * @mixin ConversationMessage + * @mixin ConversationMessage + * @extends DatabaseObjectDecorator */ class ConversationMessageUserNotificationObject extends DatabaseObjectDecorator implements IUserNotificationObject { diff --git a/files/lib/system/user/notification/object/ConversationUserNotificationObject.class.php b/files/lib/system/user/notification/object/ConversationUserNotificationObject.class.php index 5bedbae6..e20b654b 100644 --- a/files/lib/system/user/notification/object/ConversationUserNotificationObject.class.php +++ b/files/lib/system/user/notification/object/ConversationUserNotificationObject.class.php @@ -12,8 +12,8 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method Conversation getDecoratedObject() - * @mixin Conversation + * @mixin Conversation + * @extends DatabaseObjectDecorator */ class ConversationUserNotificationObject extends DatabaseObjectDecorator implements IUserNotificationObject { diff --git a/files/lib/system/worker/ConversationMessageRebuildDataWorker.class.php b/files/lib/system/worker/ConversationMessageRebuildDataWorker.class.php index 97adba35..d92ae3eb 100644 --- a/files/lib/system/worker/ConversationMessageRebuildDataWorker.class.php +++ b/files/lib/system/worker/ConversationMessageRebuildDataWorker.class.php @@ -16,7 +16,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationMessageList getObjectList() + * @extends AbstractRebuildDataWorker */ class ConversationMessageRebuildDataWorker extends AbstractRebuildDataWorker { diff --git a/files/lib/system/worker/ConversationMessageSearchIndexRebuildDataWorker.class.php b/files/lib/system/worker/ConversationMessageSearchIndexRebuildDataWorker.class.php index 7972ef1f..8ae4d47b 100644 --- a/files/lib/system/worker/ConversationMessageSearchIndexRebuildDataWorker.class.php +++ b/files/lib/system/worker/ConversationMessageSearchIndexRebuildDataWorker.class.php @@ -14,7 +14,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationMessageList getObjectList() + * @extends AbstractRebuildDataWorker */ final class ConversationMessageSearchIndexRebuildDataWorker extends AbstractRebuildDataWorker { diff --git a/files/lib/system/worker/ConversationRebuildDataWorker.class.php b/files/lib/system/worker/ConversationRebuildDataWorker.class.php index 0b104101..016de8be 100644 --- a/files/lib/system/worker/ConversationRebuildDataWorker.class.php +++ b/files/lib/system/worker/ConversationRebuildDataWorker.class.php @@ -15,7 +15,7 @@ * @copyright 2001-2019 WoltLab GmbH * @license GNU Lesser General Public License * - * @method ConversationList getObjectList() + * @extends AbstractRebuildDataWorker */ class ConversationRebuildDataWorker extends AbstractRebuildDataWorker { diff --git a/phpstan-ambient.neon b/phpstan-ambient.neon new file mode 100644 index 00000000..db87f942 --- /dev/null +++ b/phpstan-ambient.neon @@ -0,0 +1,7 @@ +parameters: + dynamicConstantNames: + - MODULE_CONVERSATION + - CONVERSATIONS_PER_PAGE + - CONVERSATION_MESSAGES_PER_PAGE + - CONVERSATION_LIST_DEFAULT_SORT_FIELD + - CONVERSATION_LIST_DEFAULT_SORT_ORDER diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..69b765aa --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,13 @@ +includes: + - phpstan-ambient.neon + - ../WCF/phpstan-ambient.neon + +parameters: + level: 6 + paths: + - files + scanFiles: + - constants.php + - ../WCF/constants.php + scanDirectories: + - ../WCF/wcfsetup/install/files