diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000000..c550309f34 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,23 @@ +name: Run PHPStan +on: + push: + branches: + - main + - '[0-9]+.[0-9]+' + pull_request: + branches: + - main + - '[0-9]+.[0-9]+' + +jobs: + phpstan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install DOMjudge + run: .github/jobs/baseinstall.sh admin + - uses: php-actions/phpstan@v3 + with: + configuration: phpstan.dist.neon + path: webapp/src webapp/tests + php_extensions: gd intl mysqli pcntl zip diff --git a/composer.json b/composer.json index 85f2e85897..7a93f3ab6d 100644 --- a/composer.json +++ b/composer.json @@ -107,6 +107,8 @@ "require-dev": { "ext-dom": "*", "dama/doctrine-test-bundle": "^7.0", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-doctrine": "^1.3", "squizlabs/php_codesniffer": "*", "symfony/debug-bundle": "6.3.*", "symfony/maker-bundle": "^1.42", diff --git a/composer.lock b/composer.lock index 0aaa45a905..1649f694f8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fb0e3f844b1f1a6759c293d8cac50833", + "content-hash": "34ea8f7e3c61264830002afe29dbf8f1", "packages": [ { "name": "apalfrey/select2-bootstrap-5-theme", @@ -12244,6 +12244,138 @@ }, "time": "2023-02-07T10:02:27+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.10.22", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "97d694dfd4ceb57bcce4e3b38548f13ea62e4287" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/97d694dfd4ceb57bcce4e3b38548f13ea62e4287", + "reference": "97d694dfd4ceb57bcce4e3b38548f13ea62e4287", + "shasum": "" + }, + "require": { + "php": "^7.2|^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" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2023-06-30T20:04:11+00:00" + }, + { + "name": "phpstan/phpstan-doctrine", + "version": "1.3.40", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-doctrine.git", + "reference": "f741919a720af6f84249abc62befeb15eee7bc88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/f741919a720af6f84249abc62befeb15eee7bc88", + "reference": "f741919a720af6f84249abc62befeb15eee7bc88", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.10.12" + }, + "conflict": { + "doctrine/collections": "<1.0", + "doctrine/common": "<2.7", + "doctrine/mongodb-odm": "<1.2", + "doctrine/orm": "<2.5", + "doctrine/persistence": "<1.3" + }, + "require-dev": { + "composer/semver": "^3.3.2", + "doctrine/annotations": "^1.11.0", + "doctrine/collections": "^1.6", + "doctrine/common": "^2.7 || ^3.0", + "doctrine/dbal": "^2.13.8 || ^3.3.3", + "doctrine/lexer": "^1.2.1", + "doctrine/mongodb-odm": "^1.3 || ^2.1", + "doctrine/orm": "^2.11.0", + "doctrine/persistence": "^1.3.8 || ^2.2.1", + "gedmo/doctrine-extensions": "^3.8", + "nesbot/carbon": "^2.49", + "nikic/php-parser": "^4.13.2", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5.10", + "ramsey/uuid-doctrine": "^1.5.0", + "symfony/cache": "^4.4.35" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Doctrine extensions for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-doctrine/issues", + "source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.40" + }, + "time": "2023-05-11T11:26:04+00:00" + }, { "name": "squizlabs/php_codesniffer", "version": "3.7.2", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000000..fe0361c6c0 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,2066 @@ +parameters: + ignoreErrors: + - + message: "#^Method App\\\\Controller\\\\API\\\\AbstractRestController\\:\\:listActionHelper\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/AbstractRestController.php + + - + message: "#^PHPDoc tag @var for variable \\$objects has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/AbstractRestController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\AccessController\\:\\:getStatusAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/AccessController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\AwardsController\\:\\:getAwardsData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/AwardsController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\AwardsController\\:\\:listAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/AwardsController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\AwardsController\\:\\:singleAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/AwardsController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\BalloonController\\:\\:listAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/BalloonController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\ContestController\\:\\:getContestStateAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/ContestController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\ContestController\\:\\:getStatusAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/ContestController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\GeneralInfoController\\:\\:addProblemAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/GeneralInfoController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\GeneralInfoController\\:\\:getDatabaseConfigurationAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/GeneralInfoController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\GeneralInfoController\\:\\:getInfoAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/GeneralInfoController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\GeneralInfoController\\:\\:getStatusAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/GeneralInfoController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\GeneralInfoController\\:\\:getVersionAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/GeneralInfoController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\GeneralInfoController\\:\\:updateConfigurationAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/GeneralInfoController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:checkVersions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:createJudgehostAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:getExecutableFiles\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:getFilesAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:getJudgeTasksAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:getJudgehostsAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:getJudgetasks\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:getSourceFiles\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:getTestcaseFiles\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:getVersionCommands\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:serializeJudgeTasks\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgehostController\\:\\:updateJudgeHostAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^PHPDoc tag @var for variable \\$judgings has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgehostController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgementTypeController\\:\\:getJudgementTypes\\(\\) has parameter \\$filteredOn with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgementTypeController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgementTypeController\\:\\:getJudgementTypes\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgementTypeController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgementTypeController\\:\\:listAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgementTypeController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\JudgementTypeController\\:\\:singleAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/JudgementTypeController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\ProblemController\\:\\:addProblemAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/ProblemController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\ProblemController\\:\\:addProblemsAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/ProblemController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\ProblemController\\:\\:transformObject\\(\\) has parameter \\$object with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/ProblemController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\ScoreboardController\\:\\:getScoreboardAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/ScoreboardController.php + + - + message: "#^Method App\\\\Controller\\\\API\\\\SubmissionController\\:\\:getSubmissionSourceCodeAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/API/SubmissionController.php + + - + message: "#^Method App\\\\Controller\\\\BaseController\\:\\:buildDeleteTree\\(\\) has parameter \\$entities with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/BaseController.php + + - + message: "#^Method App\\\\Controller\\\\BaseController\\:\\:buildDeleteTree\\(\\) has parameter \\$relations with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/BaseController.php + + - + message: "#^Method App\\\\Controller\\\\BaseController\\:\\:buildDeleteTree\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/BaseController.php + + - + message: "#^Method App\\\\Controller\\\\BaseController\\:\\:commitDeleteEntity\\(\\) has parameter \\$primaryKeyData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/BaseController.php + + - + message: "#^Method App\\\\Controller\\\\BaseController\\:\\:deleteEntities\\(\\) has parameter \\$entities with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/BaseController.php + + - + message: "#^Method App\\\\Controller\\\\BaseController\\:\\:getDatabaseRelations\\(\\) has parameter \\$files with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/BaseController.php + + - + message: "#^Method App\\\\Controller\\\\BaseController\\:\\:getDatabaseRelations\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/BaseController.php + + - + message: "#^Method App\\\\Controller\\\\BaseController\\:\\:getDependentEntities\\(\\) has parameter \\$relations with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/BaseController.php + + - + message: "#^Method App\\\\Controller\\\\BaseController\\:\\:getDependentEntities\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/BaseController.php + + - + message: "#^PHPDoc tag @var for variable \\$delayedJudgings has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/AnalysisController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\BalloonController\\:\\:areDefault\\(\\) has parameter \\$defaultCategories with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/BalloonController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\BalloonController\\:\\:areDefault\\(\\) has parameter \\$filters with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/BalloonController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\ClarificationController\\:\\:getClarificationFormData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/ClarificationController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\ContestController\\:\\:judgeRemaining\\(\\) has parameter \\$judgings with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/ContestController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\ExecutableController\\:\\:dataForEditor\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/ExecutableController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\LanguageController\\:\\:judgeRemaining\\(\\) has parameter \\$judgings with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/LanguageController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\ProblemController\\:\\:addTestcasesToZip\\(\\) has parameter \\$testcases with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/ProblemController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\ProblemController\\:\\:judgeRemaining\\(\\) has parameter \\$judgings with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/ProblemController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\RejudgingController\\:\\:generateFlashMessagesForSkippedJudgings\\(\\) has parameter \\$skipped with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/RejudgingController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\RejudgingController\\:\\:getStats\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/RejudgingController.php + + - + message: "#^PHPDoc tag @var for variable \\$judgings has no value type specified in iterable type array\\.$#" + count: 2 + path: webapp/src/Controller/Jury/RejudgingController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\SubmissionController\\:\\:determineFileChanged\\(\\) has parameter \\$files with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/SubmissionController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\SubmissionController\\:\\:determineFileChanged\\(\\) has parameter \\$oldFiles with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/SubmissionController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\SubmissionController\\:\\:determineFileChanged\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/SubmissionController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\SubmissionController\\:\\:judgeRemaining\\(\\) has parameter \\$judgings with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/SubmissionController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\SubmissionController\\:\\:maybeGetErrors\\(\\) has parameter \\$allErrors with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/SubmissionController.php + + - + message: "#^Method App\\\\Controller\\\\Jury\\\\TeamCategoryController\\:\\:judgeRemaining\\(\\) has parameter \\$judgings with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Controller/Jury/TeamCategoryController.php + + - + message: "#^Method App\\\\DataFixtures\\\\Test\\\\RejudgingStatesFixture\\:\\:rejudgingStages\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/DataFixtures/Test/RejudgingStatesFixture.php + + - + message: "#^Method App\\\\Entity\\\\Clarification\\:\\:getExternalRelationships\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Clarification.php + + - + message: "#^Method App\\\\Entity\\\\Contest\\:\\:getDataForJuryInterface\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Contest.php + + - + message: "#^Method App\\\\Entity\\\\Contest\\:\\:getState\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Contest.php + + - + message: "#^Method App\\\\Entity\\\\ExternalRelationshipEntityInterface\\:\\:getExternalRelationships\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/ExternalRelationshipEntityInterface.php + + - + message: "#^Method App\\\\Entity\\\\ExternalSourceWarning\\:\\:getContent\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/ExternalSourceWarning.php + + - + message: "#^Method App\\\\Entity\\\\ExternalSourceWarning\\:\\:setContent\\(\\) has parameter \\$content with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/ExternalSourceWarning.php + + - + message: "#^Property App\\\\Entity\\\\ExternalSourceWarning\\:\\:\\$content type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/ExternalSourceWarning.php + + - + message: "#^Method App\\\\Entity\\\\InternalError\\:\\:getDisabled\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/InternalError.php + + - + message: "#^Method App\\\\Entity\\\\InternalError\\:\\:setDisabled\\(\\) has parameter \\$disabled with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/InternalError.php + + - + message: "#^Property App\\\\Entity\\\\InternalError\\:\\:\\$disabled type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/InternalError.php + + - + message: "#^Method App\\\\Entity\\\\Judging\\:\\:getExternalRelationships\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Judging.php + + - + message: "#^Method App\\\\Entity\\\\Judging\\:\\:getJudgehosts\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Judging.php + + - + message: "#^Method App\\\\Entity\\\\Language\\:\\:getExtensions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Language.php + + - + message: "#^Method App\\\\Entity\\\\Language\\:\\:setExtensions\\(\\) has parameter \\$extensions with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Language.php + + - + message: "#^Method App\\\\Entity\\\\Submission\\:\\:getExpectedResults\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Submission.php + + - + message: "#^Method App\\\\Entity\\\\Submission\\:\\:getExternalRelationships\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Submission.php + + - + message: "#^Method App\\\\Entity\\\\Submission\\:\\:setExpectedResults\\(\\) has parameter \\$expectedResults with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Submission.php + + - + message: "#^Property App\\\\Entity\\\\Submission\\:\\:\\$expected_results type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Submission.php + + - + message: "#^Method App\\\\Entity\\\\Team\\:\\:getExternalRelationships\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Team.php + + - + message: "#^Method App\\\\Entity\\\\Team\\:\\:getGroupIds\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/Team.php + + - + message: "#^Method App\\\\Entity\\\\User\\:\\:__unserialize\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/User.php + + - + message: "#^Method App\\\\Entity\\\\User\\:\\:getExternalRelationships\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/User.php + + - + message: "#^Method App\\\\Entity\\\\User\\:\\:getRoleList\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/User.php + + - + message: "#^Method App\\\\Entity\\\\User\\:\\:getUserRoles\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Entity/User.php + + - + message: "#^Method App\\\\FosRestBundle\\\\FlattenExceptionHandler\\:\\:convertToArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/FosRestBundle/FlattenExceptionHandler.php + + - + message: "#^Method App\\\\FosRestBundle\\\\FlattenExceptionHandler\\:\\:getSubscribingMethods\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/FosRestBundle/FlattenExceptionHandler.php + + - + message: "#^Method App\\\\FosRestBundle\\\\FlattenExceptionHandler\\:\\:serializeToJson\\(\\) has parameter \\$type with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/FosRestBundle/FlattenExceptionHandler.php + + - + message: "#^Method App\\\\FosRestBundle\\\\FlattenExceptionHandler\\:\\:serializeToJson\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/FosRestBundle/FlattenExceptionHandler.php + + - + message: "#^Method App\\\\Helpers\\\\OrdinalArray\\:\\:__construct\\(\\) has parameter \\$items with no value type specified in iterable type Traversable\\.$#" + count: 1 + path: webapp/src/Helpers/OrdinalArray.php + + - + message: "#^Method App\\\\Helpers\\\\OrdinalArray\\:\\:__construct\\(\\) has parameter \\$items with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Helpers/OrdinalArray.php + + - + message: "#^Method App\\\\Helpers\\\\OrdinalArray\\:\\:__construct\\(\\) has parameter \\$items with no value type specified in iterable type array\\|Traversable\\.$#" + count: 1 + path: webapp/src/Helpers/OrdinalArray.php + + - + message: "#^Method App\\\\Serializer\\\\ContestProblemVisitor\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Serializer/ContestProblemVisitor.php + + - + message: "#^Method App\\\\Serializer\\\\ContestVisitor\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Serializer/ContestVisitor.php + + - + message: "#^Method App\\\\Serializer\\\\SetExternalIdVisitor\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Serializer/SetExternalIdVisitor.php + + - + message: "#^Method App\\\\Serializer\\\\SubmissionVisitor\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Serializer/SubmissionVisitor.php + + - + message: "#^Method App\\\\Serializer\\\\TeamAffiliationVisitor\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Serializer/TeamAffiliationVisitor.php + + - + message: "#^Method App\\\\Serializer\\\\TeamVisitor\\:\\:getSubscribedEvents\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Serializer/TeamVisitor.php + + - + message: "#^Method App\\\\Service\\\\AwardService\\:\\:getAwards\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/AwardService.php + + - + message: "#^Property App\\\\Service\\\\AwardService\\:\\:\\$awardCache type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/AwardService.php + + - + message: "#^Method App\\\\Service\\\\BalloonService\\:\\:collectBalloonTable\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/BalloonService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkAdminPass\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkAffiliations\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkAllExternalIdentifiers\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkContestActive\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkContestBanners\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkContestsValidate\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkDebugDisabled\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkDefaultCompareRunExist\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkExternalIdentifiers\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkHashTime\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkLanguagesValidate\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkMysqlSettings\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkPhpExtensions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkPhpSettings\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkPhpVersion\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkProblemsValidate\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkScriptFilesizevsMemoryLimit\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkSelfRegistration\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkTeamDuplicateNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkTeamPhotos\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:checkTmpdirWritable\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\CheckConfigService\\:\\:runAll\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^PHPDoc tag @var for variable \\$tcs_size has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/CheckConfigService.php + + - + message: "#^Method App\\\\Service\\\\ConfigurationService\\:\\:addOptions\\(\\) has parameter \\$item with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ConfigurationService.php + + - + message: "#^Method App\\\\Service\\\\ConfigurationService\\:\\:addOptions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ConfigurationService.php + + - + message: "#^Method App\\\\Service\\\\ConfigurationService\\:\\:all\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ConfigurationService.php + + - + message: "#^Method App\\\\Service\\\\ConfigurationService\\:\\:findExecutableOptions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ConfigurationService.php + + - + message: "#^Method App\\\\Service\\\\ConfigurationService\\:\\:getConfigSpecification\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ConfigurationService.php + + - + message: "#^Method App\\\\Service\\\\ConfigurationService\\:\\:getDbValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ConfigurationService.php + + - + message: "#^Method App\\\\Service\\\\ConfigurationService\\:\\:saveChanges\\(\\) has parameter \\$dataToSet with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ConfigurationService.php + + - + message: "#^Property App\\\\Service\\\\ConfigurationService\\:\\:\\$dbConfigCache type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ConfigurationService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:apiRelativeUrl\\(\\) has parameter \\$params with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:getAssetFiles\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:getContestStats\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:getDocLinks\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:getProblemsForExecutable\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:getTwigDataForProblemsAction\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:getUnreadClarifications\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:getUpdates\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:getVerdicts\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:internalApiRequest\\(\\) has parameter \\$queryOrPostData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:parseMetadata\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:printFile\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\DOMJudgeService\\:\\:setInternalError\\(\\) has parameter \\$disabled with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/DOMJudgeService.php + + - + message: "#^Method App\\\\Service\\\\EventLogService\\:\\:getExternalIds\\(\\) has parameter \\$ids with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/EventLogService.php + + - + message: "#^Method App\\\\Service\\\\EventLogService\\:\\:getExternalIds\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/EventLogService.php + + - + message: "#^Method App\\\\Service\\\\EventLogService\\:\\:hasAllDependentObjectEvents\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/EventLogService.php + + - + message: "#^Method App\\\\Service\\\\EventLogService\\:\\:insertEvent\\(\\) has parameter \\$content with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/EventLogService.php + + - + message: "#^Method App\\\\Service\\\\EventLogService\\:\\:insertEvents\\(\\) has parameter \\$contents with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/EventLogService.php + + - + message: "#^Method App\\\\Service\\\\EventLogService\\:\\:insertEvents\\(\\) has parameter \\$endpointIds with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/EventLogService.php + + - + message: "#^Property App\\\\Service\\\\EventLogService\\:\\:\\$entityToEndpoint type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/EventLogService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:addOrUpdateWarning\\(\\) has parameter \\$content with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:addPendingEvent\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:compareOrCreateValues\\(\\) has parameter \\$extraDiff with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:compareOrCreateValues\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:getEventFeedFormat\\(\\) has parameter \\$event with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:import\\(\\) has parameter \\$eventsToSkip with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:importClarification\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:importEvent\\(\\) has parameter \\$event with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:importEvent\\(\\) has parameter \\$eventsToSKip with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:importFromCcsApi\\(\\) has parameter \\$eventsToSkip with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:importFromContestArchive\\(\\) has parameter \\$eventsToSkip with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:importJudgement\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:importJudgementType\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:importRun\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:importSubmission\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:validateAndUpdateContest\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:validateAndUpdateGroup\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:validateAndUpdateOrganization\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:validateAndUpdateProblem\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:validateAndUpdateTeam\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:validateLanguage\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ExternalContestSourceService\\:\\:warningIfUnsupported\\(\\) has parameter \\$supportedActions with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Property App\\\\Service\\\\ExternalContestSourceService\\:\\:\\$cachedApiInfoData type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Property App\\\\Service\\\\ExternalContestSourceService\\:\\:\\$cachedContestData type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Property App\\\\Service\\\\ExternalContestSourceService\\:\\:\\$pendingEvents type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Property App\\\\Service\\\\ExternalContestSourceService\\:\\:\\$verdicts type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ExternalContestSourceService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:convertImportedTime\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:convertImportedTime\\(\\) has parameter \\$fields with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:getContestYamlData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:getDjRoles\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:getGroupData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:getResultsData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:getTeamData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importAccountData\\(\\) has parameter \\$accountData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importAccountsJson\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importAccountsTsv\\(\\) has parameter \\$content with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importGroupData\\(\\) has parameter \\$groupData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importGroupsJson\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importGroupsTsv\\(\\) has parameter \\$content with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importOrganizationData\\(\\) has parameter \\$organizationData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importOrganizationsJson\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importProblemsData\\(\\) has parameter \\$ids with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importProblemsData\\(\\) has parameter \\$problems with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importTeamData\\(\\) has parameter \\$teamData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importTeamsJson\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportExportService\\:\\:importTeamsTsv\\(\\) has parameter \\$content with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportExportService.php + + - + message: "#^Method App\\\\Service\\\\ImportProblemService\\:\\:importProblemFromRequest\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportProblemService.php + + - + message: "#^Method App\\\\Service\\\\ImportProblemService\\:\\:importZippedProblem\\(\\) has parameter \\$messages with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportProblemService.php + + - + message: "#^Method App\\\\Service\\\\ImportProblemService\\:\\:searchAndAddValidator\\(\\) has parameter \\$messages with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ImportProblemService.php + + - + message: "#^Method App\\\\Service\\\\RejudgingService\\:\\:calculateTodo\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/RejudgingService.php + + - + message: "#^Method App\\\\Service\\\\RejudgingService\\:\\:createRejudging\\(\\) has parameter \\$judgings with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/RejudgingService.php + + - + message: "#^Method App\\\\Service\\\\RejudgingService\\:\\:createRejudging\\(\\) has parameter \\$skipped with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/RejudgingService.php + + - + message: "#^PHPDoc tag @var for variable \\$submissions has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/RejudgingService.php + + - + message: "#^Method App\\\\Service\\\\ScoreboardService\\:\\:getFilterValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ScoreboardService.php + + - + message: "#^Method App\\\\Service\\\\ScoreboardService\\:\\:getGroupedAffiliations\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ScoreboardService.php + + - + message: "#^Method App\\\\Service\\\\ScoreboardService\\:\\:getScoreboardTwigData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/ScoreboardService.php + + - + message: "#^Method App\\\\Service\\\\StatisticsService\\:\\:getGroupedProblemsStats\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/StatisticsService.php + + - + message: "#^Method App\\\\Service\\\\StatisticsService\\:\\:getMiscContestStatistics\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/StatisticsService.php + + - + message: "#^Method App\\\\Service\\\\StatisticsService\\:\\:getProblemStats\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/StatisticsService.php + + - + message: "#^Method App\\\\Service\\\\StatisticsService\\:\\:getTeamNumSubmissions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/StatisticsService.php + + - + message: "#^Method App\\\\Service\\\\StatisticsService\\:\\:getTeamStats\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/StatisticsService.php + + - + message: "#^Method App\\\\Service\\\\StatisticsService\\:\\:setOrIncrement\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/StatisticsService.php + + - + message: "#^Method App\\\\Service\\\\SubmissionService\\:\\:getExpectedResults\\(\\) has parameter \\$resultsRemap with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/SubmissionService.php + + - + message: "#^Method App\\\\Service\\\\SubmissionService\\:\\:getExpectedResults\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/SubmissionService.php + + - + message: "#^Method App\\\\Service\\\\SubmissionService\\:\\:getFinalResult\\(\\) has parameter \\$resultsPrio with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/SubmissionService.php + + - + message: "#^Method App\\\\Service\\\\SubmissionService\\:\\:getSourceFilename\\(\\) has parameter \\$fileData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/SubmissionService.php + + - + message: "#^Method App\\\\Service\\\\SubmissionService\\:\\:getSubmissionList\\(\\) has parameter \\$contests with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/SubmissionService.php + + - + message: "#^Method App\\\\Service\\\\SubmissionService\\:\\:getSubmissionList\\(\\) has parameter \\$restrictions with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/SubmissionService.php + + - + message: "#^Method App\\\\Service\\\\SubmissionService\\:\\:getSubmissionList\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Service/SubmissionService.php + + - + message: "#^Method App\\\\Twig\\\\TwigExtension\\:\\:customAssetFiles\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Twig/TwigExtension.php + + - + message: "#^Method App\\\\Twig\\\\TwigExtension\\:\\:displayTestcaseResults\\(\\) has parameter \\$testcases with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Twig/TwigExtension.php + + - + message: "#^Method App\\\\Twig\\\\TwigExtension\\:\\:getCommonPrefix\\(\\) has parameter \\$strings with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Twig/TwigExtension.php + + - + message: "#^Method App\\\\Twig\\\\TwigExtension\\:\\:numTableActions\\(\\) has parameter \\$tableData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Twig/TwigExtension.php + + - + message: "#^Method App\\\\Twig\\\\TwigExtension\\:\\:printHosts\\(\\) has parameter \\$hostnames with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Twig/TwigExtension.php + + - + message: "#^Method App\\\\Twig\\\\TwigExtension\\:\\:runDiff\\(\\) has parameter \\$runOutput with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Twig/TwigExtension.php + + - + message: "#^Method App\\\\Utils\\\\Scoreboard\\\\Scoreboard\\:\\:getUsedCategories\\(\\) has parameter \\$limitToTeamIds with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Scoreboard/Scoreboard.php + + - + message: "#^Method App\\\\Utils\\\\Scoreboard\\\\Scoreboard\\:\\:hasCategoryColors\\(\\) has parameter \\$limitToTeamIds with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Scoreboard/Scoreboard.php + + - + message: "#^Method App\\\\Utils\\\\Scoreboard\\\\Scoreboard\\:\\:isBestInCategory\\(\\) has parameter \\$limitToTeamIds with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Scoreboard/Scoreboard.php + + - + message: "#^Property App\\\\Utils\\\\Scoreboard\\\\Scoreboard\\:\\:\\$bestInCategoryData type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Scoreboard/Scoreboard.php + + - + message: "#^Method App\\\\Utils\\\\Scoreboard\\\\Summary\\:\\:__construct\\(\\) has parameter \\$problems with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Scoreboard/Summary.php + + - + message: "#^Method App\\\\Utils\\\\Utils\\:\\:computeLcsDiff\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Utils.php + + - + message: "#^Method App\\\\Utils\\\\Utils\\:\\:getImageSize\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Utils.php + + - + message: "#^Method App\\\\Utils\\\\Utils\\:\\:parseHexColor\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Utils.php + + - + message: "#^Method App\\\\Utils\\\\Utils\\:\\:parseTsvLine\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Utils.php + + - + message: "#^Method App\\\\Utils\\\\Utils\\:\\:reindex\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Utils.php + + - + message: "#^Method App\\\\Utils\\\\Utils\\:\\:reindex\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Utils.php + + - + message: "#^Method App\\\\Utils\\\\Utils\\:\\:rgbToHex\\(\\) has parameter \\$color with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/src/Utils/Utils.php + + - + message: "#^Method App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:getAllPages\\(\\) has parameter \\$urlsToCheck with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Method App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:getAllPages\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Method App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:getLoops\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Method App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:getPagesRoles\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Method App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:roleCombinations\\(\\) has parameter \\$possible_roles with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Method App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:roleCombinations\\(\\) has parameter \\$start_roles with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Method App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:roleCombinations\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Method App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:testNoContestAccess\\(\\) has parameter \\$baseRoles with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Method App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:verifyAccess\\(\\) has parameter \\$combinations with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Property App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:\\$fullstrings type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Property App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:\\$riskyURLs type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Property App\\\\Tests\\\\E2E\\\\Controller\\\\ControllerRolesTraversalTest\\:\\:\\$substrings type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\BaseTestCase\\:\\:getDatasourceLoops\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/BaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\BaseTestCase\\:\\:loadFixtures\\(\\) has parameter \\$fixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/BaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\BaseTestCase\\:\\:unzipString\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/BaseTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\BaseTestCase\\:\\:\\$dataSources type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/BaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AccountBaseTestCase\\:\\:helperVerifyApiUsers\\(\\) has parameter \\$newUserPostData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AccountBaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AccountBaseTestCase\\:\\:helperVerifyApiUsers\\(\\) has parameter \\$objectsBeforeTest with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AccountBaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AccountBaseTestCase\\:\\:helperVerifyApiUsers\\(\\) has parameter \\$overwritten with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AccountBaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AccountBaseTestCase\\:\\:testCreateUser\\(\\) has parameter \\$newUserPostData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AccountBaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AccountBaseTestCase\\:\\:testCreateUser\\(\\) has parameter \\$overwritten with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AccountBaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AccountBaseTestCase\\:\\:testCreateUserFileImport\\(\\) has parameter \\$newUserPostData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AccountBaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AccountBaseTestCase\\:\\:testCreateUserFileImport\\(\\) has parameter \\$overwritten with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AccountBaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AccountControllerTest\\:\\:testCurrentAccount\\(\\) has parameter \\$expectedData with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AccountControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AccountControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AccountControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\AwardsControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/AwardsControllerTest.php + + - + message: "#^PHPDoc tag @var for variable \\$response has no value type specified in iterable type array\\.$#" + count: 2 + path: webapp/tests/Unit/Controller/API/BalloonsControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\BaseTestCase\\:\\:testSingle\\(\\) has parameter \\$expectedProperties with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/BaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\BaseTestCase\\:\\:verifyApiJsonResponse\\(\\) has parameter \\$files with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/BaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\BaseTestCase\\:\\:verifyApiResponse\\(\\) has parameter \\$files with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/BaseTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\BaseTestCase\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/BaseTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\BaseTestCase\\:\\:\\$rootEndpoints type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/BaseTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ClarificationControllerTest\\:\\:testAddInvalidData\\(\\) has parameter \\$dataToSend with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ClarificationControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ClarificationControllerTest\\:\\:testAddSuccess\\(\\) has parameter \\$dataToSend with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ClarificationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ClarificationControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ClarificationControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ContestControllerAdminTest\\:\\:parseSortYaml\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ContestControllerAdminTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ContestControllerAdminTest\\:\\:testChangeTimes\\(\\) has parameter \\$body with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ContestControllerAdminTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ContestControllerAdminTest\\:\\:testChangeTimes\\(\\) has parameter \\$extraFixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ContestControllerAdminTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ContestControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ContestControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ExecutableControllerTest\\:\\:base64unzip\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ExecutableControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\GeneralInfoControllerTest\\:\\:testUserEndpoint\\(\\) has parameter \\$roles with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/GeneralInfoControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\GroupControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/GroupControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\GroupControllerTest\\:\\:\\$newGroupPostData type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/GroupControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\JudgehostControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/JudgehostControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\JudgementTypesControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/JudgementTypesControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\LanguageControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/LanguageControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\OrganizationControllerTest\\:\\:testSingle\\(\\) has parameter \\$expectedProperties with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/OrganizationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\OrganizationControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/OrganizationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ProblemControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ProblemControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\ScoreboardControllerTest\\:\\:testFilteredScoreboard\\(\\) has parameter \\$filters with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ScoreboardControllerTest.php + + - + message: "#^PHPDoc tag @var for variable \\$scoreboardRows has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/ScoreboardControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\SubmissionControllerTest\\:\\:base64ZipWithFiles\\(\\) has parameter \\$files with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/SubmissionControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\SubmissionControllerTest\\:\\:testAddInvalidData\\(\\) has parameter \\$dataToSend with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/SubmissionControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\SubmissionControllerTest\\:\\:testAddSuccess\\(\\) has parameter \\$dataToSend with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/SubmissionControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\SubmissionControllerTest\\:\\:testAddSuccess\\(\\) has parameter \\$expectedFiles with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/SubmissionControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\SubmissionControllerTest\\:\\:testAddSuccess\\(\\) has parameter \\$filesToSend with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/SubmissionControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\SubmissionControllerTest\\:\\:testAddSuccess\\(\\) has parameter \\$zipFiles with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/SubmissionControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\SubmissionControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/SubmissionControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\TeamControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/TeamControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\API\\\\UserControllerTest\\:\\:\\$expectedObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/API/UserControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ContestControllerTest\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ContestControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ContestControllerTest\\:\\:\\$addEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ContestControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ContestControllerTest\\:\\:\\$addEntitiesShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ContestControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ContestControllerTest\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ContestControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ContestControllerTest\\:\\:\\$deleteExtra type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ContestControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ContestControllerTest\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ContestControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ExecutableControllerTest\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ExecutableControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ExecutableControllerTest\\:\\:\\$addEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ExecutableControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ExecutableControllerTest\\:\\:\\$addEntitiesShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ExecutableControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ExecutableControllerTest\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ExecutableControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ExecutableControllerTest\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ExecutableControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JudgehostControllerTest\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JudgehostControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JudgehostControllerTest\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JudgehostControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JudgehostControllerTest\\:\\:\\$deleteFixtures type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JudgehostControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JudgehostControllerTest\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JudgehostControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:helperCheckExistence\\(\\) has parameter \\$element with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:testCheckEditEntityAdmin\\(\\) has parameter \\$formDataKeys with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:testCheckEditEntityAdmin\\(\\) has parameter \\$formDataValues with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:testPageOverview\\(\\) has parameter \\$elements with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^PHPDoc tag @var for variable \\$item has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$addEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$addEntitiesCount type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$addEntitiesShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$deleteExtra type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$deleteFixtures type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$editEntitiesSkipFields type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$overviewNotShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$rolesDisallowed type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$rolesView type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryControllerTestCase\\:\\:\\$specialFieldOnlyUpdate type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryMiscControllerTest\\:\\:testBalloonScoreboard\\(\\) has parameter \\$fixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryMiscControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryMiscControllerTest\\:\\:testJuryAjax\\(\\) has parameter \\$finalObject with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryMiscControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\JuryMiscControllerTest\\:\\:testJuryAjax\\(\\) has parameter \\$newRoles with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/JuryMiscControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\LanguagesControllerTest\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/LanguagesControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\LanguagesControllerTest\\:\\:\\$addEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/LanguagesControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\LanguagesControllerTest\\:\\:\\$addEntitiesShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/LanguagesControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\LanguagesControllerTest\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/LanguagesControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\LanguagesControllerTest\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/LanguagesControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ProblemControllerTest\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ProblemControllerTest\\:\\:\\$addEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ProblemControllerTest\\:\\:\\$addEntitiesShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ProblemControllerTest\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ProblemControllerTest\\:\\:\\$deleteExtra type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\ProblemControllerTest\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/ProblemControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\RejudgingControllerTest\\:\\:testRejudgingCounterMenu\\(\\) has parameter \\$hidden with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/RejudgingControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\RejudgingControllerTest\\:\\:testRejudgingCounterMenu\\(\\) has parameter \\$shown with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/RejudgingControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\RejudgingControllerTest\\:\\:testRejudgingCurrentContest\\(\\) has parameter \\$hidden with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/RejudgingControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\RejudgingControllerTest\\:\\:testRejudgingCurrentContest\\(\\) has parameter \\$shown with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/RejudgingControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\RejudgingControllerTest\\:\\:testStartPage\\(\\) has parameter \\$roles with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/RejudgingControllerTest.php + + - + message: "#^PHPDoc tag @var for variable \\$rejudgings has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/RejudgingControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\SubmissionControllerTest\\:\\:testIndexViewFilter\\(\\) has parameter \\$fixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/SubmissionControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamAffiliationControllerTest\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamAffiliationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamAffiliationControllerTest\\:\\:\\$addEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamAffiliationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamAffiliationControllerTest\\:\\:\\$addEntitiesShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamAffiliationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamAffiliationControllerTest\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamAffiliationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamAffiliationControllerTest\\:\\:\\$deleteFixtures type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamAffiliationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamAffiliationControllerTest\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamAffiliationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamAffiliationControllerTest\\:\\:\\$overviewNotShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamAffiliationControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamCategoryControllerTest\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamCategoryControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamCategoryControllerTest\\:\\:\\$addEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamCategoryControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamCategoryControllerTest\\:\\:\\$addEntitiesShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamCategoryControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamCategoryControllerTest\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamCategoryControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamCategoryControllerTest\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamCategoryControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamControllerTest\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamControllerTest\\:\\:\\$addEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamControllerTest\\:\\:\\$addEntitiesCount type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamControllerTest\\:\\:\\$addEntitiesShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamControllerTest\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamControllerTest\\:\\:\\$editEntitiesSkipFields type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamControllerTest\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\TeamControllerTest\\:\\:\\$overviewNotShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/TeamControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\UserControllerTest\\:\\:\\$DOM_elements type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/UserControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\UserControllerTest\\:\\:\\$addEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/UserControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\UserControllerTest\\:\\:\\$addEntitiesShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/UserControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\UserControllerTest\\:\\:\\$deleteEntities type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/UserControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\UserControllerTest\\:\\:\\$editEntitiesSkipFields type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/UserControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\UserControllerTest\\:\\:\\$exampleEntries type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/UserControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\UserControllerTest\\:\\:\\$overviewNotShown type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/UserControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\Jury\\\\UserControllerTest\\:\\:\\$specialFieldOnlyUpdate type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/Jury/UserControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:setupSelfRegisterForm\\(\\) has parameter \\$fixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:setupSelfRegisterForm\\(\\) has parameter \\$inputs with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:setupSelfRegisterForm\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegister\\(\\) has parameter \\$fixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegister\\(\\) has parameter \\$inputs with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegisterDuplicateValue\\(\\) has parameter \\$fixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegisterDuplicateValue\\(\\) has parameter \\$inputs with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegisterMissingField\\(\\) has parameter \\$fixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegisterMissingField\\(\\) has parameter \\$inputs with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegisterNonExistingValues\\(\\) has parameter \\$fixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegisterNonExistingValues\\(\\) has parameter \\$inputs with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegisterWrongPassword\\(\\) has parameter \\$fixtures with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:testSelfRegisterWrongPassword\\(\\) has parameter \\$inputs with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:\\$duplicateFields type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:\\$formFields type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Controller\\\\PublicControllerTest\\:\\:\\$requiredFields type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Controller/PublicControllerTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Integration\\\\QueuetaskIntegrationTest\\:\\:\\$configValues type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Integration/QueuetaskIntegrationTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Integration\\\\ScoreboardIntegrationTest\\:\\:assertFTSMatch\\(\\) has parameter \\$expected_fts with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Integration/ScoreboardIntegrationTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Integration\\\\ScoreboardIntegrationTest\\:\\:assertScoresMatch\\(\\) has parameter \\$expected_scores with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Integration/ScoreboardIntegrationTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Integration\\\\ScoreboardIntegrationTest\\:\\:\\$configValues type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Integration/ScoreboardIntegrationTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Service\\\\AwardServiceTest\\:\\:getAward\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Service/AwardServiceTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Service\\\\ConfigurationServiceTest\\:\\:findItem\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Service/ConfigurationServiceTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Service\\\\ConfigurationServiceTest\\:\\:testAddOptionsExecutables\\(\\) has parameter \\$expected with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Service/ConfigurationServiceTest.php + + - + message: "#^Property App\\\\Tests\\\\Unit\\\\Service\\\\ConfigurationServiceTest\\:\\:\\$dbConfig type has no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Service/ConfigurationServiceTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Service\\\\ImportExportServiceTest\\:\\:testImportContestDataSuccess\\(\\) has parameter \\$expectedProblems with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Service/ImportExportServiceTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Service\\\\ImportExportServiceTest\\:\\:testImportProblemsDataSuccess\\(\\) has parameter \\$expectedProblems with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Service/ImportExportServiceTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Service\\\\SubmissionServiceTest\\:\\:testGetFinalResult\\(\\) has parameter \\$resultsPrio with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Service/SubmissionServiceTest.php + + - + message: "#^Method App\\\\Tests\\\\Unit\\\\Service\\\\SubmissionServiceTest\\:\\:testGetFinalResult\\(\\) has parameter \\$runresults with no value type specified in iterable type array\\.$#" + count: 1 + path: webapp/tests/Unit/Service/SubmissionServiceTest.php diff --git a/phpstan.dist.neon b/phpstan.dist.neon new file mode 100644 index 0000000000..b78640c93b --- /dev/null +++ b/phpstan.dist.neon @@ -0,0 +1,10 @@ +parameters: + level: 6 + paths: + - webapp/src + - webapp/tests + excludePaths: + - webapp/src/Utils/Adminer.php +includes: + - phpstan-baseline.neon + - lib/vendor/phpstan/phpstan-doctrine/extension.neon diff --git a/webapp/src/Command/CallApiActionCommand.php b/webapp/src/Command/CallApiActionCommand.php index 4ffda37e72..a1b9aa6ba6 100644 --- a/webapp/src/Command/CallApiActionCommand.php +++ b/webapp/src/Command/CallApiActionCommand.php @@ -84,7 +84,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } else { // Find an admin user as we need one to make sure we can read all events. - /** @var User $user */ + /** @var User|null $user */ $user = $this->em->createQueryBuilder() ->from(User::class, 'u') ->select('u') diff --git a/webapp/src/Command/ImportEventFeedCommand.php b/webapp/src/Command/ImportEventFeedCommand.php index 3a22fde774..f310c61339 100644 --- a/webapp/src/Command/ImportEventFeedCommand.php +++ b/webapp/src/Command/ImportEventFeedCommand.php @@ -114,7 +114,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } // Find an admin user as we need one to make sure we can read all events. - /** @var User $user */ + /** @var User|null $user */ $user = $this->em->createQueryBuilder() ->from(User::class, 'u') ->select('u') diff --git a/webapp/src/Command/ScoreboardMergeCommand.php b/webapp/src/Command/ScoreboardMergeCommand.php index c8dfbae8ca..e3acf5299f 100644 --- a/webapp/src/Command/ScoreboardMergeCommand.php +++ b/webapp/src/Command/ScoreboardMergeCommand.php @@ -213,7 +213,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->request('GET', $path . '/scoreboard?public=1') ->toArray(); - if ($contest->getStarttimeString() === null) { + if (!$contest->getStarttimeString()) { $state = $scoreboardData['state']; $contest ->setStarttimeString($state['started']) diff --git a/webapp/src/Config/Loader/YamlConfigLoader.php b/webapp/src/Config/Loader/YamlConfigLoader.php index 4eab8e358c..af65092ab0 100644 --- a/webapp/src/Config/Loader/YamlConfigLoader.php +++ b/webapp/src/Config/Loader/YamlConfigLoader.php @@ -15,12 +15,12 @@ class YamlConfigLoader extends FileLoader /** * @return mixed */ - public function load(mixed $resource, $type = null) + public function load(mixed $resource, string $type = null) { return Yaml::parse(file_get_contents($resource)); } - public function supports($resource, $type = null): bool + public function supports($resource, string $type = null): bool { return is_string($resource) && pathinfo($resource, PATHINFO_EXTENSION) === 'yaml'; diff --git a/webapp/src/Controller/API/AbstractRestController.php b/webapp/src/Controller/API/AbstractRestController.php index 5f2ac1e0ac..af0266d0bb 100644 --- a/webapp/src/Controller/API/AbstractRestController.php +++ b/webapp/src/Controller/API/AbstractRestController.php @@ -198,7 +198,7 @@ protected function getContestId(Request $request): int ->andWhere(sprintf('c.%s = :cid', $this->getContestIdField())) ->setParameter('cid', $request->attributes->get('cid')); - /** @var Contest $contest */ + /** @var Contest|null $contest */ $contest = $qb->getQuery()->getOneOrNullResult(); if ($contest === null) { diff --git a/webapp/src/Controller/API/ClarificationController.php b/webapp/src/Controller/API/ClarificationController.php index 0e2b5149fa..17fe05722f 100644 --- a/webapp/src/Controller/API/ClarificationController.php +++ b/webapp/src/Controller/API/ClarificationController.php @@ -123,7 +123,7 @@ public function addAction(Request $request, ?string $id): Response if ($problemId = $request->request->get('problem_id')) { // Load the problem - /** @var ContestProblem $problem */ + /** @var ContestProblem|null $problem */ $problem = $this->em->createQueryBuilder() ->from(ContestProblem::class, 'cp') ->join('cp.problem', 'p') @@ -148,7 +148,7 @@ public function addAction(Request $request, ?string $id): Response if ($replyToId = $request->request->get('reply_to_id')) { // Load the clarification. - /** @var Clarification $replyTo */ + /** @var Clarification|null $replyTo */ $replyTo = $this->em->createQueryBuilder() ->from(Clarification::class, 'c') ->select('c') diff --git a/webapp/src/Controller/API/ContestController.php b/webapp/src/Controller/API/ContestController.php index 37a3b41257..8709cec921 100644 --- a/webapp/src/Controller/API/ContestController.php +++ b/webapp/src/Controller/API/ContestController.php @@ -12,6 +12,7 @@ use App\Service\ImportExportService; use App\Utils\EventFeedFormat; use App\Utils\Utils; +use BadMethodCallException; use Doctrine\Inflector\InflectorFactory; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\NonUniqueResultException; @@ -89,10 +90,10 @@ public function __construct( #[OA\Response(response: 200, description: 'Returns the API ID of the added contest.')] public function addContestAction(Request $request): string { - /** @var UploadedFile $yamlFile */ - $yamlFile = $request->files->get('yaml') ?: []; - /** @var UploadedFile $jsonFile */ - $jsonFile = $request->files->get('json') ?: []; + /** @var UploadedFile|null $yamlFile */ + $yamlFile = $request->files->get('yaml'); + /** @var UploadedFile|null $jsonFile */ + $jsonFile = $request->files->get('json'); if ((!$yamlFile && !$jsonFile) || ($yamlFile && $jsonFile)) { throw new BadRequestHttpException('Supply exactly one of \'json\' or \'yaml\''); } @@ -178,7 +179,7 @@ public function singleAction(Request $request, string $cid): Response #[OA\Parameter(ref: '#/components/parameters/cid')] public function bannerAction(Request $request, string $cid): Response { - /** @var Contest $contest */ + /** @var Contest|null $contest */ $contest = $this->getQueryBuilder($request) ->andWhere(sprintf('%s = :id', $this->getIdField())) ->setParameter('id', $cid) @@ -244,10 +245,9 @@ public function deleteBannerAction(Request $request, string $cid): Response #[OA\Parameter(ref: '#/components/parameters/cid')] public function setBannerAction(Request $request, string $cid, ValidatorInterface $validator): Response { - /** @var Contest $contest */ $contest = $this->getContestAndCheckIfLocked($request, $cid); - /** @var UploadedFile $banner */ + /** @var UploadedFile|null $banner */ $banner = $request->files->get('banner'); if (!$banner) { return new JsonResponse(['title' => 'Validation failed', 'errors' => ['Please supply a banner']], Response::HTTP_BAD_REQUEST); @@ -322,6 +322,7 @@ public function changeStartTimeAction( #[OA\PathParameter(description: 'The ID of the contest to change the start time for')] string $cid ): Response { + $response = new Response('', Response::HTTP_NO_CONTENT); $contest = $this->getContestWithId($request, $cid); $now = (int)Utils::now(); $changed = false; @@ -349,7 +350,6 @@ public function changeStartTimeAction( if ($request->request->get('start_time') === null) { $contest->setStarttimeEnabled(false); - $response = new Response('', Response::HTTP_NO_CONTENT); $this->em->flush(); $changed = true; } else { @@ -366,7 +366,6 @@ public function changeStartTimeAction( $contest->setStarttimeEnabled(true); $contest->setStarttime($new_start_time); $contest->setStarttimeString($newStartTimeString); - $response = new Response('', Response::HTTP_NO_CONTENT); $this->em->flush(); $changed = true; } @@ -396,7 +395,6 @@ public function changeStartTimeAction( $contest->setUnfreezetimeString($newUnfreezeTimeString); $this->em->flush(); $changed = true; - $response = new Response('', Response::HTTP_NO_CONTENT); if ($returnContest) { $response = $this->renderData($request, $contest); } @@ -720,6 +718,8 @@ public function getEventFeedAction( 'data' => $data, ]; break; + default: + throw new BadMethodCallException(sprintf('Invalid event feed format %s', $format)); } if (!$strict) { @@ -849,7 +849,7 @@ protected function getContestWithId(Request $request, string $id): Contest /** To be used when contest data is modified. */ private function getContestAndCheckIfLocked(Request $request, string $cid): Contest { - /** @var Contest $contest */ + /** @var Contest|null $contest */ $contest = $this->getQueryBuilder($request) ->andWhere(sprintf('%s = :id', $this->getIdField())) ->setParameter('id', $cid) diff --git a/webapp/src/Controller/API/JudgehostController.php b/webapp/src/Controller/API/JudgehostController.php index cfb467b0b0..4b8507a816 100644 --- a/webapp/src/Controller/API/JudgehostController.php +++ b/webapp/src/Controller/API/JudgehostController.php @@ -224,7 +224,6 @@ public function updateJudgeHostAction( throw new BadRequestHttpException('Argument \'enabled\' is mandatory'); } - /** @var Judgehost $judgehost */ $judgehost = $this->em->getRepository(Judgehost::class)->findOneBy(['hostname' => $hostname]); if ($judgehost) { $judgehost->setEnabled($request->request->getBoolean('enabled')); @@ -281,13 +280,11 @@ public function updateJudgingAction( #[OA\PathParameter(description: 'The ID of the judgetask to update')] int $judgetaskid ): void { - /** @var Judgehost $judgehost */ $judgehost = $this->em->getRepository(Judgehost::class)->findOneBy(['hostname' => $hostname]); if (!$judgehost) { throw new BadRequestHttpException("Who are you and why are you sending us any data?"); } - /** @var JudgingRun $judgingRun */ $judgingRun = $this->em->getRepository(JudgingRun::class)->findOneBy(['judgetaskid' => $judgetaskid]); $query = $this->em->createQueryBuilder() ->from(Judging::class, 'j') @@ -301,7 +298,7 @@ public function updateJudgingAction( ->setMaxResults(1) ->getQuery(); - /** @var Judging $judging */ + /** @var Judging|null $judging */ $judging = $query->getOneOrNullResult(); if (!$judging) { throw new BadRequestHttpException("We don't know this judging with judgetaskid ID $judgetaskid."); @@ -379,7 +376,6 @@ public function updateJudgingAction( } } else { $this->em->wrapInTransaction(function () use ( - $request, $judgehost, $judging, $query, @@ -475,7 +471,6 @@ public function addDebugInfo( #[OA\PathParameter(description: 'The ID of the judgetask to add')] int $judgeTaskId ): void { - /** @var JudgeTask $judgeTask */ $judgeTask = $this->em->getRepository(JudgeTask::class)->find($judgeTaskId); if ($judgeTask === null) { throw new BadRequestHttpException( @@ -501,7 +496,6 @@ public function addDebugInfo( } } - /** @var Judgehost $judgehost */ $judgehost = $this->em->getRepository(Judgehost::class)->findOneBy(['hostname' => $hostname]); if (!$judgehost) { throw new BadRequestHttpException("Who are you and why are you sending us any data?"); @@ -525,7 +519,6 @@ public function addDebugInfo( ->setFilename($tempFilename); $this->em->persist($debug_package); } else { - /** @var JudgingRun $judgingRun */ $judgingRun = $this->em->getRepository(JudgingRun::class)->findOneBy( [ 'judging' => $judgeTask->getJobId(), @@ -640,7 +633,6 @@ public function addJudgingRunAction( $teamMessage = $request->request->get('team_message'); $metadata = $request->request->get('metadata'); - /** @var Judgehost $judgehost */ $judgehost = $this->em->getRepository(Judgehost::class)->findOneBy(['hostname' => $hostname]); if (!$judgehost) { throw new BadRequestHttpException("Who are you and why are you sending us any data?"); @@ -743,7 +735,6 @@ public function internalErrorAction(Request $request): ?int // Since these are the immutable executables, we need to map it to the mutable one first to make linking and // re-enabling possible. - /** @var Executable $executable */ $executable = $this->em->getRepository(Executable::class) ->findOneBy(['immutableExecutable' => $disabled[$field_name]]); if (!$executable) { @@ -768,7 +759,7 @@ public function internalErrorAction(Request $request): ?int ->setParameter('status', 'open') ->setMaxResults(1); - /** @var InternalError $error */ + /** @var InternalError|null $error */ $error = $queryBuilder->getQuery()->getOneOrNullResult(); if ($error) { @@ -803,7 +794,7 @@ public function internalErrorAction(Request $request): ?int 'id' => $disabled_id, ] )->fetchFirstColumn(); - $judgings = $em->getRepository(Judging::class)->findByJudgingid($judgingids); + $judgings = $em->getRepository(Judging::class)->findBy(['judgingid' => $judgingids]); foreach ($judgings as $judging) { /** @var Judging $judging */ $judging->setInternalError($error); @@ -844,7 +835,6 @@ public function internalErrorAction(Request $request): ?int */ protected function giveBackJudging(int $judgingId, ?Judgehost $judgehost): void { - /** @var Judging $judging */ $judging = $this->em->getRepository(Judging::class)->find($judgingId); if ($judging) { $this->em->wrapInTransaction(function () use ($judging, $judgehost) { @@ -935,7 +925,6 @@ private function addSingleJudgingRun( $teamMessage, $metadata ) { - /** @var JudgingRun $judgingRun */ $judgingRun = $this->em->getRepository(JudgingRun::class)->findOneBy( ['judgetaskid' => $judgeTaskId]); if ($judgingRun === null) { @@ -1203,24 +1192,20 @@ public function getFilesAction( )] public function getVersionCommands(string $judgetaskid): array { - /** @var JudgeTask $judgeTask */ $judgeTask = $this->em->getRepository(JudgeTask::class) ->findOneBy(['judgetaskid' => $judgetaskid]); if (!$judgeTask) { throw new BadRequestHttpException('Unknown judge task with id ' . $judgetaskid); } - /** @var Submission $submission */ $submission = $this->em->getRepository(Submission::class) ->findOneBy(['submitid' => $judgeTask->getSubmitid()]); if (!$submission) { throw new HttpException(500, 'Unknown submission with submitid ' . $judgeTask->getSubmitid()); } - /** @var Language $language */ $language = $submission->getLanguage(); - $ret = []; if (!empty($language->getCompilerVersionCommand())) { $ret['compiler_version_command'] = $language->getCompilerVersionCommand(); @@ -1266,27 +1251,23 @@ public function getVersionCommands(string $judgetaskid): array ), ] )] - public function checkVersions(Request $request, string $judgetaskid) + public function checkVersions(Request $request, string $judgetaskid): array { - /** @var JudgeTask $judgeTask */ $judgeTask = $this->em->getRepository(JudgeTask::class) ->findOneBy(['judgetaskid' => $judgetaskid]); if (!$judgeTask) { throw new BadRequestHttpException('Unknown judge task with id ' . $judgetaskid); } - /** @var Submission $submission */ $submission = $this->em->getRepository(Submission::class) ->findOneBy(['submitid' => $judgeTask->getSubmitid()]); if (!$submission) { throw new BadRequestHttpException('Unknown submission with submitid ' . $judgeTask->getSubmitid()); } - /** @var Language $language */ $language = $submission->getLanguage(); $hostname = $request->request->get('hostname'); - /** @var Judgehost $judgehost */ $judgehost = $this->em->getRepository(Judgehost::class)->findOneBy(['hostname' => $hostname]); if (!$judgehost) { throw new BadRequestHttpException( @@ -1301,12 +1282,10 @@ public function checkVersions(Request $request, string $judgetaskid) $reportedVersions['runner'] = base64_decode($request->request->get('runner')); } $this->em->wrapInTransaction(function () use ( - $request, $judgehost, $reportedVersions, $language ) { - /** @var Version $version */ $version = $this->em->getRepository(Version::class) ->findOneBy(['language' => $language, 'judgehost' => $judgehost]); @@ -1434,7 +1413,6 @@ public function getJudgeTasksAction(Request $request): array } $hostname = $request->request->get('hostname'); - /** @var Judgehost $judgehost */ $judgehost = $this->em->getRepository(Judgehost::class)->findOneBy(['hostname' => $hostname]); if (!$judgehost) { throw new BadRequestHttpException( diff --git a/webapp/src/Controller/API/OrganizationController.php b/webapp/src/Controller/API/OrganizationController.php index e1efd31088..0584351f79 100644 --- a/webapp/src/Controller/API/OrganizationController.php +++ b/webapp/src/Controller/API/OrganizationController.php @@ -113,7 +113,7 @@ public function singleAction(Request $request, string $id): Response #[OA\Parameter(ref: '#/components/parameters/id')] public function logoAction(Request $request, string $id): Response { - /** @var TeamAffiliation $teamAffiliation */ + /** @var TeamAffiliation|null $teamAffiliation */ $teamAffiliation = $this->getQueryBuilder($request) ->andWhere(sprintf('%s = :id', $this->getIdField())) ->setParameter('id', $id) @@ -144,7 +144,7 @@ public function logoAction(Request $request, string $id): Response public function deleteLogoAction(Request $request, string $id): Response { $contestId = null; - /** @var TeamAffiliation $teamAffiliation */ + /** @var TeamAffiliation|null $teamAffiliation */ $teamAffiliation = $this->getQueryBuilder($request) ->andWhere(sprintf('%s = :id', $this->getIdField())) ->setParameter('id', $id) @@ -196,7 +196,7 @@ public function deleteLogoAction(Request $request, string $id): Response #[OA\Parameter(ref: '#/components/parameters/id')] public function setLogoAction(Request $request, string $id, ValidatorInterface $validator): Response { - /** @var TeamAffiliation $teamAffiliation */ + /** @var TeamAffiliation|null $teamAffiliation */ $teamAffiliation = $this->getQueryBuilder($request) ->andWhere(sprintf('%s = :id', $this->getIdField())) ->setParameter('id', $id) @@ -207,7 +207,7 @@ public function setLogoAction(Request $request, string $id, ValidatorInterface $ throw new NotFoundHttpException(sprintf('Object with ID \'%s\' not found', $id)); } - /** @var UploadedFile $logo */ + /** @var UploadedFile|null $logo */ $logo = $request->files->get('logo'); if (!$logo) { diff --git a/webapp/src/Controller/API/ProblemController.php b/webapp/src/Controller/API/ProblemController.php index b632d4010a..c2519bfc3d 100644 --- a/webapp/src/Controller/API/ProblemController.php +++ b/webapp/src/Controller/API/ProblemController.php @@ -87,8 +87,9 @@ public function addProblemsAction(Request $request): array throw new AccessDeniedHttpException('Contest is locked, go to ' . $contestUrl . ' to unlock it.'); } - /** @var UploadedFile $file */ - if (!$file = $request->files->get('data')) { + /** @var UploadedFile|null $file */ + $file = $request->files->get('data'); + if (!$file) { throw new BadRequestHttpException("Data field is missing."); } // Note: we read the JSON as YAML, since any JSON is also YAML and this allows us @@ -340,7 +341,7 @@ public function linkProblemAction(Request $request, string $id): Response $lazyEvalResults = null; if ($request->request->has('lazy_eval_results')) { - $lazyEvalResults = $request->request->getBoolean('lazy_eval_results'); + $lazyEvalResults = (int)$request->request->getBoolean('lazy_eval_results'); } $contestProblem = (new ContestProblem()) diff --git a/webapp/src/Controller/API/ScoreboardController.php b/webapp/src/Controller/API/ScoreboardController.php index 139ae8c6ce..026dc51a57 100644 --- a/webapp/src/Controller/API/ScoreboardController.php +++ b/webapp/src/Controller/API/ScoreboardController.php @@ -133,7 +133,7 @@ public function getScoreboardAction( $contest = $this->em->getRepository(Contest::class)->find($this->getContestId($request)); // Get the event for this scoreboard. - /** @var Event $event */ + /** @var Event|null $event */ $event = $this->em->createQueryBuilder() ->from(Event::class, 'e') ->select('e') diff --git a/webapp/src/Controller/API/SubmissionController.php b/webapp/src/Controller/API/SubmissionController.php index 4a8b0ea43a..7da7bcfeb7 100644 --- a/webapp/src/Controller/API/SubmissionController.php +++ b/webapp/src/Controller/API/SubmissionController.php @@ -286,7 +286,7 @@ public function addSubmissionAction(Request $request, ?string $id): Response } // Load the problem. - /** @var ContestProblem $problem */ + /** @var ContestProblem|null $problem */ $problem = $this->em->createQueryBuilder() ->from(ContestProblem::class, 'cp') ->join('cp.problem', 'p') @@ -307,7 +307,7 @@ public function addSubmissionAction(Request $request, ?string $id): Response } // Load the language. - /** @var Language $language */ + /** @var Language|null $language */ $language = $this->em->createQueryBuilder() ->from(Language::class, 'lang') ->select('lang') diff --git a/webapp/src/Controller/API/TeamController.php b/webapp/src/Controller/API/TeamController.php index 211af2cf12..e32ab1ca7a 100644 --- a/webapp/src/Controller/API/TeamController.php +++ b/webapp/src/Controller/API/TeamController.php @@ -126,7 +126,7 @@ public function singleAction(Request $request, string $id): Response #[OA\Parameter(ref: '#/components/parameters/id')] public function photoAction(Request $request, string $id): Response { - /** @var Team $team */ + /** @var Team|null $team */ $team = $this->getQueryBuilder($request) ->andWhere(sprintf('%s = :id', $this->getIdField())) ->setParameter('id', $id) @@ -156,7 +156,7 @@ public function photoAction(Request $request, string $id): Response public function deletePhotoAction(Request $request, string $id): Response { $contestId = null; - /** @var Team $team */ + /** @var Team|null $team */ $team = $this->getQueryBuilder($request) ->andWhere(sprintf('%s = :id', $this->getIdField())) ->setParameter('id', $id) @@ -208,7 +208,7 @@ public function deletePhotoAction(Request $request, string $id): Response #[OA\Parameter(ref: '#/components/parameters/id')] public function setPhotoAction(Request $request, string $id, ValidatorInterface $validator): Response { - /** @var Team $team */ + /** @var Team|null $team */ $team = $this->getQueryBuilder($request) ->andWhere(sprintf('%s = :id', $this->getIdField())) ->setParameter('id', $id) @@ -219,7 +219,7 @@ public function setPhotoAction(Request $request, string $id, ValidatorInterface throw new NotFoundHttpException(sprintf('Object with ID \'%s\' not found', $id)); } - /** @var UploadedFile $photo */ + /** @var UploadedFile|null $photo */ $photo = $request->files->get('photo'); if (!$photo) { diff --git a/webapp/src/Controller/API/UserController.php b/webapp/src/Controller/API/UserController.php index 0f40ec41c7..487bd3e606 100644 --- a/webapp/src/Controller/API/UserController.php +++ b/webapp/src/Controller/API/UserController.php @@ -70,10 +70,10 @@ public function __construct( #[OA\Response(response: 200, description: 'Returns a (currently meaningless) status message.')] public function addGroupsAction(Request $request): string { - /** @var UploadedFile $tsvFile */ - $tsvFile = $request->files->get('tsv') ?: []; - /** @var UploadedFile $jsonFile */ - $jsonFile = $request->files->get('json') ?: []; + /** @var UploadedFile|null $tsvFile */ + $tsvFile = $request->files->get('tsv'); + /** @var UploadedFile|null $jsonFile */ + $jsonFile = $request->files->get('json'); if ((!$tsvFile && !$jsonFile) || ($tsvFile && $jsonFile)) { throw new BadRequestHttpException('Supply exactly one of \'json\' or \'tsv\''); } @@ -113,8 +113,9 @@ public function addGroupsAction(Request $request): string public function addOrganizationsAction(Request $request): string { $message = null; - /** @var UploadedFile $jsonFile */ - if (($jsonFile = $request->files->get('json')) && + /** @var UploadedFile|null $jsonFile */ + $jsonFile = $request->files->get('json'); + if ($jsonFile && ($result = $this->importExportService->importJson('organizations', $jsonFile, $message)) && $result >= 0 ) { @@ -155,10 +156,10 @@ public function addOrganizationsAction(Request $request): string #[OA\Response(response: 200, description: 'Returns a (currently meaningless) status message.')] public function addTeamsAction(Request $request): string { - /** @var UploadedFile $tsvFile */ - $tsvFile = $request->files->get('tsv') ?: []; - /** @var UploadedFile $jsonFile */ - $jsonFile = $request->files->get('json') ?: []; + /** @var UploadedFile|null $tsvFile */ + $tsvFile = $request->files->get('tsv'); + /** @var UploadedFile|null $jsonFile */ + $jsonFile = $request->files->get('json'); if ((!$tsvFile && !$jsonFile) || ($tsvFile && $jsonFile)) { throw new BadRequestHttpException('Supply exactly one of \'json\' or \'tsv\''); } @@ -210,12 +211,12 @@ public function addTeamsAction(Request $request): string #[OA\Response(ref: '#/components/responses/PostAccountResponse', response: 200)] public function addAccountsAction(Request $request): string { - /** @var UploadedFile $tsvFile */ - $tsvFile = $request->files->get('tsv') ?: []; - /** @var UploadedFile $jsonFile */ - $jsonFile = $request->files->get('json') ?: []; - /** @var UploadedFile $yamlFile */ - $yamlFile = $request->files->get('yaml') ?: []; + /** @var UploadedFile|null $tsvFile */ + $tsvFile = $request->files->get('tsv'); + /** @var UploadedFile|null $jsonFile */ + $jsonFile = $request->files->get('json'); + /** @var UploadedFile|null $yamlFile */ + $yamlFile = $request->files->get('yaml'); $providedFiles = array_filter([$tsvFile, $jsonFile, $yamlFile]); if (count($providedFiles) !== 1) { throw new BadRequestHttpException('Supply exactly one of \'json\', \'yaml\' or \'tsv\''); @@ -333,7 +334,7 @@ public function addAction(Request $request): Response ->setEnabled($request->request->getBoolean('enabled', true)); if ($request->request->get('team_id')) { - /** @var Team $team */ + /** @var Team|null $team */ $team = $this->em->createQueryBuilder() ->from(Team::class, 't') ->select('t') diff --git a/webapp/src/Controller/BaseController.php b/webapp/src/Controller/BaseController.php index e9a62255af..d6edfd1e6f 100644 --- a/webapp/src/Controller/BaseController.php +++ b/webapp/src/Controller/BaseController.php @@ -18,6 +18,7 @@ use Doctrine\DBAL\Exception as DBALException; use Doctrine\Inflector\InflectorFactory; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\MappingException; use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; @@ -98,7 +99,7 @@ protected function saveEntity( EventLogService $eventLogService, DOMJudgeService $DOMJudgeService, object $entity, - $id, + mixed $id, bool $isNewEntity ): void { $auditLogType = Utils::tableForEntity($entity); @@ -170,7 +171,7 @@ protected function getDatabaseRelations(array $files, EntityManagerInterface $en * Handle the actual removal of an entity and the dependencies in the database. */ protected function commitDeleteEntity( - $entity, + object $entity, DOMJudgeService $DOMJudgeService, EntityManagerInterface $entityManager, array $primaryKeyData, @@ -279,6 +280,7 @@ protected function buildDeleteTree( $propertyAccessor = PropertyAccess::createPropertyAccessor(); $inflector = InflectorFactory::create()->build(); $readableType = str_replace('_', ' ', Utils::tableForEntity($entities[0])); + /** @phpstan-ignore-next-line */ $metadata = $entityManager->getClassMetadata($entities[0]::class); $primaryKeyData = []; $messages = []; @@ -515,66 +517,4 @@ protected function streamResponse(RequestStack $requestStack, callable $callback }); return $response; } - - protected function judgeRemaining(array $judgings): void - { - $inProgress = []; - $alreadyRequested = []; - $invalidJudgings = []; - $numRequested = 0; - foreach ($judgings as $judging) { - $judgingId = $judging->getJudgingid(); - if ($judging->getResult() === null) { - $inProgress[] = $judgingId; - } elseif ($judging->getJudgeCompletely()) { - $alreadyRequested[] = $judgingId; - } elseif (!$judging->getValid()) { - $invalidJudgings[] = $judgingId; - } else { - $numRequested = $this->em->getConnection()->executeStatement( - 'UPDATE judgetask SET valid=1' - . ' WHERE jobid=:jobid' - . ' AND judgehostid IS NULL', - [ - 'jobid' => $judgingId, - ] - ); - $judging->setJudgeCompletely(true); - - $submission = $judging->getSubmission(); - - $queueTask = new QueueTask(); - $queueTask->setJudging($judging) - ->setPriority(JudgeTask::PRIORITY_LOW) - ->setTeam($submission->getTeam()) - ->setTeamPriority((int)$submission->getSubmittime()) - ->setStartTime(null); - $this->em->persist($queueTask); - } - } - $this->em->flush(); - if (count($judgings) === 1) { - if ($inProgress !== []) { - $this->addFlash('warning', 'Please be patient, this judging is still in progress.'); - } - if ($alreadyRequested !== []) { - $this->addFlash('warning', 'This judging was already requested to be judged completely.'); - } - } else { - if ($inProgress !== []) { - $this->addFlash('warning', sprintf('Please be patient, these judgings are still in progress: %s', implode(', ', $inProgress))); - } - if ($alreadyRequested !== []) { - $this->addFlash('warning', sprintf('These judgings were already requested to be judged completely: %s', implode(', ', $alreadyRequested))); - } - if ($invalidJudgings !== []) { - $this->addFlash('warning', sprintf('These judgings were skipped as they were superseded by other judgings: %s', implode(', ', $invalidJudgings))); - } - } - if ($numRequested === 0) { - $this->addFlash('warning', 'No more remaining runs to be judged.'); - } else { - $this->addFlash('info', "Requested $numRequested remaining runs to be judged."); - } - } } diff --git a/webapp/src/Controller/Jury/AuditLogController.php b/webapp/src/Controller/Jury/AuditLogController.php index 7c3be1388d..3669f7e5b3 100644 --- a/webapp/src/Controller/Jury/AuditLogController.php +++ b/webapp/src/Controller/Jury/AuditLogController.php @@ -110,7 +110,7 @@ public function indexAction( ]); } - private function generateDatatypeUrl(string $type, $id): ?string + private function generateDatatypeUrl(string $type, int|string|null $id): ?string { switch ($type) { case 'balloon': diff --git a/webapp/src/Controller/Jury/ClarificationController.php b/webapp/src/Controller/Jury/ClarificationController.php index 895cb9791c..33e2ce0d08 100644 --- a/webapp/src/Controller/Jury/ClarificationController.php +++ b/webapp/src/Controller/Jury/ClarificationController.php @@ -72,12 +72,12 @@ public function indexAction( ->setParameter('queue', $currentQueue); } - /** - * @var Clarification[] $newClarifications - * @var Clarification[] $oldClarifications - * @var Clarification[] $generalClarifications - */ - $newClarifications = $oldClarifications = $generalClarifications = []; + /** @var Clarification[] $newClarifications */ + $newClarifications = []; + /** @var Clarification[] $oldClarifications */ + $oldClarifications = []; + /** @var Clarification[] $generalClarifications */ + $generalClarifications = []; $wheres = [ 'new' => 'clar.sender IS NOT NULL AND clar.answered = 0', 'old' => 'clar.sender IS NOT NULL AND clar.answered != 0', @@ -119,7 +119,6 @@ public function indexAction( #[Route(path: '/{id<\d+>}', name: 'jury_clarification')] public function viewAction(int $id): Response { - /** @var Clarification $clarification */ $clarification = $this->em->getRepository(Clarification::class)->find($id); if (!$clarification) { throw new NotFoundHttpException(sprintf('Clarification with ID %s not found', $id)); @@ -137,7 +136,7 @@ public function viewAction(int $id): Response $clarification = $inReplyTo; } $clarlist = [$clarification]; - $replies = $clarification->getReplies() ?? []; + $replies = $clarification->getReplies(); foreach ($replies as $clar_reply) { $clarlist[] = $clar_reply; } @@ -278,10 +277,9 @@ public function composeClarificationAction( #[Route(path: '/{clarId<\d+>}/claim', name: 'jury_clarification_claim')] public function toggleClaimAction(Request $request, int $clarId): Response { - /** @var Clarification $clarification */ $clarification = $this->em->getReference(Clarification::class, $clarId); if (!$clarification) { - throw new NotFoundHttpException(sprintf('Clarification with ID %i not found', $clarId)); + throw new NotFoundHttpException(sprintf('Clarification with ID %d not found', $clarId)); } if ($request->request->getBoolean('claimed')) { @@ -298,10 +296,9 @@ public function toggleClaimAction(Request $request, int $clarId): Response #[Route(path: '/{clarId<\d+>}/set-answered', name: 'jury_clarification_set_answered')] public function toggleAnsweredAction(Request $request, int $clarId): Response { - /** @var Clarification $clarification */ $clarification = $this->em->getReference(Clarification::class, $clarId); if (!$clarification) { - throw new NotFoundHttpException(sprintf('Clarification with ID %i not found', $clarId)); + throw new NotFoundHttpException(sprintf('Clarification with ID %d not found', $clarId)); } $answered = $request->request->getBoolean('answered'); @@ -318,10 +315,9 @@ public function toggleAnsweredAction(Request $request, int $clarId): Response #[Route(path: '/{clarId<\d+>}/change-subject', name: 'jury_clarification_change_subject')] public function changeSubjectAction(Request $request, int $clarId): Response { - /** @var Clarification $clarification */ $clarification = $this->em->getReference(Clarification::class, $clarId); if (!$clarification) { - throw new NotFoundHttpException(sprintf('Clarification with ID %i not found', $clarId)); + throw new NotFoundHttpException(sprintf('Clarification with ID %d not found', $clarId)); } $subject = $request->request->get('subject'); @@ -347,10 +343,9 @@ public function changeSubjectAction(Request $request, int $clarId): Response #[Route(path: '/{clarId<\d+>}/change-queue', name: 'jury_clarification_change_queue')] public function changeQueueAction(Request $request, int $clarId): Response { - /** @var Clarification $clarification */ $clarification = $this->em->getReference(Clarification::class, $clarId); if (!$clarification) { - throw new NotFoundHttpException(sprintf('Clarification with ID %i not found', $clarId)); + throw new NotFoundHttpException(sprintf('Clarification with ID %d not found', $clarId)); } $queue = $request->request->get('queue'); diff --git a/webapp/src/Controller/Jury/ContestController.php b/webapp/src/Controller/Jury/ContestController.php index b174f1abb4..f1320634a1 100644 --- a/webapp/src/Controller/Jury/ContestController.php +++ b/webapp/src/Controller/Jury/ContestController.php @@ -32,11 +32,10 @@ use Doctrine\ORM\NoResultException; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Query\Expr\Join; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -44,11 +43,14 @@ use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[IsGranted('ROLE_JURY')] #[Route(path: '/jury/contests')] class ContestController extends BaseController { + use JudgeRemainingTrait; + public function __construct( protected readonly EntityManagerInterface $em, protected readonly DOMJudgeService $dj, @@ -76,7 +78,6 @@ public function indexAction(Request $request): Response if (!$this->isGranted('ROLE_ADMIN')) { throw new AccessDeniedHttpException(); } - /** @var Contest $contest */ $contest = $em->getRepository(Contest::class)->find($request->request->get('contest')); if (!$contest) { throw new NotFoundHttpException('Contest not found'); @@ -368,7 +369,6 @@ public function indexAction(Request $request): Response #[Route(path: '/{contestId<\d+>}', name: 'jury_contest')] public function viewAction(Request $request, int $contestId): Response { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if (!$contest) { throw new NotFoundHttpException(sprintf('Contest with ID %s not found', $contestId)); @@ -422,7 +422,6 @@ public function viewAction(Request $request, int $contestId): Response #[Route(path: '/{contestId}/toggle-submit', name: 'jury_contest_toggle_submit')] public function toggleSubmitAction(Request $request, string $contestId): Response { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if (!$contest) { throw new NotFoundHttpException(sprintf('Contest with ID %s not found', $contestId)); @@ -439,13 +438,11 @@ public function toggleSubmitAction(Request $request, string $contestId): Respons #[Route(path: '/{contestId<\d+>}/remove-interval/{intervalId}', name: 'jury_contest_remove_interval', methods: ['POST'])] public function removeIntervalAction(int $contestId, int $intervalId): RedirectResponse { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if (!$contest) { throw new NotFoundHttpException(sprintf('Contest with ID %s not found', $contestId)); } - /** @var RemovedInterval $removedInterval */ $removedInterval = $this->em->getRepository(RemovedInterval::class)->find($intervalId); if (!$removedInterval) { throw new NotFoundHttpException( @@ -473,7 +470,6 @@ public function removeIntervalAction(int $contestId, int $intervalId): RedirectR #[Route(path: '/{contestId<\d+>}/edit', name: 'jury_contest_edit')] public function editAction(Request $request, int $contestId): Response { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if (!$contest) { throw new NotFoundHttpException(sprintf('Contest with ID %s not found', $contestId)); @@ -543,8 +539,16 @@ public function editAction(Request $request, int $contestId): Response // overcomplicate this function. // Note that getSnapshot() returns the data as retrieved from the // database. - $getDeletedEntities = function (Collection $collection, string $idMethod) { - /** @var PersistentCollection $collection */ + /** + * @param Collection $collection + * + * @return array + * @template T + */ + $getDeletedEntities = function (Collection $collection, string $idMethod): array { + if (!$collection instanceof PersistentCollection) { + return []; + } $deletedEntities = []; foreach ($collection->getSnapshot() as $oldEntity) { $oldId = call_user_func([$oldEntity, $idMethod]); @@ -608,7 +612,6 @@ public function editAction(Request $request, int $contestId): Response #[Route(path: '/{contestId<\d+>}/delete', name: 'jury_contest_delete')] public function deleteAction(Request $request, int $contestId): Response { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if (!$contest) { throw new NotFoundHttpException(sprintf('Contest with ID %s not found', $contestId)); @@ -627,7 +630,6 @@ public function deleteAction(Request $request, int $contestId): Response #[Route(path: '/{contestId<\d+>}/problems/{probId<\d+>}/delete', name: 'jury_contest_problem_delete')] public function deleteProblemAction(Request $request, int $contestId, int $probId): Response { - /** @var ContestProblem $contestProblem */ $contestProblem = $this->em->getRepository(ContestProblem::class)->find([ 'contest' => $contestId, 'problem' => $probId @@ -702,7 +704,6 @@ public function addAction(Request $request): Response #[Route(path: '/{contestId<\d+>}/prefetch', name: 'jury_contest_prefetch')] public function prefetchAction(Request $request, int $contestId): Response { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if ($contest === null) { throw new BadRequestHttpException("Contest with cid=$contestId not found."); @@ -712,10 +713,10 @@ public function prefetchAction(Request $request, int $contestId): Response 'hidden' => false, ]); $cnt = 0; + /** @var Judgehost $judgehost */ foreach ($judgehosts as $judgehost) { - /** @var Judgehost $judgehost */ + /** @var ContestProblem $contestProblem */ foreach ($contest->getProblems() as $contestProblem) { - /** @var ContestProblem $contestProblem */ if (!$contestProblem->getAllowJudge() || !$contestProblem->getAllowSubmit()) { continue; } @@ -851,7 +852,6 @@ public function finalizeAction(Request $request, int $contestId): Response #[Route(path: '/{contestId<\d+>}/request-remaining', name: 'jury_contest_request_remaining')] public function requestRemainingRunsWholeContestAction(int $contestId): RedirectResponse { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if (!$contest) { throw new NotFoundHttpException(sprintf('Contest with ID %s not found', $contestId)); @@ -877,7 +877,6 @@ public function requestRemainingRunsWholeContestAction(int $contestId): Redirect #[Route(path: '/{contestId<\d+>}/problems/{probId<\d+>}/request-remaining', name: 'jury_contest_problem_request_remaining')] public function requestRemainingRunsContestProblemAction(int $contestId, int $probId): RedirectResponse { - /** @var ContestProblem $contestProblem */ $contestProblem = $this->em->getRepository(ContestProblem::class)->find([ 'contest' => $contestId, 'problem' => $probId @@ -947,7 +946,6 @@ public function unlockAction(Request $request, int $contestId): Response #[Route(path: '/{contestId<\d+>}/samples.zip', name: 'jury_contest_samples_data_zip')] public function samplesDataZipAction(Request $request, int $contestId): Response { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if (!$contest) { throw new NotFoundHttpException(sprintf('Contest with ID %s not found', $contestId)); @@ -958,7 +956,6 @@ public function samplesDataZipAction(Request $request, int $contestId): Response private function doLock(int $contestId, bool $locked): Response { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if (!$contest) { throw new NotFoundHttpException(sprintf('Contest with ID %s not found.', $contestId)); @@ -984,7 +981,6 @@ public function publicScoreboardDataZipAction( Request $request, ScoreboardService $scoreboardService ): Response { - /** @var Contest $contest */ $contest = $this->em->getRepository(Contest::class)->find($contestId); if (!$contest) { throw new NotFoundHttpException(sprintf('Contest with ID %s not found', $contestId)); diff --git a/webapp/src/Controller/Jury/ExecutableController.php b/webapp/src/Controller/Jury/ExecutableController.php index bd66ab78cf..518b7beb6a 100644 --- a/webapp/src/Controller/Jury/ExecutableController.php +++ b/webapp/src/Controller/Jury/ExecutableController.php @@ -180,7 +180,6 @@ public function viewAction( #[MapQueryParameter] ?int $index = null ): Response { - /** @var Executable $executable */ $executable = $this->em->getRepository(Executable::class)->find($execId); if (!$executable) { throw new NotFoundHttpException(sprintf('Executable with ID %s not found', $execId)); @@ -292,7 +291,6 @@ public function viewAction( #[Route(path: '/{execId}/download', name: 'jury_executable_download')] public function downloadAction(string $execId): Response { - /** @var Executable $executable */ $executable = $this->em->getRepository(Executable::class)->find($execId); if (!$executable) { throw new NotFoundHttpException(sprintf('Executable with ID %s not found', $execId)); @@ -308,7 +306,6 @@ public function downloadAction(string $execId): Response #[Route(path: '/{execId}/delete/{rankToDelete}', name: 'jury_executable_delete_single')] public function deleteSingleAction(Request $request, string $execId, int $rankToDelete): Response { - /** @var Executable $executable */ $executable = $this->em->getRepository(Executable::class)->find($execId); if (!$executable) { throw new NotFoundHttpException(sprintf('Executable with ID %s not found.', $execId)); @@ -375,7 +372,6 @@ public function deleteSingleAction(Request $request, string $execId, int $rankTo #[Route(path: '/{execId}/download/{rank}', name: 'jury_executable_download_single')] public function downloadSingleAction(string $execId, int $rank): Response { - /** @var Executable $executable */ $executable = $this->em->getRepository(Executable::class)->find($execId); if (!$executable) { throw new NotFoundHttpException(sprintf('Executable with ID %s not found.', $execId)); @@ -396,7 +392,6 @@ public function downloadSingleAction(string $execId, int $rank): Response #[Route(path: '/{execId}/delete', name: 'jury_executable_delete')] public function deleteAction(Request $request, string $execId): Response { - /** @var Executable $executable */ $executable = $this->em->getRepository(Executable::class)->find($execId); if (!$executable) { throw new NotFoundHttpException(sprintf('Executable with ID %s not found', $execId)); diff --git a/webapp/src/Controller/Jury/ExternalContestController.php b/webapp/src/Controller/Jury/ExternalContestController.php index 6f8871ba0d..7a79720e75 100644 --- a/webapp/src/Controller/Jury/ExternalContestController.php +++ b/webapp/src/Controller/Jury/ExternalContestController.php @@ -36,7 +36,7 @@ public function __construct( #[Route(path: '/', name: 'jury_external_contest')] public function indexAction(Request $request): Response { - /** @var ExternalContestSource $externalContestSource */ + /** @var ExternalContestSource|null $externalContestSource */ $externalContestSource = $this->em->createQueryBuilder() ->from(ExternalContestSource::class, 'ecs') ->select('ecs') diff --git a/webapp/src/Controller/Jury/ImportExportController.php b/webapp/src/Controller/Jury/ImportExportController.php index 8c23665f8c..357071eccc 100644 --- a/webapp/src/Controller/Jury/ImportExportController.php +++ b/webapp/src/Controller/Jury/ImportExportController.php @@ -28,6 +28,7 @@ use Doctrine\ORM\EntityManagerInterface; use Exception; use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\Form\SubmitButton; use Symfony\Component\HttpKernel\Attribute\MapQueryParameter; use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -110,7 +111,9 @@ public function indexAction(Request $request): Response if ($icpcCmsForm->isSubmitted() && $icpcCmsForm->isValid()) { $contestId = $icpcCmsForm->get('contest_id')->getData(); $accessToken = $icpcCmsForm->get('access_token')->getData(); - if ($icpcCmsForm->get('fetch_teams')->isClicked()) { + /** @var SubmitButton $fetchTeams */ + $fetchTeams = $icpcCmsForm->get('fetch_teams'); + if ($fetchTeams->isClicked()) { if ($this->icpcCmsService->importTeams($accessToken, $contestId, $message)) { $this->addFlash('success', 'Teams successfully imported'); } else { diff --git a/webapp/src/Controller/Jury/InternalErrorController.php b/webapp/src/Controller/Jury/InternalErrorController.php index 9f730fde55..adb4bd971f 100644 --- a/webapp/src/Controller/Jury/InternalErrorController.php +++ b/webapp/src/Controller/Jury/InternalErrorController.php @@ -87,7 +87,6 @@ public function indexAction(): Response #[Route(path: '/{errorId<\d+>}', methods: ['GET'], name: 'jury_internal_error')] public function viewAction(int $errorId): Response { - /** @var InternalError $internalError */ $internalError = $this->em->getRepository(InternalError::class)->find($errorId); if (!$internalError) { throw new NotFoundHttpException(sprintf('Internal Error with ID %s not found', $errorId)); @@ -161,7 +160,7 @@ public function handleAction(Request $request, ?Profiler $profiler, int $errorId ob_flush(); flush(); }; - return $this->streamResponse($this->requestStack, function () use ($request, $progressReporter, $internalError) { + return $this->streamResponse($this->requestStack, function () use ($progressReporter, $internalError) { $this->em->wrapInTransaction(function () use ($progressReporter, $internalError) { $internalError->setStatus(InternalErrorStatusType::STATUS_RESOLVED); $this->dj->setInternalError( diff --git a/webapp/src/Controller/Jury/JudgeRemainingTrait.php b/webapp/src/Controller/Jury/JudgeRemainingTrait.php new file mode 100644 index 0000000000..5a60a52449 --- /dev/null +++ b/webapp/src/Controller/Jury/JudgeRemainingTrait.php @@ -0,0 +1,71 @@ +getJudgingid(); + if ($judging->getResult() === null) { + $inProgress[] = $judgingId; + } elseif ($judging->getJudgeCompletely()) { + $alreadyRequested[] = $judgingId; + } elseif (!$judging->getValid()) { + $invalidJudgings[] = $judgingId; + } else { + $numRequested = $this->em->getConnection()->executeStatement( + 'UPDATE judgetask SET valid=1' + . ' WHERE jobid=:jobid' + . ' AND judgehostid IS NULL', + [ + 'jobid' => $judgingId, + ] + ); + $judging->setJudgeCompletely(true); + + $submission = $judging->getSubmission(); + + $queueTask = new QueueTask(); + $queueTask->setJudging($judging) + ->setPriority(JudgeTask::PRIORITY_LOW) + ->setTeam($submission->getTeam()) + ->setTeamPriority((int)$submission->getSubmittime()) + ->setStartTime(null); + $this->em->persist($queueTask); + } + } + $this->em->flush(); + if (count($judgings) === 1) { + if ($inProgress !== []) { + $this->addFlash('warning', 'Please be patient, this judging is still in progress.'); + } + if ($alreadyRequested !== []) { + $this->addFlash('warning', 'This judging was already requested to be judged completely.'); + } + } else { + if ($inProgress !== []) { + $this->addFlash('warning', sprintf('Please be patient, these judgings are still in progress: %s', implode(', ', $inProgress))); + } + if ($alreadyRequested !== []) { + $this->addFlash('warning', sprintf('These judgings were already requested to be judged completely: %s', implode(', ', $alreadyRequested))); + } + if ($invalidJudgings !== []) { + $this->addFlash('warning', sprintf('These judgings were skipped as they were superseded by other judgings: %s', implode(', ', $invalidJudgings))); + } + } + if ($numRequested === 0) { + $this->addFlash('warning', 'No more remaining runs to be judged.'); + } else { + $this->addFlash('info', "Requested $numRequested remaining runs to be judged."); + } + } +} diff --git a/webapp/src/Controller/Jury/JudgehostController.php b/webapp/src/Controller/Jury/JudgehostController.php index 9049ff4842..fe2dcd07d1 100644 --- a/webapp/src/Controller/Jury/JudgehostController.php +++ b/webapp/src/Controller/Jury/JudgehostController.php @@ -188,7 +188,7 @@ public function indexAction(Request $request): Response #[Route(path: '/{judgehostid}', methods: ['GET'], name: 'jury_judgehost')] public function viewAction(Request $request, int $judgehostid): Response { - /** @var Judgehost $judgehost */ + /** @var Judgehost|null $judgehost */ $judgehost = $this->em->createQueryBuilder() ->from(Judgehost::class, 'j') ->select('j') diff --git a/webapp/src/Controller/Jury/JuryMiscController.php b/webapp/src/Controller/Jury/JuryMiscController.php index 0c20021068..dc419804b5 100644 --- a/webapp/src/Controller/Jury/JuryMiscController.php +++ b/webapp/src/Controller/Jury/JuryMiscController.php @@ -336,7 +336,7 @@ public function adminer( #[Autowire('%domjudge.etcdir%')] string $etcDir, #[Autowire('%kernel.project_dir%')] string $projectDir, ConfigurationService $config - ) { + ): Response { if (!$config->get('adminer_enabled')) { throw new NotFoundHttpException(); } diff --git a/webapp/src/Controller/Jury/LanguageController.php b/webapp/src/Controller/Jury/LanguageController.php index f960d99f6e..2851ac2d02 100644 --- a/webapp/src/Controller/Jury/LanguageController.php +++ b/webapp/src/Controller/Jury/LanguageController.php @@ -14,7 +14,6 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; -use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -22,11 +21,14 @@ use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[IsGranted('ROLE_JURY')] #[Route(path: '/jury/languages')] class LanguageController extends BaseController { + use JudgeRemainingTrait; + public function __construct( protected readonly EntityManagerInterface $em, protected readonly DOMJudgeService $dj, @@ -168,7 +170,6 @@ public function addAction(Request $request): Response #[Route(path: '/{langId}', name: 'jury_language')] public function viewAction(Request $request, SubmissionService $submissionService, string $langId): Response { - /** @var Language $language */ $language = $this->em->getRepository(Language::class)->find($langId); if (!$language) { throw new NotFoundHttpException(sprintf('Language with ID %s not found', $langId)); @@ -207,7 +208,6 @@ public function viewAction(Request $request, SubmissionService $submissionServic #[Route(path: '/{langId}/toggle-submit', name: 'jury_language_toggle_submit')] public function toggleSubmitAction(Request $request, string $langId): Response { - /** @var Language $language */ $language = $this->em->getRepository(Language::class)->find($langId); if (!$language) { throw new NotFoundHttpException(sprintf('Language with ID %s not found', $langId)); @@ -224,7 +224,6 @@ public function toggleSubmitAction(Request $request, string $langId): Response #[Route(path: '/{langId}/toggle-judge', name: 'jury_language_toggle_judge')] public function toggleJudgeAction(Request $request, string $langId): Response { - /** @var Language $language */ $language = $this->em->getRepository(Language::class)->find($langId); if (!$language) { throw new NotFoundHttpException(sprintf('Language with ID %s not found', $langId)); @@ -247,7 +246,6 @@ public function toggleJudgeAction(Request $request, string $langId): Response #[Route(path: '/{langId}/edit', name: 'jury_language_edit')] public function editAction(Request $request, string $langId): Response { - /** @var Language $language */ $language = $this->em->getRepository(Language::class)->find($langId); if (!$language) { throw new NotFoundHttpException(sprintf('Language with ID %s not found', $langId)); @@ -280,7 +278,6 @@ public function editAction(Request $request, string $langId): Response #[Route(path: '/{langId}/delete', name: 'jury_language_delete')] public function deleteAction(Request $request, string $langId): Response { - /** @var Language $language */ $language = $this->em->getRepository(Language::class)->find($langId); if (!$language) { throw new NotFoundHttpException(sprintf('Language with ID %s not found', $langId)); @@ -294,7 +291,6 @@ public function deleteAction(Request $request, string $langId): Response #[Route(path: '/{langId}/request-remaining', name: 'jury_language_request_remaining')] public function requestRemainingRunsWholeLanguageAction(string $langId): RedirectResponse { - /** @var Language $language */ $language = $this->em->getRepository(Language::class)->find($langId); if (!$language) { throw new NotFoundHttpException(sprintf('Language with ID %s not found', $langId)); diff --git a/webapp/src/Controller/Jury/PrintController.php b/webapp/src/Controller/Jury/PrintController.php index 2c8d71f950..af9e453fb5 100644 --- a/webapp/src/Controller/Jury/PrintController.php +++ b/webapp/src/Controller/Jury/PrintController.php @@ -42,7 +42,7 @@ public function showAction(Request $request): Response /** @var UploadedFile $file */ $file = $data['code']; $realfile = $file->getRealPath(); - $originalfilename = $file->getClientOriginalName() ?? ''; + $originalfilename = $file->getClientOriginalName(); $langid = $data['langid']; $username = $this->getUser()->getUserIdentifier(); diff --git a/webapp/src/Controller/Jury/ProblemController.php b/webapp/src/Controller/Jury/ProblemController.php index 51f8acdbdf..7c0abd365a 100644 --- a/webapp/src/Controller/Jury/ProblemController.php +++ b/webapp/src/Controller/Jury/ProblemController.php @@ -46,6 +46,8 @@ #[Route(path: '/jury/problems')] class ProblemController extends BaseController { + use JudgeRemainingTrait; + public function __construct( protected readonly EntityManagerInterface $em, protected readonly DOMJudgeService $dj, @@ -214,7 +216,6 @@ public function problemsetAction(StatisticsService $stats): Response public function sampleZipAction(int $probId): StreamedResponse { $contest = $this->dj->getCurrentContest(); - /** @var ContestProblem $contestProblem */ $contestProblem = $this->em->getRepository(ContestProblem::class)->find([ 'problem' => $probId, 'contest' => $contest, @@ -376,7 +377,6 @@ public function exportAction(int $problemId): StreamedResponse #[Route(path: '/{probId<\d+>}', name: 'jury_problem')] public function viewAction(Request $request, SubmissionService $submissionService, int $probId): Response { - /** @var Problem $problem */ $problem = $this->em->getRepository(Problem::class)->find($probId); if (!$problem) { throw new NotFoundHttpException(sprintf('Problem with ID %s not found', $probId)); @@ -406,7 +406,7 @@ public function viewAction(Request $request, SubmissionService $submissionServic $name = $file->getClientOriginalName(); $fileParts = explode('.', $name); - if (count($fileParts) > 0) { + if (count($fileParts) > 1) { $type = $fileParts[count($fileParts) - 1]; } else { $type = 'txt'; @@ -468,7 +468,6 @@ public function viewAction(Request $request, SubmissionService $submissionServic #[Route(path: '/{probId<\d+>}/text', name: 'jury_problem_text')] public function viewTextAction(int $probId): StreamedResponse { - /** @var Problem $problem */ $problem = $this->em->getRepository(Problem::class)->find($probId); if (!$problem) { throw new NotFoundHttpException(sprintf('Problem with ID %s not found', $probId)); @@ -480,7 +479,6 @@ public function viewTextAction(int $probId): StreamedResponse #[Route(path: '/{probId<\d+>}/testcases', name: 'jury_problem_testcases')] public function testcasesAction(Request $request, int $probId): Response { - /** @var Problem $problem */ $problem = $this->em->getRepository(Problem::class)->find($probId); if (!$problem) { throw new NotFoundHttpException(sprintf('Problem with ID %s not found', $probId)); @@ -726,7 +724,7 @@ public function testcasesAction(Request $request, int $probId): Response 'testcases' => $testcases, 'testcaseData' => $testcaseData, 'extensionMapping' => Testcase::EXTENSION_MAPPING, - 'allowEdit' => $this->isGranted('ROLE_ADMIN') && empty($lockedContest), + 'allowEdit' => $this->isGranted('ROLE_ADMIN') && empty($lockedContests), ]; return $this->render('jury/problem_testcases.html.twig', $data); @@ -736,7 +734,6 @@ public function testcasesAction(Request $request, int $probId): Response #[Route(path: '/{probId<\d+>}/testcases/{rank<\d+>}/move/{direction}', name: 'jury_problem_testcase_move')] public function moveTestcaseAction(int $probId, int $rank, string $direction): Response { - /** @var Problem $problem */ $problem = $this->em->getRepository(Problem::class)->find($probId); if (!$problem) { throw new NotFoundHttpException(sprintf('Problem with ID %s not found', $probId)); @@ -810,7 +807,7 @@ public function moveTestcaseAction(int $probId, int $rank, string $direction): R #[Route(path: '/{probId<\d+>}/testcases/{rank<\d+>}/fetch/{type}', name: 'jury_problem_testcase_fetch')] public function fetchTestcaseAction(int $probId, int $rank, string $type): Response { - /** @var Testcase $testcase */ + /** @var Testcase|null $testcase */ $testcase = $this->em->createQueryBuilder() ->from(Testcase::class, 'tc') ->join('tc.content', 'tcc') @@ -864,7 +861,6 @@ public function fetchTestcaseAction(int $probId, int $rank, string $type): Respo #[Route(path: '/{probId<\d+>}/edit', name: 'jury_problem_edit')] public function editAction(Request $request, int $probId): Response { - /** @var Problem $problem */ $problem = $this->em->getRepository(Problem::class)->find($probId); if (!$problem) { throw new NotFoundHttpException(sprintf('Problem with ID %s not found', $probId)); @@ -947,7 +943,6 @@ public function editAction(Request $request, int $probId): Response #[Route(path: '/{probId<\d+>}/delete', name: 'jury_problem_delete')] public function deleteAction(Request $request, int $probId): Response { - /** @var Problem $problem */ $problem = $this->em->getRepository(Problem::class)->find($probId); if (!$problem) { throw new NotFoundHttpException(sprintf('Problem with ID %s not found', $probId)); @@ -968,7 +963,6 @@ public function deleteAction(Request $request, int $probId): Response #[Route(path: '/attachments/{attachmentId<\d+>}', name: 'jury_attachment_fetch')] public function fetchAttachmentAction(int $attachmentId): StreamedResponse { - /** @var ProblemAttachment $attachment */ $attachment = $this->em->getRepository(ProblemAttachment::class)->find($attachmentId); if (!$attachment) { throw new NotFoundHttpException(sprintf('Attachment with ID %s not found', @@ -982,7 +976,6 @@ public function fetchAttachmentAction(int $attachmentId): StreamedResponse #[Route(path: '/attachments/{attachmentId<\d+>}/delete', name: 'jury_attachment_delete')] public function deleteAttachmentAction(Request $request, int $attachmentId): Response { - /** @var ProblemAttachment $attachment */ $attachment = $this->em->getRepository(ProblemAttachment::class)->find($attachmentId); if (!$attachment) { throw new NotFoundHttpException(sprintf('Attachment with ID %s not found', $attachmentId)); @@ -1007,7 +1000,6 @@ public function deleteAttachmentAction(Request $request, int $attachmentId): Res #[Route(path: '/{testcaseId<\d+>}/delete_testcase', name: 'jury_testcase_delete')] public function deleteTestcaseAction(Request $request, int $testcaseId): Response { - /** @var Testcase $testcase */ $testcase = $this->em->getRepository(Testcase::class)->find($testcaseId); if (!$testcase) { throw new NotFoundHttpException(sprintf('Testcase with ID %s not found', $testcaseId)); @@ -1086,7 +1078,6 @@ private function addTestcasesToZip(array $testcases, ZipArchive $zip, bool $isSa #[Route(path: '/{probId<\d+>}/request-remaining', name: 'jury_problem_request_remaining')] public function requestRemainingRunsWholeProblemAction(string $probId): RedirectResponse { - /** @var Problem $problem */ $problem = $this->em->getRepository(Problem::class)->find($probId); if (!$problem) { throw new NotFoundHttpException(sprintf('Problem with ID %s not found', $probId)); diff --git a/webapp/src/Controller/Jury/RejudgingController.php b/webapp/src/Controller/Jury/RejudgingController.php index cdd0821a69..7eb150e001 100644 --- a/webapp/src/Controller/Jury/RejudgingController.php +++ b/webapp/src/Controller/Jury/RejudgingController.php @@ -203,7 +203,7 @@ public function viewAction( // Close the session, as this might take a while and we don't need the session below. $this->requestStack->getSession()->save(); - /** @var Rejudging $rejudging */ + /** @var Rejudging|null $rejudging */ $rejudging = $this->em->createQueryBuilder() ->from(Rejudging::class, 'r') ->leftJoin('r.start_user', 's') @@ -233,9 +233,9 @@ public function viewAction( } /** @var Judging[] $originalVerdicts */ - /** @var Judging[] $newVerdicts */ $originalVerdicts = []; - $newVerdicts = []; + /** @var Judging[] $newVerdicts */ + $newVerdicts = []; $this->em->wrapInTransaction(function () use ($rejudging, &$originalVerdicts, &$newVerdicts) { $expr = $this->em->getExpressionBuilder(); @@ -616,7 +616,7 @@ public function addAction(Request $request, FormFactoryInterface $formFactory): $skipped = []; $res = $this->rejudgingService->createRejudging( - $reason, (int)$data['priority'], $judgings, false, (int)$data['repeat'] ?? 1, null, $skipped, $progressReporter); + $reason, (int)$data['priority'], $judgings, false, (int)($data['repeat'] ?? 1), null, $skipped, $progressReporter); $this->generateFlashMessagesForSkippedJudgings($skipped); if ($res === null) { @@ -904,7 +904,7 @@ private function getStats(Rejudging $rejudging): array 'count' => count($submissions[$submitid]), 'verdict' => ( !array_key_exists($submitid, $submissions_to_result) - ? join(', ', $results) + ? implode(', ', $results ?? []) : $submissions_to_result[$submitid] ) ]; diff --git a/webapp/src/Controller/Jury/ShadowDifferencesController.php b/webapp/src/Controller/Jury/ShadowDifferencesController.php index 01bfae7597..792dbc6ea3 100644 --- a/webapp/src/Controller/Jury/ShadowDifferencesController.php +++ b/webapp/src/Controller/Jury/ShadowDifferencesController.php @@ -69,10 +69,6 @@ public function indexAction( $contest = $this->dj->getCurrentContest(); $verdicts = array_merge(['judging' => 'JU'], $this->dj->getVerdicts(mergeExternal: true)); - if (!$contest) { - return $this->render('jury/shadow_differences.html.twig'); - } - $verdicts['import-error'] = 'IE'; $used = []; diff --git a/webapp/src/Controller/Jury/SubmissionController.php b/webapp/src/Controller/Jury/SubmissionController.php index 7067ef4a76..b99110d434 100644 --- a/webapp/src/Controller/Jury/SubmissionController.php +++ b/webapp/src/Controller/Jury/SubmissionController.php @@ -35,8 +35,6 @@ use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; use Doctrine\ORM\Query\Expr\Join; -use Symfony\Component\HttpKernel\Attribute\MapQueryParameter; -use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; @@ -46,16 +44,20 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; +use Symfony\Component\HttpKernel\Attribute\MapQueryParameter; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\RouterInterface; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[IsGranted('ROLE_JURY')] #[Route(path: '/jury/submissions')] class SubmissionController extends BaseController { + use JudgeRemainingTrait; + public function __construct( protected readonly EntityManagerInterface $em, protected readonly DOMJudgeService $dj, @@ -364,7 +366,7 @@ public function viewAction( } } $cnt++; - /** @var JudgingRun $firstJudgingRun */ + /** @var JudgingRun|null $firstJudgingRun */ $firstJudgingRun = $runResult[0]->getFirstJudgingRun(); if ($firstJudgingRun !== null && $firstJudgingRun->getRunresult() === null) { $runsOutstanding = true; @@ -557,7 +559,6 @@ public function viewAction( public function requestFullDebug(Request $request, Judging $jid): RedirectResponse { $submission = $jid->getSubmission(); - /** @var Executable $defaultFullDebugExecutable */ $defaultFullDebugExecutable = $this->em ->getRepository(Executable::class) ->findOneBy(['execid' => $this->config->get('default_full_debug')]); @@ -689,7 +690,7 @@ public function sourceAction( ?int $fetch = null ): Response { if ($fetch !== null) { - /** @var SubmissionFile $file */ + /** @var SubmissionFile|null $file */ $file = $this->em->createQueryBuilder() ->from(SubmissionFile::class, 'file') ->select('file') @@ -925,7 +926,6 @@ public function editSourceAction(Request $request, Submission $submission, #[Map #[Route(path: '/{judgingId<\d+>}/request-remaining', name: 'jury_submission_request_remaining', methods: ['POST'])] public function requestRemainingRuns(Request $request, int $judgingId): RedirectResponse { - /** @var Judging $judging */ $judging = $this->em->getRepository(Judging::class)->find($judgingId); if ($judging === null) { throw new BadRequestHttpException("Unknown judging with '$judgingId' requested."); @@ -1055,7 +1055,7 @@ public function verifyShadowDifferenceAction( ): RedirectResponse { /** @var ExternalJudgement $judgement */ $judgement = $this->em->getRepository(ExternalJudgement::class)->find($extjudgementid); - $this->em->wrapInTransaction(function () use ($eventLogService, $request, $judgement) { + $this->em->wrapInTransaction(function () use ($request, $judgement) { $verified = $request->request->getBoolean('verified'); $comment = $request->request->get('comment'); $judgement @@ -1170,7 +1170,7 @@ public function createJudgeTasks(string $submitId): RedirectResponse return $this->redirectToRoute('jury_submission', ['submitId' => $submitId]); } - private function maybeGetErrors(string $type, string $expectedConfigString, string $observedConfigString, array &$allErrors) + private function maybeGetErrors(string $type, string $expectedConfigString, string $observedConfigString, array &$allErrors): void { $expectedConfig = $this->dj->jsonDecode($expectedConfigString); $observedConfig = $this->dj->jsonDecode($observedConfigString); diff --git a/webapp/src/Controller/Jury/TeamAffiliationController.php b/webapp/src/Controller/Jury/TeamAffiliationController.php index e9b2935f41..8c60ffd2e0 100644 --- a/webapp/src/Controller/Jury/TeamAffiliationController.php +++ b/webapp/src/Controller/Jury/TeamAffiliationController.php @@ -134,7 +134,6 @@ public function indexAction( #[Route(path: '/{affilId<\d+>}', name: 'jury_team_affiliation')] public function viewAction(Request $request, ScoreboardService $scoreboardService, int $affilId): Response { - /** @var TeamAffiliation $teamAffiliation */ $teamAffiliation = $this->em->getRepository(TeamAffiliation::class)->find($affilId); if (!$teamAffiliation) { throw new NotFoundHttpException(sprintf('Team affiliation with ID %s not found', $affilId)); @@ -174,7 +173,6 @@ public function viewAction(Request $request, ScoreboardService $scoreboardServic #[Route(path: '/{affilId<\d+>}/edit', name: 'jury_team_affiliation_edit')] public function editAction(Request $request, int $affilId): Response { - /** @var TeamAffiliation $teamAffiliation */ $teamAffiliation = $this->em->getRepository(TeamAffiliation::class)->find($affilId); if (!$teamAffiliation) { throw new NotFoundHttpException(sprintf('Team affiliation with ID %s not found', $affilId)); @@ -201,7 +199,6 @@ public function editAction(Request $request, int $affilId): Response #[Route(path: '/{affilId<\d+>}/delete', name: 'jury_team_affiliation_delete')] public function deleteAction(Request $request, int $affilId): Response { - /** @var TeamAffiliation $teamAffiliation */ $teamAffiliation = $this->em->getRepository(TeamAffiliation::class)->find($affilId); if (!$teamAffiliation) { throw new NotFoundHttpException(sprintf('Team affiliation with ID %s not found', $affilId)); diff --git a/webapp/src/Controller/Jury/TeamCategoryController.php b/webapp/src/Controller/Jury/TeamCategoryController.php index def1c98ec0..9d41e881b8 100644 --- a/webapp/src/Controller/Jury/TeamCategoryController.php +++ b/webapp/src/Controller/Jury/TeamCategoryController.php @@ -15,19 +15,21 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; -use Symfony\Component\Security\Http\Attribute\IsGranted; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[IsGranted('ROLE_JURY')] #[Route(path: '/jury/categories')] class TeamCategoryController extends BaseController { + use JudgeRemainingTrait; + public function __construct( protected readonly EntityManagerInterface $em, protected readonly DOMJudgeService $dj, @@ -121,7 +123,6 @@ public function indexAction(): Response #[Route(path: '/{categoryId<\d+>}', name: 'jury_team_category')] public function viewAction(Request $request, SubmissionService $submissionService, int $categoryId): Response { - /** @var TeamCategory $teamCategory */ $teamCategory = $this->em->getRepository(TeamCategory::class)->find($categoryId); if (!$teamCategory) { throw new NotFoundHttpException(sprintf('Team category with ID %s not found', $categoryId)); @@ -161,7 +162,6 @@ public function viewAction(Request $request, SubmissionService $submissionServic #[Route(path: '/{categoryId<\d+>}/edit', name: 'jury_team_category_edit')] public function editAction(Request $request, int $categoryId): Response { - /** @var TeamCategory $teamCategory */ $teamCategory = $this->em->getRepository(TeamCategory::class)->find($categoryId); if (!$teamCategory) { throw new NotFoundHttpException(sprintf('Team category with ID %s not found', $categoryId)); @@ -204,7 +204,6 @@ public function editAction(Request $request, int $categoryId): Response #[Route(path: '/{categoryId<\d+>}/delete', name: 'jury_team_category_delete')] public function deleteAction(Request $request, int $categoryId): Response { - /** @var TeamCategory $teamCategory */ $teamCategory = $this->em->getRepository(TeamCategory::class)->find($categoryId); if (!$teamCategory) { throw new NotFoundHttpException(sprintf('Team category with ID %s not found', $categoryId)); @@ -238,7 +237,6 @@ public function addAction(Request $request): Response #[Route(path: '/{categoryId<\d+>}/request-remaining', name: 'jury_team_category_request_remaining')] public function requestRemainingRunsWholeTeamCategoryAction(string $categoryId): RedirectResponse { - /** @var TeamCategory $category */ $category = $this->em->getRepository(TeamCategory::class)->find($categoryId); if (!$category) { throw new NotFoundHttpException(sprintf('Team category with ID %s not found', $categoryId)); diff --git a/webapp/src/Controller/Jury/TeamController.php b/webapp/src/Controller/Jury/TeamController.php index 2d42ad1114..89af02df10 100644 --- a/webapp/src/Controller/Jury/TeamController.php +++ b/webapp/src/Controller/Jury/TeamController.php @@ -234,7 +234,6 @@ public function viewAction( #[MapQueryParameter] ?int $cid = null, ): Response { - /** @var Team $team */ $team = $this->em->getRepository(Team::class)->find($teamId); if (!$team) { throw new NotFoundHttpException(sprintf('Team with ID %s not found', $teamId)); @@ -311,7 +310,6 @@ public function viewAction( #[Route(path: '/{teamId<\d+>}/edit', name: 'jury_team_edit')] public function editAction(Request $request, int $teamId): Response { - /** @var Team $team */ $team = $this->em->getRepository(Team::class)->find($teamId); if (!$team) { throw new NotFoundHttpException(sprintf('Team with ID %s not found', $teamId)); @@ -338,7 +336,6 @@ public function editAction(Request $request, int $teamId): Response #[Route(path: '/{teamId<\d+>}/delete', name: 'jury_team_delete')] public function deleteAction(Request $request, int $teamId): Response { - /** @var Team $team */ $team = $this->em->getRepository(Team::class)->find($teamId); if (!$team) { throw new NotFoundHttpException(sprintf('Team with ID %s not found', $teamId)); diff --git a/webapp/src/Controller/Jury/UserController.php b/webapp/src/Controller/Jury/UserController.php index dd73b8a3c5..4f3ebedf0d 100644 --- a/webapp/src/Controller/Jury/UserController.php +++ b/webapp/src/Controller/Jury/UserController.php @@ -173,7 +173,6 @@ public function indexAction(): Response #[Route(path: '/{userId<\d+>}', name: 'jury_user')] public function viewAction(int $userId, SubmissionService $submissionService): Response { - /** @var User $user */ $user = $this->em->getRepository(User::class)->find($userId); if (!$user) { throw new NotFoundHttpException(sprintf('User with ID %s not found', $userId)); @@ -219,7 +218,6 @@ public function checkPasswordLength(User $user, FormInterface $form): ?Response #[Route(path: '/{userId<\d+>}/edit', name: 'jury_user_edit')] public function editAction(Request $request, int $userId): Response { - /** @var User $user */ $user = $this->em->getRepository(User::class)->find($userId); if (!$user) { throw new NotFoundHttpException(sprintf('User with ID %s not found', $userId)); @@ -262,7 +260,6 @@ public function editAction(Request $request, int $userId): Response #[Route(path: '/{userId<\d+>}/delete', name: 'jury_user_delete')] public function deleteAction(Request $request, int $userId): Response { - /** @var User $user */ $user = $this->em->getRepository(User::class)->find($userId); if (!$user) { throw new NotFoundHttpException(sprintf('User with ID %s not found', $userId)); @@ -318,6 +315,7 @@ public function generatePasswordsAction(Request $request): Response $changes = []; foreach ($users as $user) { + $role = null; $doit = false; $roles = $user->getRoleList(); diff --git a/webapp/src/Controller/Jury/VersionController.php b/webapp/src/Controller/Jury/VersionController.php index fe66498f70..aaa6028da4 100644 --- a/webapp/src/Controller/Jury/VersionController.php +++ b/webapp/src/Controller/Jury/VersionController.php @@ -95,7 +95,6 @@ public function indexAction(): Response #[Route(path: '/{versionId<\d+>}/promote_compiler', name: 'jury_compiler_promote')] public function promoteCompilerAction(int $versionId): Response { - /** @var Version $version */ $version = $this->em->getRepository(Version::class)->find($versionId); if (!$version) { throw new NotFoundHttpException(sprintf('Version with ID %s not found', $versionId)); @@ -114,7 +113,6 @@ public function promoteCompilerAction(int $versionId): Response #[Route(path: '/{versionId<\d+>}/promote_runner', name: 'jury_runner_promote')] public function promoteRunnerAction(int $versionId): Response { - /** @var Version $version */ $version = $this->em->getRepository(Version::class)->find($versionId); if (!$version) { throw new NotFoundHttpException(sprintf('Version with ID %s not found', $versionId)); diff --git a/webapp/src/Controller/PublicController.php b/webapp/src/Controller/PublicController.php index 48a1fdb833..78649bd1be 100644 --- a/webapp/src/Controller/PublicController.php +++ b/webapp/src/Controller/PublicController.php @@ -224,7 +224,6 @@ protected function getBinaryFile(int $probId, callable $response): StreamedRespo if (!$contest || !$contest->getFreezeData()->started()) { throw new NotFoundHttpException(sprintf('Problem p%d not found or not available', $probId)); } - /** @var ContestProblem $contestProblem */ $contestProblem = $this->em->getRepository(ContestProblem::class)->find([ 'problem' => $probId, 'contest' => $contest, diff --git a/webapp/src/Controller/RootController.php b/webapp/src/Controller/RootController.php index a0a109b54a..b99888dda4 100644 --- a/webapp/src/Controller/RootController.php +++ b/webapp/src/Controller/RootController.php @@ -44,7 +44,7 @@ public function markdownPreview( Request $request, #[Autowire(service: 'twig.runtime.markdown')] MarkdownRuntime $markdownRuntime - ) { + ): JsonResponse { $message = $request->request->get('message'); if ($message === null) { throw new BadRequestHttpException('A message is required'); diff --git a/webapp/src/Controller/Team/MiscController.php b/webapp/src/Controller/Team/MiscController.php index 68d1fa7083..7b1e03c1d8 100644 --- a/webapp/src/Controller/Team/MiscController.php +++ b/webapp/src/Controller/Team/MiscController.php @@ -164,7 +164,7 @@ public function printAction(Request $request): Response /** @var UploadedFile $file */ $file = $data['code']; $realfile = $file->getRealPath(); - $originalfilename = $file->getClientOriginalName() ?? ''; + $originalfilename = $file->getClientOriginalName(); $langid = $data['langid']; $username = $this->getUser()->getUserIdentifier(); diff --git a/webapp/src/Controller/Team/ProblemController.php b/webapp/src/Controller/Team/ProblemController.php index ac68640b8d..3ac8df3b6f 100644 --- a/webapp/src/Controller/Team/ProblemController.php +++ b/webapp/src/Controller/Team/ProblemController.php @@ -97,7 +97,6 @@ protected function getBinaryFile(int $probId, callable $response): StreamedRespo if (!$contest || !$contest->getFreezeData()->started()) { throw new NotFoundHttpException(sprintf('Problem p%d not found or not available', $probId)); } - /** @var ContestProblem $contestProblem */ $contestProblem = $this->em->getRepository(ContestProblem::class)->find([ 'problem' => $probId, 'contest' => $contest, diff --git a/webapp/src/Controller/Team/SubmissionController.php b/webapp/src/Controller/Team/SubmissionController.php index eb857a5980..29d3ceae8c 100644 --- a/webapp/src/Controller/Team/SubmissionController.php +++ b/webapp/src/Controller/Team/SubmissionController.php @@ -117,7 +117,7 @@ public function viewAction(Request $request, int $submitId): Response $user = $this->dj->getUser(); $team = $user->getTeam(); $contest = $this->dj->getCurrentContest($team->getTeamid()); - /** @var Judging $judging */ + /** @var Judging|null $judging */ $judging = $this->em->createQueryBuilder() ->from(Judging::class, 'j') ->join('j.submission', 's') @@ -217,7 +217,7 @@ public function downloadAction(int $submitId): Response $user = $this->dj->getUser(); $team = $user->getTeam(); - /** @var Submission $submission */ + /** @var Submission|null $submission */ $submission = $this->em->createQueryBuilder() ->from(Submission::class, 's') ->join('s.files', 'f') diff --git a/webapp/src/Doctrine/DBAL/Types/JudgeTaskType.php b/webapp/src/Doctrine/DBAL/Types/JudgeTaskType.php index 788a60fb18..b9c2575113 100644 --- a/webapp/src/Doctrine/DBAL/Types/JudgeTaskType.php +++ b/webapp/src/Doctrine/DBAL/Types/JudgeTaskType.php @@ -21,9 +21,6 @@ class JudgeTaskType extends Type self::PREFETCH, ]; - /** - * @return mixed - */ public function getSQLDeclaration(array $column, AbstractPlatform $platform): string { $statuses = implode(', ', array_map( diff --git a/webapp/src/Entity/Clarification.php b/webapp/src/Entity/Clarification.php index ac12ffc18b..c19330ff42 100644 --- a/webapp/src/Entity/Clarification.php +++ b/webapp/src/Entity/Clarification.php @@ -98,6 +98,9 @@ class Clarification extends BaseApiEntity implements ExternalRelationshipEntityI #[Serializer\Exclude] private ?Clarification $in_reply_to = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'in_reply_to', targetEntity: Clarification::class)] #[Serializer\Exclude] private Collection $replies; @@ -279,6 +282,9 @@ public function addReply(Clarification $reply): Clarification return $this; } + /** + * @return Collection + */ public function getReplies(): Collection { return $this->replies; diff --git a/webapp/src/Entity/Contest.php b/webapp/src/Entity/Contest.php index 564f0069a7..ada65062dc 100644 --- a/webapp/src/Entity/Contest.php +++ b/webapp/src/Entity/Contest.php @@ -86,7 +86,7 @@ class Contest extends BaseApiEntity implements AssetEntityInterface options: ['comment' => 'Time contest becomes visible in team/public views', 'unsigned' => true] )] #[Serializer\Exclude] - private string|float $activatetime; + private string|float|null $activatetime; #[ORM\Column( type: 'decimal', @@ -121,7 +121,7 @@ class Contest extends BaseApiEntity implements AssetEntityInterface options: ['comment' => 'Time after which no more submissions are accepted', 'unsigned' => true] )] #[Serializer\Exclude] - private string|float $endtime; + private string|float|null $endtime; #[ORM\Column( type: 'decimal', @@ -165,6 +165,9 @@ class Contest extends BaseApiEntity implements AssetEntityInterface #[Serializer\Exclude] private ?bool $medalsEnabled = false; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: TeamCategory::class, inversedBy: 'contests_for_medals')] #[ORM\JoinTable(name: 'contestteamcategoryformedals')] #[ORM\JoinColumn(name: 'cid', referencedColumnName: 'cid', onDelete: 'CASCADE')] @@ -313,6 +316,9 @@ class Contest extends BaseApiEntity implements AssetEntityInterface #[Serializer\Exclude] private bool $isLocked = false; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: Team::class, inversedBy: 'contests')] #[ORM\JoinTable(name: 'contestteam')] #[ORM\JoinColumn(name: 'cid', referencedColumnName: 'cid', onDelete: 'CASCADE')] @@ -320,6 +326,9 @@ class Contest extends BaseApiEntity implements AssetEntityInterface #[Serializer\Exclude] private Collection $teams; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: TeamCategory::class, inversedBy: 'contests')] #[ORM\JoinTable(name: 'contestteamcategory')] #[ORM\JoinColumn(name: 'cid', referencedColumnName: 'cid', onDelete: 'CASCADE')] @@ -327,14 +336,23 @@ class Contest extends BaseApiEntity implements AssetEntityInterface #[Serializer\Exclude] private Collection $team_categories; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'contest', targetEntity: Clarification::class)] #[Serializer\Exclude] private Collection $clarifications; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'contest', targetEntity: Submission::class)] #[Serializer\Exclude] private Collection $submissions; + /** + * @var Collection + */ #[ORM\OneToMany( mappedBy: 'contest', targetEntity: ContestProblem::class, @@ -346,15 +364,24 @@ class Contest extends BaseApiEntity implements AssetEntityInterface #[Serializer\Exclude] private Collection $problems; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'contest', targetEntity: InternalError::class)] #[Serializer\Exclude] private Collection $internal_errors; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'contest', targetEntity: RemovedInterval::class)] #[Assert\Valid] #[Serializer\Exclude] private Collection $removedIntervals; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'contest', targetEntity: ExternalContestSource::class)] #[Assert\Valid] #[Serializer\Exclude] @@ -511,7 +538,7 @@ public function getB(): ?int return $this->b; } - public function setB(?int $b) + public function setB(?int $b): void { $this->b = $b; } @@ -709,7 +736,7 @@ public function getMedalsEnabled(): bool } /** - * @return Collection|TeamCategory[] + * @return Collection */ public function getMedalCategories(): Collection { @@ -811,6 +838,14 @@ public function addTeam(Team $team): Contest return $this; } + public function removeTeam(Team $team): void + { + $this->teams->removeElement($team); + } + + /** + * @return Collection + */ public function getTeams(): Collection { return $this->teams; @@ -827,6 +862,9 @@ public function removeProblem(ContestProblem $problem): void $this->problems->removeElement($problem); } + /** + * @return Collection + */ public function getProblems(): Collection { return $this->problems; @@ -838,6 +876,9 @@ public function addClarification(Clarification $clarification): Contest return $this; } + /** + * @return Collection + */ public function getClarifications(): Collection { return $this->clarifications; @@ -849,6 +890,9 @@ public function addSubmission(Submission $submission): Contest return $this; } + /** + * @return Collection + */ public function getSubmissions(): Collection { return $this->submissions; @@ -860,6 +904,9 @@ public function addInternalError(InternalError $internalError): Contest return $this; } + /** + * @return Collection + */ public function getInternalErrors(): Collection { return $this->internal_errors; @@ -922,7 +969,7 @@ public function getAbsoluteTime(?string $time_string): float|int|string|null static fn( RemovedInterval $a, RemovedInterval $b - ) => Utils::difftime((float)$a->getStarttime(), (float)$b->getStarttime()) + ) => (int)Utils::difftime((float)$a->getStarttime(), (float)$b->getStarttime()) ); foreach ($removedIntervals as $removedInterval) { if (Utils::difftime((float)$removedInterval->getStarttime(), (float)$absoluteTime) <= 0) { @@ -953,6 +1000,9 @@ public function removeRemovedInterval(RemovedInterval $removedInterval): void $this->removedIntervals->removeElement($removedInterval); } + /** + * @return Collection + */ public function getRemovedIntervals(): Collection { return $this->removedIntervals; @@ -1171,7 +1221,7 @@ public function validate(ExecutionContextInterface $context): void ->addViolation(); } } - if ($this->medal_categories === null || $this->medal_categories->isEmpty()) { + if ($this->medal_categories->isEmpty()) { $context ->buildViolation('This field is required when \'Process medals\' is set.') ->atPath('medalCategories') @@ -1241,7 +1291,7 @@ public function getOpenToAllTeams(): ?bool } /** - * @return Collection|TeamCategory[] + * @return Collection */ public function getTeamCategories(): Collection { @@ -1258,7 +1308,7 @@ public function addTeamCategory(TeamCategory $teamCategory): self } /** - * @return Collection|ExternalContestSource[] + * @return Collection */ public function getExternalContestSources(): Collection { diff --git a/webapp/src/Entity/ContestProblem.php b/webapp/src/Entity/ContestProblem.php index f4d6ef5c92..63ebe3574d 100644 --- a/webapp/src/Entity/ContestProblem.php +++ b/webapp/src/Entity/ContestProblem.php @@ -87,6 +87,9 @@ class ContestProblem #[Serializer\Inline] private ?Problem $problem = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'contest_problem', targetEntity: Submission::class)] #[Serializer\Exclude] private Collection $submissions; @@ -205,6 +208,9 @@ public function addSubmission(Submission $submission): ContestProblem return $this; } + /** + * @return Collection + */ public function getSubmissions(): Collection { return $this->submissions; diff --git a/webapp/src/Entity/Executable.php b/webapp/src/Entity/Executable.php index 3f8e1af5c4..30eb1aa422 100644 --- a/webapp/src/Entity/Executable.php +++ b/webapp/src/Entity/Executable.php @@ -38,12 +38,21 @@ class Executable #[ORM\JoinColumn(name: 'immutable_execid', referencedColumnName: 'immutable_execid')] private ImmutableExecutable $immutableExecutable; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'compile_executable', targetEntity: Language::class)] private Collection $languages; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'compare_executable', targetEntity: Problem::class)] private Collection $problems_compare; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'run_executable', targetEntity: Problem::class)] private Collection $problems_run; @@ -98,6 +107,9 @@ public function addLanguage(Language $language): Executable return $this; } + /** + * @return Collection + */ public function getLanguages(): Collection { return $this->languages; @@ -109,6 +121,9 @@ public function addProblemsCompare(Problem $problemsCompare): Executable return $this; } + /** + * @return Collection + */ public function getProblemsCompare(): Collection { return $this->problems_compare; @@ -120,6 +135,9 @@ public function addProblemsRun(Problem $problemsRun): Executable return $this; } + /** + * @return Collection + */ public function getProblemsRun(): Collection { return $this->problems_run; diff --git a/webapp/src/Entity/ExternalContestSource.php b/webapp/src/Entity/ExternalContestSource.php index c178d5c21c..39eaf14de5 100644 --- a/webapp/src/Entity/ExternalContestSource.php +++ b/webapp/src/Entity/ExternalContestSource.php @@ -53,6 +53,9 @@ class ExternalContestSource #[ORM\JoinColumn(name: 'cid', referencedColumnName: 'cid', onDelete: 'CASCADE')] private Contest $contest; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'externalContestSource', targetEntity: ExternalSourceWarning::class)] private Collection $warnings; @@ -149,7 +152,7 @@ public function getContest(): Contest } /** - * @return Collection|ExternalSourceWarning[] + * @return Collection */ public function getExternalSourceWarnings(): Collection { diff --git a/webapp/src/Entity/ExternalJudgement.php b/webapp/src/Entity/ExternalJudgement.php index 96c568e76b..95bc555897 100644 --- a/webapp/src/Entity/ExternalJudgement.php +++ b/webapp/src/Entity/ExternalJudgement.php @@ -92,6 +92,9 @@ class ExternalJudgement #[ORM\JoinColumn(name: 'submitid', referencedColumnName: 'submitid', onDelete: 'CASCADE')] private Submission $submission; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'external_judgement', targetEntity: ExternalRun::class)] private Collection $external_runs; @@ -221,6 +224,9 @@ public function addExternalRun(ExternalRun $externalRun): ExternalJudgement return $this; } + /** + * @return Collection + */ public function getExternalRuns(): Collection { return $this->external_runs; diff --git a/webapp/src/Entity/ImmutableExecutable.php b/webapp/src/Entity/ImmutableExecutable.php index 5b6a46d00a..956582213b 100644 --- a/webapp/src/Entity/ImmutableExecutable.php +++ b/webapp/src/Entity/ImmutableExecutable.php @@ -33,6 +33,9 @@ class ImmutableExecutable #[Serializer\Exclude] private ?User $user = null; + /** + * @var Collection|null + */ #[ORM\OneToMany(mappedBy: 'immutableExecutable', targetEntity: ExecutableFile::class)] #[ORM\OrderBy(['filename' => 'ASC'])] #[Serializer\Exclude] @@ -64,7 +67,7 @@ public function getUser(): User return $this->user; } - protected function updateHash() + protected function updateHash(): void { if ($this->files === null) { $this->hash = null; @@ -82,6 +85,9 @@ protected function updateHash() ); } + /** + * @return Collection + */ public function getFiles(): Collection { return $this->files; diff --git a/webapp/src/Entity/InternalError.php b/webapp/src/Entity/InternalError.php index e858fdb8e3..2147357baf 100644 --- a/webapp/src/Entity/InternalError.php +++ b/webapp/src/Entity/InternalError.php @@ -66,6 +66,9 @@ class InternalError #[ORM\JoinColumn(name: 'judgingid', referencedColumnName: 'judgingid', onDelete: 'SET NULL')] private ?Judging $judging = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'internalError', targetEntity: Judging::class)] #[Serializer\Exclude] private Collection $affectedJudgings; @@ -163,6 +166,9 @@ public function getJudging(): ?Judging return $this->judging; } + /** + * @return Collection + */ public function getAffectedJudgings(): Collection { return $this->affectedJudgings; diff --git a/webapp/src/Entity/JudgeTask.php b/webapp/src/Entity/JudgeTask.php index 569dce4d0e..03e9359f0b 100644 --- a/webapp/src/Entity/JudgeTask.php +++ b/webapp/src/Entity/JudgeTask.php @@ -70,7 +70,7 @@ class JudgeTask private ?string $uuid = null; - #[ORM\ManyToOne(inversedBy: 'judgetasks')] + #[ORM\ManyToOne()] #[ORM\JoinColumn(name: 'submitid', nullable: true, referencedColumnName: 'submitid', onDelete: 'CASCADE', options: ['comment' => 'Submission ID being judged', 'unsigned' => true]) ] @@ -155,6 +155,9 @@ public function getSubmitid(): ?int #[Serializer\Exclude] private string|float|null $starttime = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'judgetask', targetEntity: JudgingRun::class)] #[Serializer\Exclude] private Collection $judging_runs; @@ -202,7 +205,7 @@ public function getPriority(): int return $this->priority; } - public function setJobId($jobid): JudgeTask + public function setJobId(?int $jobid): JudgeTask { $this->jobid = $jobid; return $this; @@ -360,6 +363,9 @@ public function addJudgingRun(JudgingRun $judgingRun): JudgeTask return $this; } + /** + * @return Collection + */ public function getJudgingRuns(): Collection { return $this->judging_runs; diff --git a/webapp/src/Entity/Judgehost.php b/webapp/src/Entity/Judgehost.php index 47395bf033..7d72e19b06 100644 --- a/webapp/src/Entity/Judgehost.php +++ b/webapp/src/Entity/Judgehost.php @@ -44,6 +44,9 @@ class Judgehost #[OA\Property(nullable: true)] private string|float|null $polltime = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'judgehost', targetEntity: JudgeTask::class)] #[Serializer\Exclude] private Collection $judgetasks; @@ -105,6 +108,9 @@ public function addJudgeTask(JudgeTask $judgeTask): Judgehost return $this; } + /** + * @return Collection + */ public function getJudgeTasks(): Collection { return $this->judgetasks; diff --git a/webapp/src/Entity/Judging.php b/webapp/src/Entity/Judging.php index b752ac2074..66e0708d12 100644 --- a/webapp/src/Entity/Judging.php +++ b/webapp/src/Entity/Judging.php @@ -144,10 +144,16 @@ class Judging extends BaseApiEntity implements ExternalRelationshipEntityInterfa #[Serializer\Exclude] private ?Judging $original_judging = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'judging', targetEntity: JudgingRun::class)] #[Serializer\Exclude] private Collection $runs; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'judging', targetEntity: DebugPackage::class)] #[Serializer\Exclude] private Collection $debug_packages; @@ -414,6 +420,9 @@ public function addRun(JudgingRun $run): Judging return $this; } + /** + * @return Collection + */ public function getRuns(): Collection { return $this->runs; @@ -483,6 +492,9 @@ public function getJudgehosts(): array return $hostnames; } + /** + * @return Collection + */ public function getDebugPackages(): Collection { return $this->debug_packages; @@ -493,7 +505,7 @@ public function getCompileMetadata(): ?string return $this->compile_metadata; } - public function setCompileMetadata($compile_metadata): self + public function setCompileMetadata(?string $compile_metadata): self { $this->compile_metadata = $compile_metadata; return $this; diff --git a/webapp/src/Entity/JudgingRun.php b/webapp/src/Entity/JudgingRun.php index d0483a14bb..9cb2863071 100644 --- a/webapp/src/Entity/JudgingRun.php +++ b/webapp/src/Entity/JudgingRun.php @@ -71,6 +71,8 @@ class JudgingRun extends BaseApiEntity private Testcase $testcase; /** + * @var Collection + * * We use a OneToMany instead of a OneToOne here, because otherwise this * relation will always be loaded. See the commit message of commit * 9e421f96691ec67ed62767fe465a6d8751edd884 for a more elaborate explanation diff --git a/webapp/src/Entity/JudgingRunOutput.php b/webapp/src/Entity/JudgingRunOutput.php index 9d38fae7ba..ac312e9565 100644 --- a/webapp/src/Entity/JudgingRunOutput.php +++ b/webapp/src/Entity/JudgingRunOutput.php @@ -79,7 +79,7 @@ public function getRun(): JudgingRun return $this->run; } - public function setOutputRun($outputRun): JudgingRunOutput + public function setOutputRun(?string $outputRun): JudgingRunOutput { $this->output_run = $outputRun; return $this; @@ -139,7 +139,7 @@ public function getMetadata(): string return $this->metadata; } - public function setMetadata($metadata): self + public function setMetadata(?string $metadata): self { $this->metadata = $metadata; return $this; diff --git a/webapp/src/Entity/Language.php b/webapp/src/Entity/Language.php index c440b62750..1e0e118448 100644 --- a/webapp/src/Entity/Language.php +++ b/webapp/src/Entity/Language.php @@ -110,10 +110,16 @@ class Language extends BaseApiEntity #[Serializer\Exclude] private ?Executable $compile_executable = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'language', targetEntity: Submission::class)] #[Serializer\Exclude] private Collection $submissions; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'language', targetEntity: Version::class)] #[Serializer\Exclude] private Collection $versions; @@ -130,7 +136,19 @@ class Language extends BaseApiEntity #[ORM\Column(type: 'string', length: 255, nullable: true, options: ['comment' => 'Compiler version command'])] private ?string $compilerVersionCommand = null; - public function getVersions() + /** + * @param Collection $versions + */ + public function setVersions(Collection $versions): Language + { + $this->versions = $versions; + return $this; + } + + /** + * @return Collection + */ + public function getVersions(): Collection { return $this->versions; } @@ -318,6 +336,7 @@ public function getCompileExecutable(): ?Executable public function __construct() { $this->submissions = new ArrayCollection(); + $this->versions = new ArrayCollection(); } public function addSubmission(Submission $submission): Language @@ -326,6 +345,9 @@ public function addSubmission(Submission $submission): Language return $this; } + /** + * @return Collection + */ public function getSubmissions(): Collection { return $this->submissions; diff --git a/webapp/src/Entity/Problem.php b/webapp/src/Entity/Problem.php index 9ceb1adef8..c233737d66 100644 --- a/webapp/src/Entity/Problem.php +++ b/webapp/src/Entity/Problem.php @@ -115,14 +115,23 @@ class Problem extends BaseApiEntity #[Serializer\Exclude] private ?string $problemtext_type = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'problem', targetEntity: Submission::class)] #[Serializer\Exclude] private Collection $submissions; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'problem', targetEntity: Clarification::class)] #[Serializer\Exclude] private Collection $clarifications; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'problem', targetEntity: ContestProblem::class)] #[Serializer\Exclude] private Collection $contest_problems; @@ -137,11 +146,17 @@ class Problem extends BaseApiEntity #[Serializer\Exclude] private ?Executable $run_executable = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'problem', targetEntity: Testcase::class)] #[ORM\OrderBy(['ranknumber' => 'ASC'])] #[Serializer\Exclude] private Collection $testcases; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'problem', targetEntity: ProblemAttachment::class, orphanRemoval: true)] #[ORM\OrderBy(['name' => 'ASC'])] #[Serializer\Exclude] @@ -244,7 +259,7 @@ public function getCombinedRunCompare(): bool } /** - * @param resource|string $problemtext + * @param resource|string|null $problemtext */ public function setProblemtext($problemtext): Problem { @@ -336,6 +351,9 @@ public function addTestcase(Testcase $testcase): Problem return $this; } + /** + * @return Collection + */ public function getTestcases(): Collection { return $this->testcases; @@ -348,9 +366,9 @@ public function addContestProblem(ContestProblem $contestProblem): Problem } /** - * @return Collection|ContestProblem[] + * @return Collection */ - public function getContestProblems(): Collection|array + public function getContestProblems(): Collection { return $this->contest_problems; } @@ -361,6 +379,9 @@ public function addSubmission(Submission $submission): Problem return $this; } + /** + * @return Collection + */ public function getSubmissions(): Collection { return $this->submissions; @@ -372,6 +393,9 @@ public function addClarification(Clarification $clarification): Problem return $this; } + /** + * @return Collection + */ public function getClarifications(): Collection { return $this->clarifications; @@ -401,7 +425,7 @@ public function removeAttachment(ProblemAttachment $attachment): self } /** - * @return Collection|ProblemAttachment[] + * @return Collection */ public function getAttachments(): Collection { diff --git a/webapp/src/Entity/ProblemAttachment.php b/webapp/src/Entity/ProblemAttachment.php index 7a06f09216..282d0f8e79 100644 --- a/webapp/src/Entity/ProblemAttachment.php +++ b/webapp/src/Entity/ProblemAttachment.php @@ -33,6 +33,8 @@ class ProblemAttachment private ?Problem $problem = null; /** + * @var Collection + * * We use a OneToMany instead of a OneToOne here, because otherwise this * relation will always be loaded. See the commit message of commit * 9e421f96691ec67ed62767fe465a6d8751edd884 for a more elaborate explanation diff --git a/webapp/src/Entity/Rejudging.php b/webapp/src/Entity/Rejudging.php index bab66cfc7c..ea60dd2ce6 100644 --- a/webapp/src/Entity/Rejudging.php +++ b/webapp/src/Entity/Rejudging.php @@ -63,12 +63,16 @@ class Rejudging private ?User $finish_user = null; /** + * @var Collection + * * One rejudging has many judgings. */ #[ORM\OneToMany(mappedBy: 'rejudging', targetEntity: Judging::class)] private Collection $judgings; /** + * @var Collection + * * One rejudging has many submissions. */ #[ORM\OneToMany(mappedBy: 'rejudging', targetEntity: Submission::class)] @@ -175,6 +179,9 @@ public function addJudging(Judging $judging): Rejudging return $this; } + /** + * @return Collection + */ public function getJudgings(): Collection { return $this->judgings; @@ -186,6 +193,9 @@ public function addSubmission(Submission $submission): Rejudging return $this; } + /** + * @return Collection + */ public function getSubmissions(): Collection { return $this->submissions; diff --git a/webapp/src/Entity/RemovedInterval.php b/webapp/src/Entity/RemovedInterval.php index 04966fa37d..f853da5d39 100644 --- a/webapp/src/Entity/RemovedInterval.php +++ b/webapp/src/Entity/RemovedInterval.php @@ -134,7 +134,7 @@ public function getContest(): Contest } #[Assert\Callback] - public function validate(ExecutionContextInterface $context) + public function validate(ExecutionContextInterface $context): void { // Update all contest timing, taking into account all removed intervals $this->getContest()->setStarttimeString($this->getContest()->getStarttimeString()); diff --git a/webapp/src/Entity/Role.php b/webapp/src/Entity/Role.php index 486c03ecd2..42fa4a840c 100644 --- a/webapp/src/Entity/Role.php +++ b/webapp/src/Entity/Role.php @@ -29,6 +29,9 @@ class Role implements Stringable #[ORM\Column(options: ['comment' => 'Description for the web interface'])] private string $description; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'user_roles')] private Collection $users; @@ -75,6 +78,9 @@ public function addUser(User $user): Role return $this; } + /** + * @return Collection + */ public function getUsers(): Collection { return $this->users; diff --git a/webapp/src/Entity/Submission.php b/webapp/src/Entity/Submission.php index 7552ed6ec7..367d837988 100644 --- a/webapp/src/Entity/Submission.php +++ b/webapp/src/Entity/Submission.php @@ -129,22 +129,30 @@ class Submission extends BaseApiEntity implements ExternalRelationshipEntityInte #[Serializer\Exclude] private ContestProblem $contest_problem; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'submission', targetEntity: Judging::class)] #[Serializer\Exclude] private Collection $judgings; - #[ORM\OneToMany(mappedBy: 'submission', targetEntity: JudgeTask::class)] - #[Serializer\Exclude] - private Collection $judgetasks; - + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'submission', targetEntity: ExternalJudgement::class)] #[Serializer\Exclude] private Collection $external_judgements; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'submission', targetEntity: SubmissionFile::class)] #[Serializer\Exclude] private Collection $files; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'submission', targetEntity: Balloon::class)] #[Serializer\Exclude] private Collection $balloons; @@ -162,6 +170,9 @@ class Submission extends BaseApiEntity implements ExternalRelationshipEntityInte #[Serializer\Exclude] private ?Submission $originalSubmission = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'originalSubmission', targetEntity: Submission::class)] #[Serializer\Exclude] private Collection $resubmissions; @@ -322,6 +333,9 @@ public function addJudging(Judging $judging): Submission return $this; } + /** + * @return Collection + */ public function getJudgings(): Collection { return $this->judgings; @@ -344,6 +358,9 @@ public function addFile(SubmissionFile $file): Submission return $this; } + /** + * @return Collection + */ public function getFiles(): Collection { return $this->files; @@ -355,6 +372,9 @@ public function addBalloon(Balloon $balloon): Submission return $this; } + /** + * @return Collection + */ public function getBalloons(): Collection { return $this->balloons; @@ -461,7 +481,7 @@ public function addResubmission(Submission $submission): Submission } /** - * @return Collection|Submission[] + * @return Collection */ public function getResubmissions(): Collection { @@ -502,6 +522,9 @@ public function addExternalJudgement(ExternalJudgement $externalJudgement): Subm return $this; } + /** + * @return Collection + */ public function getExternalJudgements(): Collection { return $this->external_judgements; diff --git a/webapp/src/Entity/Team.php b/webapp/src/Entity/Team.php index 3b82292b1c..de682b3301 100644 --- a/webapp/src/Entity/Team.php +++ b/webapp/src/Entity/Team.php @@ -139,27 +139,45 @@ class Team extends BaseApiEntity implements ExternalRelationshipEntityInterface, #[Serializer\Exclude] private ?TeamCategory $category = null; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: Contest::class, mappedBy: 'teams')] #[Serializer\Exclude] private Collection $contests; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'team', targetEntity: User::class, cascade: ['persist'])] #[Assert\Valid] #[Serializer\Exclude] private Collection $users; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'team', targetEntity: Submission::class)] #[Serializer\Exclude] private Collection $submissions; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'sender', targetEntity: Clarification::class)] #[Serializer\Exclude] private Collection $sent_clarifications; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'recipient', targetEntity: Clarification::class)] #[Serializer\Exclude] private Collection $received_clarifications; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: Clarification::class)] #[ORM\JoinTable(name: 'team_unread')] #[ORM\JoinColumn(name: 'teamid', referencedColumnName: 'teamid', onDelete: 'CASCADE')] @@ -440,6 +458,9 @@ public function removeContest(Contest $contest): void $contest->removeTeam($this); } + /** + * @return Collection + */ public function getContests(): Collection { return $this->contests; @@ -452,6 +473,9 @@ public function addUser(User $user): Team return $this; } + /** + * @return Collection + */ public function getUsers(): Collection { return $this->users; @@ -463,6 +487,9 @@ public function addSubmission(Submission $submission): Team return $this; } + /** + * @return Collection + */ public function getSubmissions(): Collection { return $this->submissions; @@ -474,6 +501,9 @@ public function addSentClarification(Clarification $sentClarification): Team return $this; } + /** + * @return Collection + */ public function getSentClarifications(): Collection { return $this->sent_clarifications; @@ -485,6 +515,9 @@ public function addReceivedClarification(Clarification $receivedClarification): return $this; } + /** + * @return Collection + */ public function getReceivedClarifications(): Collection { return $this->received_clarifications; @@ -501,6 +534,9 @@ public function removeUnreadClarification(Clarification $unreadClarification): v $this->unread_clarifications->removeElement($unreadClarification); } + /** + * @return Collection + */ public function getUnreadClarifications(): Collection { return $this->unread_clarifications; diff --git a/webapp/src/Entity/TeamAffiliation.php b/webapp/src/Entity/TeamAffiliation.php index 2a40f4e282..9f2dde7dff 100644 --- a/webapp/src/Entity/TeamAffiliation.php +++ b/webapp/src/Entity/TeamAffiliation.php @@ -89,6 +89,9 @@ class TeamAffiliation extends BaseApiEntity implements AssetEntityInterface #[Serializer\Exclude] private ?string $internalComments = null; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'affiliation', targetEntity: Team::class)] #[Serializer\Exclude] private Collection $teams; @@ -210,6 +213,9 @@ public function addTeam(Team $team): TeamAffiliation return $this; } + /** + * @return Collection + */ public function getTeams(): Collection { return $this->teams; diff --git a/webapp/src/Entity/TeamCategory.php b/webapp/src/Entity/TeamCategory.php index bc71dccbd0..9daf2d5d22 100644 --- a/webapp/src/Entity/TeamCategory.php +++ b/webapp/src/Entity/TeamCategory.php @@ -84,14 +84,23 @@ class TeamCategory extends BaseApiEntity implements Stringable #[Serializer\Exclude] private bool $allow_self_registration = false; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'category', targetEntity: Team::class)] #[Serializer\Exclude] private Collection $teams; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: Contest::class, mappedBy: 'team_categories')] #[Serializer\Exclude] private Collection $contests; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: Contest::class, mappedBy: 'medal_categories')] #[Serializer\Exclude] private Collection $contests_for_medals; @@ -207,13 +216,16 @@ public function addTeam(Team $team): TeamCategory return $this; } + /** + * @return Collection + */ public function getTeams(): Collection { return $this->teams; } /** - * @return Collection|Contest[] + * @return Collection */ public function getContests(): Collection { @@ -231,7 +243,7 @@ public function addContest(Contest $contest): self } /** - * @return Collection|Contest[] + * @return Collection */ public function getContestsForMedals(): Collection { diff --git a/webapp/src/Entity/Testcase.php b/webapp/src/Entity/Testcase.php index 53b7f8ea35..6bf6d35d7d 100644 --- a/webapp/src/Entity/Testcase.php +++ b/webapp/src/Entity/Testcase.php @@ -86,15 +86,23 @@ class Testcase #[Serializer\Exclude] private bool $deleted = false; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'testcase', targetEntity: JudgingRun::class)] #[Serializer\Exclude] private Collection $judging_runs; + /** + * @var Collection> + */ #[ORM\OneToMany(mappedBy: 'testcase', targetEntity: ExternalRun::class)] #[Serializer\Exclude] private Collection $external_runs; /** + * @var Collection + * * We use a OneToMany instead of a OneToOne here, because otherwise this * relation will always be loaded. See the commit message of commit * 9e421f96691ec67ed62767fe465a6d8751edd884 for a more elaborate explanation. @@ -226,6 +234,9 @@ public function addJudgingRun(JudgingRun $judgingRun): Testcase return $this; } + /** + * @return Collection + */ public function getJudgingRuns(): Collection { return $this->judging_runs; @@ -282,6 +293,9 @@ public function addExternalRun(ExternalRun $externalRun): Testcase return $this; } + /** + * @return Collection + */ public function getExternalRuns(): Collection { return $this->external_runs; diff --git a/webapp/src/Entity/User.php b/webapp/src/Entity/User.php index 2bfdb1a00f..e3129e0e84 100644 --- a/webapp/src/Entity/User.php +++ b/webapp/src/Entity/User.php @@ -119,6 +119,9 @@ class User extends BaseApiEntity implements UserInterface, PasswordAuthenticated #[Serializer\Exclude] private ?Team $team = null; + /** + * @var Collection + */ #[ORM\ManyToMany(targetEntity: Role::class, inversedBy: 'users')] #[ORM\JoinTable(name: 'userrole')] #[ORM\JoinColumn(name: 'userid', referencedColumnName: 'userid', onDelete: 'CASCADE')] @@ -127,6 +130,9 @@ class User extends BaseApiEntity implements UserInterface, PasswordAuthenticated #[Serializer\Exclude] private Collection $user_roles; + /** + * @var Collection + */ #[ORM\OneToMany(mappedBy: 'user', targetEntity: Submission::class)] #[Serializer\Exclude] private Collection $submissions; @@ -448,6 +454,9 @@ public function addSubmission(Submission $submission): User return $this; } + /** + * @return Collection + */ public function getSubmissions(): Collection { return $this->submissions; diff --git a/webapp/src/Entity/Version.php b/webapp/src/Entity/Version.php index 361b304db4..71fc2b4b68 100644 --- a/webapp/src/Entity/Version.php +++ b/webapp/src/Entity/Version.php @@ -3,6 +3,7 @@ namespace App\Entity; use Doctrine\ORM\Mapping as ORM; +use JMS\Serializer\Annotation as Serializer; /** * Runner and compiler versions per language. diff --git a/webapp/src/EventListener/AddCurrentContestListener.php b/webapp/src/EventListener/AddCurrentContestListener.php index fbe46a8b50..8ae470f572 100644 --- a/webapp/src/EventListener/AddCurrentContestListener.php +++ b/webapp/src/EventListener/AddCurrentContestListener.php @@ -11,7 +11,7 @@ class AddCurrentContestListener { public function __construct(protected readonly DOMJudgeService $dj) {} - public function __invoke(ResponseEvent $event) + public function __invoke(ResponseEvent $event): void { $event->getResponse()->headers->set('X-Current-Contest', $this->dj->getCurrentContestCookie()); } diff --git a/webapp/src/Helpers/OrdinalArray.php b/webapp/src/Helpers/OrdinalArray.php index 378ae7c71d..11b04f6eac 100644 --- a/webapp/src/Helpers/OrdinalArray.php +++ b/webapp/src/Helpers/OrdinalArray.php @@ -12,10 +12,7 @@ class OrdinalArray /** @var OrdinalItem[] */ protected array $items; - /** - * @param array|Traversable $items - */ - public function __construct($items) + public function __construct(Traversable|array $items) { $this->items = []; $ordinal = 0; diff --git a/webapp/src/Security/DOMJudgeBasicAuthenticator.php b/webapp/src/Security/DOMJudgeBasicAuthenticator.php index b1c256917c..b39c329060 100644 --- a/webapp/src/Security/DOMJudgeBasicAuthenticator.php +++ b/webapp/src/Security/DOMJudgeBasicAuthenticator.php @@ -3,13 +3,11 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Bundle\SecurityBundle\Security; -use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; @@ -18,8 +16,7 @@ class DOMJudgeBasicAuthenticator extends AbstractAuthenticator { public function __construct( - private readonly Security $security, - private readonly UserPasswordHasherInterface $passwordHasher + private readonly Security $security ) {} /** @@ -58,12 +55,7 @@ public function authenticate(Request $request): Passport return new Passport(new UserBadge($request->headers->get('php-auth-user')), new PasswordCredentials($request->headers->get('php-auth-pw'))); } - public function checkCredentials($credentials, UserInterface $user): bool - { - return $this->passwordHasher->isPasswordValid($user, $credentials['password']); - } - - public function onAuthenticationSuccess(Request $request, TokenInterface $token, $firewallName): ?Response + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { // On success, let the request continue. return null; diff --git a/webapp/src/Security/DOMJudgeIPAuthenticator.php b/webapp/src/Security/DOMJudgeIPAuthenticator.php index 8d7892f162..d2fd8ab12e 100644 --- a/webapp/src/Security/DOMJudgeIPAuthenticator.php +++ b/webapp/src/Security/DOMJudgeIPAuthenticator.php @@ -15,7 +15,6 @@ use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Bundle\SecurityBundle\Security; -use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; @@ -35,8 +34,7 @@ public function __construct( private readonly EntityManagerInterface $em, private readonly ConfigurationService $config, private readonly RouterInterface $router, - private readonly RequestStack $requestStack, - private readonly UserProviderInterface $userProvider + private readonly RequestStack $requestStack ) {} public function supports(Request $request): bool @@ -117,7 +115,7 @@ public function authenticate(Request $request): Passport return new SelfValidatingPassport(new UserBadge($user->getUsername())); } - public function onAuthenticationSuccess(Request $request, TokenInterface $token, $firewallName): ?Response + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { // On success, redirect to the last page or the homepage if it was a user triggered action. if ($request->attributes->get('_route') === 'login' diff --git a/webapp/src/Security/DOMJudgeXHeadersAuthenticator.php b/webapp/src/Security/DOMJudgeXHeadersAuthenticator.php index 456c43156c..d8957ab7bb 100644 --- a/webapp/src/Security/DOMJudgeXHeadersAuthenticator.php +++ b/webapp/src/Security/DOMJudgeXHeadersAuthenticator.php @@ -6,13 +6,11 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Bundle\SecurityBundle\Security; -use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; @@ -26,8 +24,6 @@ class DOMJudgeXHeadersAuthenticator extends AbstractAuthenticator implements Aut public function __construct( private readonly Security $security, - private readonly UserProviderInterface $userProvider, - private readonly UserPasswordHasherInterface $hasher, private readonly ConfigurationService $config, private readonly RouterInterface $router ) {} @@ -73,7 +69,7 @@ public function authenticate(Request $request): Passport return new Passport(new UserBadge($username), new PasswordCredentials($password)); } - public function onAuthenticationSuccess(Request $request, TokenInterface $token, $firewallName): ?Response + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { // On success, redirect to the last page or the homepage if it was a user triggered action. if ($request->attributes->get('_route') === 'login' diff --git a/webapp/src/Security/UserStateUpdater.php b/webapp/src/Security/UserStateUpdater.php index 0f091db977..981e9e079b 100644 --- a/webapp/src/Security/UserStateUpdater.php +++ b/webapp/src/Security/UserStateUpdater.php @@ -25,7 +25,7 @@ public static function getSubscribedEvents(): array public function updateUserState(AuthenticationSuccessEvent $event): void { - if ($event->getAuthenticationToken() && ($user = $event->getAuthenticationToken()->getUser()) && $user instanceof User) { + if (($user = $event->getAuthenticationToken()->getUser()) && $user instanceof User) { $firewallName = 'main'; if (method_exists($event->getAuthenticationToken(), 'getFirewallName')) { $firewallName = $event->getAuthenticationToken()->getFirewallName(); diff --git a/webapp/src/Service/CheckConfigService.php b/webapp/src/Service/CheckConfigService.php index 226c99f20d..760fda8be0 100644 --- a/webapp/src/Service/CheckConfigService.php +++ b/webapp/src/Service/CheckConfigService.php @@ -247,7 +247,6 @@ public function checkAdminPass(): array $res = 'O'; $desc = 'Password for "admin" has been changed from the default.'; - /** @var User $user */ $user = $this->em->getRepository(User::class)->findOneBy(['username' => 'admin']); if ($user && password_verify('admin', $user->getPassword())) { $res = 'E'; @@ -429,6 +428,7 @@ public function checkContestsValidate(): array $desc = ''; foreach ($contesterrors as $cid => $errors) { $desc .= "Contest: c$cid: " . + /* @phpstan-ignore-next-line */ (count($errors) == 0 ? 'no errors' : (string)$errors) ."\n" .$cperrors[$cid]; } @@ -502,7 +502,7 @@ public function checkProblemsValidate(): array $moreproblemerrors[$probid] .= sprintf("Special compare script %s not found for p%s\n", $special_compare->getExecid(), $probid); } elseif ($exec->getType() !== "compare") { $result = 'E'; - $moreproblemerrors[$probid] .= sprintf("Special compare script %s exists but is of wrong type (%s instead of compare) for p%s\n", $special_compare, $exec->getType(), $probid); + $moreproblemerrors[$probid] .= sprintf("Special compare script %s exists but is of wrong type (%s instead of compare) for p%s\n", $special_compare->getExecid(), $exec->getType(), $probid); } } if ($special_run = $problem->getRunExecutable()) { @@ -512,7 +512,7 @@ public function checkProblemsValidate(): array $moreproblemerrors[$probid] .= sprintf("Special run script %s not found for p%s\n", $special_run->getExecid(), $probid); } elseif ($exec->getType() !== "run") { $result = 'E'; - $moreproblemerrors[$probid] .= sprintf("Special run script %s exists but is of wrong type (%s instead of run) for p%s\n", $special_run, $exec->getType(), $probid); + $moreproblemerrors[$probid] .= sprintf("Special run script %s exists but is of wrong type (%s instead of run) for p%s\n", $special_run->getExecid(), $exec->getType(), $probid); } } @@ -552,6 +552,7 @@ public function checkProblemsValidate(): array foreach ($problemerrors as $probid => $errors) { $desc .= "Problem p$probid: "; if (count($errors) > 0 || !empty($moreproblemerrors[$probid])) { + /* @phpstan-ignore-next-line */ $desc .= (string)$errors . " " . $moreproblemerrors[$probid] . "\n"; } else { @@ -602,6 +603,7 @@ public function checkLanguagesValidate(): array foreach ($languageerrors as $langid => $errors) { $desc .= "Language $langid: "; if (count($errors) > 0 || !empty($morelanguageerrors[$langid])) { + /* @phpstan-ignore-next-line */ $desc .= (string)$errors . " " . $morelanguageerrors[$langid] . "\n"; } else { @@ -786,6 +788,9 @@ public function checkAllExternalIdentifiers(): array return $result; } + /** + * @param class-string $class + */ protected function checkExternalIdentifiers(string $class, string $externalIdField): array { $this->stopwatch->start(__FUNCTION__); diff --git a/webapp/src/Service/ConfigurationService.php b/webapp/src/Service/ConfigurationService.php index 530f83af55..eeeccf9d73 100644 --- a/webapp/src/Service/ConfigurationService.php +++ b/webapp/src/Service/ConfigurationService.php @@ -149,7 +149,7 @@ public function saveChanges( array $dataToSet, EventLogService $eventLog, DOMJudgeService $dj - ) { + ): void { $specs = $this->getConfigSpecification(); foreach ($specs as &$spec) { $spec = $this->addOptions($spec); @@ -346,6 +346,7 @@ public function addOptions(array $item): array if ($item['type'] === 'enum') { $enumClass = $item['enum_class']; + /** @var \BackedEnum[] $cases */ $cases = call_user_func($enumClass . '::cases'); foreach ($cases as $case) { if (method_exists($case, 'getConfigDescription')) { diff --git a/webapp/src/Service/DOMJudgeService.php b/webapp/src/Service/DOMJudgeService.php index 5c11f3d379..6c52d190b4 100644 --- a/webapp/src/Service/DOMJudgeService.php +++ b/webapp/src/Service/DOMJudgeService.php @@ -252,9 +252,6 @@ public function getCookie(string $cookieName): bool|float|int|string|InputBag|nu if (!$this->requestStack->getCurrentRequest()) { return null; } - if (!$this->requestStack->getCurrentRequest()->cookies) { - return null; - } return $this->requestStack->getCurrentRequest()->cookies->get($cookieName); } @@ -486,12 +483,12 @@ public function withAllRoles(callable $callable, ?UserInterface $user = null): v */ public function auditlog( string $datatype, - $dataid, + mixed $dataid, string $action, - $extraInfo = null, - $forceUsername = null, + mixed $extraInfo = null, + ?string $forceUsername = null, string|int|null $cid = null - ) { + ): void { if (!empty($forceUsername)) { $user = $forceUsername; } else { @@ -546,7 +543,7 @@ public function jsonEncode(mixed $data): string /** * Dis- or re-enable what caused an internal error. */ - public function setInternalError(array $disabled, ?Contest $contest, ?bool $enabled) + public function setInternalError(array $disabled, ?Contest $contest, ?bool $enabled): void { switch ($disabled['kind']) { case 'problem': @@ -589,10 +586,10 @@ public function setInternalError(array $disabled, ?Contest $contest, ?bool $enab /** @var Language $language */ $language->setAllowJudge($enabled); } + /** @var Problem $problem */ foreach ($this->getProblemsForExecutable($executable) as $problem) { - /** @var Problem $problem */ + /** @var ContestProblem $contestProblem */ foreach ($problem->getContestProblems() as $contestProblem) { - /** @var ContestProblem $contestProblem */ $contestProblem->setAllowJudge($enabled); } } @@ -878,7 +875,7 @@ public function getSamplesZipForContest(Contest $contest): StreamedResponse */ public function getAttachmentStreamedResponse(ContestProblem $contestProblem, int $attachmentId): StreamedResponse { - /** @var ProblemAttachment $attachment */ + /** @var ProblemAttachment|null $attachment */ $attachment = $this->em->createQueryBuilder() ->from(ProblemAttachment::class, 'a') ->join('a.problem', 'p') @@ -1276,7 +1273,6 @@ public function maybeCreateJudgeTasks(Judging $judging, int $priority = JudgeTas public function getImmutableCompareExecutable(ContestProblem $problem): ImmutableExecutable { - /** @var Executable $executable */ $executable = $problem ->getProblem() ->getCompareExecutable(); @@ -1293,7 +1289,6 @@ public function getImmutableCompareExecutable(ContestProblem $problem): Immutabl public function getImmutableRunExecutable(ContestProblem $problem): ImmutableExecutable { - /** @var Executable $executable */ $executable = $problem ->getProblem() ->getRunExecutable(); @@ -1438,7 +1433,7 @@ public function loadTeam(string $idField, string $teamId, Contest $contest): Tea ->setParameter('cid', $contest->getCid()); } - /** @var Team $team */ + /** @var Team|null $team */ $team = $queryBuilder->getQuery()->getOneOrNullResult(); if (!$team) { @@ -1448,7 +1443,7 @@ public function loadTeam(string $idField, string $teamId, Contest $contest): Tea return $team; } - public function parseMetadata($raw_metadata): array + public function parseMetadata(string $raw_metadata): array { // TODO: Reduce duplication with judgedaemon code. $contents = explode("\n", $raw_metadata); @@ -1537,7 +1532,7 @@ public function getScoreboardZip( ?Contest $contest, ScoreboardService $scoreboardService, bool $forceUnfrozen = false - ) { + ): StreamedResponse { $data = $scoreboardService->getScoreboardTwigData( request: $request, response: null, diff --git a/webapp/src/Service/EventLogService.php b/webapp/src/Service/EventLogService.php index 8194852b6d..5d1f39742a 100644 --- a/webapp/src/Service/EventLogService.php +++ b/webapp/src/Service/EventLogService.php @@ -2,6 +2,7 @@ namespace App\Service; +use App\Entity\BaseApiEntity; use App\Entity\Clarification; use App\Entity\Contest; use App\Entity\ContestProblem; @@ -54,6 +55,7 @@ class EventLogService implements ContainerAwareInterface // TODO: Add a way to specify when to use external ID using some (DB) // config instead of hardcoding it here. Also relates to // AbstractRestController::getIdField. + /** @var mixed[] */ public array $apiEndpoints = [ 'contests' => [ self::KEY_TYPE => self::TYPE_CONFIGURATION, @@ -206,9 +208,9 @@ public function log( string $action, ?int $contestId = null, ?string $json = null, - $ids = null, + mixed $ids = null, bool $checkEvents = true - ) { + ): void { // Sanitize and check input if (!is_array($dataIds)) { $dataIds = [$dataIds]; @@ -287,7 +289,7 @@ public function log( $ids = [$ids]; } - $idsCombined = $ids === null ? null : (is_array($ids) ? $this->dj->jsonEncode($ids) : $ids); + $idsCombined = $this->dj->jsonEncode($ids); // State is a special case, as it works without an ID if ($type !== 'state' && count(array_filter($ids)) !== count($dataIds)) { @@ -839,6 +841,7 @@ protected function getExternalIds(string $type, array $ids): array return $ids; } + /** @var class-string $entity */ $entity = $endpointData[self::KEY_ENTITY]; if (!$entity) { throw new BadMethodCallException(sprintf('No entity defined for type \'%s\'', $type)); @@ -950,6 +953,7 @@ public function apiIdFieldForEntity($entity): string if ($field = $this->externalIdFieldForEntity($entity)) { return $field; } + /** @var class-string $class */ $class = is_object($entity) ? $entity::class : $entity; $metadata = $this->em->getClassMetadata($class); try { diff --git a/webapp/src/Service/ExternalContestSourceService.php b/webapp/src/Service/ExternalContestSourceService.php index 7ecfd0ff7f..2a2d2385bb 100644 --- a/webapp/src/Service/ExternalContestSourceService.php +++ b/webapp/src/Service/ExternalContestSourceService.php @@ -85,17 +85,19 @@ public function __construct( protected readonly ConfigurationService $config, protected readonly EventLogService $eventLog, protected readonly SubmissionService $submissionService, - protected readonly ScoreboardService $scoreboardService + protected readonly ScoreboardService $scoreboardService, + #[Autowire('%domjudge.version%')] + string $domjudgeVersion ) { $clientOptions = [ 'headers' => [ - 'User-Agent' => 'DOMjudge/' . DOMJUDGE_VERSION, + 'User-Agent' => 'DOMjudge/' . $domjudgeVersion, ], ]; $this->httpClient = $httpClient->withOptions($clientOptions); } - public function setSource(ExternalContestSource $source) + public function setSource(ExternalContestSource $source): void { $this->source = $source; } @@ -408,7 +410,6 @@ function ( &$shouldStop ) use ( $eventsToSkip, - $file, &$skipEventsUpTo, $progressReporter ) { @@ -476,6 +477,7 @@ protected function readEventsFromFile($filePointer, callable $callback): void $event = $this->dj->jsonDecode($line); $shouldStop = false; $callback($event, $line, $shouldStop); + /** @phpstan-ignore-next-line The callable can modify $shouldStop but currently we can't indicate this */ if ($shouldStop) { return; } @@ -557,7 +559,6 @@ protected function loadContest(): void /** * Import the given event. - * @param string[] * @throws DBALException * @throws NonUniqueResultException * @throws TransportExceptionInterface @@ -691,12 +692,12 @@ protected function validateAndUpdateContest(string $entityType, ?string $eventId preg_match($reltimeRegex, $freeze, $freezeData); $freezeNegative = ($freezeData[1] === '-'); $freezeHourModifier = $freezeNegative ? -1 : 1; - $freezeInSeconds = $freezeHourModifier * $freezeData[2] * 3600 - + 60 * $freezeData[3] + $freezeInSeconds = $freezeHourModifier * (int)$freezeData[2] * 3600 + + 60 * (int)$freezeData[3] + (double)sprintf('%d.%03d', $freezeData[4], $freezeData[5]); $durationHourModifier = $durationNegative ? -1 : 1; - $durationInSeconds = $durationHourModifier * $durationData[2] * 3600 - + 60 * $durationData[3] + $durationInSeconds = $durationHourModifier * (int)$durationData[2] * 3600 + + 60 * (int)$durationData[3] + (double)sprintf('%d.%03d', $durationData[4], $durationData[5]); $freezeStartSeconds = $durationInSeconds - $freezeInSeconds; $freezeHour = floor($freezeStartSeconds / 3600); @@ -815,7 +816,6 @@ protected function validateLanguage(string $entityType, ?string $eventId, string } $extId = $data['id']; - /** @var Language $language */ $language = $this->em ->getRepository(Language::class) ->findOneBy(['externalid' => $extId]); @@ -955,7 +955,6 @@ protected function validateAndUpdateProblem(string $entityType, ?string $eventId $problemId = $data['id']; // First, load the problem. - /** @var Problem $problem */ $problem = $this->em->getRepository(Problem::class)->findOneBy(['externalid' => $problemId]); if (!$problem) { $this->addOrUpdateWarning($eventId, $entityType, $data['id'], ExternalSourceWarning::TYPE_ENTITY_NOT_FOUND); @@ -963,7 +962,6 @@ protected function validateAndUpdateProblem(string $entityType, ?string $eventId } // Now find the contest problem. - /** @var ContestProblem $contestProblem */ $contestProblem = $this->em ->getRepository(ContestProblem::class) ->find([ @@ -1114,7 +1112,6 @@ protected function importClarification(string $entityType, ?string $eventId, str } // First, load the clarification - /** @var Clarification $clarification */ $clarification = $this->em ->getRepository(Clarification::class) ->findOneBy([ @@ -1133,7 +1130,6 @@ protected function importClarification(string $entityType, ?string $eventId, str $fromTeamId = $data['from_team_id'] ?? null; $fromTeam = null; if ($fromTeamId !== null) { - /** @var Team $fromTeam */ $fromTeam = $this->em ->getRepository(Team::class) ->findOneBy(['externalid' => $fromTeamId]); @@ -1146,7 +1142,6 @@ protected function importClarification(string $entityType, ?string $eventId, str $toTeamId = $data['to_team_id'] ?? null; $toTeam = null; if ($toTeamId !== null) { - /** @var Team $toTeam */ $toTeam = $this->em ->getRepository(Team::class) ->findOneBy(['externalid' => $toTeamId]); @@ -1159,7 +1154,6 @@ protected function importClarification(string $entityType, ?string $eventId, str $inReplyToId = $data['reply_to_id'] ?? null; $inReplyTo = null; if ($inReplyToId !== null) { - /** @var Clarification $inReplyTo */ $inReplyTo = $this->em ->getRepository(Clarification::class) ->findOneBy([ @@ -1175,7 +1169,6 @@ protected function importClarification(string $entityType, ?string $eventId, str $problemId = $data['problem_id'] ?? null; $problem = null; if ($problemId !== null) { - /** @var Problem $problem */ $problem = $this->em ->getRepository(Problem::class) ->findOneBy(['externalid' => $problemId]); @@ -1254,7 +1247,6 @@ protected function importSubmission(string $entityType, ?string $eventId, string } // First, load the submission - /** @var Submission $submission */ $submission = $this->em ->getRepository(Submission::class) ->findOneBy([ @@ -1263,7 +1255,6 @@ protected function importSubmission(string $entityType, ?string $eventId, string ]); $languageId = $data['language_id']; - /** @var Language $language */ $language = $this->em->getRepository(Language::class)->findOneBy(['externalid' => $languageId]); if (!$language) { $this->addOrUpdateWarning($eventId, $entityType, $data['id'], ExternalSourceWarning::TYPE_DEPENDENCY_MISSING, [ @@ -1277,7 +1268,6 @@ protected function importSubmission(string $entityType, ?string $eventId, string $this->removeWarning($entityType, $data['id'], ExternalSourceWarning::TYPE_DEPENDENCY_MISSING); $problemId = $data['problem_id']; - /** @var Problem $problem */ $problem = $this->em->getRepository(Problem::class)->findOneBy(['externalid' => $problemId]); if (!$problem) { $this->addPendingEvent('problem', $problemId, $operation, $entityType, $eventId, $data); @@ -1285,10 +1275,9 @@ protected function importSubmission(string $entityType, ?string $eventId, string } // Find the contest problem. - /** @var ContestProblem $contestProblem */ $contestProblem = $this->em ->getRepository(ContestProblem::class) - ->find([ + ->findOneBy([ 'contest' => $this->getSourceContest(), 'problem' => $problem, ]); @@ -1303,7 +1292,6 @@ protected function importSubmission(string $entityType, ?string $eventId, string } $teamId = $data['team_id']; - /** @var Team $team */ $team = $this->em->getRepository(Team::class)->findOneBy(['externalid' => $teamId]); if (!$team) { $this->addPendingEvent('team', $teamId, $operation, $entityType, $eventId, $data); @@ -1435,7 +1423,7 @@ protected function importSubmission(string $entityType, ?string $eventId, string } } - if ($submissionDownloadSucceeded) { + if (isset($response, $ziphandler) && $submissionDownloadSucceeded) { foreach ($this->httpClient->stream($response) as $chunk) { fwrite($ziphandler, $chunk->getContent()); } @@ -1561,7 +1549,6 @@ protected function importJudgement(string $entityType, ?string $eventId, string } // First, load the external judgement. - /** @var ExternalJudgement $judgement */ $judgement = $this->em ->getRepository(ExternalJudgement::class) ->findOneBy([ @@ -1579,7 +1566,6 @@ protected function importJudgement(string $entityType, ?string $eventId, string // Now check if we have all dependent data. $submissionId = $data['submission_id'] ?? null; - /** @var Submission $submission */ $submission = $this->em ->getRepository(Submission::class) ->findOneBy([ @@ -1682,7 +1668,6 @@ protected function importRun(string $entityType, ?string $eventId, string $opera } // First, load the external run. - /** @var ExternalRun $run */ $run = $this->em ->getRepository(ExternalRun::class) ->findOneBy([ @@ -1700,7 +1685,6 @@ protected function importRun(string $entityType, ?string $eventId, string $opera // Now check if we have all dependent data. $judgementId = $data['judgement_id'] ?? null; - /** @var ExternalJudgement $externalJudgement */ $externalJudgement = $this->em ->getRepository(ExternalJudgement::class) ->findOneBy([ @@ -1768,7 +1752,7 @@ protected function importRun(string $entityType, ?string $eventId, string $opera $this->em->flush(); } - protected function processPendingEvents(string $type, $id): void + protected function processPendingEvents(string $type, string|int $id): void { // Process pending events. if (isset($this->pendingEvents[$type][$id])) { @@ -1783,7 +1767,7 @@ protected function processPendingEvents(string $type, $id): void } } - protected function addPendingEvent(string $type, $id, string $operation, string $entityType, ?string $eventId, array $data): void + protected function addPendingEvent(string $type, string|int $id, string $operation, string $entityType, ?string $eventId, array $data): void { // First, check if we already have pending events for this event. // We do this by loading the warnings with the correct hash. @@ -1792,7 +1776,6 @@ protected function addPendingEvent(string $type, $id, string $operation, string $entityType, $data['id'] ); - /** @var ExternalSourceWarning|null $warning */ $warning = $this->em ->getRepository(ExternalSourceWarning::class) ->findOneBy([ diff --git a/webapp/src/Service/ICPCCmsService.php b/webapp/src/Service/ICPCCmsService.php index 9d0ba24e2d..207403182b 100644 --- a/webapp/src/Service/ICPCCmsService.php +++ b/webapp/src/Service/ICPCCmsService.php @@ -74,7 +74,7 @@ public function importTeams(string $token, string $contest, ?string &$message = $json = $response->toArray(); - if ($json === null) { + if (!$json) { $message = sprintf('Error retrieving API data. API gave us: %s', $response->getContent()); return false; } @@ -103,7 +103,6 @@ public function importTeams(string $token, string $contest, ?string &$message = * FIXME: team members are behind a different API call and not important for now */ - /** @var Team $team */ $team = $this->em->getRepository(Team::class)->findOneBy(['icpcid' => $teamData['teamId']]); // Note: teams are not deleted but disabled depending on their status $enabled = $teamData['status'] === 'ACCEPTED'; diff --git a/webapp/src/Service/ImportExportService.php b/webapp/src/Service/ImportExportService.php index 15531508a6..2403e0c23a 100644 --- a/webapp/src/Service/ImportExportService.php +++ b/webapp/src/Service/ImportExportService.php @@ -123,7 +123,7 @@ protected function convertImportedTime(array $fields, array $data, ?string &$err // Make sure ISO 8601 but with the T replaced with a space also works. date_create_from_format('Y-m-d H:i:sO', $timeValue); } else { - /** @var DateTime $time */ + /** @var DateTime|DateTimeImmutable $time */ $time = $timeValue; } // If/When parsing fails we get a false instead of a null @@ -136,7 +136,7 @@ protected function convertImportedTime(array $fields, array $data, ?string &$err return $time instanceof DateTime ? DateTimeImmutable::createFromMutable($time) : $time; } - public function importContestData($data, ?string &$errorMessage = null, string &$cid = null): bool + public function importContestData(mixed $data, ?string &$errorMessage = null, string &$cid = null): bool { if (empty($data) || !is_array($data)) { $errorMessage = 'Error parsing YAML file.'; @@ -278,7 +278,7 @@ public function importContestData($data, ?string &$errorMessage = null, string & return true; } - public function importProblemsData(Contest $contest, $problems, array &$ids = null): bool + public function importProblemsData(Contest $contest, array $problems, array &$ids = null): bool { // For problemset.yaml the root key is called `problems`, so handle that case if (isset($problems['problems'])) { @@ -443,11 +443,11 @@ public function getResultsData(int $sortOrder, bool $full = false): array $rank = $teamScore->rank; $numPoints = $teamScore->numPoints; - if ($rank <= ($contest->getGoldMedals() ?? 4)) { + if ($rank <= $contest->getGoldMedals()) { $awardString = 'Gold Medal'; - } elseif ($rank <= ($contest->getGoldMedals() ?? 4) + ($contest->getSilverMedals() ?? 4)) { + } elseif ($rank <= $contest->getGoldMedals() + $contest->getSilverMedals()) { $awardString = 'Silver Medal'; - } elseif ($rank <= ($contest->getGoldMedals() ?? 4) + ($contest->getSilverMedals() ?? 4) + ($contest->getBronzeMedals() ?? 4) + $contest->getB()) { + } elseif ($rank <= $contest->getGoldMedals() + $contest->getSilverMedals() + $contest->getBronzeMedals() + $contest->getB()) { $awardString = 'Bronze Medal'; } elseif ($numPoints >= $median) { // Teams with equally solved number of problems get the same rank unless $full is true. diff --git a/webapp/src/Service/ImportProblemService.php b/webapp/src/Service/ImportProblemService.php index 8ee24ee7a4..8a0d1883e5 100644 --- a/webapp/src/Service/ImportProblemService.php +++ b/webapp/src/Service/ImportProblemService.php @@ -539,7 +539,7 @@ public function importZippedProblem( $name = basename($filename); $fileParts = explode('.', $name); - if (count($fileParts) > 0) { + if (count($fileParts) > 1) { $type = $fileParts[count($fileParts) - 1]; } else { $type = 'txt'; @@ -740,7 +740,7 @@ public function importZippedProblem( } $results = [$expectedResult]; } - $jury_team_id = $this->dj->getUser()->getTeam() ? $this->dj->getUser()->getTeam()->getTeamid() : null; + $jury_team_id = $this->dj->getUser()->getTeam()->getTeamid(); $jury_user = $this->dj->getUser(); if (isset($submission_details[$path]['team'])) { /** @var Team|null $json_team */ @@ -898,7 +898,7 @@ public function importProblemFromRequest(Request $request, ?int $contestId = nul ]; } - private function searchAndAddValidator(ZipArchive $zip, ?array &$messages, $externalId, $validationMode, ?Problem $problem): void + private function searchAndAddValidator(ZipArchive $zip, ?array &$messages, string $externalId, string $validationMode, ?Problem $problem): void { $validatorFiles = []; for ($i = 0; $i < $zip->numFiles; $i++) { diff --git a/webapp/src/Service/RejudgingService.php b/webapp/src/Service/RejudgingService.php index 5170322474..12c098d369 100644 --- a/webapp/src/Service/RejudgingService.php +++ b/webapp/src/Service/RejudgingService.php @@ -96,15 +96,13 @@ public function createRejudging( $judging, $rejudging ) { - if ($rejudging) { - $this->em->getConnection()->executeStatement( - 'UPDATE submission SET rejudgingid = :rejudgingid WHERE submitid = :submitid AND rejudgingid IS NULL', - [ - 'rejudgingid' => $rejudging->getRejudgingid(), - 'submitid' => $judging->getSubmissionId(), - ] - ); - } + $this->em->getConnection()->executeStatement( + 'UPDATE submission SET rejudgingid = :rejudgingid WHERE submitid = :submitid AND rejudgingid IS NULL', + [ + 'rejudgingid' => $rejudging->getRejudgingid(), + 'submitid' => $judging->getSubmissionId(), + ] + ); if ($singleJudging) { $teamid = $judging->getSubmission()->getTeamId(); diff --git a/webapp/src/Service/ScoreboardService.php b/webapp/src/Service/ScoreboardService.php index ead8dedfdd..5352292e78 100644 --- a/webapp/src/Service/ScoreboardService.php +++ b/webapp/src/Service/ScoreboardService.php @@ -119,7 +119,7 @@ public function calculateTeamRank( ?RankCache $rankCache = null, ?FreezeData $freezeData = null, bool $jury = false - ) { + ): int { if ($freezeData === null) { $freezeData = new FreezeData($contest); } @@ -418,6 +418,7 @@ public function calculateScoreRow( 'cid' => $contest->getCid(), 'probid' => $problem->getProbid(), 'teamSortOrder' => $team->getCategory()->getSortorder(), + /** @phpstan-ignore-next-line $absSubmitTime is always set when $correctJury is true */ 'submitTime' => $absSubmitTime, 'correctResult' => Judging::RESULT_CORRECT, ]; @@ -672,21 +673,8 @@ public function refreshCache(Contest $contest, ?callable $progressReporter = nul } // Drop all teams and problems that do not exist in the contest. - if (!empty($problems)) { - $problemIds = array_map(fn(Problem $problem) => $problem->getProbid(), $problems); - } else { - // problemId -1 will never happen, but otherwise the array is - // empty and that is not supported. - $problemIds = [-1]; - } - - if (!empty($teams)) { - $teamIds = array_map(fn(Team $team) => $team->getTeamid(), $teams); - } else { - // teamId -1 will never happen, but otherwise the array is empty - // and that is not supported. - $teamIds = [-1]; - } + $problemIds = array_map(fn(Problem $problem) => $problem->getProbid(), $problems); + $teamIds = array_map(fn(Team $team) => $team->getTeamid(), $teams); $params = [ 'cid' => $contest->getCid(), @@ -1007,6 +995,7 @@ protected function getProblems(Contest $contest): array $contestProblems = $queryBuilder->getQuery()->getResult(); $contestProblemsIndexed = []; foreach ($contestProblems as $cp) { + /** @var Problem|int $p */ $p = $cp->getProblem(); // Doctrine has a bug with eagerly loaded second level hydration // when the object is already loaded. In that case it might happen diff --git a/webapp/src/Service/StatisticsService.php b/webapp/src/Service/StatisticsService.php index 96514ee51f..e54ca4008d 100644 --- a/webapp/src/Service/StatisticsService.php +++ b/webapp/src/Service/StatisticsService.php @@ -254,7 +254,7 @@ public function getTeamStats(Contest $contest, Team $team): array continue; } if ($j->getResult()) { - static::setOrIncrement($results, $j->getResult() ?? 'pending'); + static::setOrIncrement($results, $j->getResult()); } } // Sort the judgings by runtime. @@ -276,7 +276,7 @@ public function getTeamStats(Contest $contest, Team $team): array } } usort($submissions, static fn(Submission $a, Submission $b) => $a->getSubmitTime() <=> $b->getSubmitTime()); - usort($problems, static fn(Judging $a, Judging $b) => $a->getName() <=> $b->getName()); + usort($problems, static fn(Problem $a, Problem $b) => $a->getName() <=> $b->getName()); usort($judgings, static fn(Judging $a, Judging $b) => $a->getJudgingid() <=> $b->getJudgingid()); $misc = []; @@ -492,7 +492,7 @@ protected function applyFilter(QueryBuilder $queryBuilder, string $filter): Quer }; } - protected static function setOrIncrement(array &$array, $index): void + protected static function setOrIncrement(array &$array, int|string $index): void { if (!array_key_exists($index, $array)) { $array[$index] = 0; diff --git a/webapp/src/Service/SubmissionService.php b/webapp/src/Service/SubmissionService.php index 4a2da40f95..789a3e0a86 100644 --- a/webapp/src/Service/SubmissionService.php +++ b/webapp/src/Service/SubmissionService.php @@ -297,7 +297,7 @@ public function getSubmissionList( * judging runs. Runs can be NULL if not run yet. A return value of * NULL means that a final result cannot be determined yet; this may * only occur when not all testcases have been run yet. - * @param string[] $runresults + * @param array $runresults */ public static function getFinalResult(array $runresults, array $resultsPrio): ?string { @@ -655,7 +655,7 @@ public function submitSolution( $language->getLangid(), $problem->getProblem()->getProbid())); $this->dj->auditlog('submission', $submission->getSubmitid(), 'added', - 'via ' . $source ?? 'unknown', null, $contest->getCid()); + 'via ' . ($source ?? 'unknown'), null, $contest->getCid()); if (Utils::difftime((float)$contest->getEndtime(), $submitTime) <= 0) { $this->logger->info( diff --git a/webapp/src/Twig/TwigExtension.php b/webapp/src/Twig/TwigExtension.php index ba7774d630..38755afc62 100644 --- a/webapp/src/Twig/TwigExtension.php +++ b/webapp/src/Twig/TwigExtension.php @@ -6,6 +6,7 @@ use App\Entity\Contest; use App\Entity\ContestProblem; use App\Entity\ExternalJudgement; +use App\Entity\ExternalRun; use App\Entity\ExternalSourceWarning; use App\Entity\Judging; use App\Entity\JudgingRun; @@ -241,9 +242,6 @@ public function printHumanTimeDiff(float|null $datetime): string */ public function printtimeHover(string|float $datetime, ?Contest $contest = null): string { - if ($datetime === null) { - $datetime = Utils::now(); - } return '' . $this->printtime($datetime, null, $contest) . @@ -442,7 +440,7 @@ public function displayTestcaseResults(array $testcases, bool $submissionDone, b $class = $submissionDone ? 'secondary' : 'primary'; $text = '?'; $isCorrect = false; - /** @var JudgingRun $run */ + /** @var JudgingRun|ExternalRun|null $run */ $run = $isExternal ? $testcase->getFirstExternalRun() : $testcase->getFirstJudgingRun(); if ($isExternal) { $runResult = $run?->getResult(); @@ -589,6 +587,8 @@ public function externalCcsUrl(Submission $submission): ?string /** * Prints the first file (and potentially the number of additional files). + * + * @param Collection $files */ public function printFiles(Collection $files): string { @@ -853,9 +853,9 @@ public function codeEditor( sprintf($editor, $code, $editable ? 'false' : 'true', $mode, $extraForEdit)); } - protected function parseSourceDiff($difftext): string + protected function parseSourceDiff(string $difftext): string { - $line = strtok((string)$difftext, "\n"); // first line + $line = strtok($difftext, "\n"); // first line $return = ''; while ($line !== false && strlen($line) != 0) { // Strip any additional DOS/MAC newline characters: diff --git a/webapp/src/Utils/Scoreboard/ProblemSummary.php b/webapp/src/Utils/Scoreboard/ProblemSummary.php index 9a3452504e..9ee839a7e7 100644 --- a/webapp/src/Utils/Scoreboard/ProblemSummary.php +++ b/webapp/src/Utils/Scoreboard/ProblemSummary.php @@ -24,7 +24,7 @@ public function addSubmissionCounts( int $numSubmissions, int $numSubmissionsPending, int $numSubmissionsCorrect - ) { + ): void { if (!isset($this->numSubmissions[$sortorder])) { $this->numSubmissions[$sortorder] = 0; } @@ -50,7 +50,7 @@ public function getBestTimeInMinutes(int $sortorder): ?int return null; } - public function updateBestTime(int $sortorder, string|float $bestTime) + public function updateBestTime(int $sortorder, string|float $bestTime): void { $this->bestTimes[$sortorder] = $bestTime; } @@ -66,7 +66,7 @@ public function getBestRuntime(int $sortorder): int /** * update fastest runtime if given time is a new record for this problem/sortorder */ - public function updateBestRuntime(int $sortorder, int $runtime) + public function updateBestRuntime(int $sortorder, int $runtime): void { if ($runtime < $this->getBestRuntime($sortorder)) { $this->bestRuntimes[$sortorder] = $runtime; diff --git a/webapp/src/Utils/Utils.php b/webapp/src/Utils/Utils.php index ce591dbfdb..2dfded802c 100644 --- a/webapp/src/Utils/Utils.php +++ b/webapp/src/Utils/Utils.php @@ -10,7 +10,7 @@ */ class Utils { - /** @var array Mapping from HTML colors to hex values */ + /** @var array Mapping from HTML colors to hex values */ final public const HTML_COLORS = [ "black" => "#000000", "silver" => "#C0C0C0", @@ -177,7 +177,7 @@ private static function getMillis(float $seconds): string * Prints the absolute time as yyyy-mm-ddThh:mm:ss(.uuu)?[+-]zz(:mm)? * (with millis if $floored is false). */ - public static function absTime($epoch, bool $floored = false): ?string + public static function absTime(mixed $epoch, bool $floored = false): ?string { if ($epoch === null) { return null; @@ -799,9 +799,8 @@ public static function phpiniToBytes(string $size_str): int /** * Return the table name for the given entity. - * @param $entity */ - public static function tableForEntity($entity): string + public static function tableForEntity(object $entity): string { $class = $entity::class; $parts = explode('\\', $class); diff --git a/webapp/src/Validator/Constraints/CountryValidator.php b/webapp/src/Validator/Constraints/CountryValidator.php index 7751b1196c..c9495deda7 100644 --- a/webapp/src/Validator/Constraints/CountryValidator.php +++ b/webapp/src/Validator/Constraints/CountryValidator.php @@ -9,7 +9,7 @@ class CountryValidator extends ConstraintValidator { - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof Country) { throw new UnexpectedTypeException($constraint, Country::class); diff --git a/webapp/src/Validator/Constraints/IdentifierValidator.php b/webapp/src/Validator/Constraints/IdentifierValidator.php index 2689c7004d..799a82afce 100644 --- a/webapp/src/Validator/Constraints/IdentifierValidator.php +++ b/webapp/src/Validator/Constraints/IdentifierValidator.php @@ -9,7 +9,7 @@ class IdentifierValidator extends ConstraintValidator { - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof Identifier) { throw new UnexpectedTypeException($constraint, Identifier::class); diff --git a/webapp/src/Validator/Constraints/TimeStringValidator.php b/webapp/src/Validator/Constraints/TimeStringValidator.php index 48931a7f18..9a47c47b4d 100644 --- a/webapp/src/Validator/Constraints/TimeStringValidator.php +++ b/webapp/src/Validator/Constraints/TimeStringValidator.php @@ -8,7 +8,7 @@ class TimeStringValidator extends ConstraintValidator { - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof TimeString) { throw new UnexpectedTypeException($constraint, TimeString::class); diff --git a/webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php b/webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php index 14b4c7add2..efaf72d0cc 100644 --- a/webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php +++ b/webapp/tests/E2E/Controller/ControllerRolesTraversalTest.php @@ -147,10 +147,10 @@ protected function getAllPages(array $urlsToCheck, string $skip): array /** * Finds all the pages reachable with $roles on URL $roleBaseURL with optionally traversing all links. - * @var string[] $roleBaseURL The URL of the current roles. - * @var string[] $roles The tested roles. + * @param string[] $roleBaseURL The URL of the current roles. + * @param string[] $roles The tested roles. */ - protected function getPagesRoles(array $roleBaseURL, array $roles, bool $allPages, $skip): array + protected function getPagesRoles(array $roleBaseURL, array $roles, bool $allPages, string $skip): array { $this->roles = $roles; $this->logOut(); @@ -172,7 +172,7 @@ protected function getPagesRoles(array $roleBaseURL, array $roles, bool $allPage * (Sub)Test that having the role(s) gives access to all visible pages. * This test should detect mistakes where a page is disallowed when the user has a * specific role instead of allowing when the correct role is there. - * @var string[] $roleURLs + * @param string[] $roleURLs */ protected function verifyAccess(array $combinations, array $roleURLs, string $skip): void { @@ -192,10 +192,10 @@ protected function verifyAccess(array $combinations, array $roleURLs, string $sk * Test that having the team role for example is enough to view pages of that role. * This test should detect mistakes where a page is disabled when the user has a * certain role instead of allowing when the correct role is there. - * @var string $roleBaseURL The base URL of the role. - * @var string[] $baseRoles The default role of the user. - * @var string[] $optionalRoles The roles which should not restrict the viewable pages. - * @var int $dataSource Put the installation in this dataSource mode. + * @param string $roleBaseURL The base URL of the role. + * @param string[] $baseRoles The default role of the user. + * @param string[] $optionalRoles The roles which should not restrict the viewable pages. + * @param int $dataSource Put the installation in this dataSource mode. * @dataProvider provideRoleAccessData */ public function testRoleAccess(string $roleBaseURL, array $baseRoles, array $optionalRoles, bool $allPages, int $dataSource, string $skip): void @@ -228,10 +228,10 @@ public function visitWithNoContest(string $url, bool $dropdown): void /** * Test that having for example the jury role does not allow access to the pages of other roles. - * @var string $roleBaseURL The base URL of the role. - * @var string[] $roleOthersBaseURL The base URLs of the other roles. - * @var string[] $roles The tested roles. - * @var string[] $rolesOther The other roles. + * @param string $roleBaseURL The base URL of the role. + * @param string[] $roleOthersBaseURL The base URLs of the other roles. + * @param string[] $roles The tested roles. + * @param string[] $rolesOther The other roles. * @dataProvider provideRoleAccessOtherRoles */ public function testRoleAccessOtherRoles( @@ -260,7 +260,7 @@ public function testRoleAccessOtherRoles( * Test that pages depending on an active contest do not crash on the server. * @dataProvider provideNoContestScenario */ - public function testNoContestAccess(string $roleBaseURL, array $baseRoles, int $dataSource, $skip): void + public function testNoContestAccess(string $roleBaseURL, array $baseRoles, int $dataSource, string $skip): void { $this->setupDataSource($dataSource); $this->roles = $baseRoles; @@ -282,7 +282,7 @@ public function testNoContestAccess(string $roleBaseURL, array $baseRoles, int $ */ public function provideRoleAccessData(): Generator { - extract($this->getLoops()); + ['dataSources' => $dataSources, 'riskyURLs' => $riskyURLs] = $this->getLoops(); foreach ($riskyURLs as $skip) { foreach ($dataSources as $str_data_source) { $data_source = (int)$str_data_source; @@ -307,7 +307,7 @@ public function provideRoleAccessData(): Generator **/ public function provideRoleAccessOtherRoles(): Generator { - extract($this->getLoops()); + ['dataSources' => $dataSources, 'riskyURLs' => $riskyURLs] = $this->getLoops(); foreach ($riskyURLs as $skip) { foreach ($dataSources as $str_data_source) { $data_source = (int)$str_data_source; @@ -323,7 +323,7 @@ public function provideRoleAccessOtherRoles(): Generator public function provideNoContestScenario(): Generator { - extract($this->getLoops()); + ['dataSources' => $dataSources, 'riskyURLs' => $riskyURLs] = $this->getLoops(); foreach ($riskyURLs as $skip) { foreach ($dataSources as $str_data_source) { $data_source = (int)$str_data_source; diff --git a/webapp/tests/Unit/BaseTestCase.php b/webapp/tests/Unit/BaseTestCase.php index f4b799a9e3..d3f0426221 100644 --- a/webapp/tests/Unit/BaseTestCase.php +++ b/webapp/tests/Unit/BaseTestCase.php @@ -16,6 +16,7 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\DomCrawler\Crawler; use Symfony\Component\DomCrawler\Link; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\PropertyAccess\PropertyAccess; use ZipArchive; @@ -86,7 +87,7 @@ protected function loadFixture(string $fixture): void /** * Resolve any references in the given ID. */ - protected function resolveReference($id) + protected function resolveReference(int|string $id): int|string { // If the object ID contains a :, it is a reference to a fixture item, so get it. if (is_string($id) && str_contains($id, ':')) { @@ -165,7 +166,6 @@ protected function logOut(): void protected function setupUser(): User { $em = $this->client->getContainer()->get('doctrine.orm.entity_manager'); - /** @var User $user */ $user = $em->getRepository(User::class)->findOneBy(['username' => 'demo']); if ($user === null) { throw new Exception("No user 'demo' found, are you using the correct database?"); @@ -221,6 +221,7 @@ protected function verifyPageResponse( $message = var_export($response, true); self::assertEquals($status, $response->getStatusCode(), $message . "\nURI = $uri"); if ($responseUrl !== null) { + self::assertInstanceOf(RedirectResponse::class, $response); self::assertEquals($responseUrl, $response->getTargetUrl(), $message); } } @@ -255,20 +256,6 @@ protected function dataSourceIsLocal(): bool return $dataSource === DOMJudgeService::DATA_SOURCE_LOCAL; } - /** - * Get the contest ID of the demo contest based on the data source setting. - * - * @return string - */ - protected function getDemoContestId(): string - { - if ($this->dataSourceIsLocal()) { - return (string)$this->demoContest->getCid(); - } - - return $this->demoContest->getExternalid(); - } - /** * Resolve the entity ID for the given class if not running in local mode. */ diff --git a/webapp/tests/Unit/Command/ResetUserPasswordCommandTest.php b/webapp/tests/Unit/Command/ResetUserPasswordCommandTest.php index 424d6ab9c6..8e04406fb9 100644 --- a/webapp/tests/Unit/Command/ResetUserPasswordCommandTest.php +++ b/webapp/tests/Unit/Command/ResetUserPasswordCommandTest.php @@ -28,7 +28,9 @@ protected function setUp(): void $this->app = new Application(self::$kernel); /** @var LazyCommand $command */ $command = $this->app->find(static::$commandName); - $this->command = $command->getCommand(); + /** @var ResetUserPasswordCommand $resetCommand */ + $resetCommand = $command->getCommand(); + $this->command = $resetCommand; $this->commandTester = new CommandTester($this->command); } diff --git a/webapp/tests/Unit/Controller/API/AccountBaseTestCase.php b/webapp/tests/Unit/Controller/API/AccountBaseTestCase.php index c6cfdb1a4e..ad0765a53e 100644 --- a/webapp/tests/Unit/Controller/API/AccountBaseTestCase.php +++ b/webapp/tests/Unit/Controller/API/AccountBaseTestCase.php @@ -115,7 +115,7 @@ public function provideNewAccount(): Generator } foreach ($accountCombinations as $combination) { $newUpload = array_merge($defaultData, $combination[0]); - yield [$newUpload, $combination[1] ?? null]; + yield [$newUpload, $combination[1]]; } } } @@ -131,7 +131,7 @@ public function testCreateUserFileImport(string $newUsersFile, string $type, arr $tempFile = tempnam(sys_get_temp_dir(), "/accounts-upload-test-"); file_put_contents($tempFile, $newUsersFile); $tempUploadFile = new UploadedFile($tempFile, 'accounts.'.$type); - + $result = $this->verifyApiJsonResponse('POST', $usersURL, 200, 'admin', null, [$type => $tempUploadFile]); self::assertEquals($result, "1 new account(s) successfully added."); diff --git a/webapp/tests/Unit/Controller/API/BaseTestCase.php b/webapp/tests/Unit/Controller/API/BaseTestCase.php index efedc5b81b..aa10a53bf7 100644 --- a/webapp/tests/Unit/Controller/API/BaseTestCase.php +++ b/webapp/tests/Unit/Controller/API/BaseTestCase.php @@ -60,6 +60,20 @@ protected function setUp(): void ->findOneBy(['shortname' => 'demo']); } + /** + * Get the contest ID of the demo contest based on the data source setting. + * + * @return string + */ + protected function getDemoContestId(): string + { + if ($this->dataSourceIsLocal()) { + return (string)$this->demoContest->getCid(); + } + + return $this->demoContest->getExternalid(); + } + /** * Verify the given API URL produces the given status code and return the body. * @@ -294,7 +308,7 @@ public function testListWithAbsentIds(): void * * @dataProvider provideSingle */ - public function testSingle($id, array $expectedProperties): void + public function testSingle(int|string $id, array $expectedProperties): void { foreach ($this->entityReferences as $field => $class) { $expectedProperties[$field] = $this->resolveEntityId($class, $expectedProperties[$field]); diff --git a/webapp/tests/Unit/Controller/API/ContestControllerAdminTest.php b/webapp/tests/Unit/Controller/API/ContestControllerAdminTest.php index 372a29cc2d..1cdb9bb461 100644 --- a/webapp/tests/Unit/Controller/API/ContestControllerAdminTest.php +++ b/webapp/tests/Unit/Controller/API/ContestControllerAdminTest.php @@ -109,7 +109,7 @@ public function testAddJson(): void self::assertSame('NWERC 2018 - Testing', $this->getContest($cid)->getName()); } - protected function getContest($cid): Contest + protected function getContest(int|string $cid): Contest { // First clear the entity manager to have all data. static::getContainer()->get(EntityManagerInterface::class)->clear(); diff --git a/webapp/tests/Unit/Controller/API/GeneralInfoControllerTest.php b/webapp/tests/Unit/Controller/API/GeneralInfoControllerTest.php index 7b76224619..a01488dd02 100644 --- a/webapp/tests/Unit/Controller/API/GeneralInfoControllerTest.php +++ b/webapp/tests/Unit/Controller/API/GeneralInfoControllerTest.php @@ -17,7 +17,7 @@ public function testVersionReturnsApiVersion(): void { $response = $this->verifyApiJsonResponse('GET', "/version", 200); - $expected = ['api_version' => static::API_VERSION]; + $expected = ['api_version' => self::API_VERSION]; static::assertEquals($expected, $response); } diff --git a/webapp/tests/Unit/Controller/API/OrganizationControllerTest.php b/webapp/tests/Unit/Controller/API/OrganizationControllerTest.php index 91144abd4f..ec8f627d6e 100644 --- a/webapp/tests/Unit/Controller/API/OrganizationControllerTest.php +++ b/webapp/tests/Unit/Controller/API/OrganizationControllerTest.php @@ -92,7 +92,7 @@ public function testList(): void /** * @dataProvider provideSingle */ - public function testSingle($id, array $expectedProperties): void + public function testSingle(int|string $id, array $expectedProperties): void { // Remove country and country flag if not enabled. $showFlags = static::getContainer()->get(ConfigurationService::class)->get('show_flags'); @@ -182,7 +182,7 @@ public function testFilterList(): void $url = $this->helperGetEndpointURL($apiEndpoint).'?country='.$country; $objects = $this->verifyApiJsonResponse('GET', $url, 200, $this->apiUser); - + static::assertIsArray($objects); foreach ($this->expectedObjects as $expectedObjectId => $expectedObject) { $filteredAway = true; @@ -192,7 +192,7 @@ public function testFilterList(): void foreach ($this->entityReferences as $field => $class) { $expectedObject[$field] = $this->resolveEntityId($class, $expectedObject[$field]); } - + $expectedObjectId = $this->resolveReference($expectedObjectId); if ($this->objectClassForExternalId !== null) { $expectedObjectId = $this->resolveEntityId($this->objectClassForExternalId, (string)$expectedObjectId); diff --git a/webapp/tests/Unit/Controller/API/ProblemControllerTest.php b/webapp/tests/Unit/Controller/API/ProblemControllerTest.php index 9133b050ef..867bec7c0f 100644 --- a/webapp/tests/Unit/Controller/API/ProblemControllerTest.php +++ b/webapp/tests/Unit/Controller/API/ProblemControllerTest.php @@ -111,7 +111,7 @@ public function testAddNotAllowed(): void * * @dataProvider provideSingle */ - public function testStatement($id): void + public function testStatement(int|string $id): void { $id = $this->resolveReference($id); if (($apiEndpoint = $this->apiEndpoint) === null) { diff --git a/webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php b/webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php index cb21ad06f6..8c88566b7e 100644 --- a/webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php +++ b/webapp/tests/Unit/Controller/Jury/JuryControllerTestCase.php @@ -11,6 +11,7 @@ use App\Tests\Unit\BaseTestCase; use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; +use DOMElement; use Generator; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -21,6 +22,7 @@ */ abstract class JuryControllerTestCase extends BaseTestCase { + protected static string $baseUrl = ''; protected array $roles = ['admin']; protected string $addButton = ''; protected string $editButton = ' Edit'; @@ -44,6 +46,7 @@ abstract class JuryControllerTestCase extends BaseTestCase protected static ?array $deleteExtra = null; protected static array $addEntities = []; protected static array $addEntitiesCount = []; + protected static array $addEntitiesShown = []; protected static ?string $defaultEditEntityName = null; protected static array $specialFieldOnlyUpdate = []; protected static array $editEntitiesSkipFields = []; @@ -181,6 +184,7 @@ public function testCheckEditDeleteEntityJury(): void continue; } $singlePageLink = null; + /** @var DOMElement $node */ foreach ($crawler->filter('a') as $node) { if (str_contains($node->nodeValue, $identifier)) { $singlePageLink = $node->getAttribute('href'); @@ -222,7 +226,7 @@ public function testCheckEditDeleteEntityJury(): void } } - public function helperCheckExistence(string $id, $value, array $element): void + public function helperCheckExistence(string $id, mixed $value, array $element): void { if (in_array($id, static::$addEntitiesShown)) { $tmpValue = $element[$id]; @@ -346,6 +350,7 @@ public function testCheckEditEntityAdmin(string $identifier, array $formDataKeys $singlePageLink = null; $this->client->followRedirects(true); $crawler = $this->getCurrentCrawler(); + /** @var DOMElement $node */ foreach ($crawler->filter('a') as $node) { if (str_contains($node->nodeValue, $identifier)) { $singlePageLink = $node->getAttribute('href'); @@ -353,6 +358,7 @@ public function testCheckEditEntityAdmin(string $identifier, array $formDataKeys } $this->verifyPageResponse('GET', $singlePageLink, 200); $crawler = $this->getCurrentCrawler(); + /** @var DOMElement $node */ foreach ($crawler->filter('a') as $node) { if (str_contains($node->nodeValue, 'Edit')) { $editLink = $node->getAttribute('href'); diff --git a/webapp/tests/Unit/Controller/Jury/QueueTaskControllerTest.php b/webapp/tests/Unit/Controller/Jury/QueueTaskControllerTest.php index 19afc4132f..56f29e01d2 100644 --- a/webapp/tests/Unit/Controller/Jury/QueueTaskControllerTest.php +++ b/webapp/tests/Unit/Controller/Jury/QueueTaskControllerTest.php @@ -301,7 +301,7 @@ protected function verifyJudgetaskPage(Submission $submission): void public function provideLazyDataSource(): Generator { - extract($this->getDatasourceLoops()); + ['dataSources' => $dataSources] = $this->getDatasourceLoops(); foreach ($dataSources as $str_data_source) { $dataSource = (int)$str_data_source; foreach ([DOMJudgeService::EVAL_DEMAND, diff --git a/webapp/tests/Unit/Controller/PublicControllerTest.php b/webapp/tests/Unit/Controller/PublicControllerTest.php index b12875d66b..91e60b86ab 100644 --- a/webapp/tests/Unit/Controller/PublicControllerTest.php +++ b/webapp/tests/Unit/Controller/PublicControllerTest.php @@ -247,7 +247,7 @@ public function selfRegisterDuplicateValueProvider(): Generator $fixtures = [EnableSelfregisterFixture::class, SelfRegisteredUserFixture::class]; $category = ''; foreach (static::$duplicateFields as $field => $value) { - extract($value); + ['input' => $input, 'error' => $error] = $value; $newInputs = $inputs; $newInputs[$field] = $input; if (str_contains($field, 'affiliation')) { diff --git a/webapp/tests/Unit/Controller/Team/MiscControllerTest.php b/webapp/tests/Unit/Controller/Team/MiscControllerTest.php index 37c3028975..322567973e 100644 --- a/webapp/tests/Unit/Controller/Team/MiscControllerTest.php +++ b/webapp/tests/Unit/Controller/Team/MiscControllerTest.php @@ -82,7 +82,7 @@ public function testPrintingDisabledAccessDenied(): void */ public function testPrintingEnabledTeamMenu(): void { - $this->withChangedConfiguration('print_command', static::PRINT_COMMAND, + $this->withChangedConfiguration('print_command', self::PRINT_COMMAND, function () { $this->verifyPageResponse('GET', '/team', 200); $this->assertSelectorExists('a:contains("Print")'); @@ -94,7 +94,7 @@ function () { */ public function testPrintingEnabledSubmitForm(): void { - $this->withChangedConfiguration('print_command', static::PRINT_COMMAND, + $this->withChangedConfiguration('print_command', self::PRINT_COMMAND, function () { $this->client->request('GET', '/team/print'); @@ -148,36 +148,36 @@ public function testChangeContest(bool $withReferrer): void // TODO: Enable again when unit tests are rewritten $this->markTestSkipped('Needs to be rewritten to handle different DB states.'); - // Verify we are on the demo contest. - self::assertSelectorTextContains('.card-header span', 'Demo contest'); - - if ($withReferrer) { - // Now click the change contest menu item. - $link = $crawler->filter('a.dropdown-item:contains("switch")')->link(); - - $this->client->click($link); - } else { - // Make sure to clear the history, so we do not have a referrer. - $this->client->getHistory()->clear(); - $this->client->request('GET', '/team/change-contest/' . $contest->getCid()); - } - - $this->client->followRedirect(); - - // Check that we are still on the scoreboard. - if ($withReferrer) { - self::assertEquals('http://localhost/team/scoreboard', - $this->client->getRequest()->getUri()); - } else { - self::assertEquals('http://localhost/team', - $this->client->getRequest()->getUri()); - - // Go to the scoreboard again. - $this->client->request('GET', '/team/scoreboard'); - } - - // And check that the contest has changed. - self::assertSelectorTextContains('.card-header span', 'Test contest for switching'); +// // Verify we are on the demo contest. +// self::assertSelectorTextContains('.card-header span', 'Demo contest'); +// +// if ($withReferrer) { +// // Now click the change contest menu item. +// $link = $crawler->filter('a.dropdown-item:contains("switch")')->link(); +// +// $this->client->click($link); +// } else { +// // Make sure to clear the history, so we do not have a referrer. +// $this->client->getHistory()->clear(); +// $this->client->request('GET', '/team/change-contest/' . $contest->getCid()); +// } +// +// $this->client->followRedirect(); +// +// // Check that we are still on the scoreboard. +// if ($withReferrer) { +// self::assertEquals('http://localhost/team/scoreboard', +// $this->client->getRequest()->getUri()); +// } else { +// self::assertEquals('http://localhost/team', +// $this->client->getRequest()->getUri()); +// +// // Go to the scoreboard again. +// $this->client->request('GET', '/team/scoreboard'); +// } +// +// // And check that the contest has changed. +// self::assertSelectorTextContains('.card-header span', 'Test contest for switching'); } public function withReferrerProvider(): Generator diff --git a/webapp/tests/Unit/Controller/Team/ProblemControllerTest.php b/webapp/tests/Unit/Controller/Team/ProblemControllerTest.php index 88a4ad4b95..92fc544cc9 100644 --- a/webapp/tests/Unit/Controller/Team/ProblemControllerTest.php +++ b/webapp/tests/Unit/Controller/Team/ProblemControllerTest.php @@ -51,7 +51,6 @@ public function testIndex(bool $withLimits): void function () use ( $problemTexts, $descriptions, - $problems, $withLimits, $letters ) { diff --git a/webapp/tests/Unit/Integration/QueuetaskIntegrationTest.php b/webapp/tests/Unit/Integration/QueuetaskIntegrationTest.php index b13fffae7a..cbd2d0b6cf 100644 --- a/webapp/tests/Unit/Integration/QueuetaskIntegrationTest.php +++ b/webapp/tests/Unit/Integration/QueuetaskIntegrationTest.php @@ -156,7 +156,7 @@ protected function setUp(): void self::getContainer()->get('security.untracked_token_storage')->setToken($token); } - private function submit($time, ?Team $team = null, ?Problem $problem = null, string $source = 'team page'): QueueTask + private function submit(?float $time, ?Team $team = null, ?Problem $problem = null, string $source = 'team page'): QueueTask { $contest = $this->em->getRepository(Contest::class)->find($this->contest->getCid()); $team ??= $this->teams[0]; @@ -335,12 +335,12 @@ public function testPriorities(): void self::assertEquals(JudgeTask::PRIORITY_LOW, $problem_import->getPriority()); } - public function setConfig(string $name, $value): void + public function setConfig(string $name, mixed $value): void { $this->configValues[$name] = $value; } - public function getConfig(string $name) + public function getConfig(string $name): mixed { if (!array_key_exists($name, $this->configValues)) { throw new \Exception("No configuration value set for '$name'"); diff --git a/webapp/tests/Unit/Integration/ScoreboardIntegrationTest.php b/webapp/tests/Unit/Integration/ScoreboardIntegrationTest.php index 40c7ed6740..ba3e8580e5 100644 --- a/webapp/tests/Unit/Integration/ScoreboardIntegrationTest.php +++ b/webapp/tests/Unit/Integration/ScoreboardIntegrationTest.php @@ -16,6 +16,7 @@ use App\Service\DOMJudgeService; use App\Service\EventLogService; use App\Service\ScoreboardService; +use App\Utils\Scoreboard\Scoreboard; use App\Utils\Scoreboard\ScoreboardMatrixItem; use App\Utils\Scoreboard\SingleTeamScoreboard; use App\Utils\Scoreboard\TeamScore; @@ -170,7 +171,7 @@ protected function tearDown(): void $this->em = null; // avoid memory leaks } - public function testScoreboardsEmpty() + public function testScoreboardsEmpty(): void { $this->recalcScoreCaches(); @@ -186,7 +187,7 @@ public function testScoreboardsEmpty() } } - public function testScoreboardsNoFreeze() + public function testScoreboardsNoFreeze(): void { $this->contest->setFreezetimeString(null); $this->createDefaultSubmissions(); @@ -210,7 +211,7 @@ public function testScoreboardsNoFreeze() } } - public function testScoreboardJuryFreeze() + public function testScoreboardJuryFreeze(): void { $this->createDefaultSubmissions(); // Scoreboard cache is recalculated below for each freeze time. @@ -237,7 +238,7 @@ public function testScoreboardJuryFreeze() } } - public function testScoreboardPublicFreeze() + public function testScoreboardPublicFreeze(): void { $this->contest->setFreezetimeString('+1:10:00'); $this->createDefaultSubmissions(); @@ -259,7 +260,7 @@ public function testScoreboardPublicFreeze() $this->assertFTSMatch($expected_fts, $scoreboard); } - public function testScoreboardReproducible() + public function testScoreboardReproducible(): void { $this->createDefaultSubmissions(); @@ -273,7 +274,7 @@ public function testScoreboardReproducible() $this->assertEquals($first, $second, 'Repeated scoreboard is equal'); } - public function testTeamScoreboardFreezeFTS() + public function testTeamScoreboardFreezeFTS(): void { $this->contest->setFreezetimeString('+1:10:00'); $this->createDefaultSubmissions(); @@ -293,7 +294,7 @@ public function testTeamScoreboardFreezeFTS() $this->assertFTSMatch($expected_fts, $scoreboard); } - public function testOneSingleFTS() + public function testOneSingleFTS(): void { $lang = $this->em->getRepository(Language::class)->find('c'); @@ -326,7 +327,7 @@ public function testOneSingleFTS() } } - public function testFTSwithVerificationRequired() + public function testFTSwithVerificationRequired(): void { $lang = $this->em->getRepository(Language::class)->find('c'); @@ -362,7 +363,7 @@ public function testFTSwithVerificationRequired() } } - public function testFTSwithQueuedRejudging() + public function testFTSwithQueuedRejudging(): void { $lang = $this->em->getRepository(Language::class)->find('c'); @@ -388,7 +389,7 @@ public function testFTSwithQueuedRejudging() } } - protected function assertScoresMatch($expected_scores, $scoreboard) + protected function assertScoresMatch(array $expected_scores, Scoreboard $scoreboard): void { $scores = $scoreboard->getScores(); @@ -405,7 +406,7 @@ protected function assertScoresMatch($expected_scores, $scoreboard) } } - protected function assertFTSMatch($expected_fts, $scoreboard) + protected function assertFTSMatch(array $expected_fts, Scoreboard $scoreboard): void { $matrix = $scoreboard->getMatrix(); $teams = []; @@ -436,13 +437,13 @@ protected function assertFTSMatch($expected_fts, $scoreboard) } } - protected function recalcScoreCaches() + protected function recalcScoreCaches(): void { $this->em->flush(); $this->ss->refreshCache($this->contest); } - protected function createDefaultSubmissions() + protected function createDefaultSubmissions(): void { $lang = $this->em->getRepository(Language::class)->find('cpp'); @@ -469,7 +470,7 @@ protected function createSubmission( Problem $problem, Team $team, float $contest_time_seconds, - $verdict, + ?string $verdict, bool $verified = false ): Submission { $cp = $this->em->getRepository(ContestProblem::class)->find( @@ -509,12 +510,12 @@ protected function createSubmission( return $submission; } - public function setConfig(string $name, $value) + public function setConfig(string $name, mixed $value): void { $this->configValues[$name] = $value; } - public function getConfig(string $name) + public function getConfig(string $name): mixed { if (!array_key_exists($name, $this->configValues)) { throw new Exception("No configuration value set for '$name'"); diff --git a/webapp/tests/Unit/Service/AwardServiceTest.php b/webapp/tests/Unit/Service/AwardServiceTest.php index 7baf6982aa..8ca908e562 100644 --- a/webapp/tests/Unit/Service/AwardServiceTest.php +++ b/webapp/tests/Unit/Service/AwardServiceTest.php @@ -253,7 +253,7 @@ public function testFirstToSolve(): void /** * @dataProvider provideMedalType */ - public function testMedalType(int $teamIndex, ?string $expectedMedalType) + public function testMedalType(int $teamIndex, ?string $expectedMedalType): void { $awardsService = $this->getAwardService(); $team = $this->scoreboard->getTeams()[$teamIndex]; diff --git a/webapp/tests/Unit/Service/ConfigurationServiceTest.php b/webapp/tests/Unit/Service/ConfigurationServiceTest.php index f03dfbaa17..6ba67d587e 100644 --- a/webapp/tests/Unit/Service/ConfigurationServiceTest.php +++ b/webapp/tests/Unit/Service/ConfigurationServiceTest.php @@ -23,6 +23,9 @@ class ConfigurationServiceTest extends KernelTestCase */ private ?EntityManagerInterface $em; + /** + * @var ObjectRepository&MockObject + */ private ObjectRepository&MockObject $configRepository; private InvocationMocker $emGetRepositoryExpects; @@ -135,7 +138,7 @@ public function provideInvalidItem(): Generator public function testConfigFromDatabase( string $itemName, mixed $dbValue, - $expectedValue = null + mixed $expectedValue = null ): void { $config = new Configuration(); $config @@ -164,7 +167,7 @@ public function testConfigFromDatabase( public function testConfigFromDatabaseAll( string $itemName, mixed $dbValue, - $expectedValue = null + mixed $expectedValue = null ): void { $config = new Configuration(); $config diff --git a/webapp/tests/Unit/Service/ImportExportServiceTest.php b/webapp/tests/Unit/Service/ImportExportServiceTest.php index c5103a68ce..be1a9554e4 100644 --- a/webapp/tests/Unit/Service/ImportExportServiceTest.php +++ b/webapp/tests/Unit/Service/ImportExportServiceTest.php @@ -28,7 +28,7 @@ protected function setUp(): void /** * @dataProvider provideImportContestDataErrors */ - public function testImportContestDataErrors($data, string $expectedMessage): void + public function testImportContestDataErrors(mixed $data, string $expectedMessage): void { /** @var ImportExportService $importExportService */ $importExportService = static::getContainer()->get(ImportExportService::class); @@ -95,7 +95,7 @@ public function provideImportContestDataErrors(): Generator /** * @dataProvider provideImportContestDataSuccess */ - public function testImportContestDataSuccess($data, string $expectedShortName, array $expectedProblems = []): void + public function testImportContestDataSuccess(mixed $data, string $expectedShortName, array $expectedProblems = []): void { /** @var ImportExportService $importExportService */ $importExportService = static::getContainer()->get(ImportExportService::class); @@ -195,7 +195,7 @@ public function provideImportContestDataSuccess(): Generator /** * @dataProvider provideImportProblemsDataSuccess */ - public function testImportProblemsDataSuccess($data, array $expectedProblems): void + public function testImportProblemsDataSuccess(mixed $data, array $expectedProblems): void { // First create a new contest by import it $contestData = [ @@ -604,9 +604,6 @@ protected function testImportAccounts(int $importCount, ?string $message, bool $ if (isset($data['team']['members'])) { self::assertEquals($data['team']['members'], $team->getPublicDescription()); } - if (isset($data['team']['description'])) { - self::assertEquals($data['team']['description'], $team->getPublicDescription()); - } } else { self::assertNull($user->getTeam()); } @@ -619,7 +616,7 @@ protected function testImportAccounts(int $importCount, ?string $message, bool $ } } - public function testImportTeamsTsv() + public function testImportTeamsTsv(): void { // Example from the manual, but we have changed the ID's to not mix them with fixtures $teamsData = <<getRepository(TeamAffiliation::class)->findOneBy(['externalid' => $data['externalid']]); self::assertNotNull($affiliation, "Team affiliation $data[name] does not exist"); - self::assertEquals($data['icpcid'] ?? null, $affiliation->getIcpcId()); + self::assertEquals($data['icpcid'], $affiliation->getIcpcId()); self::assertEquals($data['shortname'], $affiliation->getShortname()); self::assertEquals($data['name'], $affiliation->getName()); self::assertEquals($data['country'], $affiliation->getCountry()); @@ -956,7 +953,7 @@ public function testImportOrganizationsJson() } - protected function getContest($cid): Contest + protected function getContest(int|string $cid): Contest { // First clear the entity manager to have all data. static::getContainer()->get(EntityManagerInterface::class)->clear(); diff --git a/webapp/tests/Unit/Utils/UtilsTest.php b/webapp/tests/Unit/Utils/UtilsTest.php index dea0a1dedc..1501661d44 100644 --- a/webapp/tests/Unit/Utils/UtilsTest.php +++ b/webapp/tests/Unit/Utils/UtilsTest.php @@ -652,7 +652,7 @@ public function testGetImageTypeError(): void * test image thumbnail creation * @dataProvider provideImagesToThumb */ - public function testGetImageThumb($imageLocation, $mime) : void + public function testGetImageThumb(string $imageLocation, string $mime) : void { $logo = __DIR__ . $imageLocation; $image = file_get_contents($logo);