From 0e91dd886e9f637b3790d70b4dd677c6e71433a1 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Wed, 18 Jan 2023 14:47:48 +0100 Subject: [PATCH] release 2.0 beta 2 (#3757) * do not traverse into invoice template subdirectories (#3735) * fix security open api definition * fix currency can be null, removed fluent interface * merged release 1.30.3 * allow to pre-fill timesheet metafields via URL * fix api description * added test accounts with simpler names and password * upgrade to Symfony 6.2 * removed FrameworkExtraBundle (by Sensio) and replaced with new native SF annotations * fixed symfony 6.2 deprecations * fixed #3768 --- composer.json | 7 +- composer.lock | 1279 +++++++++-------- config/bundles.php | 1 - config/packages/fos_rest.yaml | 2 +- config/packages/nelmio_api_doc.yaml | 2 +- config/packages/sensio_framework_extra.yaml | 3 - phpstan.neon | 50 - src/API/ActionsController.php | 4 +- src/API/ActivityController.php | 19 +- src/API/ConfigurationController.php | 4 +- src/API/CustomerController.php | 19 +- src/API/ProjectController.php | 19 +- .../ValidationFailedExceptionErrorHandler.php | 2 +- src/API/StatusController.php | 4 +- src/API/TagController.php | 6 +- src/API/TeamController.php | 56 +- src/API/TimesheetController.php | 29 +- src/API/UserController.php | 12 +- src/Controller/ActivityController.php | 24 +- src/Controller/Auth/SamlController.php | 2 +- src/Controller/CalendarController.php | 4 +- src/Controller/CustomerController.php | 32 +- src/Controller/DashboardController.php | 4 +- src/Controller/DoctorController.php | 6 +- src/Controller/ExportController.php | 4 +- src/Controller/FavoriteController.php | 10 +- src/Controller/HomepageController.php | 4 +- src/Controller/InvoiceController.php | 44 +- src/Controller/PermissionController.php | 13 +- src/Controller/PluginController.php | 4 +- src/Controller/ProfileController.php | 30 +- src/Controller/ProjectController.php | 34 +- src/Controller/QuickEntryController.php | 4 +- .../CustomerMonthlyProjectsController.php | 5 +- .../Reporting/ProjectDateRangeController.php | 6 +- .../Reporting/ProjectDetailsController.php | 6 +- .../Reporting/ProjectInactiveController.php | 6 +- .../Reporting/ProjectViewController.php | 6 +- .../Reporting/ReportUsersMonthController.php | 4 +- .../Reporting/ReportUsersWeekController.php | 4 +- .../Reporting/ReportUsersYearController.php | 4 +- .../Reporting/UserMonthController.php | 4 +- .../Reporting/UserWeekController.php | 4 +- .../Reporting/UserYearController.php | 4 +- src/Controller/ReportingController.php | 4 +- .../SystemConfigurationController.php | 5 +- src/Controller/TagController.php | 10 +- src/Controller/TeamController.php | 13 +- .../TimesheetAbstractController.php | 3 +- src/Controller/TimesheetController.php | 18 +- src/Controller/TimesheetTeamController.php | 20 +- src/Controller/UserController.php | 11 +- src/Controller/WidgetController.php | 6 +- src/Controller/WizardController.php | 6 +- src/DataFixtures/InvoiceFixtures.php | 6 +- src/DataFixtures/TeamFixtures.php | 4 +- src/DataFixtures/TimesheetFixtures.php | 30 +- src/DataFixtures/UserFixtures.php | 81 +- src/Entity/Customer.php | 68 +- src/Entity/Timesheet.php | 4 + src/Entity/User.php | 2 +- src/EventSubscriber/MenuBuilderSubscriber.php | 2 +- .../MenuFavoritesSubscriber.php | 2 +- src/EventSubscriber/UserDetailsSubscriber.php | 2 +- .../Base/AbstractSpreadsheetRenderer.php | 2 +- src/Form/Extension/UserExtension.php | 2 +- src/Form/TimesheetPreCreateForm.php | 2 + src/Form/Type/QuickEntryTimesheetType.php | 2 +- src/Invoice/InvoiceModel.php | 7 +- src/Timesheet/FavoriteRecordService.php | 2 +- src/Twig/LocaleFormatExtensions.php | 2 +- src/Twig/Runtime/WidgetExtension.php | 2 +- src/Utils/ProfileManager.php | 3 +- src/Validator/Constraints/ColorChoices.php | 2 +- src/Validator/Constraints/DateTimeFormat.php | 2 +- src/Validator/Constraints/HexColor.php | 2 +- src/Validator/Constraints/Project.php | 2 +- src/Validator/Constraints/Role.php | 2 +- src/Validator/Constraints/RoleName.php | 2 +- src/Validator/Constraints/Team.php | 2 +- src/Validator/Constraints/TimeFormat.php | 2 +- src/Validator/Constraints/TimesheetBasic.php | 2 +- .../Constraints/TimesheetExported.php | 2 +- .../TimesheetExportedValidator.php | 2 +- .../Constraints/TimesheetFutureTimes.php | 2 +- .../Constraints/TimesheetLockdown.php | 2 +- .../TimesheetLockdownValidator.php | 2 +- .../Constraints/TimesheetLongRunning.php | 2 +- .../Constraints/TimesheetMultiUpdate.php | 2 +- .../Constraints/TimesheetMultiUser.php | 2 +- .../Constraints/TimesheetOverlapping.php | 2 +- .../Constraints/TimesheetRestart.php | 2 +- .../Constraints/TimesheetRestartValidator.php | 2 +- .../Constraints/TimesheetZeroDuration.php | 2 +- src/Validator/Constraints/User.php | 2 +- symfony.lock | 9 - templates/invoice/renderer/default.pdf.twig | 4 +- templates/invoice/renderer/invoice.html.twig | 6 +- .../invoice/renderer/service-date.pdf.twig | 2 +- templates/user/stats.html.twig | 4 +- tests/API/ApiDocControllerTest.php | 2 +- tests/API/ProjectControllerTest.php | 58 +- ...idationFailedExceptionErrorHandlerTest.php | 2 +- tests/API/TimesheetControllerTest.php | 50 +- tests/Controller/Auth/SamlControllerTest.php | 2 +- .../ExportServiceCompilerPassTest.php | 69 + .../InvoiceServiceCompilerPassTest.php | 76 + .../Compiler/TwigContextCompilerPassTest.php | 65 + .../Compiler/WidgetCompilerPassTest.php | 53 + tests/Entity/CustomerTest.php | 27 +- tests/Entity/TimesheetValidationTest.php | 119 +- .../Export/Renderer/AbstractRendererTest.php | 2 +- .../Export/Timesheet/AbstractRendererTest.php | 2 +- .../Form/Type/QuickEntryTimesheetTypeTest.php | 2 +- tests/Twig/LocaleFormatExtensionsTest.php | 2 +- tests/Twig/Runtime/WidgetExtensionTest.php | 2 +- .../Constraints/ColorChoicesValidatorTest.php | 3 +- .../DateTimeFormatValidatorTest.php | 3 +- .../Constraints/DurationValidatorTest.php | 3 +- .../Constraints/HexColorValidatorTest.php | 3 +- .../Constraints/ProjectValidatorTest.php | 3 +- .../QuickEntryModelValidatorTest.php | 3 +- .../QuickEntryTimesheetValidatorTest.php | 7 +- .../Constraints/RoleNameValidatorTest.php | 1 + .../Constraints/RoleValidatorTest.php | 3 +- .../Constraints/TeamValidatorTest.php | 5 +- .../Constraints/TimeFormatValidatorTest.php | 3 +- .../TimesheetBasicValidatorTest.php | 5 +- .../TimesheetBudgetUsedValidatorTest.php | 8 +- .../TimesheetExportedValidatorTest.php | 9 +- .../TimesheetFutureTimesValidatorTest.php | 7 +- .../TimesheetLockdownValidatorTest.php | 9 +- .../TimesheetLongRunningValidatorTest.php | 7 +- .../TimesheetMultiUpdateValidatorTest.php | 3 +- .../TimesheetMultiUserValidatorTest.php | 3 +- .../TimesheetOverlappingValidatorTest.php | 7 +- .../TimesheetRestartValidatorTest.php | 9 +- .../Constraints/TimesheetValidatorTest.php | 7 +- .../TimesheetZeroDurationValidatorTest.php | 7 +- .../Constraints/UserValidatorTest.php | 9 +- tests/phpstan.neon | 175 --- 141 files changed, 1600 insertions(+), 1415 deletions(-) delete mode 100644 config/packages/sensio_framework_extra.yaml create mode 100644 tests/DependencyInjection/Compiler/ExportServiceCompilerPassTest.php create mode 100644 tests/DependencyInjection/Compiler/InvoiceServiceCompilerPassTest.php create mode 100644 tests/DependencyInjection/Compiler/TwigContextCompilerPassTest.php create mode 100644 tests/DependencyInjection/Compiler/WidgetCompilerPassTest.php diff --git a/composer.json b/composer.json index 164c5d3a..5a1e4d29 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "ext-zip": "*", "composer/package-versions-deprecated": "^1.8", "composer/semver": "^3.3", - "doctrine/doctrine-bundle": "^2.0", + "doctrine/doctrine-bundle": "^2.7", "doctrine/doctrine-migrations-bundle": "^3.0", "doctrine/orm": "^2.8", "endroid/qr-code": "^4.4.9", @@ -49,7 +49,6 @@ "scheb/2fa-backup-code": "^6.2", "scheb/2fa-bundle": "^6.2", "scheb/2fa-totp": "^6.2", - "sensio/framework-extra-bundle": "^6.0", "symfony/asset": "^6.0", "symfony/console": "^6.0", "symfony/dotenv": "^6.0", @@ -68,7 +67,7 @@ "symfony/translation": "^6.0", "symfony/twig-bundle": "^6.0", "symfony/validator": "^6.0", - "symfony/webpack-encore-bundle": "^1.5", + "symfony/webpack-encore-bundle": "^1.16", "symfony/yaml": "^6.0", "twig/cssinliner-extra": "^3.0", "twig/extra-bundle": "^3.0", @@ -196,7 +195,7 @@ "symfony": { "id": "01C3FWRDJJEX9K6Y3A4XDFXPBR", "allow-contrib": true, - "require": "6.0.*" + "require": "6.2.*" } } } diff --git a/composer.lock b/composer.lock index 40fb409b..ac1229fb 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": "f3b0627c043009647c1ab9c3ddea3f22", + "content-hash": "28a3255e3b7098abd50383910cd0cf9b", "packages": [ { "name": "bacon/bacon-qr-code", @@ -642,16 +642,16 @@ }, { "name": "doctrine/dbal", - "version": "3.5.2", + "version": "3.5.3", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "63e513cebbbaf96a6795e5c5ee34d205831bfc85" + "reference": "88fa7e5189fd5ec6682477044264dc0ed4e3aa1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/63e513cebbbaf96a6795e5c5ee34d205831bfc85", - "reference": "63e513cebbbaf96a6795e5c5ee34d205831bfc85", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/88fa7e5189fd5ec6682477044264dc0ed4e3aa1e", + "reference": "88fa7e5189fd5ec6682477044264dc0ed4e3aa1e", "shasum": "" }, "require": { @@ -666,7 +666,7 @@ "require-dev": { "doctrine/coding-standard": "11.0.0", "jetbrains/phpstorm-stubs": "2022.3", - "phpstan/phpstan": "1.9.2", + "phpstan/phpstan": "1.9.4", "phpstan/phpstan-strict-rules": "^1.4", "phpunit/phpunit": "9.5.27", "psalm/plugin-phpunit": "0.18.4", @@ -733,7 +733,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.5.2" + "source": "https://github.com/doctrine/dbal/tree/3.5.3" }, "funding": [ { @@ -749,7 +749,7 @@ "type": "tidelift" } ], - "time": "2022-12-19T08:17:34+00:00" + "time": "2023-01-12T10:21:44+00:00" }, { "name": "doctrine/deprecations", @@ -796,16 +796,16 @@ }, { "name": "doctrine/doctrine-bundle", - "version": "2.8.1", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "fe9b2cc1cd0c9b76553b1d4c1a077590ba231a2d" + "reference": "251cd5aaea32bb92cdad4204840786b317dcdd4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/fe9b2cc1cd0c9b76553b1d4c1a077590ba231a2d", - "reference": "fe9b2cc1cd0c9b76553b1d4c1a077590ba231a2d", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/251cd5aaea32bb92cdad4204840786b317dcdd4c", + "reference": "251cd5aaea32bb92cdad4204840786b317dcdd4c", "shasum": "" }, "require": { @@ -891,7 +891,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.8.1" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.8.2" }, "funding": [ { @@ -907,7 +907,7 @@ "type": "tidelift" } ], - "time": "2023-01-06T00:24:26+00:00" + "time": "2023-01-06T11:42:10+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", @@ -1249,31 +1249,33 @@ }, { "name": "doctrine/lexer", - "version": "1.2.3", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.0", "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9.0", + "doctrine/coding-standard": "^9 || ^10", "phpstan/phpstan": "^1.3", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.11" + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^4.11 || ^5.0" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + "Doctrine\\Common\\Lexer\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1305,7 +1307,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.3" + "source": "https://github.com/doctrine/lexer/tree/2.1.0" }, "funding": [ { @@ -1321,25 +1323,25 @@ "type": "tidelift" } ], - "time": "2022-02-28T11:07:21+00:00" + "time": "2022-12-14T08:49:07+00:00" }, { "name": "doctrine/migrations", - "version": "3.5.2", + "version": "3.5.4", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "61c6ef3a10b7df43c3b6388a184754f26e58700a" + "reference": "e327d1f241e964161f1d3f4e82f7aefbe2da45dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/61c6ef3a10b7df43c3b6388a184754f26e58700a", - "reference": "61c6ef3a10b7df43c3b6388a184754f26e58700a", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/e327d1f241e964161f1d3f4e82f7aefbe2da45dd", + "reference": "e327d1f241e964161f1d3f4e82f7aefbe2da45dd", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/dbal": "^3.3", + "doctrine/dbal": "^3.5.1", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.0", "friendsofphp/proxy-manager-lts": "^1.0", @@ -1353,10 +1355,9 @@ }, "require-dev": { "doctrine/coding-standard": "^9", - "doctrine/orm": "^2.12", + "doctrine/orm": "^2.13", "doctrine/persistence": "^2 || ^3", "doctrine/sql-formatter": "^1.0", - "ergebnis/composer-normalize": "^2.9", "ext-pdo_sqlite": "*", "phpstan/phpstan": "^1.5", "phpstan/phpstan-deprecation-rules": "^1", @@ -1376,12 +1377,6 @@ "bin/doctrine-migrations" ], "type": "library", - "extra": { - "composer-normalize": { - "indent-size": 4, - "indent-style": "space" - } - }, "autoload": { "psr-4": { "Doctrine\\Migrations\\": "lib/Doctrine/Migrations" @@ -1414,7 +1409,7 @@ ], "support": { "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.5.2" + "source": "https://github.com/doctrine/migrations/tree/3.5.4" }, "funding": [ { @@ -1430,20 +1425,20 @@ "type": "tidelift" } ], - "time": "2022-08-04T14:29:49+00:00" + "time": "2023-01-17T20:39:56+00:00" }, { "name": "doctrine/orm", - "version": "2.14.0", + "version": "2.14.1", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "f82485e651763fbd1b34879726f4d3b91c358bd9" + "reference": "de7eee5ed7b1b35c99b118f26f210a8281e6db8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/f82485e651763fbd1b34879726f4d3b91c358bd9", - "reference": "f82485e651763fbd1b34879726f4d3b91c358bd9", + "url": "https://api.github.com/repos/doctrine/orm/zipball/de7eee5ed7b1b35c99b118f26f210a8281e6db8e", + "reference": "de7eee5ed7b1b35c99b118f26f210a8281e6db8e", "shasum": "" }, "require": { @@ -1472,14 +1467,14 @@ "doctrine/annotations": "^1.13 || ^2", "doctrine/coding-standard": "^9.0.2 || ^11.0", "phpbench/phpbench": "^0.16.10 || ^1.0", - "phpstan/phpstan": "~1.4.10 || 1.9.4", + "phpstan/phpstan": "~1.4.10 || 1.9.8", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.7.1", "symfony/cache": "^4.4 || ^5.4 || ^6.0", "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2", "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0", - "vimeo/psalm": "4.30.0 || 5.3.0" + "vimeo/psalm": "4.30.0 || 5.4.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", @@ -1529,9 +1524,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.14.0" + "source": "https://github.com/doctrine/orm/tree/2.14.1" }, - "time": "2022-12-19T21:51:58+00:00" + "time": "2023-01-16T18:36:59+00:00" }, { "name": "doctrine/persistence", @@ -2020,16 +2015,16 @@ }, { "name": "friendsofsymfony/rest-bundle", - "version": "3.4.0", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/FriendsOfSymfony/FOSRestBundle.git", - "reference": "b888195589d245002880d07073ef23ab60e3795d" + "reference": "893f3a01e4d88789abc399c6f1b3cfff79238734" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/b888195589d245002880d07073ef23ab60e3795d", - "reference": "b888195589d245002880d07073ef23ab60e3795d", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/893f3a01e4d88789abc399c6f1b3cfff79238734", + "reference": "893f3a01e4d88789abc399c6f1b3cfff79238734", "shasum": "" }, "require": { @@ -2056,7 +2051,7 @@ "doctrine/annotations": "^1.13.2", "friendsofphp/php-cs-fixer": "^3.0", "jms/serializer": "^1.13|^2.0|^3.0", - "jms/serializer-bundle": "^2.4.3|^3.0.1|^4.0|^5.0@beta", + "jms/serializer-bundle": "^2.4.3|^3.0.1|^4.0|^5.0", "psr/http-message": "^1.0", "psr/log": "^1.0|^2.0|^3.0", "sensio/framework-extra-bundle": "^6.1", @@ -2120,9 +2115,9 @@ ], "support": { "issues": "https://github.com/FriendsOfSymfony/FOSRestBundle/issues", - "source": "https://github.com/FriendsOfSymfony/FOSRestBundle/tree/3.4.0" + "source": "https://github.com/FriendsOfSymfony/FOSRestBundle/tree/3.5.0" }, - "time": "2022-09-18T04:54:54+00:00" + "time": "2023-01-06T15:33:47+00:00" }, { "name": "gedmo/doctrine-extensions", @@ -2350,22 +2345,22 @@ }, { "name": "jms/serializer", - "version": "3.18.2", + "version": "3.21.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "329e29c323fb1e5c65b4ae4c77ba747678755a6c" + "reference": "cc49ca6cd97baa173166c1f4fc54521964cf28bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/329e29c323fb1e5c65b4ae4c77ba747678755a6c", - "reference": "329e29c323fb1e5c65b4ae4c77ba747678755a6c", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/cc49ca6cd97baa173166c1f4fc54521964cf28bd", + "reference": "cc49ca6cd97baa173166c1f4fc54521964cf28bd", "shasum": "" }, "require": { - "doctrine/annotations": "^1.13", + "doctrine/annotations": "^1.13 || ^2.0", "doctrine/instantiator": "^1.0.3", - "doctrine/lexer": "^1.1", + "doctrine/lexer": "^1.1 || ^2", "jms/metadata": "^2.6", "php": "^7.2||^8.0", "phpstan/phpdoc-parser": "^0.4 || ^0.5 || ^1.0" @@ -2423,7 +2418,7 @@ "email": "goetas@gmail.com" } ], - "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", + "description": "Library for (de-)serializing data of any complexity; supports XML, and JSON.", "homepage": "http://jmsyst.com/libs/serializer", "keywords": [ "deserialization", @@ -2434,7 +2429,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/serializer/issues", - "source": "https://github.com/schmittjoh/serializer/tree/3.18.2" + "source": "https://github.com/schmittjoh/serializer/tree/3.21.0" }, "funding": [ { @@ -2442,25 +2437,25 @@ "type": "github" } ], - "time": "2022-09-12T08:40:16+00:00" + "time": "2023-01-10T13:08:17+00:00" }, { "name": "jms/serializer-bundle", - "version": "5.0.2", + "version": "5.2.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/JMSSerializerBundle.git", - "reference": "aadf3d14cfb4bf1347ecf0a5426c82a7b99a48f5" + "reference": "cdc876a8bc4611279a7ec970f3da2052cda55078" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/aadf3d14cfb4bf1347ecf0a5426c82a7b99a48f5", - "reference": "aadf3d14cfb4bf1347ecf0a5426c82a7b99a48f5", + "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/cdc876a8bc4611279a7ec970f3da2052cda55078", + "reference": "cdc876a8bc4611279a7ec970f3da2052cda55078", "shasum": "" }, "require": { "jms/metadata": "^2.5", - "jms/serializer": "^3.18", + "jms/serializer": "^3.20", "php": "^7.2 || ^8.0", "symfony/dependency-injection": "^3.4 || ^4.0 || ^5.0 || ^6.0", "symfony/framework-bundle": "^3.4 || ^4.0 || ^5.0 || ^6.0" @@ -2521,7 +2516,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/JMSSerializerBundle/issues", - "source": "https://github.com/schmittjoh/JMSSerializerBundle/tree/5.0.2" + "source": "https://github.com/schmittjoh/JMSSerializerBundle/tree/5.2.0" }, "funding": [ { @@ -2529,7 +2524,7 @@ "type": "github" } ], - "time": "2022-11-03T11:53:29+00:00" + "time": "2023-01-09T16:25:13+00:00" }, { "name": "kevinpapst/tabler-bundle", @@ -2816,16 +2811,16 @@ }, { "name": "lorenzo/pinky", - "version": "1.0.7", + "version": "1.0.9", "source": { "type": "git", "url": "https://github.com/lorenzo/pinky.git", - "reference": "60afc9f8c2b8fb6a2f77050b485ce93143dd8dcf" + "reference": "f890472e4a25f89591f176aa03d9588a9d3332a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lorenzo/pinky/zipball/60afc9f8c2b8fb6a2f77050b485ce93143dd8dcf", - "reference": "60afc9f8c2b8fb6a2f77050b485ce93143dd8dcf", + "url": "https://api.github.com/repos/lorenzo/pinky/zipball/f890472e4a25f89591f176aa03d9588a9d3332a7", + "reference": "f890472e4a25f89591f176aa03d9588a9d3332a7", "shasum": "" }, "require": { @@ -2863,9 +2858,9 @@ ], "support": { "issues": "https://github.com/lorenzo/pinky/issues", - "source": "https://github.com/lorenzo/pinky/tree/1.0.7" + "source": "https://github.com/lorenzo/pinky/tree/1.0.9" }, - "time": "2022-10-02T12:15:42+00:00" + "time": "2023-01-12T16:15:52+00:00" }, { "name": "maennchen/zipstream-php", @@ -3054,27 +3049,27 @@ }, { "name": "monolog/monolog", - "version": "2.8.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50" + "reference": "305444bc6fb6c89e490f4b34fa6e979584d7fa81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/720488632c590286b88b80e62aa3d3d551ad4a50", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/305444bc6fb6c89e490f4b34fa6e979584d7fa81", + "reference": "305444bc6fb6c89e490f4b34fa6e979584d7fa81", "shasum": "" }, "require": { - "php": ">=7.2", - "psr/log": "^1.0.1 || ^2.0 || ^3.0" + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" }, "provide": { - "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + "psr/log-implementation": "3.0.0" }, "require-dev": { - "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "aws/aws-sdk-php": "^3.0", "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7 || ^8", "ext-json": "*", @@ -3083,13 +3078,12 @@ "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "phpspec/prophecy": "^1.15", - "phpstan/phpstan": "^0.12.91", - "phpunit/phpunit": "^8.5.14", - "predis/predis": "^1.1 || ^2.0", - "rollbar/rollbar": "^1.3 || ^2 || ^3", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^9.5.16", + "predis/predis": "^1.1", "ruflin/elastica": "^7", - "swiftmailer/swiftmailer": "^5.3|^6.0", "symfony/mailer": "^5.4 || ^6", "symfony/mime": "^5.4 || ^6" }, @@ -3112,7 +3106,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.x-dev" + "dev-main": "3.x-dev" } }, "autoload": { @@ -3140,7 +3134,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.8.0" + "source": "https://github.com/Seldaek/monolog/tree/3.2.0" }, "funding": [ { @@ -3152,7 +3146,7 @@ "type": "tidelift" } ], - "time": "2022-07-24T11:55:47+00:00" + "time": "2022-07-24T12:00:55+00:00" }, { "name": "mpdf/mpdf", @@ -4907,85 +4901,6 @@ }, "time": "2022-12-10T15:20:09+00:00" }, - { - "name": "sensio/framework-extra-bundle", - "version": "v6.2.9", - "source": { - "type": "git", - "url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git", - "reference": "dcfac94d6bdcf95c126e8ccac2104917c7c8f135" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/dcfac94d6bdcf95c126e8ccac2104917c7c8f135", - "reference": "dcfac94d6bdcf95c126e8ccac2104917c7c8f135", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^1.0", - "php": ">=7.2.5", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/framework-bundle": "^4.4|^5.0|^6.0", - "symfony/http-kernel": "^4.4|^5.0|^6.0" - }, - "conflict": { - "doctrine/doctrine-cache-bundle": "<1.3.1", - "doctrine/persistence": "<1.3" - }, - "require-dev": { - "doctrine/dbal": "^2.10|^3.0", - "doctrine/doctrine-bundle": "^1.11|^2.0", - "doctrine/orm": "^2.5", - "symfony/browser-kit": "^4.4|^5.0|^6.0", - "symfony/doctrine-bridge": "^4.4|^5.0|^6.0", - "symfony/dom-crawler": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/monolog-bridge": "^4.0|^5.0|^6.0", - "symfony/monolog-bundle": "^3.2", - "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0", - "symfony/security-bundle": "^4.4|^5.0|^6.0", - "symfony/twig-bundle": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0", - "twig/twig": "^1.34|^2.4|^3.0" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "6.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Sensio\\Bundle\\FrameworkExtraBundle\\": "src/" - }, - "exclude-from-classmap": [ - "/tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "This bundle provides a way to configure your controllers with annotations", - "keywords": [ - "annotations", - "controllers" - ], - "support": { - "issues": "https://github.com/sensiolabs/SensioFrameworkExtraBundle/issues", - "source": "https://github.com/sensiolabs/SensioFrameworkExtraBundle/tree/v6.2.9" - }, - "abandoned": "Symfony", - "time": "2022-11-01T17:17:13+00:00" - }, { "name": "setasign/fpdi", "version": "v2.3.6", @@ -5140,20 +5055,20 @@ }, { "name": "symfony/asset", - "version": "v6.0.13", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "77b6b2273185bae723c38b40c6b6990a09616327" + "reference": "a0ebf67f56f028217256d5f99438175430b3836c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/77b6b2273185bae723c38b40c6b6990a09616327", - "reference": "77b6b2273185bae723c38b40c6b6990a09616327", + "url": "https://api.github.com/repos/symfony/asset/zipball/a0ebf67f56f028217256d5f99438175430b3836c", + "reference": "a0ebf67f56f028217256d5f99438175430b3836c", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "conflict": { "symfony/http-foundation": "<5.4" @@ -5192,7 +5107,7 @@ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v6.0.13" + "source": "https://github.com/symfony/asset/tree/v6.2.0" }, "funding": [ { @@ -5208,29 +5123,29 @@ "type": "tidelift" } ], - "time": "2022-08-31T08:17:34+00:00" + "time": "2022-10-19T16:13:28+00:00" }, { "name": "symfony/cache", - "version": "v6.0.18", + "version": "v6.2.4", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "079ec0afe323fdcd5ac1f16e3ffdb4991fb5d4c9" + "reference": "ddd1a70bfdf4ed19facad0db689c7bca979d322e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/079ec0afe323fdcd5ac1f16e3ffdb4991fb5d4c9", - "reference": "079ec0afe323fdcd5ac1f16e3ffdb4991fb5d4c9", + "url": "https://api.github.com/repos/symfony/cache/zipball/ddd1a70bfdf4ed19facad0db689c7bca979d322e", + "reference": "ddd1a70bfdf4ed19facad0db689c7bca979d322e", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/cache": "^2.0|^3.0", "psr/log": "^1.1|^2|^3", "symfony/cache-contracts": "^1.1.7|^2|^3", "symfony/service-contracts": "^1.1|^2|^3", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/var-exporter": "^6.2" }, "conflict": { "doctrine/dbal": "<2.13.1", @@ -5260,6 +5175,9 @@ "psr-4": { "Symfony\\Component\\Cache\\": "" }, + "classmap": [ + "Traits/ValueWrapper.php" + ], "exclude-from-classmap": [ "/Tests/" ] @@ -5285,7 +5203,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.0.18" + "source": "https://github.com/symfony/cache/tree/v6.2.4" }, "funding": [ { @@ -5301,7 +5219,7 @@ "type": "tidelift" } ], - "time": "2022-12-29T16:27:58+00:00" + "time": "2022-12-29T16:29:13+00:00" }, { "name": "symfony/cache-contracts", @@ -5384,27 +5302,26 @@ }, { "name": "symfony/config", - "version": "v6.0.11", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "956d4ec5df274dda91a4cedfccc2bfd063f6f649" + "reference": "ebf27792246165a2a0b6b69ec9c620cac8c5a2f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/956d4ec5df274dda91a4cedfccc2bfd063f6f649", - "reference": "956d4ec5df274dda91a4cedfccc2bfd063f6f649", + "url": "https://api.github.com/repos/symfony/config/zipball/ebf27792246165a2a0b6b69ec9c620cac8c5a2f0", + "reference": "ebf27792246165a2a0b6b69ec9c620cac8c5a2f0", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/deprecation-contracts": "^2.1|^3", "symfony/filesystem": "^5.4|^6.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php81": "^1.22" + "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<4.4" + "symfony/finder": "<5.4" }, "require-dev": { "symfony/event-dispatcher": "^5.4|^6.0", @@ -5442,7 +5359,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.0.11" + "source": "https://github.com/symfony/config/tree/v6.2.0" }, "funding": [ { @@ -5458,24 +5375,25 @@ "type": "tidelift" } ], - "time": "2022-06-27T17:10:44+00:00" + "time": "2022-11-02T09:08:04+00:00" }, { "name": "symfony/console", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "2ab307342a7233b9a260edd5ef94087aaca57d18" + "reference": "0f579613e771dba2dbb8211c382342a641f5da06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2ab307342a7233b9a260edd5ef94087aaca57d18", - "reference": "2ab307342a7233b9a260edd5ef94087aaca57d18", + "url": "https://api.github.com/repos/symfony/console/zipball/0f579613e771dba2dbb8211c382342a641f5da06", + "reference": "0f579613e771dba2dbb8211c382342a641f5da06", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^1.1|^2|^3", "symfony/string": "^5.4|^6.0" @@ -5537,7 +5455,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.0.17" + "source": "https://github.com/symfony/console/tree/v6.2.3" }, "funding": [ { @@ -5553,24 +5471,24 @@ "type": "tidelift" } ], - "time": "2022-12-28T14:21:34+00:00" + "time": "2022-12-28T14:26:22+00:00" }, { "name": "symfony/css-selector", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "3e526b732295b5d4c16c38d557b74ba8498a92b4" + "reference": "ab1df4ba3ded7b724766ba3a6e0eca0418e74f80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/3e526b732295b5d4c16c38d557b74ba8498a92b4", - "reference": "3e526b732295b5d4c16c38d557b74ba8498a92b4", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/ab1df4ba3ded7b724766ba3a6e0eca0418e74f80", + "reference": "ab1df4ba3ded7b724766ba3a6e0eca0418e74f80", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "type": "library", "autoload": { @@ -5602,7 +5520,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.0.17" + "source": "https://github.com/symfony/css-selector/tree/v6.2.3" }, "funding": [ { @@ -5618,34 +5536,34 @@ "type": "tidelift" } ], - "time": "2022-12-28T14:21:34+00:00" + "time": "2022-12-28T14:26:22+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "37ffd67504beedbacaa7fd7358eff7042970d4dc" + "reference": "d10309b75035ce8aae33a377375dac04cab941d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/37ffd67504beedbacaa7fd7358eff7042970d4dc", - "reference": "37ffd67504beedbacaa7fd7358eff7042970d4dc", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/d10309b75035ce8aae33a377375dac04cab941d6", + "reference": "d10309b75035ce8aae33a377375dac04cab941d6", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/container": "^1.1|^2.0", "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php81": "^1.22", - "symfony/service-contracts": "^1.1.6|^2.0|^3.0" + "symfony/service-contracts": "^1.1.6|^2.0|^3.0", + "symfony/var-exporter": "^6.2" }, "conflict": { "ext-psr": "<1.1|>=2", - "symfony/config": "<5.4", + "symfony/config": "<6.1", "symfony/finder": "<5.4", - "symfony/proxy-manager-bridge": "<5.4", + "symfony/proxy-manager-bridge": "<6.2", "symfony/yaml": "<5.4" }, "provide": { @@ -5653,7 +5571,7 @@ "symfony/service-implementation": "1.1|2.0|3.0" }, "require-dev": { - "symfony/config": "^5.4|^6.0", + "symfony/config": "^6.1", "symfony/expression-language": "^5.4|^6.0", "symfony/yaml": "^5.4|^6.0" }, @@ -5661,7 +5579,6 @@ "symfony/config": "", "symfony/expression-language": "For using expressions in service container configuration", "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", "symfony/yaml": "" }, "type": "library", @@ -5690,7 +5607,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.0.17" + "source": "https://github.com/symfony/dependency-injection/tree/v6.2.3" }, "funding": [ { @@ -5706,7 +5623,7 @@ "type": "tidelift" } ], - "time": "2022-12-28T14:21:34+00:00" + "time": "2022-12-28T14:43:49+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5777,22 +5694,22 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "0cc7195607bf655f182e905c141a22140ef9aa9e" + "reference": "f0f0d9d81a172a334c29f536500475c741a5d4c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/0cc7195607bf655f182e905c141a22140ef9aa9e", - "reference": "0cc7195607bf655f182e905c141a22140ef9aa9e", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/f0f0d9d81a172a334c29f536500475c741a5d4c0", + "reference": "f0f0d9d81a172a334c29f536500475c741a5d4c0", "shasum": "" }, "require": { - "doctrine/event-manager": "^1|^2", + "doctrine/event-manager": "^1.2|^2", "doctrine/persistence": "^2|^3", - "php": ">=8.0.2", + "php": ">=8.1", "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", @@ -5806,7 +5723,7 @@ "symfony/cache": "<5.4", "symfony/dependency-injection": "<5.4", "symfony/form": "<5.4", - "symfony/http-kernel": "<5.4", + "symfony/http-kernel": "<6.2", "symfony/messenger": "<5.4", "symfony/property-info": "<5.4", "symfony/security-bundle": "<5.4", @@ -5826,7 +5743,7 @@ "symfony/doctrine-messenger": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/form": "^5.4.9|^6.0.9", - "symfony/http-kernel": "^5.4|^6.0", + "symfony/http-kernel": "^6.2", "symfony/messenger": "^5.4|^6.0", "symfony/property-access": "^5.4|^6.0", "symfony/property-info": "^5.4|^6.0", @@ -5872,7 +5789,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v6.0.17" + "source": "https://github.com/symfony/doctrine-bridge/tree/v6.2.3" }, "funding": [ { @@ -5888,24 +5805,28 @@ "type": "tidelift" } ], - "time": "2022-12-20T16:40:04+00:00" + "time": "2022-12-20T16:41:15+00:00" }, { "name": "symfony/dotenv", - "version": "v6.0.5", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "1c2288fdfd0787288cd04b9868f879f2212159c4" + "reference": "bdc3766f31a0944cadfcdf52170ad3fb80b1540b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/1c2288fdfd0787288cd04b9868f879f2212159c4", - "reference": "1c2288fdfd0787288cd04b9868f879f2212159c4", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/bdc3766f31a0944cadfcdf52170ad3fb80b1540b", + "reference": "bdc3766f31a0944cadfcdf52170ad3fb80b1540b", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" + }, + "conflict": { + "symfony/console": "<5.4", + "symfony/process": "<5.4" }, "require-dev": { "symfony/console": "^5.4|^6.0", @@ -5942,7 +5863,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.0.5" + "source": "https://github.com/symfony/dotenv/tree/v6.2.0" }, "funding": [ { @@ -5958,24 +5879,24 @@ "type": "tidelift" } ], - "time": "2022-02-21T17:15:17+00:00" + "time": "2022-09-30T13:41:10+00:00" }, { "name": "symfony/error-handler", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "1113c4bcf3bc77a9c79562543317479c90ba7b82" + "reference": "0926124c95d220499e2baf0fb465772af3a4eddb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/1113c4bcf3bc77a9c79562543317479c90ba7b82", - "reference": "1113c4bcf3bc77a9c79562543317479c90ba7b82", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/0926124c95d220499e2baf0fb465772af3a4eddb", + "reference": "0926124c95d220499e2baf0fb465772af3a4eddb", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/var-dumper": "^5.4|^6.0" }, @@ -6013,7 +5934,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.0.17" + "source": "https://github.com/symfony/error-handler/tree/v6.2.3" }, "funding": [ { @@ -6029,24 +5950,24 @@ "type": "tidelift" } ], - "time": "2022-12-14T15:52:41+00:00" + "time": "2022-12-19T14:33:49+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "42b3985aa07837c9df36013ec5b965e9f2d480bc" + "reference": "3ffeb31139b49bf6ef0bc09d1db95eac053388d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/42b3985aa07837c9df36013ec5b965e9f2d480bc", - "reference": "42b3985aa07837c9df36013ec5b965e9f2d480bc", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3ffeb31139b49bf6ef0bc09d1db95eac053388d1", + "reference": "3ffeb31139b49bf6ef0bc09d1db95eac053388d1", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/event-dispatcher-contracts": "^2|^3" }, "conflict": { @@ -6096,7 +6017,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.0.17" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.2.2" }, "funding": [ { @@ -6112,7 +6033,7 @@ "type": "tidelift" } ], - "time": "2022-12-14T15:52:41+00:00" + "time": "2022-12-14T16:11:27+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -6195,20 +6116,20 @@ }, { "name": "symfony/expression-language", - "version": "v6.0.14", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "80fc98c72206ee7caa3c427e91467d6bf48862c6" + "reference": "e558680a661eddd31f8718f968e75c9c3c8bdad1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/80fc98c72206ee7caa3c427e91467d6bf48862c6", - "reference": "80fc98c72206ee7caa3c427e91467d6bf48862c6", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/e558680a661eddd31f8718f968e75c9c3c8bdad1", + "reference": "e558680a661eddd31f8718f968e75c9c3c8bdad1", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/cache": "^5.4|^6.0", "symfony/service-contracts": "^1.1|^2|^3" }, @@ -6238,7 +6159,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v6.0.14" + "source": "https://github.com/symfony/expression-language/tree/v6.2.2" }, "funding": [ { @@ -6254,24 +6175,24 @@ "type": "tidelift" } ], - "time": "2022-10-07T08:02:12+00:00" + "time": "2022-12-13T15:46:14+00:00" }, { "name": "symfony/filesystem", - "version": "v6.0.13", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "3adca49133bd055ebe6011ed1e012be3c908af79" + "reference": "50b2523c874605cf3d4acf7a9e2b30b6a440a016" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3adca49133bd055ebe6011ed1e012be3c908af79", - "reference": "3adca49133bd055ebe6011ed1e012be3c908af79", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/50b2523c874605cf3d4acf7a9e2b30b6a440a016", + "reference": "50b2523c874605cf3d4acf7a9e2b30b6a440a016", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, @@ -6301,7 +6222,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.0.13" + "source": "https://github.com/symfony/filesystem/tree/v6.2.0" }, "funding": [ { @@ -6317,24 +6238,27 @@ "type": "tidelift" } ], - "time": "2022-09-21T20:25:27+00:00" + "time": "2022-11-20T13:01:27+00:00" }, { "name": "symfony/finder", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "d467d625fc88f7cebf96f495e588a7196a669db1" + "reference": "81eefbddfde282ee33b437ba5e13d7753211ae8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/d467d625fc88f7cebf96f495e588a7196a669db1", - "reference": "d467d625fc88f7cebf96f495e588a7196a669db1", + "url": "https://api.github.com/repos/symfony/finder/zipball/81eefbddfde282ee33b437ba5e13d7753211ae8e", + "reference": "81eefbddfde282ee33b437ba5e13d7753211ae8e", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^6.0" }, "type": "library", "autoload": { @@ -6362,7 +6286,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.0.17" + "source": "https://github.com/symfony/finder/tree/v6.2.3" }, "funding": [ { @@ -6378,7 +6302,7 @@ "type": "tidelift" } ], - "time": "2022-12-22T17:53:58+00:00" + "time": "2022-12-22T17:55:15+00:00" }, { "name": "symfony/flex", @@ -6447,27 +6371,26 @@ }, { "name": "symfony/form", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "8e16d402fc7e52c2d7b7f185a66b4f792a308546" + "reference": "fac98f69461aa8bcabe6bf254de69da892ba9b5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/8e16d402fc7e52c2d7b7f185a66b4f792a308546", - "reference": "8e16d402fc7e52c2d7b7f185a66b4f792a308546", + "url": "https://api.github.com/repos/symfony/form/zipball/fac98f69461aa8bcabe6bf254de69da892ba9b5b", + "reference": "fac98f69461aa8bcabe6bf254de69da892ba9b5b", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/deprecation-contracts": "^2.1|^3", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/options-resolver": "^5.4|^6.0", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "^1.21", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php81": "^1.23", "symfony/property-access": "^5.4|^6.0", "symfony/service-contracts": "^1.1|^2|^3" }, @@ -6489,9 +6412,11 @@ "symfony/console": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", + "symfony/html-sanitizer": "^6.1", "symfony/http-foundation": "^5.4|^6.0", "symfony/http-kernel": "^5.4|^6.0", "symfony/intl": "^5.4|^6.0", + "symfony/security-core": "^6.2", "symfony/security-csrf": "^5.4|^6.0", "symfony/translation": "^5.4|^6.0", "symfony/uid": "^5.4|^6.0", @@ -6499,6 +6424,7 @@ "symfony/var-dumper": "^5.4|^6.0" }, "suggest": { + "symfony/security-core": "For hashing users passwords.", "symfony/security-csrf": "For protecting forms against CSRF attacks.", "symfony/twig-bridge": "For templating with Twig.", "symfony/validator": "For form validation." @@ -6529,7 +6455,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v6.0.17" + "source": "https://github.com/symfony/form/tree/v6.2.3" }, "funding": [ { @@ -6545,37 +6471,37 @@ "type": "tidelift" } ], - "time": "2022-12-28T14:21:34+00:00" + "time": "2022-12-28T14:26:22+00:00" }, { "name": "symfony/framework-bundle", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "76a74c36915079e80dd0d538ae3f65a205881f2b" + "reference": "c26ddbb2c2d8e5eaebbb1297b833be0967725fbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/76a74c36915079e80dd0d538ae3f65a205881f2b", - "reference": "76a74c36915079e80dd0d538ae3f65a205881f2b", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/c26ddbb2c2d8e5eaebbb1297b833be0967725fbc", + "reference": "c26ddbb2c2d8e5eaebbb1297b833be0967725fbc", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.0.2", + "php": ">=8.1", "symfony/cache": "^5.4|^6.0", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4.5|^6.0.5", - "symfony/error-handler": "^5.4|^6.0", + "symfony/config": "^6.1", + "symfony/dependency-injection": "^6.2", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/error-handler": "^6.1", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/filesystem": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", + "symfony/http-foundation": "^6.2", + "symfony/http-kernel": "^6.2.1", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php81": "^1.22", "symfony/routing": "^5.4|^6.0" }, "conflict": { @@ -6592,13 +6518,13 @@ "symfony/http-client": "<5.4", "symfony/lock": "<5.4", "symfony/mailer": "<5.4", - "symfony/messenger": "<5.4", - "symfony/mime": "<5.4", + "symfony/messenger": "<6.2", + "symfony/mime": "<6.2", "symfony/property-access": "<5.4", "symfony/property-info": "<5.4", "symfony/security-core": "<5.4", "symfony/security-csrf": "<5.4", - "symfony/serializer": "<5.4", + "symfony/serializer": "<6.1", "symfony/stopwatch": "<5.4", "symfony/translation": "<5.4", "symfony/twig-bridge": "<5.4", @@ -6619,22 +6545,25 @@ "symfony/dotenv": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/form": "^5.4|^6.0", + "symfony/html-sanitizer": "^6.1", "symfony/http-client": "^5.4|^6.0", "symfony/lock": "^5.4|^6.0", "symfony/mailer": "^5.4|^6.0", - "symfony/messenger": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", + "symfony/messenger": "^6.2", + "symfony/mime": "^6.2", "symfony/notifier": "^5.4|^6.0", "symfony/polyfill-intl-icu": "~1.0", "symfony/process": "^5.4|^6.0", "symfony/property-info": "^5.4|^6.0", "symfony/rate-limiter": "^5.4|^6.0", "symfony/security-bundle": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0", + "symfony/semaphore": "^5.4|^6.0", + "symfony/serializer": "^6.1", "symfony/stopwatch": "^5.4|^6.0", "symfony/string": "^5.4|^6.0", "symfony/translation": "^5.4|^6.0", "symfony/twig-bundle": "^5.4|^6.0", + "symfony/uid": "^5.4|^6.0", "symfony/validator": "^5.4|^6.0", "symfony/web-link": "^5.4|^6.0", "symfony/workflow": "^5.4|^6.0", @@ -6677,7 +6606,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.0.17" + "source": "https://github.com/symfony/framework-bundle/tree/v6.2.3" }, "funding": [ { @@ -6693,25 +6622,26 @@ "type": "tidelift" } ], - "time": "2022-12-20T16:40:04+00:00" + "time": "2022-12-20T16:41:15+00:00" }, { "name": "symfony/http-client", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "d104286d135d29a17ead777888087e7f0fd11771" + "reference": "7054ad466f836309aef511789b9c697bc986d8ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/d104286d135d29a17ead777888087e7f0fd11771", - "reference": "d104286d135d29a17ead777888087e7f0fd11771", + "url": "https://api.github.com/repos/symfony/http-client/zipball/7054ad466f836309aef511789b9c697bc986d8ce", + "reference": "7054ad466f836309aef511789b9c697bc986d8ce", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/http-client-contracts": "^3", "symfony/service-contracts": "^1.0|^2|^3" }, @@ -6761,7 +6691,7 @@ "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-client/tree/v6.0.17" + "source": "https://github.com/symfony/http-client/tree/v6.2.2" }, "funding": [ { @@ -6777,20 +6707,20 @@ "type": "tidelift" } ], - "time": "2022-12-14T15:52:41+00:00" + "time": "2022-12-14T16:11:27+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v3.1.1", + "version": "v3.2.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "fd038f08c623ab5d22b26e9ba35afe8c79071800" + "reference": "c5f587eb445224ddfeb05b5ee703476742d730bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/fd038f08c623ab5d22b26e9ba35afe8c79071800", - "reference": "fd038f08c623ab5d22b26e9ba35afe8c79071800", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/c5f587eb445224ddfeb05b5ee703476742d730bf", + "reference": "c5f587eb445224ddfeb05b5ee703476742d730bf", "shasum": "" }, "require": { @@ -6802,7 +6732,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", @@ -6842,7 +6772,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.2.0" }, "funding": [ { @@ -6858,27 +6788,30 @@ "type": "tidelift" } ], - "time": "2022-04-22T07:30:54+00:00" + "time": "2022-11-25T10:21:52+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "22fe17e40b0481d39212e7165e004eb26422085d" + "reference": "ddf4dd35de1623e7c02013523e6c2137b67b636f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/22fe17e40b0481d39212e7165e004eb26422085d", - "reference": "22fe17e40b0481d39212e7165e004eb26422085d", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ddf4dd35de1623e7c02013523e6c2137b67b636f", + "reference": "ddf4dd35de1623e7c02013523e6c2137b67b636f", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.1" }, + "conflict": { + "symfony/cache": "<6.2" + }, "require-dev": { "predis/predis": "~1.0", "symfony/cache": "^5.4|^6.0", @@ -6917,7 +6850,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.0.17" + "source": "https://github.com/symfony/http-foundation/tree/v6.2.2" }, "funding": [ { @@ -6933,26 +6866,27 @@ "type": "tidelift" } ], - "time": "2022-12-14T15:52:41+00:00" + "time": "2022-12-14T16:11:27+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.0.18", + "version": "v6.2.4", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "71b52f9e5740b124894b454244fa0db48bb15814" + "reference": "74f2e638ec3fa0315443bd85fab7fc8066b77f83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/71b52f9e5740b124894b454244fa0db48bb15814", - "reference": "71b52f9e5740b124894b454244fa0db48bb15814", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/74f2e638ec3fa0315443bd85fab7fc8066b77f83", + "reference": "74f2e638ec3fa0315443bd85fab7fc8066b77f83", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "psr/log": "^1|^2|^3", - "symfony/error-handler": "^5.4|^6.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/error-handler": "^6.1", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/http-foundation": "^5.4|^6.0", "symfony/polyfill-ctype": "^1.8" @@ -6960,9 +6894,9 @@ "conflict": { "symfony/browser-kit": "<5.4", "symfony/cache": "<5.4", - "symfony/config": "<5.4", + "symfony/config": "<6.1", "symfony/console": "<5.4", - "symfony/dependency-injection": "<5.4", + "symfony/dependency-injection": "<6.2", "symfony/doctrine-bridge": "<5.4", "symfony/form": "<5.4", "symfony/http-client": "<5.4", @@ -6979,10 +6913,10 @@ "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", "symfony/browser-kit": "^5.4|^6.0", - "symfony/config": "^5.4|^6.0", + "symfony/config": "^6.1", "symfony/console": "^5.4|^6.0", "symfony/css-selector": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", + "symfony/dependency-injection": "^6.2", "symfony/dom-crawler": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", @@ -6992,6 +6926,7 @@ "symfony/stopwatch": "^5.4|^6.0", "symfony/translation": "^5.4|^6.0", "symfony/translation-contracts": "^1.1|^2|^3", + "symfony/uid": "^5.4|^6.0", "twig/twig": "^2.13|^3.0.4" }, "suggest": { @@ -7026,7 +6961,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.0.18" + "source": "https://github.com/symfony/http-kernel/tree/v6.2.4" }, "funding": [ { @@ -7042,27 +6977,28 @@ "type": "tidelift" } ], - "time": "2022-12-29T18:58:12+00:00" + "time": "2022-12-29T19:05:08+00:00" }, { "name": "symfony/intl", - "version": "v6.0.15", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "3377841a596c69da08086c50e09a37f2b5b1b598" + "reference": "04726ae6cec43582f7dfbfc67a313d1ecdd81c0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/3377841a596c69da08086c50e09a37f2b5b1b598", - "reference": "3377841a596c69da08086c50e09a37f2b5b1b598", + "url": "https://api.github.com/repos/symfony/intl/zipball/04726ae6cec43582f7dfbfc67a313d1ecdd81c0f", + "reference": "04726ae6cec43582f7dfbfc67a313d1ecdd81c0f", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "require-dev": { - "symfony/filesystem": "^5.4|^6.0" + "symfony/filesystem": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0" }, "type": "library", "autoload": { @@ -7106,7 +7042,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v6.0.15" + "source": "https://github.com/symfony/intl/tree/v6.2.0" }, "funding": [ { @@ -7122,37 +7058,42 @@ "type": "tidelift" } ], - "time": "2022-10-23T10:33:07+00:00" + "time": "2022-11-02T09:08:04+00:00" }, { "name": "symfony/mailer", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "0d4562cd13f1e5b78b578120ae5cbd5527ec1534" + "reference": "b355ad81f1d2987c47dcd3b04d5dce669e1e62e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/0d4562cd13f1e5b78b578120ae5cbd5527ec1534", - "reference": "0d4562cd13f1e5b78b578120ae5cbd5527ec1534", + "url": "https://api.github.com/repos/symfony/mailer/zipball/b355ad81f1d2987c47dcd3b04d5dce669e1e62e6", + "reference": "b355ad81f1d2987c47dcd3b04d5dce669e1e62e6", "shasum": "" }, "require": { "egulias/email-validator": "^2.1.10|^3", - "php": ">=8.0.2", + "php": ">=8.1", "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", + "symfony/mime": "^6.2", "symfony/service-contracts": "^1.1|^2|^3" }, "conflict": { - "symfony/http-kernel": "<5.4" + "symfony/http-kernel": "<5.4", + "symfony/messenger": "<6.2", + "symfony/mime": "<6.2", + "symfony/twig-bridge": "<6.2.1" }, "require-dev": { + "symfony/console": "^5.4|^6.0", "symfony/http-client-contracts": "^1.1|^2|^3", - "symfony/messenger": "^5.4|^6.0" + "symfony/messenger": "^6.2", + "symfony/twig-bridge": "^6.2" }, "type": "library", "autoload": { @@ -7180,7 +7121,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.0.17" + "source": "https://github.com/symfony/mailer/tree/v6.2.2" }, "funding": [ { @@ -7196,24 +7137,24 @@ "type": "tidelift" } ], - "time": "2022-12-14T15:52:41+00:00" + "time": "2022-12-14T16:11:27+00:00" }, { "name": "symfony/mime", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "3e6a7ba15997020778312ed576ad01ab60dc2336" + "reference": "8c98bf40406e791043890a163f6f6599b9cfa1ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/3e6a7ba15997020778312ed576ad01ab60dc2336", - "reference": "3e6a7ba15997020778312ed576ad01ab60dc2336", + "url": "https://api.github.com/repos/symfony/mime/zipball/8c98bf40406e791043890a163f6f6599b9cfa1ed", + "reference": "8c98bf40406e791043890a163f6f6599b9cfa1ed", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, @@ -7222,15 +7163,16 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/mailer": "<5.4", - "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6" + "symfony/serializer": "<6.2" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1", + "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/property-access": "^5.4|^6.0", "symfony/property-info": "^5.4|^6.0", - "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6" + "symfony/serializer": "^6.2" }, "type": "library", "autoload": { @@ -7262,7 +7204,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.0.17" + "source": "https://github.com/symfony/mime/tree/v6.2.2" }, "funding": [ { @@ -7278,25 +7220,25 @@ "type": "tidelift" } ], - "time": "2022-12-14T16:19:02+00:00" + "time": "2022-12-14T16:38:10+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "58e36c79d0fd5fdfc7e1208adcd2209bcc5692d5" + "reference": "56172b511312a7ea9759311109df060d14b55e08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/58e36c79d0fd5fdfc7e1208adcd2209bcc5692d5", - "reference": "58e36c79d0fd5fdfc7e1208adcd2209bcc5692d5", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/56172b511312a7ea9759311109df060d14b55e08", + "reference": "56172b511312a7ea9759311109df060d14b55e08", "shasum": "" }, "require": { - "monolog/monolog": "^1.25.1|^2", - "php": ">=8.0.2", + "monolog/monolog": "^1.25.1|^2|^3", + "php": ">=8.1", "symfony/http-kernel": "^5.4|^6.0", "symfony/service-contracts": "^1.1|^2|^3" }, @@ -7345,7 +7287,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v6.0.17" + "source": "https://github.com/symfony/monolog-bridge/tree/v6.2.2" }, "funding": [ { @@ -7361,7 +7303,7 @@ "type": "tidelift" } ], - "time": "2022-12-14T15:52:41+00:00" + "time": "2022-12-14T16:11:27+00:00" }, { "name": "symfony/monolog-bundle", @@ -7446,20 +7388,20 @@ }, { "name": "symfony/options-resolver", - "version": "v6.0.3", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "51f7006670febe4cbcbae177cbffe93ff833250d" + "reference": "d28f02acde71ff75e957082cd36e973df395f626" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/51f7006670febe4cbcbae177cbffe93ff833250d", - "reference": "51f7006670febe4cbcbae177cbffe93ff833250d", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d28f02acde71ff75e957082cd36e973df395f626", + "reference": "d28f02acde71ff75e957082cd36e973df395f626", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/deprecation-contracts": "^2.1|^3" }, "type": "library", @@ -7493,7 +7435,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.0.3" + "source": "https://github.com/symfony/options-resolver/tree/v6.2.0" }, "funding": [ { @@ -7509,24 +7451,24 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:55:41+00:00" + "time": "2022-11-02T09:08:04+00:00" }, { "name": "symfony/password-hasher", - "version": "v6.0.11", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "7ff6706266cbe55310d029b42299eb6e2bebe849" + "reference": "955ce6bdbb53933897043ad00776a88ba916208a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/7ff6706266cbe55310d029b42299eb6e2bebe849", - "reference": "7ff6706266cbe55310d029b42299eb6e2bebe849", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/955ce6bdbb53933897043ad00776a88ba916208a", + "reference": "955ce6bdbb53933897043ad00776a88ba916208a", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "conflict": { "symfony/security-core": "<5.4" @@ -7565,7 +7507,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.0.11" + "source": "https://github.com/symfony/password-hasher/tree/v6.2.0" }, "funding": [ { @@ -7581,7 +7523,7 @@ "type": "tidelift" } ], - "time": "2022-07-20T14:06:08+00:00" + "time": "2022-09-01T02:03:18+00:00" }, { "name": "symfony/polyfill-ctype", @@ -8006,20 +7948,21 @@ }, { "name": "symfony/property-access", - "version": "v6.0.15", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "bdcd636b962c10eb3575dac41cf60a704da42c89" + "reference": "9c267d87dd665d5d33e897290bbb9f64ae905b94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/bdcd636b962c10eb3575dac41cf60a704da42c89", - "reference": "bdcd636b962c10eb3575dac41cf60a704da42c89", + "url": "https://api.github.com/repos/symfony/property-access/zipball/9c267d87dd665d5d33e897290bbb9f64ae905b94", + "reference": "9c267d87dd665d5d33e897290bbb9f64ae905b94", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/property-info": "^5.4|^6.0" }, "require-dev": { @@ -8065,7 +8008,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.0.15" + "source": "https://github.com/symfony/property-access/tree/v6.2.3" }, "funding": [ { @@ -8081,29 +8024,29 @@ "type": "tidelift" } ], - "time": "2022-10-26T20:57:43+00:00" + "time": "2022-12-23T08:18:26+00:00" }, { "name": "symfony/property-info", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "a8593a44d1d3621c3fefd03bd6f1d10b26ca9ab2" + "reference": "b4cbbbcc8679460cfeb1d5bdcb8127a2e85c376c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/a8593a44d1d3621c3fefd03bd6f1d10b26ca9ab2", - "reference": "a8593a44d1d3621c3fefd03bd6f1d10b26ca9ab2", + "url": "https://api.github.com/repos/symfony/property-info/zipball/b4cbbbcc8679460cfeb1d5bdcb8127a2e85c376c", + "reference": "b4cbbbcc8679460cfeb1d5bdcb8127a2e85c376c", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/string": "^5.4|^6.0" }, "conflict": { "phpdocumentor/reflection-docblock": "<5.2", - "phpdocumentor/type-resolver": "<1.4.0", + "phpdocumentor/type-resolver": "<1.5.1", "symfony/dependency-injection": "<5.4" }, "require-dev": { @@ -8154,7 +8097,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.0.17" + "source": "https://github.com/symfony/property-info/tree/v6.2.3" }, "funding": [ { @@ -8170,35 +8113,35 @@ "type": "tidelift" } ], - "time": "2022-12-20T16:40:04+00:00" + "time": "2022-12-20T16:41:15+00:00" }, { "name": "symfony/routing", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "61687a0aa80f6807c52e116ee64072f6ec53780c" + "reference": "35fec764f3e2c8c08fb340d275c84bc78ca7e0c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/61687a0aa80f6807c52e116ee64072f6ec53780c", - "reference": "61687a0aa80f6807c52e116ee64072f6ec53780c", + "url": "https://api.github.com/repos/symfony/routing/zipball/35fec764f3e2c8c08fb340d275c84bc78ca7e0c9", + "reference": "35fec764f3e2c8c08fb340d275c84bc78ca7e0c9", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "conflict": { "doctrine/annotations": "<1.12", - "symfony/config": "<5.4", + "symfony/config": "<6.2", "symfony/dependency-injection": "<5.4", "symfony/yaml": "<5.4" }, "require-dev": { "doctrine/annotations": "^1.12|^2", "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", + "symfony/config": "^6.2", "symfony/dependency-injection": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/http-foundation": "^5.4|^6.0", @@ -8242,7 +8185,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.0.17" + "source": "https://github.com/symfony/routing/tree/v6.2.3" }, "funding": [ { @@ -8258,25 +8201,25 @@ "type": "tidelift" } ], - "time": "2022-12-20T16:40:04+00:00" + "time": "2022-12-20T16:41:15+00:00" }, { "name": "symfony/runtime", - "version": "v6.0.11", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "88813c1735d9ce6e1a7cccf63d6f2b6faca79018" + "reference": "45a63a5885f92741c8def9cbd81c925e6b5b891d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/88813c1735d9ce6e1a7cccf63d6f2b6faca79018", - "reference": "88813c1735d9ce6e1a7cccf63d6f2b6faca79018", + "url": "https://api.github.com/repos/symfony/runtime/zipball/45a63a5885f92741c8def9cbd81c925e6b5b891d", + "reference": "45a63a5885f92741c8def9cbd81c925e6b5b891d", "shasum": "" }, "require": { "composer-plugin-api": "^1.0|^2.0", - "php": ">=8.0.2" + "php": ">=8.1" }, "conflict": { "symfony/dotenv": "<5.4" @@ -8318,7 +8261,7 @@ "description": "Enables decoupling PHP applications from global state", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/runtime/tree/v6.0.11" + "source": "https://github.com/symfony/runtime/tree/v6.2.0" }, "funding": [ { @@ -8334,35 +8277,35 @@ "type": "tidelift" } ], - "time": "2022-06-27T17:10:44+00:00" + "time": "2022-11-02T09:08:04+00:00" }, { "name": "symfony/security-bundle", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "2973e1f2b8af2c85bca230bfe383642a6daaa3d8" + "reference": "313c1c65828b0524a5e5e590d667890d55964ebe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/2973e1f2b8af2c85bca230bfe383642a6daaa3d8", - "reference": "2973e1f2b8af2c85bca230bfe383642a6daaa3d8", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/313c1c65828b0524a5e5e590d667890d55964ebe", + "reference": "313c1c65828b0524a5e5e590d667890d55964ebe", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.0.2", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", + "php": ">=8.1", + "symfony/config": "^6.1", + "symfony/dependency-injection": "^6.2", "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", + "symfony/http-foundation": "^6.2", + "symfony/http-kernel": "^6.2", "symfony/password-hasher": "^5.4|^6.0", - "symfony/security-core": "^5.4|^6.0", + "symfony/security-core": "^6.2", "symfony/security-csrf": "^5.4|^6.0", - "symfony/security-http": "^5.4|^6.0" + "symfony/security-http": "^6.2" }, "conflict": { "symfony/browser-kit": "<5.4", @@ -8418,7 +8361,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v6.0.17" + "source": "https://github.com/symfony/security-bundle/tree/v6.2.3" }, "funding": [ { @@ -8434,24 +8377,24 @@ "type": "tidelift" } ], - "time": "2022-12-20T16:40:04+00:00" + "time": "2022-12-21T09:01:37+00:00" }, { "name": "symfony/security-core", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "544a1f6428490bb2ed71559a6ae5d2939346d291" + "reference": "c03a0dae81e0afca9b6e70e25f1813999fcd8c75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/544a1f6428490bb2ed71559a6ae5d2939346d291", - "reference": "544a1f6428490bb2ed71559a6ae5d2939346d291", + "url": "https://api.github.com/repos/symfony/security-core/zipball/c03a0dae81e0afca9b6e70e25f1813999fcd8c75", + "reference": "c03a0dae81e0afca9b6e70e25f1813999fcd8c75", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/event-dispatcher-contracts": "^1.1|^2|^3", "symfony/password-hasher": "^5.4|^6.0", "symfony/service-contracts": "^1.1.6|^2|^3" @@ -8509,7 +8452,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.0.17" + "source": "https://github.com/symfony/security-core/tree/v6.2.2" }, "funding": [ { @@ -8525,24 +8468,24 @@ "type": "tidelift" } ], - "time": "2022-12-09T07:42:08+00:00" + "time": "2022-12-09T17:05:11+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.0.9", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "5a48bfb3ba3a4e139d8184ca1005c00d8b8e4dc0" + "reference": "12d6ef4695f522566639e58b929d90e25b509379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/5a48bfb3ba3a4e139d8184ca1005c00d8b8e4dc0", - "reference": "5a48bfb3ba3a4e139d8184ca1005c00d8b8e4dc0", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/12d6ef4695f522566639e58b929d90e25b509379", + "reference": "12d6ef4695f522566639e58b929d90e25b509379", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/security-core": "^5.4|^6.0" }, "conflict": { @@ -8580,7 +8523,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.0.9" + "source": "https://github.com/symfony/security-csrf/tree/v6.2.0" }, "funding": [ { @@ -8596,38 +8539,40 @@ "type": "tidelift" } ], - "time": "2022-05-14T12:52:12+00:00" + "time": "2022-11-21T18:36:40+00:00" }, { "name": "symfony/security-http", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "feeeebb645cb886d90fe47612531cf4253b963dd" + "reference": "9f8712ce90d97b7a7cc20c1ac354a0da44cd4831" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/feeeebb645cb886d90fe47612531cf4253b963dd", - "reference": "feeeebb645cb886d90fe47612531cf4253b963dd", + "url": "https://api.github.com/repos/symfony/security-http/zipball/9f8712ce90d97b7a7cc20c1ac354a0da44cd4831", + "reference": "9f8712ce90d97b7a7cc20c1ac354a0da44cd4831", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", + "symfony/http-kernel": "^6.2", "symfony/polyfill-mbstring": "~1.0", "symfony/property-access": "^5.4|^6.0", - "symfony/security-core": "^5.4|^6.0" + "symfony/security-core": "^6.0" }, "conflict": { - "symfony/event-dispatcher": "<5.4", + "symfony/event-dispatcher": "<5.4.9|>=6,<6.0.9", "symfony/security-bundle": "<5.4", "symfony/security-csrf": "<5.4" }, "require-dev": { "psr/log": "^1|^2|^3", "symfony/cache": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", "symfony/rate-limiter": "^5.4|^6.0", "symfony/routing": "^5.4|^6.0", "symfony/security-csrf": "^5.4|^6.0", @@ -8663,7 +8608,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v6.0.17" + "source": "https://github.com/symfony/security-http/tree/v6.2.2" }, "funding": [ { @@ -8679,24 +8624,24 @@ "type": "tidelift" } ], - "time": "2022-11-30T17:16:57+00:00" + "time": "2022-12-13T14:55:03+00:00" }, { "name": "symfony/serializer", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "65545e9a05d9aa86d1e8c1fedccf4d0e532c5b71" + "reference": "9cb1e8fd22f9ff40b9580ae822f44c13317ddb20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/65545e9a05d9aa86d1e8c1fedccf4d0e532c5b71", - "reference": "65545e9a05d9aa86d1e8c1fedccf4d0e532c5b71", + "url": "https://api.github.com/repos/symfony/serializer/zipball/9cb1e8fd22f9ff40b9580ae822f44c13317ddb20", + "reference": "9cb1e8fd22f9ff40b9580ae822f44c13317ddb20", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -8764,7 +8709,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v6.0.17" + "source": "https://github.com/symfony/serializer/tree/v6.2.3" }, "funding": [ { @@ -8780,7 +8725,7 @@ "type": "tidelift" } ], - "time": "2022-12-20T16:40:04+00:00" + "time": "2022-12-20T16:41:15+00:00" }, { "name": "symfony/service-contracts", @@ -8869,20 +8814,20 @@ }, { "name": "symfony/stopwatch", - "version": "v6.0.13", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "7554fde6848af5ef1178f8ccbdbdb8ae1092c70a" + "reference": "266636bb8f3fbdccc302491df7b3a1b9a8c238a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/7554fde6848af5ef1178f8ccbdbdb8ae1092c70a", - "reference": "7554fde6848af5ef1178f8ccbdbdb8ae1092c70a", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/266636bb8f3fbdccc302491df7b3a1b9a8c238a7", + "reference": "266636bb8f3fbdccc302491df7b3a1b9a8c238a7", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/service-contracts": "^1|^2|^3" }, "type": "library", @@ -8911,7 +8856,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.0.13" + "source": "https://github.com/symfony/stopwatch/tree/v6.2.0" }, "funding": [ { @@ -8927,24 +8872,24 @@ "type": "tidelift" } ], - "time": "2022-09-28T15:52:47+00:00" + "time": "2022-09-28T16:00:52+00:00" }, { "name": "symfony/string", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "3f57003dd8a67ed76870cc03092f8501db7788d9" + "reference": "863219fd713fa41cbcd285a79723f94672faff4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/3f57003dd8a67ed76870cc03092f8501db7788d9", - "reference": "3f57003dd8a67ed76870cc03092f8501db7788d9", + "url": "https://api.github.com/repos/symfony/string/zipball/863219fd713fa41cbcd285a79723f94672faff4d", + "reference": "863219fd713fa41cbcd285a79723f94672faff4d", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", @@ -8956,6 +8901,7 @@ "require-dev": { "symfony/error-handler": "^5.4|^6.0", "symfony/http-client": "^5.4|^6.0", + "symfony/intl": "^6.2", "symfony/translation-contracts": "^2.0|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, @@ -8996,7 +8942,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.0.17" + "source": "https://github.com/symfony/string/tree/v6.2.2" }, "funding": [ { @@ -9012,24 +8958,24 @@ "type": "tidelift" } ], - "time": "2022-12-14T15:52:41+00:00" + "time": "2022-12-14T16:11:27+00:00" }, { "name": "symfony/translation", - "version": "v6.0.14", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "6f99eb179aee4652c0a7cd7c11f2a870d904330c" + "reference": "a2a15404ef4c15d92c205718eb828b225a144379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/6f99eb179aee4652c0a7cd7c11f2a870d904330c", - "reference": "6f99eb179aee4652c0a7cd7c11f2a870d904330c", + "url": "https://api.github.com/repos/symfony/translation/zipball/a2a15404ef4c15d92c205718eb828b225a144379", + "reference": "a2a15404ef4c15d92c205718eb828b225a144379", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-mbstring": "~1.0", "symfony/translation-contracts": "^2.3|^3.0" }, @@ -9045,6 +8991,7 @@ "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { + "nikic/php-parser": "^4.13", "psr/log": "^1|^2|^3", "symfony/config": "^5.4|^6.0", "symfony/console": "^5.4|^6.0", @@ -9054,10 +9001,12 @@ "symfony/http-kernel": "^5.4|^6.0", "symfony/intl": "^5.4|^6.0", "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^5.4|^6.0", "symfony/service-contracts": "^1.1.2|^2|^3", "symfony/yaml": "^5.4|^6.0" }, "suggest": { + "nikic/php-parser": "To use PhpAstExtractor", "psr/log-implementation": "To use logging capability in translator", "symfony/config": "", "symfony/yaml": "" @@ -9091,7 +9040,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.0.14" + "source": "https://github.com/symfony/translation/tree/v6.2.3" }, "funding": [ { @@ -9107,7 +9056,7 @@ "type": "tidelift" } ], - "time": "2022-10-07T08:02:12+00:00" + "time": "2022-12-23T14:11:11+00:00" }, { "name": "symfony/translation-contracts", @@ -9192,20 +9141,20 @@ }, { "name": "symfony/twig-bridge", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "b2ba5c7bdeb7ec3fb8597cfc82a0e5c42535c1fe" + "reference": "f3b60bbbe23308fd7b5f99ad480a1852acfd4d65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/b2ba5c7bdeb7ec3fb8597cfc82a0e5c42535c1fe", - "reference": "b2ba5c7bdeb7ec3fb8597cfc82a0e5c42535c1fe", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/f3b60bbbe23308fd7b5f99ad480a1852acfd4d65", + "reference": "f3b60bbbe23308fd7b5f99ad480a1852acfd4d65", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/translation-contracts": "^1.1|^2|^3", "twig/twig": "^2.13|^3.0.4" }, @@ -9213,26 +9162,29 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/console": "<5.4", - "symfony/form": "<5.4", + "symfony/form": "<6.1", "symfony/http-foundation": "<5.4", - "symfony/http-kernel": "<5.4", + "symfony/http-kernel": "<6.2", + "symfony/mime": "<6.2", "symfony/translation": "<5.4", "symfony/workflow": "<5.4" }, "require-dev": { "doctrine/annotations": "^1.12|^2", "egulias/email-validator": "^2.1.10|^3", + "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/asset": "^5.4|^6.0", "symfony/console": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", + "symfony/form": "^6.1", + "symfony/html-sanitizer": "^6.1", "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", + "symfony/http-kernel": "^6.2", "symfony/intl": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", + "symfony/mime": "^6.2", "symfony/polyfill-intl-icu": "~1.0", "symfony/property-info": "^5.4|^6.0", "symfony/routing": "^5.4|^6.0", @@ -9240,7 +9192,7 @@ "symfony/security-core": "^5.4|^6.0", "symfony/security-csrf": "^5.4|^6.0", "symfony/security-http": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0", + "symfony/serializer": "^6.2", "symfony/stopwatch": "^5.4|^6.0", "symfony/translation": "^5.4|^6.0", "symfony/web-link": "^5.4|^6.0", @@ -9255,6 +9207,7 @@ "symfony/expression-language": "For using the ExpressionExtension", "symfony/finder": "", "symfony/form": "For using the FormExtension", + "symfony/html-sanitizer": "For using the HtmlSanitizerExtension", "symfony/http-kernel": "For using the HttpKernelExtension", "symfony/routing": "For using the RoutingExtension", "symfony/security-core": "For using the SecurityExtension", @@ -9292,7 +9245,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.0.17" + "source": "https://github.com/symfony/twig-bridge/tree/v6.2.3" }, "funding": [ { @@ -9308,41 +9261,39 @@ "type": "tidelift" } ], - "time": "2022-12-20T16:40:04+00:00" + "time": "2022-12-20T16:41:15+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "97ef8de536976ac13d34806624853a4ab1554a91" + "reference": "6d32d5f8f36a543663e9db6aa4aefd184f492883" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/97ef8de536976ac13d34806624853a4ab1554a91", - "reference": "97ef8de536976ac13d34806624853a4ab1554a91", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/6d32d5f8f36a543663e9db6aa4aefd184f492883", + "reference": "6d32d5f8f36a543663e9db6aa4aefd184f492883", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", - "php": ">=8.0.2", - "symfony/config": "^5.4|^6.0", + "php": ">=8.1", + "symfony/config": "^6.1", + "symfony/dependency-injection": "^6.1", "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/twig-bridge": "^5.4|^6.0", + "symfony/http-kernel": "^6.2", + "symfony/twig-bridge": "^6.2", "twig/twig": "^2.13|^3.0.4" }, "conflict": { - "symfony/dependency-injection": "<5.4", "symfony/framework-bundle": "<5.4", "symfony/translation": "<5.4" }, "require-dev": { "doctrine/annotations": "^1.10.4|^2", "symfony/asset": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", "symfony/form": "^5.4|^6.0", @@ -9379,7 +9330,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.0.17" + "source": "https://github.com/symfony/twig-bundle/tree/v6.2.3" }, "funding": [ { @@ -9395,27 +9346,27 @@ "type": "tidelift" } ], - "time": "2022-12-20T16:40:04+00:00" + "time": "2022-12-20T16:41:15+00:00" }, { "name": "symfony/validator", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "c61685fe00eeedebda629c394bce75d1d0d34398" + "reference": "bd44a9ae3b19ae81c723b5a5fff6a1a36844ee01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/c61685fe00eeedebda629c394bce75d1d0d34398", - "reference": "c61685fe00eeedebda629c394bce75d1d0d34398", + "url": "https://api.github.com/repos/symfony/validator/zipball/bd44a9ae3b19ae81c723b5a5fff6a1a36844ee01", + "reference": "bd44a9ae3b19ae81c723b5a5fff6a1a36844ee01", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php81": "^1.22", "symfony/translation-contracts": "^1.1|^2|^3" }, "conflict": { @@ -9487,7 +9438,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.0.17" + "source": "https://github.com/symfony/validator/tree/v6.2.3" }, "funding": [ { @@ -9503,24 +9454,24 @@ "type": "tidelift" } ], - "time": "2022-12-22T17:53:58+00:00" + "time": "2022-12-22T17:55:15+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "7d8e7c3c67c77790425ebe33691419dada154e65" + "reference": "fdbadd4803bc3c96ef89238c9c9e2ebe424ec2e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7d8e7c3c67c77790425ebe33691419dada154e65", - "reference": "7d8e7c3c67c77790425ebe33691419dada154e65", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/fdbadd4803bc3c96ef89238c9c9e2ebe424ec2e0", + "reference": "fdbadd4803bc3c96ef89238c9c9e2ebe424ec2e0", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { @@ -9575,7 +9526,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.0.17" + "source": "https://github.com/symfony/var-dumper/tree/v6.2.3" }, "funding": [ { @@ -9591,24 +9542,24 @@ "type": "tidelift" } ], - "time": "2022-12-22T17:53:58+00:00" + "time": "2022-12-22T17:55:15+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "d87c15d59421d38fe5eb4f6724eb75891479e3da" + "reference": "d055d12b20b42e407e607460e7552a1fe6d27f08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/d87c15d59421d38fe5eb4f6724eb75891479e3da", - "reference": "d87c15d59421d38fe5eb4f6724eb75891479e3da", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/d055d12b20b42e407e607460e7552a1fe6d27f08", + "reference": "d055d12b20b42e407e607460e7552a1fe6d27f08", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "require-dev": { "symfony/var-dumper": "^5.4|^6.0" @@ -9644,10 +9595,12 @@ "export", "hydrate", "instantiate", + "lazy loading", + "proxy", "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.0.17" + "source": "https://github.com/symfony/var-exporter/tree/v6.2.3" }, "funding": [ { @@ -9663,7 +9616,7 @@ "type": "tidelift" } ], - "time": "2022-12-22T17:53:58+00:00" + "time": "2022-12-22T17:55:15+00:00" }, { "name": "symfony/webpack-encore-bundle", @@ -9740,20 +9693,20 @@ }, { "name": "symfony/yaml", - "version": "v6.0.17", + "version": "v6.2.2", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "76c08913ea1c50541503a4563b2172710189fa29" + "reference": "6ed8243aa5f2cb5a57009f826b5e7fb3c4200cf3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/76c08913ea1c50541503a4563b2172710189fa29", - "reference": "76c08913ea1c50541503a4563b2172710189fa29", + "url": "https://api.github.com/repos/symfony/yaml/zipball/6ed8243aa5f2cb5a57009f826b5e7fb3c4200cf3", + "reference": "6ed8243aa5f2cb5a57009f826b5e7fb3c4200cf3", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/polyfill-ctype": "^1.8" }, "conflict": { @@ -9794,7 +9747,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.0.17" + "source": "https://github.com/symfony/yaml/tree/v6.2.2" }, "funding": [ { @@ -9810,7 +9763,7 @@ "type": "tidelift" } ], - "time": "2022-12-14T15:52:41+00:00" + "time": "2022-12-14T16:11:27+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -10461,16 +10414,16 @@ }, { "name": "zircote/swagger-php", - "version": "4.5.4", + "version": "4.6.0", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "09356f4d68d29bdf3254811fb2602a5d5d1788ea" + "reference": "ee8147745c92dd4404adb531751ce32676b888d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/09356f4d68d29bdf3254811fb2602a5d5d1788ea", - "reference": "09356f4d68d29bdf3254811fb2602a5d5d1788ea", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/ee8147745c92dd4404adb531751ce32676b888d4", + "reference": "ee8147745c92dd4404adb531751ce32676b888d4", "shasum": "" }, "require": { @@ -10533,9 +10486,9 @@ ], "support": { "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/4.5.4" + "source": "https://github.com/zircote/swagger-php/tree/4.6.0" }, - "time": "2023-01-04T00:51:43+00:00" + "time": "2023-01-13T00:51:01+00:00" } ], "packages-dev": [ @@ -10745,16 +10698,16 @@ }, { "name": "doctrine/data-fixtures", - "version": "1.6.2", + "version": "1.6.3", "source": { "type": "git", "url": "https://github.com/doctrine/data-fixtures.git", - "reference": "d52cc6d392717734fac908768a7319f8a417401a" + "reference": "c27821d038e64f1bfc852a94064d65d2a75ad01f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/d52cc6d392717734fac908768a7319f8a417401a", - "reference": "d52cc6d392717734fac908768a7319f8a417401a", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/c27821d038e64f1bfc852a94064d65d2a75ad01f", + "reference": "c27821d038e64f1bfc852a94064d65d2a75ad01f", "shasum": "" }, "require": { @@ -10807,7 +10760,7 @@ ], "support": { "issues": "https://github.com/doctrine/data-fixtures/issues", - "source": "https://github.com/doctrine/data-fixtures/tree/1.6.2" + "source": "https://github.com/doctrine/data-fixtures/tree/1.6.3" }, "funding": [ { @@ -10823,7 +10776,7 @@ "type": "tidelift" } ], - "time": "2023-01-05T18:42:27+00:00" + "time": "2023-01-07T15:10:22+00:00" }, { "name": "doctrine/doctrine-fixtures-bundle", @@ -11066,17 +11019,86 @@ "time": "2023-01-02T23:53:50+00:00" }, { - "name": "nikic/php-parser", - "version": "v4.15.2", + "name": "masterminds/html5", + "version": "2.7.6", "source": { "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc" + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "897eb517a343a2281f11bc5556d6548db7d93947" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", - "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/897eb517a343a2281f11bc5556d6548db7d93947", + "reference": "897eb517a343a2281f11bc5556d6548db7d93947", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-libxml": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.7.6" + }, + "time": "2022-08-18T16:18:26+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.15.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", "shasum": "" }, "require": { @@ -11117,9 +11139,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" }, - "time": "2022-11-12T15:38:23+00:00" + "time": "2023-01-16T22:05:37+00:00" }, { "name": "phar-io/manifest", @@ -11234,16 +11256,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.9.7", + "version": "1.9.12", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0501435cd342eac7664bd62155b1ef907fc60b6f" + "reference": "44a338ff0d5572c13fd77dfd91addb96e48c29f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0501435cd342eac7664bd62155b1ef907fc60b6f", - "reference": "0501435cd342eac7664bd62155b1ef907fc60b6f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/44a338ff0d5572c13fd77dfd91addb96e48c29f8", + "reference": "44a338ff0d5572c13fd77dfd91addb96e48c29f8", "shasum": "" }, "require": { @@ -11273,7 +11295,7 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.9.7" + "source": "https://github.com/phpstan/phpstan/tree/1.9.12" }, "funding": [ { @@ -11289,25 +11311,25 @@ "type": "tidelift" } ], - "time": "2023-01-04T21:59:57+00:00" + "time": "2023-01-17T10:44:04+00:00" }, { "name": "phpstan/phpstan-doctrine", - "version": "1.3.29", + "version": "1.3.32", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-doctrine.git", - "reference": "4967ebbc24a2d7e94f5b2f6dad78e0087dd52fc3" + "reference": "4534559a8c08ab3648c6fa09289478780e190ae7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/4967ebbc24a2d7e94f5b2f6dad78e0087dd52fc3", - "reference": "4967ebbc24a2d7e94f5b2f6dad78e0087dd52fc3", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/4534559a8c08ab3648c6fa09289478780e190ae7", + "reference": "4534559a8c08ab3648c6fa09289478780e190ae7", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.9.7" + "phpstan/phpstan": "^1.9.11" }, "conflict": { "doctrine/collections": "<1.0", @@ -11317,6 +11339,7 @@ "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", @@ -11356,9 +11379,9 @@ "description": "Doctrine extensions for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-doctrine/issues", - "source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.29" + "source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.32" }, - "time": "2023-01-04T21:51:32+00:00" + "time": "2023-01-12T13:39:08+00:00" }, { "name": "phpstan/phpstan-phpunit", @@ -11414,21 +11437,21 @@ }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.4.4", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6" + "reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6", - "reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d", + "reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.8.6" + "phpstan/phpstan": "^1.9.7" }, "require-dev": { "nikic/php-parser": "^4.13.0", @@ -11456,22 +11479,22 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.4" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.5" }, - "time": "2022-09-21T11:38:17+00:00" + "time": "2023-01-11T14:16:29+00:00" }, { "name": "phpstan/phpstan-symfony", - "version": "1.2.19", + "version": "1.2.20", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "dac2474904b092267f0a19dfba8c46b6f21eab6a" + "reference": "d89a521e7e31822409bf37f70691f7a12a6e7d76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/dac2474904b092267f0a19dfba8c46b6f21eab6a", - "reference": "dac2474904b092267f0a19dfba8c46b6f21eab6a", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/d89a521e7e31822409bf37f70691f7a12a6e7d76", + "reference": "d89a521e7e31822409bf37f70691f7a12a6e7d76", "shasum": "" }, "require": { @@ -11527,9 +11550,9 @@ "description": "Symfony Framework extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.19" + "source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.20" }, - "time": "2022-12-22T20:05:46+00:00" + "time": "2023-01-15T12:28:31+00:00" }, { "name": "phpunit/php-code-coverage", @@ -11851,20 +11874,20 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.27", + "version": "9.5.28", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38" + "reference": "954ca3113a03bf780d22f07bf055d883ee04b65e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a2bc7ffdca99f92d959b3f2270529334030bba38", - "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/954ca3113a03bf780d22f07bf055d883ee04b65e", + "reference": "954ca3113a03bf780d22f07bf055d883ee04b65e", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1", + "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -11933,7 +11956,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.27" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.28" }, "funding": [ { @@ -11949,7 +11972,7 @@ "type": "tidelift" } ], - "time": "2022-12-09T07:31:23+00:00" + "time": "2023-01-14T12:32:24+00:00" }, { "name": "sebastian/cli-parser", @@ -12917,20 +12940,20 @@ }, { "name": "symfony/browser-kit", - "version": "v6.0.11", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "92e4b59bf2ef0f7a01d2620c4c87108e5c143d36" + "reference": "5602fcc9a2a696f1743050ffcafa30741da94227" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/92e4b59bf2ef0f7a01d2620c4c87108e5c143d36", - "reference": "92e4b59bf2ef0f7a01d2620c4c87108e5c143d36", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/5602fcc9a2a696f1743050ffcafa30741da94227", + "reference": "5602fcc9a2a696f1743050ffcafa30741da94227", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/dom-crawler": "^5.4|^6.0" }, "require-dev": { @@ -12968,7 +12991,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v6.0.11" + "source": "https://github.com/symfony/browser-kit/tree/v6.2.0" }, "funding": [ { @@ -12984,25 +13007,26 @@ "type": "tidelift" } ], - "time": "2022-07-27T15:50:26+00:00" + "time": "2022-11-02T09:08:04+00:00" }, { "name": "symfony/debug-bundle", - "version": "v6.0.11", + "version": "v6.2.1", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "78426ad77ab9d2429e20354bf7dc56c966205848" + "reference": "d87ef905baa453646a6e633690c184998e573e10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/78426ad77ab9d2429e20354bf7dc56c966205848", - "reference": "78426ad77ab9d2429e20354bf7dc56c966205848", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/d87ef905baa453646a6e633690c184998e573e10", + "reference": "d87ef905baa453646a6e633690c184998e573e10", "shasum": "" }, "require": { "ext-xml": "*", - "php": ">=8.0.2", + "php": ">=8.1", + "symfony/dependency-injection": "^5.4|^6.0", "symfony/http-kernel": "^5.4|^6.0", "symfony/twig-bridge": "^5.4|^6.0", "symfony/var-dumper": "^5.4|^6.0" @@ -13013,7 +13037,6 @@ }, "require-dev": { "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", "symfony/web-profiler-bundle": "^5.4|^6.0" }, "suggest": { @@ -13046,7 +13069,7 @@ "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug-bundle/tree/v6.0.11" + "source": "https://github.com/symfony/debug-bundle/tree/v6.2.1" }, "funding": [ { @@ -13062,32 +13085,29 @@ "type": "tidelift" } ], - "time": "2022-07-20T13:45:53+00:00" + "time": "2022-12-05T06:41:34+00:00" }, { "name": "symfony/dom-crawler", - "version": "v6.0.17", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "281d13dfd1a2ac4ca8be8c60b0af208ffdac95fe" + "reference": "f2743e033dd05a62978ced0ad368022e82c9fab2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/281d13dfd1a2ac4ca8be8c60b0af208ffdac95fe", - "reference": "281d13dfd1a2ac4ca8be8c60b0af208ffdac95fe", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/f2743e033dd05a62978ced0ad368022e82c9fab2", + "reference": "f2743e033dd05a62978ced0ad368022e82c9fab2", "shasum": "" }, "require": { - "php": ">=8.0.2", + "masterminds/html5": "^2.6", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0" }, - "conflict": { - "masterminds/html5": "<2.6" - }, "require-dev": { - "masterminds/html5": "^2.6", "symfony/css-selector": "^5.4|^6.0" }, "suggest": { @@ -13119,7 +13139,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.0.17" + "source": "https://github.com/symfony/dom-crawler/tree/v6.2.3" }, "funding": [ { @@ -13135,7 +13155,7 @@ "type": "tidelift" } ], - "time": "2022-12-22T17:53:58+00:00" + "time": "2022-12-22T17:55:15+00:00" }, { "name": "symfony/phpunit-bridge", @@ -13222,20 +13242,20 @@ }, { "name": "symfony/process", - "version": "v6.0.11", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "44270a08ccb664143dede554ff1c00aaa2247a43" + "reference": "ba6e55359f8f755fe996c58a81e00eaa67a35877" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/44270a08ccb664143dede554ff1c00aaa2247a43", - "reference": "44270a08ccb664143dede554ff1c00aaa2247a43", + "url": "https://api.github.com/repos/symfony/process/zipball/ba6e55359f8f755fe996c58a81e00eaa67a35877", + "reference": "ba6e55359f8f755fe996c58a81e00eaa67a35877", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "type": "library", "autoload": { @@ -13263,7 +13283,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.0.11" + "source": "https://github.com/symfony/process/tree/v6.2.0" }, "funding": [ { @@ -13279,33 +13299,32 @@ "type": "tidelift" } ], - "time": "2022-06-27T17:10:44+00:00" + "time": "2022-11-02T09:08:04+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v6.0.17", + "version": "v6.2.4", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "d970ba52d542186cdf8b592eb36a157a025d2d76" + "reference": "1c5f690bf54593ff4d3170cf6b47d76cedb557b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/d970ba52d542186cdf8b592eb36a157a025d2d76", - "reference": "d970ba52d542186cdf8b592eb36a157a025d2d76", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/1c5f690bf54593ff4d3170cf6b47d76cedb557b9", + "reference": "1c5f690bf54593ff4d3170cf6b47d76cedb557b9", "shasum": "" }, "require": { - "php": ">=8.0.2", + "php": ">=8.1", "symfony/config": "^5.4|^6.0", "symfony/framework-bundle": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", + "symfony/http-kernel": "^6.1", "symfony/routing": "^5.4|^6.0", "symfony/twig-bundle": "^5.4|^6.0", "twig/twig": "^2.13|^3.0.4" }, "conflict": { - "symfony/dependency-injection": "<5.4", "symfony/form": "<5.4", "symfony/mailer": "<5.4", "symfony/messenger": "<5.4" @@ -13342,7 +13361,7 @@ "description": "Provides a development tool that gives detailed information about the execution of any request", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.0.17" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.2.4" }, "funding": [ { @@ -13358,7 +13377,7 @@ "type": "tidelift" } ], - "time": "2022-12-14T15:52:41+00:00" + "time": "2022-12-29T18:33:43+00:00" }, { "name": "theseer/tokenizer", diff --git a/config/bundles.php b/config/bundles.php index 6413f639..6b8d787c 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -5,7 +5,6 @@ return [ Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], - Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], diff --git a/config/packages/fos_rest.yaml b/config/packages/fos_rest.yaml index ff1fa125..4ef939b2 100644 --- a/config/packages/fos_rest.yaml +++ b/config/packages/fos_rest.yaml @@ -4,7 +4,7 @@ fos_rest: cache_dir: '%kernel.cache_dir%/fos_rest' routing_loader: false body_converter: - enabled: true + enabled: false serializer: serialize_null: true view: diff --git a/config/packages/nelmio_api_doc.yaml b/config/packages/nelmio_api_doc.yaml index f5b42a7f..7525577f 100644 --- a/config/packages/nelmio_api_doc.yaml +++ b/config/packages/nelmio_api_doc.yaml @@ -63,4 +63,4 @@ nelmio_api_doc: in: header security: - X-AUTH-USER: [] - - X-AUTH-TOKEN: [] + X-AUTH-TOKEN: [] diff --git a/config/packages/sensio_framework_extra.yaml b/config/packages/sensio_framework_extra.yaml deleted file mode 100644 index 1821ccc0..00000000 --- a/config/packages/sensio_framework_extra.yaml +++ /dev/null @@ -1,3 +0,0 @@ -sensio_framework_extra: - router: - annotations: false diff --git a/phpstan.neon b/phpstan.neon index 0d8ff59e..4d6ee991 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2075,16 +2075,6 @@ parameters: count: 1 path: src/DataFixtures/TeamFixtures.php - - - message: "#^Cannot access offset 1 on mixed\\.$#" - count: 1 - path: src/DataFixtures/TimesheetFixtures.php - - - - message: "#^Cannot access offset 2 on mixed\\.$#" - count: 1 - path: src/DataFixtures/TimesheetFixtures.php - - message: "#^Cannot call method setTimestamp\\(\\) on DateTime\\|null\\.$#" count: 1 @@ -2095,51 +2085,21 @@ parameters: count: 1 path: src/DataFixtures/TimesheetFixtures.php - - - message: "#^Method App\\\\DataFixtures\\\\TimesheetFixtures\\:\\:createTimesheetEntry\\(\\) has no return type specified\\.$#" - count: 1 - path: src/DataFixtures/TimesheetFixtures.php - - - - message: "#^Method App\\\\DataFixtures\\\\TimesheetFixtures\\:\\:findRandom\\(\\) has no return type specified\\.$#" - count: 1 - path: src/DataFixtures/TimesheetFixtures.php - - message: "#^Parameter \\#1 \\$begin of method App\\\\Entity\\\\Timesheet\\:\\:setBegin\\(\\) expects DateTime, DateTime\\|null given\\.$#" count: 1 path: src/DataFixtures/TimesheetFixtures.php - - - message: "#^Parameter \\#1 \\$className of method Doctrine\\\\Persistence\\\\ObjectManager\\:\\:getRepository\\(\\) expects class\\-string\\, string given\\.$#" - count: 2 - path: src/DataFixtures/TimesheetFixtures.php - - message: "#^Parameter \\#1 \\$description of method App\\\\Entity\\\\Timesheet\\:\\:setDescription\\(\\) expects string, string\\|null given\\.$#" count: 1 path: src/DataFixtures/TimesheetFixtures.php - - - message: "#^Parameter \\#1 \\$min of function rand expects int, mixed given\\.$#" - count: 1 - path: src/DataFixtures/TimesheetFixtures.php - - message: "#^Parameter \\#1 \\$user of method App\\\\DataFixtures\\\\TimesheetFixtures\\:\\:createTimesheetEntry\\(\\) expects App\\\\Entity\\\\User, App\\\\Entity\\\\User\\|null given\\.$#" count: 2 path: src/DataFixtures/TimesheetFixtures.php - - - message: "#^Parameter \\#2 \\$max of function rand expects int, mixed given\\.$#" - count: 1 - path: src/DataFixtures/TimesheetFixtures.php - - - - message: "#^Unable to resolve the template type T in call to method Doctrine\\\\Persistence\\\\ObjectManager\\:\\:getRepository\\(\\)$#" - count: 2 - path: src/DataFixtures/TimesheetFixtures.php - - message: "#^Method App\\\\DataFixtures\\\\UserFixtures\\:\\:getUserDefinition\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -2150,16 +2110,6 @@ parameters: count: 1 path: src/DataFixtures/UserFixtures.php - - - message: "#^Method App\\\\DataFixtures\\\\UserFixtures\\:\\:loadDefaultAccounts\\(\\) has no return type specified\\.$#" - count: 1 - path: src/DataFixtures/UserFixtures.php - - - - message: "#^Method App\\\\DataFixtures\\\\UserFixtures\\:\\:loadTestUsers\\(\\) has no return type specified\\.$#" - count: 1 - path: src/DataFixtures/UserFixtures.php - - message: "#^Method App\\\\DependencyInjection\\\\AppExtension\\:\\:createPermissionParameter\\(\\) has parameter \\$config with no value type specified in iterable type array\\.$#" count: 1 diff --git a/src/API/ActionsController.php b/src/API/ActionsController.php index 4c84655d..1466ce49 100644 --- a/src/API/ActionsController.php +++ b/src/API/ActionsController.php @@ -21,14 +21,14 @@ use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Model; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Contracts\Translation\TranslatorInterface; #[Route(path: '/actions')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'Actions')] final class ActionsController extends BaseApiController { diff --git a/src/API/ActivityController.php b/src/API/ActivityController.php index 0907c212..8e225419 100644 --- a/src/API/ActivityController.php +++ b/src/API/ActivityController.php @@ -26,15 +26,15 @@ use FOS\RestBundle\View\View; use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/activities')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'Activity')] final class ActivityController extends BaseApiController { @@ -179,7 +179,7 @@ final class ActivityController extends BaseApiController /** * Update an existing activity */ - #[Security("is_granted('edit', activity)")] + #[IsGranted('edit', 'activity')] #[OA\Patch(description: 'Update an existing activity, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated activity', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ActivityEditForm'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Activity ID to update', required: true)] @@ -217,7 +217,7 @@ final class ActivityController extends BaseApiController /** * Sets the value of a meta-field for an existing activity */ - #[Security("is_granted('edit', activity)")] + #[IsGranted('edit', 'activity')] #[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Activity record ID to set the meta-field value for', required: true)] #[Rest\Patch(path: '/{id}/meta', requirements: ['id' => '\d+'])] @@ -250,7 +250,7 @@ final class ActivityController extends BaseApiController /** * Returns a collection of all rates for one activity */ - #[Security("is_granted('edit', activity)")] + #[IsGranted('edit', 'activity')] #[OA\Response(response: 200, description: 'Returns a collection of activity rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ActivityRate')))] #[OA\Parameter(name: 'id', in: 'path', description: 'The activity whose rates will be returned', required: true)] #[Rest\Get(path: '/{id}/rates', name: 'get_activity_rates', requirements: ['id' => '\d+'])] @@ -269,15 +269,14 @@ final class ActivityController extends BaseApiController /** * Deletes one rate for an activity */ - #[Security("is_granted('edit', activity)")] + #[IsGranted('edit', 'activity')] #[OA\Delete(responses: [new OA\Response(response: 204, description: 'Returns no content: 204 on successful delete')])] #[OA\Parameter(name: 'id', in: 'path', description: 'The activity whose rate will be removed', required: true)] #[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] #[Rest\Delete(path: '/{id}/rates/{rateId}', name: 'delete_activity_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])] - #[Entity('rate', expr: 'repository.find(rateId)')] - public function deleteRateAction(Activity $activity, ActivityRate $rate): Response + public function deleteRateAction(Activity $activity, #[MapEntity(mapping: ['rateId' => 'id'])] ActivityRate $rate): Response { if ($rate->getActivity() !== $activity) { throw $this->createNotFoundException(); @@ -293,7 +292,7 @@ final class ActivityController extends BaseApiController /** * Adds a new rate to an activity */ - #[Security("is_granted('edit', activity)")] + #[IsGranted('edit', 'activity')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/ActivityRate'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The activity to add the rate for', required: true)] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ActivityRateForm'))] diff --git a/src/API/ConfigurationController.php b/src/API/ConfigurationController.php index 2b844fe3..6db094d5 100644 --- a/src/API/ConfigurationController.php +++ b/src/API/ConfigurationController.php @@ -17,10 +17,10 @@ use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Model; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Http\Attribute\IsGranted; -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'Default')] final class ConfigurationController extends BaseApiController { diff --git a/src/API/CustomerController.php b/src/API/CustomerController.php index 0a531b37..4341957c 100644 --- a/src/API/CustomerController.php +++ b/src/API/CustomerController.php @@ -26,15 +26,15 @@ use FOS\RestBundle\View\View; use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/customers')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'Customer')] final class CustomerController extends BaseApiController { @@ -156,7 +156,7 @@ final class CustomerController extends BaseApiController /** * Update an existing customer */ - #[Security("is_granted('edit', customer)")] + #[IsGranted('edit', 'customer')] #[OA\Patch(description: 'Update an existing customer, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated customer', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/CustomerEditForm'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Customer ID to update', required: true)] @@ -194,7 +194,7 @@ final class CustomerController extends BaseApiController /** * Sets the value of a meta-field for an existing customer */ - #[Security("is_granted('edit', customer)")] + #[IsGranted('edit', 'customer')] #[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Customer record ID to set the meta-field value for', required: true)] #[Rest\Patch(path: '/{id}/meta', requirements: ['id' => '\d+'])] @@ -227,7 +227,7 @@ final class CustomerController extends BaseApiController /** * Returns a collection of all rates for one customer */ - #[Security("is_granted('edit', customer)")] + #[IsGranted('edit', 'customer')] #[OA\Response(response: 200, description: 'Returns a collection of customer rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/CustomerRate')))] #[OA\Parameter(name: 'id', in: 'path', description: 'The customer whose rates will be returned', required: true)] #[Rest\Get(path: '/{id}/rates', name: 'get_customer_rates', requirements: ['id' => '\d+'])] @@ -246,15 +246,14 @@ final class CustomerController extends BaseApiController /** * Deletes one rate for a customer */ - #[Security("is_granted('edit', customer)")] + #[IsGranted('edit', 'customer')] #[OA\Delete(responses: [new OA\Response(response: 204, description: 'Returns no content: 204 on successful delete')])] #[OA\Parameter(name: 'id', in: 'path', description: 'The customer whose rate will be removed', required: true)] #[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] #[Rest\Delete(path: '/{id}/rates/{rateId}', name: 'delete_customer_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])] - #[Entity('rate', expr: 'repository.find(rateId)')] - public function deleteRateAction(Customer $customer, CustomerRate $rate): Response + public function deleteRateAction(Customer $customer, #[MapEntity(mapping: ['rateId' => 'id'])] CustomerRate $rate): Response { if ($rate->getCustomer() !== $customer) { throw $this->createNotFoundException(); @@ -270,7 +269,7 @@ final class CustomerController extends BaseApiController /** * Adds a new rate to a customer */ - #[Security("is_granted('edit', customer)")] + #[IsGranted('edit', 'customer')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/CustomerRate'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The customer to add the rate for', required: true)] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/CustomerRateForm'))] diff --git a/src/API/ProjectController.php b/src/API/ProjectController.php index 7fe276db..c4713aef 100644 --- a/src/API/ProjectController.php +++ b/src/API/ProjectController.php @@ -27,16 +27,16 @@ use FOS\RestBundle\View\View; use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\Validator\Constraints; #[Route(path: '/projects')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'Project')] final class ProjectController extends BaseApiController { @@ -209,7 +209,7 @@ final class ProjectController extends BaseApiController /** * Update an existing project */ - #[Security("is_granted('edit', project)")] + #[IsGranted('edit', 'project')] #[OA\Patch(description: 'Update an existing project, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated project', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectEditForm'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Project ID to update', required: true)] @@ -249,7 +249,7 @@ final class ProjectController extends BaseApiController /** * Sets the value of a meta-field for an existing project */ - #[Security("is_granted('edit', project)")] + #[IsGranted('edit', 'project')] #[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Project record ID to set the meta-field value for', required: true)] #[Rest\Patch(path: '/{id}/meta', requirements: ['id' => '\d+'])] @@ -282,7 +282,7 @@ final class ProjectController extends BaseApiController /** * Returns a collection of all rates for one project */ - #[Security("is_granted('edit', project)")] + #[IsGranted('edit', 'project')] #[OA\Response(response: 200, description: 'Returns a collection of project rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ProjectRate')))] #[OA\Parameter(name: 'id', in: 'path', description: 'The project whose rates will be returned', required: true)] #[Rest\Get(path: '/{id}/rates', name: 'get_project_rates', requirements: ['id' => '\d+'])] @@ -301,15 +301,14 @@ final class ProjectController extends BaseApiController /** * Deletes one rate for a project */ - #[Security("is_granted('edit', project)")] + #[IsGranted('edit', 'project')] #[OA\Delete(responses: [new OA\Response(response: 204, description: 'Returns no content: 204 on successful delete')])] #[OA\Parameter(name: 'id', in: 'path', description: 'The project whose rate will be removed', required: true)] #[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] #[Rest\Delete(path: '/{id}/rates/{rateId}', name: 'delete_project_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])] - #[Entity('rate', expr: 'repository.find(rateId)')] - public function deleteRateAction(Project $project, ProjectRate $rate): Response + public function deleteRateAction(Project $project, #[MapEntity(mapping: ['rateId' => 'id'])] ProjectRate $rate): Response { if ($rate->getProject() !== $project) { throw $this->createNotFoundException(); @@ -325,7 +324,7 @@ final class ProjectController extends BaseApiController /** * Adds a new rate to a project */ - #[Security("is_granted('edit', project)")] + #[IsGranted('edit', 'project')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/ProjectRate'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The project to add the rate for', required: true)] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectRateForm'))] diff --git a/src/API/Serializer/ValidationFailedExceptionErrorHandler.php b/src/API/Serializer/ValidationFailedExceptionErrorHandler.php index 6c9f25e3..8a66c15a 100644 --- a/src/API/Serializer/ValidationFailedExceptionErrorHandler.php +++ b/src/API/Serializer/ValidationFailedExceptionErrorHandler.php @@ -16,8 +16,8 @@ use JMS\Serializer\Context; use JMS\Serializer\GraphNavigatorInterface; use JMS\Serializer\Handler\SubscribingHandlerInterface; use JMS\Serializer\JsonSerializationVisitor; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\ErrorHandler\Exception\FlattenException; -use Symfony\Component\Security\Core\Security; use Symfony\Component\Validator\ConstraintViolationInterface; use Symfony\Contracts\Translation\TranslatorInterface; diff --git a/src/API/StatusController.php b/src/API/StatusController.php index 85984252..fcf5914e 100644 --- a/src/API/StatusController.php +++ b/src/API/StatusController.php @@ -18,10 +18,10 @@ use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Model; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Http\Attribute\IsGranted; -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'Default')] final class StatusController extends BaseApiController { diff --git a/src/API/TagController.php b/src/API/TagController.php index 1b3a1f8e..4769941e 100644 --- a/src/API/TagController.php +++ b/src/API/TagController.php @@ -18,13 +18,13 @@ use FOS\RestBundle\View\View; use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/tags')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'Tag')] final class TagController extends BaseApiController { @@ -94,7 +94,7 @@ final class TagController extends BaseApiController /** * Delete a tag */ - #[Security("is_granted('delete_tag')")] + #[IsGranted('delete_tag')] #[OA\Delete(responses: [new OA\Response(response: 204, description: 'HTTP code 204 for a successful delete')])] #[OA\Parameter(name: 'id', in: 'path', description: 'Tag ID to delete', required: true)] #[ApiSecurity(name: 'apiUser')] diff --git a/src/API/TeamController.php b/src/API/TeamController.php index f57a1813..f504108b 100644 --- a/src/API/TeamController.php +++ b/src/API/TeamController.php @@ -21,15 +21,15 @@ use FOS\RestBundle\View\View; use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/teams')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'Team')] final class TeamController extends BaseApiController { @@ -44,7 +44,7 @@ final class TeamController extends BaseApiController /** * Fetch all existing teams (which are visible to the user) */ - #[Security("is_granted('view_team')")] + #[IsGranted('view_team')] #[OA\Response(response: 200, description: 'Returns the collection of teams', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TeamCollection')))] #[Rest\Get(path: '', name: 'get_teams')] #[ApiSecurity(name: 'apiUser')] @@ -62,7 +62,7 @@ final class TeamController extends BaseApiController /** * Returns one team */ - #[Security("is_granted('view_team')")] + #[IsGranted('view_team')] #[OA\Response(response: 200, description: 'Returns one team entity', content: new OA\JsonContent(ref: '#/components/schemas/Team'))] #[Rest\Get(path: '/{id}', name: 'get_team', requirements: ['id' => '\d+'])] #[ApiSecurity(name: 'apiUser')] @@ -78,7 +78,7 @@ final class TeamController extends BaseApiController /** * Delete a team */ - #[Security("is_granted('delete_team')")] + #[IsGranted('delete_team')] #[OA\Delete(responses: [new OA\Response(response: 204, description: 'Delete one team')])] #[OA\Parameter(name: 'id', in: 'path', description: 'Team ID to delete', required: true)] #[ApiSecurity(name: 'apiUser')] @@ -96,7 +96,7 @@ final class TeamController extends BaseApiController /** * Creates a new team */ - #[Security("is_granted('create_team')")] + #[IsGranted('create_team')] #[OA\Post(description: 'Creates a new team and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created team', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TeamEditForm'))] #[Rest\Post(path: '', name: 'post_team')] @@ -127,7 +127,7 @@ final class TeamController extends BaseApiController /** * Update an existing team */ - #[Security("is_granted('edit_team')")] + #[IsGranted('edit_team')] #[OA\Patch(description: 'Update an existing team, you can pass all or just a subset of all attributes (passing members will replace all existing ones)', responses: [new OA\Response(response: 200, description: 'Returns the updated team', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TeamEditForm'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Team ID to update', required: true)] @@ -167,15 +167,14 @@ final class TeamController extends BaseApiController /** * Add a new member to a team */ - #[Security("is_granted('edit_team')")] + #[IsGranted('edit_team')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new user to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team which will receive the new member', required: true)] #[OA\Parameter(name: 'userId', in: 'path', description: 'The team member to add (User ID)', required: true)] #[Rest\Post(path: '/{id}/members/{userId}', name: 'post_team_member', requirements: ['id' => '\d+', 'userId' => '\d+'])] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] - #[Entity('member', expr: 'repository.find(userId)')] - public function postMemberAction(Team $team, User $member): Response + public function postMemberAction(Team $team, #[MapEntity(mapping: ['userId' => 'id'])] User $member): Response { if ($member->isInTeam($team)) { throw new BadRequestHttpException('User is already member of the team'); @@ -194,15 +193,14 @@ final class TeamController extends BaseApiController /** * Removes a member from the team */ - #[Security("is_granted('edit_team')")] + #[IsGranted('edit_team')] #[OA\Delete(responses: [new OA\Response(response: 200, description: 'Removes a user from the team. The teamlead cannot be removed.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team from which the member will be removed', required: true)] #[OA\Parameter(name: 'userId', in: 'path', description: 'The team member to remove (User ID)', required: true)] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] #[Rest\Delete(path: '/{id}/members/{userId}', name: 'delete_team_member', requirements: ['id' => '\d+', 'userId' => '\d+'])] - #[Entity('member', expr: 'repository.find(userId)')] - public function deleteMemberAction(Team $team, User $member): Response + public function deleteMemberAction(Team $team, #[MapEntity(mapping: ['userId' => 'id'])] User $member): Response { if (!$member->isInTeam($team)) { throw new BadRequestHttpException('User is not a member of the team'); @@ -225,15 +223,14 @@ final class TeamController extends BaseApiController /** * Grant the team access to a customer */ - #[Security("is_granted('edit_team')")] + #[IsGranted('edit_team')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new customer to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)] #[OA\Parameter(name: 'customerId', in: 'path', description: 'The customer to grant acecess to (Customer ID)', required: true)] #[Rest\Post(path: '/{id}/customers/{customerId}', name: 'post_team_customer', requirements: ['id' => '\d+', 'customerId' => '\d+'])] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] - #[Entity('customer', expr: 'repository.find(customerId)')] - public function postCustomerAction(Team $team, Customer $customer): Response + public function postCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer): Response { if ($team->hasCustomer($customer)) { throw new BadRequestHttpException('Team has already access to customer'); @@ -252,15 +249,14 @@ final class TeamController extends BaseApiController /** * Revokes access for a customer from a team */ - #[Security("is_granted('edit_team')")] + #[IsGranted('edit_team')] #[OA\Delete(responses: [new OA\Response(response: 200, description: 'Removes a customer from the team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team whose permission will be revoked', required: true)] #[OA\Parameter(name: 'customerId', in: 'path', description: 'The customer to remove (Customer ID)', required: true)] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] #[Rest\Delete(path: '/{id}/customers/{customerId}', name: 'delete_team_customer', requirements: ['id' => '\d+', 'customerId' => '\d+'])] - #[Entity('customer', expr: 'repository.find(customerId)')] - public function deleteCustomerAction(Team $team, Customer $customer): Response + public function deleteCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer): Response { if (!$team->hasCustomer($customer)) { throw new BadRequestHttpException('Customer is not assigned to the team'); @@ -279,15 +275,14 @@ final class TeamController extends BaseApiController /** * Grant the team access to a project */ - #[Security("is_granted('edit_team')")] + #[IsGranted('edit_team')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new project to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)] #[OA\Parameter(name: 'projectId', in: 'path', description: 'The project to grant acecess to (Project ID)', required: true)] #[Rest\Post(path: '/{id}/projects/{projectId}', name: 'post_team_project', requirements: ['id' => '\d+', 'projectId' => '\d+'])] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] - #[Entity('project', expr: 'repository.find(projectId)')] - public function postProjectAction(Team $team, Project $project): Response + public function postProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project): Response { if ($team->hasProject($project)) { throw new BadRequestHttpException('Team has already access to project'); @@ -306,15 +301,14 @@ final class TeamController extends BaseApiController /** * Revokes access for a project from a team */ - #[Security("is_granted('edit_team')")] + #[IsGranted('edit_team')] #[OA\Delete(responses: [new OA\Response(response: 200, description: 'Removes a project from the team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team whose permission will be revoked', required: true)] #[OA\Parameter(name: 'projectId', in: 'path', description: 'The project to remove (Project ID)', required: true)] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] #[Rest\Delete(path: '/{id}/projects/{projectId}', name: 'delete_team_project', requirements: ['id' => '\d+', 'projectId' => '\d+'])] - #[Entity('project', expr: 'repository.find(projectId)')] - public function deleteProjectAction(Team $team, Project $project): Response + public function deleteProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project): Response { if (!$team->hasProject($project)) { throw new BadRequestHttpException('Project is not assigned to the team'); @@ -333,15 +327,14 @@ final class TeamController extends BaseApiController /** * Grant the team access to an activity */ - #[Security("is_granted('edit_team')")] + #[IsGranted('edit_team')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new activity to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)] #[OA\Parameter(name: 'activityId', in: 'path', description: 'The activity to grant acecess to (Activity ID)', required: true)] #[Rest\Post(path: '/{id}/activities/{activityId}', name: 'post_team_activity', requirements: ['id' => '\d+', 'activityId' => '\d+'])] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] - #[Entity('activity', expr: 'repository.find(activityId)')] - public function postActivityAction(Team $team, Activity $activity): Response + public function postActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity): Response { if ($team->hasActivity($activity)) { throw new BadRequestHttpException('Team has already access to activity'); @@ -360,15 +353,14 @@ final class TeamController extends BaseApiController /** * Revokes access for an activity from a team */ - #[Security("is_granted('edit_team')")] + #[IsGranted('edit_team')] #[OA\Delete(responses: [new OA\Response(response: 200, description: 'Removes a activity from the team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team whose permission will be revoked', required: true)] #[OA\Parameter(name: 'activityId', in: 'path', description: 'The activity to remove (Activity ID)', required: true)] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] #[Rest\Delete(path: '/{id}/activities/{activityId}', name: 'delete_team_activity', requirements: ['id' => '\d+', 'activityId' => '\d+'])] - #[Entity('activity', expr: 'repository.find(activityId)')] - public function deleteActivityAction(Team $team, Activity $activity): Response + public function deleteActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity): Response { if (!$team->hasActivity($activity)) { throw new BadRequestHttpException('Activity is not assigned to the team'); diff --git a/src/API/TimesheetController.php b/src/API/TimesheetController.php index 4a00d1ea..a8aebba5 100644 --- a/src/API/TimesheetController.php +++ b/src/API/TimesheetController.php @@ -33,16 +33,17 @@ use FOS\RestBundle\View\View; use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Form\FormError; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\Validator\Constraints; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; #[Route(path: '/timesheets')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'Timesheet')] final class TimesheetController extends BaseApiController { @@ -69,7 +70,7 @@ final class TimesheetController extends BaseApiController /** * Returns a collection of timesheet records (which are visible to the user) */ - #[Security("is_granted('view_own_timesheet') or is_granted('view_other_timesheet')")] + #[IsGranted(new Expression("is_granted('view_own_timesheet') or is_granted('view_other_timesheet')"))] #[OA\Response(response: 200, description: 'Returns a collection of timesheet records. The datetime fields are given in the users local time including the timezone offset (ISO-8601).', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TimesheetCollection')))] #[Rest\Get(path: '', name: 'get_timesheets')] #[ApiSecurity(name: 'apiUser')] @@ -256,7 +257,7 @@ final class TimesheetController extends BaseApiController /** * Returns one timesheet record */ - #[Security("is_granted('view', timesheet)")] + #[IsGranted('view', 'timesheet')] #[OA\Response(response: 200, description: 'Returns one timesheet record. Be aware that the datetime fields are given in the users local time including the timezone offset via ISO 8601.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to fetch', required: true)] #[Rest\Get(path: '/{id}', name: 'get_timesheet', requirements: ['id' => '\d+'])] @@ -273,7 +274,7 @@ final class TimesheetController extends BaseApiController /** * Creates a new timesheet record */ - #[Security("is_granted('create_own_timesheet')")] + #[IsGranted('create_own_timesheet')] #[OA\Post(description: 'Creates a new timesheet record for the current user and returns it afterwards.', responses: [new OA\Response(response: 200, description: 'Returns the new created timesheet', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEditForm'))] #[Rest\Post(path: '', name: 'post_timesheet')] @@ -328,7 +329,7 @@ final class TimesheetController extends BaseApiController /** * Update an existing timesheet record */ - #[Security("is_granted('edit', timesheet)")] + #[IsGranted('edit', 'timesheet')] #[OA\Patch(description: 'Update an existing timesheet record, you can pass all or just a subset of the attributes.', responses: [new OA\Response(response: 200, description: 'Returns the updated timesheet', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to update', required: true)] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEditForm'))] @@ -373,7 +374,7 @@ final class TimesheetController extends BaseApiController /** * Delete an existing timesheet record */ - #[Security("is_granted('delete', timesheet)")] + #[IsGranted('delete', 'timesheet')] #[OA\Delete(responses: [new OA\Response(response: 204, description: 'Delete one timesheet record')])] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to delete', required: true)] #[ApiSecurity(name: 'apiUser')] @@ -391,7 +392,7 @@ final class TimesheetController extends BaseApiController /** * Returns the collection of recent user activities */ - #[Security("is_granted('view_own_timesheet')")] + #[IsGranted('view_own_timesheet')] #[OA\Response(response: 200, description: 'Returns the collection of recent user activities (always the latest entry of a unique working set grouped by customer, project and activity)', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TimesheetCollectionExpanded')))] #[Rest\Get(path: '/recent', name: 'recent_timesheet')] #[ApiSecurity(name: 'apiUser')] @@ -427,7 +428,7 @@ final class TimesheetController extends BaseApiController /** * Returns the collection of active timesheet records */ - #[Security("is_granted('view_own_timesheet')")] + #[IsGranted('view_own_timesheet')] #[OA\Response(response: 200, description: 'Returns the collection of active timesheet records for the current user', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TimesheetCollectionExpanded')))] #[Rest\Get(path: '/active', name: 'active_timesheet')] #[ApiSecurity(name: 'apiUser')] @@ -448,7 +449,7 @@ final class TimesheetController extends BaseApiController /** * Stops an active timesheet record */ - #[Security("is_granted('stop', timesheet)")] + #[IsGranted('stop', 'timesheet')] #[OA\Response(response: 200, description: 'Stops an active timesheet record and returns it afterwards.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to stop', required: true)] #[Rest\Patch(path: '/{id}/stop', name: 'stop_timesheet', requirements: ['id' => '\d+'])] @@ -467,7 +468,7 @@ final class TimesheetController extends BaseApiController /** * Restarts a previously stopped timesheet record for the current user */ - #[Security("is_granted('start', timesheet)")] + #[IsGranted('start', 'timesheet')] #[OA\Response(response: 200, description: 'Restarts a timesheet record for the same customer, project, activity combination. The current user will be the owner of the new record. Kimai tries to stop running records, which is expected to fail depending on the configured rules. Data will be copied from the original record if requested.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to restart', required: true)] #[Rest\Patch(path: '/{id}/restart', name: 'restart_timesheet', requirements: ['id' => '\d+'])] @@ -529,7 +530,7 @@ final class TimesheetController extends BaseApiController /** * Duplicates an existing timesheet record */ - #[Security("is_granted('duplicate', timesheet)")] + #[IsGranted('duplicate', 'timesheet')] #[OA\Response(response: 200, description: 'Duplicates a timesheet record, resetting the export state only.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to duplicate', required: true)] #[Rest\Patch(path: '/{id}/duplicate', name: 'duplicate_timesheet', requirements: ['id' => '\d+'])] @@ -552,7 +553,7 @@ final class TimesheetController extends BaseApiController /** * Switch the export state of a timesheet record to (un-)lock it */ - #[Security("is_granted('edit_export', timesheet)")] + #[IsGranted('edit_export', 'timesheet')] #[OA\Response(response: 200, description: 'Switches the exported state on the record and therefor locks / unlocks it for further updates. Needs edit_export_*_timesheet permission.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to switch export state', required: true)] #[Rest\Patch(path: '/{id}/export', name: 'export_timesheet', requirements: ['id' => '\d+'])] @@ -577,7 +578,7 @@ final class TimesheetController extends BaseApiController /** * Sets the value of a meta-field for an existing timesheet. */ - #[Security("is_granted('edit', timesheet)")] + #[IsGranted('edit', 'timesheet')] #[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to set the meta-field value for', required: true)] #[Rest\Patch(path: '/{id}/meta', requirements: ['id' => '\d+'])] diff --git a/src/API/UserController.php b/src/API/UserController.php index a6c30f16..6624114b 100644 --- a/src/API/UserController.php +++ b/src/API/UserController.php @@ -23,16 +23,16 @@ use FOS\RestBundle\View\View; use FOS\RestBundle\View\ViewHandlerInterface; use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity; use OpenApi\Attributes as OA; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/users')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] #[OA\Tag(name: 'User')] final class UserController extends BaseApiController { @@ -51,7 +51,7 @@ final class UserController extends BaseApiController /** * Returns the collection of users (which are visible to the user) */ - #[Security("is_granted('view_user')")] + #[IsGranted('view_user')] #[OA\Response(response: 200, description: 'Returns the collection of users. Required permission: view_user', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/UserCollection')))] #[Rest\Get(path: '', name: 'get_users')] #[ApiSecurity(name: 'apiUser')] @@ -95,7 +95,7 @@ final class UserController extends BaseApiController /** * Return one user entity */ - #[Security("is_granted('view', profile)")] + #[IsGranted('view', 'profile')] #[OA\Response(response: 200, description: 'Return one user entity.', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'User ID to fetch', required: true)] #[Rest\Get(path: '/{id}', name: 'get_user', requirements: ['id' => '\d+'])] @@ -131,7 +131,7 @@ final class UserController extends BaseApiController /** * Creates a new user */ - #[Security("is_granted('create_user')")] + #[IsGranted('create_user')] #[OA\Post(description: 'Creates a new user and returns it afterwards')] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/UserCreateForm'))] #[Rest\Post(path: '', name: 'post_user')] @@ -184,7 +184,7 @@ final class UserController extends BaseApiController /** * Update an existing user */ - #[Security("is_granted('edit', profile)")] + #[IsGranted('edit', 'profile')] #[OA\Patch(description: 'Update an existing user, you can pass all or just a subset of all attributes (passing roles will replace all existing ones)', responses: [new OA\Response(response: 200, description: 'Returns the updated user', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/UserEditForm'))] #[OA\Parameter(name: 'id', in: 'path', description: 'User ID to update', required: true)] diff --git a/src/Controller/ActivityController.php b/src/Controller/ActivityController.php index 0a79ef9b..ed2de258 100644 --- a/src/Controller/ActivityController.php +++ b/src/Controller/ActivityController.php @@ -35,18 +35,19 @@ use App\Repository\TeamRepository; use App\Utils\DataTable; use App\Utils\PageSetup; use Exception; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Controller used to manage activities. */ #[Route(path: '/admin/activity')] -#[Security("is_granted('view_activity') or is_granted('view_teamlead_activity') or is_granted('view_team_activity')")] +#[IsGranted(new Expression("is_granted('view_activity') or is_granted('view_teamlead_activity') or is_granted('view_team_activity')"))] final class ActivityController extends AbstractController { public function __construct(private ActivityRepository $repository, private SystemConfiguration $configuration, private EventDispatcherInterface $dispatcher, private ActivityService $activityService) @@ -122,7 +123,7 @@ final class ActivityController extends AbstractController } #[Route(path: '/{id}/details', name: 'activity_details', methods: ['GET', 'POST'])] - #[Security("is_granted('view', activity)")] + #[IsGranted('view', 'activity')] public function detailsAction(Activity $activity, TeamRepository $teamRepository, ActivityRateRepository $rateRepository, ActivityStatisticService $statisticService) { $event = new ActivityMetaDefinitionEvent($activity); @@ -172,14 +173,14 @@ final class ActivityController extends AbstractController } #[Route(path: '/{id}/rate/{rate}', name: 'admin_activity_rate_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', activity)")] + #[IsGranted('edit', 'activity')] public function editRateAction(Activity $activity, ActivityRate $rate, Request $request, ActivityRateRepository $repository): Response { return $this->rateFormAction($activity, $rate, $request, $repository, $this->generateUrl('admin_activity_rate_edit', ['id' => $activity->getId(), 'rate' => $rate->getId()])); } #[Route(path: '/{id}/rate', name: 'admin_activity_rate_add', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', activity)")] + #[IsGranted('edit', 'activity')] public function addRateAction(Activity $activity, Request $request, ActivityRateRepository $repository): Response { $rate = new ActivityRate(); @@ -216,14 +217,14 @@ final class ActivityController extends AbstractController } #[Route(path: '/create/{project}', name: 'admin_activity_create_with_project', methods: ['GET', 'POST'])] - #[Security("is_granted('create_activity')")] + #[IsGranted('create_activity')] public function createWithProjectAction(Request $request, Project $project): Response { return $this->createActivity($request, $project); } #[Route(path: '/create', name: 'admin_activity_create', methods: ['GET', 'POST'])] - #[Security("is_granted('create_activity')")] + #[IsGranted('create_activity')] public function createAction(Request $request): Response { return $this->createActivity($request, null); @@ -258,7 +259,7 @@ final class ActivityController extends AbstractController } #[Route(path: '/{id}/permissions', name: 'admin_activity_permissions', methods: ['GET', 'POST'])] - #[Security("is_granted('permissions', activity)")] + #[IsGranted('permissions', 'activity')] public function teamPermissionsAction(Activity $activity, Request $request): Response { $form = $this->createForm(ActivityTeamPermissionForm::class, $activity, [ @@ -291,7 +292,8 @@ final class ActivityController extends AbstractController } #[Route(path: '/{id}/create_team', name: 'activity_team_create', methods: ['GET'])] - #[Security("is_granted('create_team') and is_granted('permissions', activity)")] + #[IsGranted('create_team')] + #[IsGranted('permissions', 'activity')] public function createDefaultTeamAction(Activity $activity, TeamRepository $teamRepository): Response { $defaultTeam = $teamRepository->findOneBy(['name' => $activity->getName()]); @@ -315,7 +317,7 @@ final class ActivityController extends AbstractController } #[Route(path: '/{id}/edit', name: 'admin_activity_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', activity)")] + #[IsGranted('edit', 'activity')] public function editAction(Activity $activity, Request $request): Response { $event = new ActivityMetaDefinitionEvent($activity); @@ -343,7 +345,7 @@ final class ActivityController extends AbstractController } #[Route(path: '/{id}/delete', name: 'admin_activity_delete', methods: ['GET', 'POST'])] - #[Security("is_granted('delete', activity)")] + #[IsGranted('delete', 'activity')] public function deleteAction(Activity $activity, Request $request, ActivityStatisticService $statisticService): Response { $stats = $statisticService->getActivityStatistics($activity); diff --git a/src/Controller/Auth/SamlController.php b/src/Controller/Auth/SamlController.php index 4dd18978..b8f14eaf 100644 --- a/src/Controller/Auth/SamlController.php +++ b/src/Controller/Auth/SamlController.php @@ -12,10 +12,10 @@ namespace App\Controller\Auth; use App\Configuration\SamlConfigurationInterface; use App\Saml\SamlAuthFactory; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Security\Core\Security; #[Route(path: '/saml')] final class SamlController extends AbstractController diff --git a/src/Controller/CalendarController.php b/src/Controller/CalendarController.php index ed3804c2..381ec686 100644 --- a/src/Controller/CalendarController.php +++ b/src/Controller/CalendarController.php @@ -15,16 +15,16 @@ use App\Entity\User; use App\Form\CalendarForm; use App\Timesheet\TrackingModeService; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Controller used to display calendars. */ #[Route(path: '/calendar')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] final class CalendarController extends AbstractController { public function __construct(private CalendarService $calendarService, private SystemConfiguration $configuration, private TrackingModeService $service) diff --git a/src/Controller/CustomerController.php b/src/Controller/CustomerController.php index 1b1e9c78..3071be44 100644 --- a/src/Controller/CustomerController.php +++ b/src/Controller/CustomerController.php @@ -38,8 +38,8 @@ use App\Utils\DataTable; use App\Utils\FileHelper; use App\Utils\PageSetup; use JeroenDesloovere\VCard\VCard; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -48,12 +48,13 @@ use Symfony\Component\Intl\Countries; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Controller used to manage customer in the admin part of the site. */ #[Route(path: '/admin/customer')] -#[Security("is_granted('view_customer') or is_granted('view_teamlead_customer') or is_granted('view_team_customer')")] +#[IsGranted(new Expression("is_granted('view_customer') or is_granted('view_teamlead_customer') or is_granted('view_team_customer')"))] final class CustomerController extends AbstractController { public function __construct(private CustomerRepository $repository, private EventDispatcherInterface $dispatcher) @@ -139,7 +140,7 @@ final class CustomerController extends AbstractController } #[Route(path: '/create', name: 'admin_customer_create', methods: ['GET', 'POST'])] - #[Security("is_granted('create_customer')")] + #[IsGranted('create_customer')] public function createAction(Request $request, CustomerService $customerService) { $customer = $customerService->createNewCustomer(''); @@ -148,7 +149,7 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/permissions', name: 'admin_customer_permissions', methods: ['GET', 'POST'])] - #[Security("is_granted('permissions', customer)")] + #[IsGranted('permissions', 'customer')] public function teamPermissionsAction(Customer $customer, Request $request) { $form = $this->createForm(CustomerTeamPermissionForm::class, $customer, [ @@ -181,7 +182,7 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/comment_delete/{token}', name: 'customer_comment_delete', methods: ['GET'])] - #[Security("is_granted('edit', comment.getCustomer()) and is_granted('comments', comment.getCustomer())")] + #[IsGranted(new Expression("is_granted('edit', subject.getCustomer()) and is_granted('comments', subject.getCustomer())"), 'comment')] public function deleteCommentAction(CustomerComment $comment, string $token, CsrfTokenManagerInterface $csrfTokenManager) { $customerId = $comment->getCustomer()->getId(); @@ -204,7 +205,7 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/comment_add', name: 'customer_comment_add', methods: ['POST'])] - #[Security("is_granted('comments', customer)")] + #[IsGranted('comments', 'customer')] public function addCommentAction(Customer $customer, Request $request) { $comment = new CustomerComment($customer); @@ -224,7 +225,7 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/comment_pin/{token}', name: 'customer_comment_pin', methods: ['GET'])] - #[Security("is_granted('edit', comment.getCustomer()) and is_granted('comments', comment.getCustomer())")] + #[IsGranted(new Expression("is_granted('edit', subject.getCustomer()) and is_granted('comments', subject.getCustomer())"), 'comment')] public function pinCommentAction(CustomerComment $comment, string $token, CsrfTokenManagerInterface $csrfTokenManager) { $customerId = $comment->getCustomer()->getId(); @@ -248,7 +249,8 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/create_team', name: 'customer_team_create', methods: ['GET'])] - #[Security("is_granted('create_team') and is_granted('permissions', customer)")] + #[IsGranted('create_team')] + #[IsGranted('permissions', 'customer')] public function createDefaultTeamAction(Customer $customer, TeamRepository $teamRepository) { $defaultTeam = $teamRepository->findOneBy(['name' => $customer->getName()]); @@ -272,7 +274,7 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/projects/{page}', defaults: ['page' => 1], name: 'customer_projects', methods: ['GET', 'POST'])] - #[Security("is_granted('view', customer)")] + #[IsGranted('view', 'customer')] public function projectsAction(Customer $customer, int $page, ProjectRepository $projectRepository) { $query = new ProjectQuery(); @@ -295,7 +297,7 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/details', name: 'customer_details', methods: ['GET', 'POST'])] - #[Security("is_granted('view', customer)")] + #[IsGranted('view', 'customer')] public function detailsAction(Customer $customer, TeamRepository $teamRepository, CustomerRateRepository $rateRepository, CustomerStatisticService $statisticService) { $event = new CustomerMetaDefinitionEvent($customer); @@ -362,7 +364,7 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/vcard', name: 'customer_vcard', methods: ['GET'])] - #[Security("is_granted('view', customer)")] + #[IsGranted('view', 'customer')] public function downloadVCard(Customer $customer): Response { $vcard = new VCard(); @@ -415,14 +417,14 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/rate/{rate}', name: 'admin_customer_rate_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', customer)")] + #[IsGranted('edit', 'customer')] public function editRateAction(Customer $customer, CustomerRate $rate, Request $request, CustomerRateRepository $repository): Response { return $this->rateFormAction($customer, $rate, $request, $repository, $this->generateUrl('admin_customer_rate_edit', ['id' => $customer->getId(), 'rate' => $rate->getId()])); } #[Route(path: '/{id}/rate', name: 'admin_customer_rate_add', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', customer)")] + #[IsGranted('edit', 'customer')] public function addRateAction(Customer $customer, Request $request, CustomerRateRepository $repository): Response { $rate = new CustomerRate(); @@ -459,14 +461,14 @@ final class CustomerController extends AbstractController } #[Route(path: '/{id}/edit', name: 'admin_customer_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', customer)")] + #[IsGranted('edit', 'customer')] public function editAction(Customer $customer, Request $request) { return $this->renderCustomerForm($customer, $request); } #[Route(path: '/{id}/delete', name: 'admin_customer_delete', methods: ['GET', 'POST'])] - #[Security("is_granted('delete', customer)")] + #[IsGranted('delete', 'customer')] public function deleteAction(Customer $customer, Request $request, CustomerStatisticService $statisticService) { $stats = $statisticService->getCustomerStatistics($customer); diff --git a/src/Controller/DashboardController.php b/src/Controller/DashboardController.php index ddb2421e..4978ebea 100644 --- a/src/Controller/DashboardController.php +++ b/src/Controller/DashboardController.php @@ -16,19 +16,19 @@ use App\Repository\BookmarkRepository; use App\Utils\PageSetup; use App\Widget\WidgetInterface; use App\Widget\WidgetService; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Dashboard controller for the admin area. */ #[Route(path: '/dashboard')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] final class DashboardController extends AbstractController { public const BOOKMARK_TYPE = 'dashboard'; diff --git a/src/Controller/DoctorController.php b/src/Controller/DoctorController.php index 7d4f99e9..6ca6be57 100644 --- a/src/Controller/DoctorController.php +++ b/src/Controller/DoctorController.php @@ -13,16 +13,16 @@ use App\Utils\FileHelper; use App\Utils\PageSetup; use App\Utils\ReleaseVersion; use Composer\InstalledVersions; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; +use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; #[Route(path: '/doctor')] -#[Security("is_granted('system_information')")] +#[IsGranted('system_information')] final class DoctorController extends AbstractController { /** @@ -51,7 +51,7 @@ final class DoctorController extends AbstractController } #[Route(path: '/flush-log/{token}', name: 'doctor_flush_log', methods: ['GET'])] - #[Security("is_granted('system_configuration')")] + #[IsGranted('system_configuration')] public function deleteLogfileAction(string $token, CsrfTokenManagerInterface $csrfTokenManager): Response { if (!$csrfTokenManager->isTokenValid(new CsrfToken('doctor.flush_log', $token))) { diff --git a/src/Controller/ExportController.php b/src/Controller/ExportController.php index ff2eb36f..c6d42ba2 100644 --- a/src/Controller/ExportController.php +++ b/src/Controller/ExportController.php @@ -16,17 +16,17 @@ use App\Export\TooManyItemsExportException; use App\Form\Toolbar\ExportToolbarForm; use App\Repository\Query\ExportQuery; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Controller used to export timesheet data. */ #[Route(path: '/export')] -#[Security("is_granted('create_export')")] +#[IsGranted('create_export')] final class ExportController extends AbstractController { public function __construct(private ServiceExport $export) diff --git a/src/Controller/FavoriteController.php b/src/Controller/FavoriteController.php index 7abc991a..94c88678 100644 --- a/src/Controller/FavoriteController.php +++ b/src/Controller/FavoriteController.php @@ -11,23 +11,23 @@ namespace App\Controller; use App\Entity\Timesheet; use App\Timesheet\FavoriteRecordService; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/favorite')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] final class FavoriteController extends AbstractController { #[Route(path: '/timesheet/', name: 'favorites_timesheets', methods: ['GET'])] - #[Security("is_granted('view_own_timesheet')")] + #[IsGranted('view_own_timesheet')] public function favoriteAction(): Response { return $this->render('partials/recent-activities.html.twig'); } #[Route(path: '/timesheet/add/{id}', name: 'favorites_timesheets_add', methods: ['GET'])] - #[Security("is_granted('view_own_timesheet')")] + #[IsGranted('view_own_timesheet')] public function add(Timesheet $timesheet, FavoriteRecordService $favoriteRecordService): Response { $favoriteRecordService->addFavorite($timesheet); @@ -36,7 +36,7 @@ final class FavoriteController extends AbstractController } #[Route(path: '/timesheet/remove/{id}', name: 'favorites_timesheets_remove', methods: ['GET'])] - #[Security("is_granted('view_own_timesheet')")] + #[IsGranted('view_own_timesheet')] public function remove(Timesheet $timesheet, FavoriteRecordService $favoriteRecordService): Response { $favoriteRecordService->removeFavorite($timesheet); diff --git a/src/Controller/HomepageController.php b/src/Controller/HomepageController.php index ca60efb3..1a6364db 100644 --- a/src/Controller/HomepageController.php +++ b/src/Controller/HomepageController.php @@ -11,16 +11,16 @@ namespace App\Controller; use App\Configuration\LocaleService; use App\Entity\User; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Homepage controller is a redirect controller with user specific logic. */ #[Route(path: '/homepage')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] final class HomepageController extends AbstractController { public const DEFAULT_ROUTE = 'timesheet'; diff --git a/src/Controller/InvoiceController.php b/src/Controller/InvoiceController.php index 2e2de619..4d7f376a 100644 --- a/src/Controller/InvoiceController.php +++ b/src/Controller/InvoiceController.php @@ -37,7 +37,7 @@ use App\Repository\Query\InvoiceQuery; use App\Utils\DataTable; use App\Utils\PageSetup; use Exception; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -46,13 +46,15 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; +use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * Controller used to create invoices and manage invoice templates. */ #[Route(path: '/invoice')] -#[Security("is_granted('IS_AUTHENTICATED_FULLY') and is_granted('view_invoice')")] +#[IsGranted('IS_AUTHENTICATED_FULLY')] +#[IsGranted('view_invoice')] final class InvoiceController extends AbstractController { public function __construct( @@ -64,7 +66,7 @@ final class InvoiceController extends AbstractController } #[Route(path: '/', name: 'invoice', methods: ['GET', 'POST'])] - #[Security("is_granted('create_invoice')")] + #[IsGranted('create_invoice')] public function indexAction(Request $request, CsrfTokenManagerInterface $csrfTokenManager): Response { if (!$this->templateRepository->hasTemplate()) { @@ -127,7 +129,8 @@ final class InvoiceController extends AbstractController } #[Route(path: '/preview/{customer}/{token}', name: 'invoice_preview', methods: ['GET'])] - #[Security("is_granted('access', customer) and is_granted('create_invoice')")] + #[IsGranted('create_invoice')] + #[IsGranted('access', 'customer')] public function previewAction(Customer $customer, string $token, Request $request): Response { if (!$this->templateRepository->hasTemplate()) { @@ -167,7 +170,8 @@ final class InvoiceController extends AbstractController } #[Route(path: '/save-invoice/{customer}/{token}', name: 'invoice_create', methods: ['GET'])] - #[Security("is_granted('access', customer) and is_granted('create_invoice')")] + #[IsGranted('create_invoice')] + #[IsGranted('access', 'customer')] public function createInvoiceAction(Customer $customer, string $token, Request $request, CustomerRepository $customerRepository): Response { if (!$this->templateRepository->hasTemplate()) { @@ -214,7 +218,8 @@ final class InvoiceController extends AbstractController } #[Route(path: '/change-status/{id}/{status}/{token}', name: 'admin_invoice_status', methods: ['GET', 'POST'])] - #[Security("is_granted('access', invoice.getCustomer()) and is_granted('create_invoice')")] + #[IsGranted('create_invoice')] + #[IsGranted(new Expression("is_granted('access', subject.getCustomer())"), 'invoice')] public function changeStatusAction(Invoice $invoice, string $status, string $token, Request $request, CsrfTokenManagerInterface $csrfTokenManager): Response { if (!$csrfTokenManager->isTokenValid(new CsrfToken('invoice.status', $token))) { @@ -250,7 +255,8 @@ final class InvoiceController extends AbstractController } #[Route(path: '/edit/{id}', name: 'admin_invoice_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('access', invoice.getCustomer()) and is_granted('create_invoice')")] + #[IsGranted('create_invoice')] + #[IsGranted(new Expression("is_granted('access', subject.getCustomer())"), 'invoice')] public function editAction(Invoice $invoice, Request $request): Response { $form = $this->createInvoiceEditForm($invoice); @@ -275,7 +281,8 @@ final class InvoiceController extends AbstractController } #[Route(path: '/delete/{id}/{token}', name: 'admin_invoice_delete', methods: ['GET'])] - #[Security("is_granted('access', invoice.getCustomer()) and is_granted('delete_invoice')")] + #[IsGranted('delete_invoice')] + #[IsGranted(new Expression("is_granted('access', subject.getCustomer())"), 'invoice')] public function deleteInvoiceAction(Invoice $invoice, string $token, CsrfTokenManagerInterface $csrfTokenManager): Response { if (!$csrfTokenManager->isTokenValid(new CsrfToken('invoice.status', $token))) { @@ -297,7 +304,8 @@ final class InvoiceController extends AbstractController } #[Route(path: '/download/{id}', name: 'admin_invoice_download', methods: ['GET'])] - #[Security("is_granted('access', invoice.getCustomer()) and is_granted('view_invoice')")] + #[IsGranted('view_invoice')] + #[IsGranted(new Expression("is_granted('access', subject.getCustomer())"), 'invoice')] public function downloadAction(Invoice $invoice): Response { $file = $this->service->getInvoiceFile($invoice); @@ -312,7 +320,7 @@ final class InvoiceController extends AbstractController } #[Route(path: '/show/{page}', defaults: ['page' => 1], requirements: ['page' => '[1-9]\d*'], name: 'admin_invoice_list', methods: ['GET'])] - #[Security("is_granted('view_invoice')")] + #[IsGranted('view_invoice')] public function showInvoicesAction(Request $request, int $page): Response { $invoice = null; @@ -371,7 +379,7 @@ final class InvoiceController extends AbstractController } #[Route(path: '/export', name: 'invoice_export', methods: ['GET'])] - #[Security("is_granted('view_invoice')")] + #[IsGranted('view_invoice')] public function exportAction(Request $request, EntityWithMetaFieldsExporter $exporter) { $query = new InvoiceArchiveQuery(); @@ -394,7 +402,7 @@ final class InvoiceController extends AbstractController } #[Route(path: '/template/{page}', requirements: ['page' => '[1-9]\d*'], defaults: ['page' => 1], name: 'admin_invoice_template', methods: ['GET', 'POST'])] - #[Security("is_granted('manage_invoice_template')")] + #[IsGranted('manage_invoice_template')] public function listTemplateAction(int $page): Response { $query = new BaseQuery(); @@ -431,14 +439,14 @@ final class InvoiceController extends AbstractController } #[Route(path: '/template/{id}/edit', name: 'admin_invoice_template_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('manage_invoice_template')")] + #[IsGranted('manage_invoice_template')] public function editTemplateAction(InvoiceTemplate $template, Request $request): Response { return $this->renderTemplateForm($template, $request); } #[Route(path: '/document_upload', name: 'admin_invoice_document_upload', methods: ['GET', 'POST'])] - #[Security("is_granted('upload_invoice_template')")] + #[IsGranted('upload_invoice_template')] public function uploadDocumentAction(Request $request, string $projectDirectory, InvoiceDocumentRepository $documentRepository) { $dir = $documentRepository->getUploadDirectory(); @@ -538,7 +546,7 @@ final class InvoiceController extends AbstractController } #[Route(path: '/document/{id}/delete/{token}', name: 'invoice_document_delete', methods: ['GET', 'POST'])] - #[Security("is_granted('manage_invoice_template')")] + #[IsGranted('manage_invoice_template')] public function deleteDocument(string $id, string $token, CsrfTokenManagerInterface $csrfTokenManager, InvoiceDocumentRepository $documentRepository): Response { $document = $documentRepository->findByName($id); @@ -581,14 +589,14 @@ final class InvoiceController extends AbstractController } #[Route(path: '/template/create/{id}', name: 'admin_invoice_template_copy', methods: ['GET', 'POST'])] - #[Security("is_granted('manage_invoice_template')")] + #[IsGranted('manage_invoice_template')] public function copyTemplateAction(Request $request, InvoiceTemplate $copyFrom): Response { return $this->createTemplate($request, $copyFrom); } #[Route(path: '/template/create', name: 'admin_invoice_template_create', methods: ['GET', 'POST'])] - #[Security("is_granted('manage_invoice_template')")] + #[IsGranted('manage_invoice_template')] public function createTemplateAction(Request $request): Response { return $this->createTemplate($request, null); @@ -608,7 +616,7 @@ final class InvoiceController extends AbstractController } #[Route(path: '/template/{id}/delete/{csrfToken}', name: 'admin_invoice_template_delete', methods: ['GET', 'POST'])] - #[Security("is_granted('manage_invoice_template')")] + #[IsGranted('manage_invoice_template')] public function deleteTemplate(InvoiceTemplate $template, string $csrfToken, CsrfTokenManagerInterface $csrfTokenManager): Response { if (!$csrfTokenManager->isTokenValid(new CsrfToken('invoice.delete_template', $csrfToken))) { diff --git a/src/Controller/PermissionController.php b/src/Controller/PermissionController.php index e0f07430..fe300314 100644 --- a/src/Controller/PermissionController.php +++ b/src/Controller/PermissionController.php @@ -22,19 +22,20 @@ use App\Repository\UserRepository; use App\Security\RolePermissionManager; use App\Security\RoleService; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Controller used to manage user roles and role permissions. */ #[Route(path: '/admin/permissions')] -#[Security("is_granted('IS_AUTHENTICATED_FULLY') and is_granted('role_permissions')")] +#[IsGranted('IS_AUTHENTICATED_FULLY')] +#[IsGranted('role_permissions')] final class PermissionController extends AbstractController { public const TOKEN_NAME = 'user_role_permissions'; @@ -44,7 +45,7 @@ final class PermissionController extends AbstractController } #[Route(path: '', name: 'admin_user_permissions', methods: ['GET', 'POST'])] - #[Security("is_granted('role_permissions')")] + #[IsGranted('role_permissions')] public function permissions(EventDispatcherInterface $dispatcher, CsrfTokenManagerInterface $csrfTokenManager, RoleService $roleService) { $all = $this->roleRepository->findAll(); @@ -161,7 +162,7 @@ final class PermissionController extends AbstractController } #[Route(path: '/roles/create', name: 'admin_user_roles', methods: ['GET', 'POST'])] - #[Security("is_granted('role_permissions')")] + #[IsGranted('role_permissions')] public function createRole(Request $request): Response { $role = new Role(); @@ -195,7 +196,7 @@ final class PermissionController extends AbstractController } #[Route(path: '/roles/{id}/delete/{csrfToken}', name: 'admin_user_role_delete', methods: ['GET', 'POST'])] - #[Security("is_granted('role_permissions')")] + #[IsGranted('role_permissions')] public function deleteRole(Role $role, string $csrfToken, UserRepository $userRepository, CsrfTokenManagerInterface $csrfTokenManager): Response { if (!$this->isCsrfTokenValid(self::TOKEN_NAME, $csrfToken)) { @@ -225,7 +226,7 @@ final class PermissionController extends AbstractController } #[Route(path: '/roles/{id}/{name}/{value}/{csrfToken}', name: 'admin_user_permission_save', methods: ['POST'])] - #[Security("is_granted('role_permissions')")] + #[IsGranted('role_permissions')] public function savePermission(Role $role, string $name, bool $value, string $csrfToken, RolePermissionRepository $rolePermissionRepository, CsrfTokenManagerInterface $csrfTokenManager): Response { if (!$this->isCsrfTokenValid(self::TOKEN_NAME, $csrfToken)) { diff --git a/src/Controller/PluginController.php b/src/Controller/PluginController.php index 89536899..8725ccf7 100644 --- a/src/Controller/PluginController.php +++ b/src/Controller/PluginController.php @@ -11,15 +11,15 @@ namespace App\Controller; use App\Plugin\PluginManager; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; #[Route(path: '/admin/plugins')] -#[Security("is_granted('plugins')")] +#[IsGranted('plugins')] final class PluginController extends AbstractController { #[Route(path: '/', name: 'plugins', methods: ['GET'])] diff --git a/src/Controller/ProfileController.php b/src/Controller/ProfileController.php index 2e20b644..1625680d 100644 --- a/src/Controller/ProfileController.php +++ b/src/Controller/ProfileController.php @@ -32,18 +32,19 @@ use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelHigh; use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeMargin; use Endroid\QrCode\Writer\PngWriter; use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Totp\TotpAuthenticatorInterface; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * User profile controller */ #[Route(path: '/profile')] -#[Security("(is_granted('view_own_profile') or is_granted('view_other_profile'))")] +#[IsGranted(new Expression("is_granted('view_own_profile') or is_granted('view_other_profile')"))] final class ProfileController extends AbstractController { #[Route(path: '/', name: 'my_profile', methods: ['GET'])] @@ -53,7 +54,7 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}', name: 'user_profile', methods: ['GET'])] - #[Security("is_granted('view', profile)")] + #[IsGranted('view', 'profile')] public function indexAction(User $profile, TimesheetRepository $repository, TimesheetStatisticService $statisticService): Response { $dateFactory = $this->getDateTimeFactory(); @@ -79,7 +80,7 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}/edit', name: 'user_profile_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', profile)")] + #[IsGranted('edit', 'profile')] public function editAction(User $profile, Request $request, UserRepository $userRepository): Response { $form = $this->createEditForm($profile); @@ -101,7 +102,8 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}/password', name: 'user_profile_password', methods: ['GET', 'POST'])] - #[Security("is_granted('IS_AUTHENTICATED_FULLY') and is_granted('password', profile)")] + #[IsGranted('IS_AUTHENTICATED_FULLY')] + #[IsGranted('password', 'profile')] public function passwordAction(User $profile, Request $request, UserService $userService): Response { $form = $this->createPasswordForm($profile); @@ -123,7 +125,8 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}/api-token', name: 'user_profile_api_token', methods: ['GET', 'POST'])] - #[Security("is_granted('IS_AUTHENTICATED_FULLY') and is_granted('api-token', profile)")] + #[IsGranted('IS_AUTHENTICATED_FULLY')] + #[IsGranted('api-token', 'profile')] public function apiTokenAction(User $profile, Request $request, UserService $userService): Response { $form = $this->createApiTokenForm($profile); @@ -145,7 +148,8 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}/roles', name: 'user_profile_roles', methods: ['GET', 'POST'])] - #[Security("is_granted('IS_AUTHENTICATED_FULLY') and is_granted('roles', profile)")] + #[IsGranted('IS_AUTHENTICATED_FULLY')] + #[IsGranted('roles', 'profile')] public function rolesAction(User $profile, Request $request, UserRepository $userRepository): Response { $isSuperAdmin = $profile->isSuperAdmin(); @@ -175,7 +179,7 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}/teams', name: 'user_profile_teams', methods: ['GET', 'POST'])] - #[Security("is_granted('teams', profile)")] + #[IsGranted('teams', 'profile')] public function teamsAction(User $profile, Request $request, UserRepository $userRepository, TeamRepository $teamRepository): Response { $originalMembers = new ArrayCollection(); @@ -210,7 +214,7 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}/prefs', name: 'user_profile_preferences', methods: ['GET', 'POST'])] - #[Security("is_granted('preferences', profile)")] + #[IsGranted('preferences', 'profile')] public function preferencesAction(User $profile, Request $request, EventDispatcherInterface $dispatcher, UserRepository $userRepository): Response { // we need to prepare the user preferences, which is done via an EventSubscriber @@ -336,7 +340,8 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}/2fa', name: 'user_profile_2fa', methods: ['GET', 'POST'])] - #[Security("is_granted('IS_AUTHENTICATED_FULLY') and is_granted('2fa', profile)")] + #[IsGranted('IS_AUTHENTICATED_FULLY')] + #[IsGranted('2fa', 'profile')] public function twoFactorAction(User $profile, Request $request, UserService $userService, TotpAuthenticatorInterface $totpAuthenticator): Response { if (!$profile->hasTotpSecret()) { @@ -382,7 +387,8 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}/2fa_deactivate', name: 'user_profile_2fa_deactivate', methods: ['POST'])] - #[Security("is_granted('IS_AUTHENTICATED_FULLY') and is_granted('2fa', profile)")] + #[IsGranted('IS_AUTHENTICATED_FULLY')] + #[IsGranted('2fa', 'profile')] public function deactivateTwoFactorAction(User $profile, Request $request, UserService $userService, TotpAuthenticatorInterface $totpAuthenticator): Response { if ($profile->hasTotpSecret()) { @@ -401,7 +407,7 @@ final class ProfileController extends AbstractController } #[Route(path: '/{username}/totp.png', name: 'user_profile_2fa_image', methods: ['GET'])] - #[Security("is_granted('2fa', profile)")] + #[IsGranted('2fa', 'profile')] public function displayTotpQrCode(User $profile, TotpAuthenticatorInterface $totpAuthenticator): Response { if (!$profile->hasTotpSecret()) { diff --git a/src/Controller/ProjectController.php b/src/Controller/ProjectController.php index 661c5b36..ac7c02f9 100644 --- a/src/Controller/ProjectController.php +++ b/src/Controller/ProjectController.php @@ -40,20 +40,21 @@ use App\Repository\TeamRepository; use App\Utils\Context; use App\Utils\DataTable; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Controller used to manage projects. */ #[Route(path: '/admin/project')] -#[Security("is_granted('view_project') or is_granted('view_teamlead_project') or is_granted('view_team_project')")] +#[IsGranted(new Expression("is_granted('view_project') or is_granted('view_teamlead_project') or is_granted('view_team_project')"))] final class ProjectController extends AbstractController { public function __construct(private ProjectRepository $repository, private SystemConfiguration $configuration, private EventDispatcherInterface $dispatcher, private ProjectService $projectService) @@ -132,7 +133,7 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/permissions', name: 'admin_project_permissions', methods: ['GET', 'POST'])] - #[Security("is_granted('permissions', project)")] + #[IsGranted('permissions', 'project')] public function teamPermissions(Project $project, Request $request) { $form = $this->createForm(ProjectTeamPermissionForm::class, $project, [ @@ -165,14 +166,14 @@ final class ProjectController extends AbstractController } #[Route(path: '/create/{customer}', name: 'admin_project_create_with_customer', methods: ['GET', 'POST'])] - #[Security("is_granted('create_project')")] + #[IsGranted('create_project')] public function createWithCustomerAction(Request $request, Customer $customer) { return $this->createProject($request, $customer); } #[Route(path: '/create', name: 'admin_project_create', methods: ['GET', 'POST'])] - #[Security("is_granted('create_project')")] + #[IsGranted('create_project')] public function createAction(Request $request) { return $this->createProject($request, null); @@ -204,7 +205,7 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/comment_delete/{token}', name: 'project_comment_delete', methods: ['GET'])] - #[Security("is_granted('edit', comment.getProject()) and is_granted('comments', comment.getProject())")] + #[IsGranted(new Expression("is_granted('edit', subject.getProject()) and is_granted('comments', subject.getProject())"), 'comment')] public function deleteCommentAction(ProjectComment $comment, string $token, CsrfTokenManagerInterface $csrfTokenManager) { $projectId = $comment->getProject()->getId(); @@ -227,7 +228,7 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/comment_add', name: 'project_comment_add', methods: ['POST'])] - #[Security("is_granted('comments', project)")] + #[IsGranted('comments', 'project')] public function addCommentAction(Project $project, Request $request) { $comment = new ProjectComment($project); @@ -247,7 +248,7 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/comment_pin/{token}', name: 'project_comment_pin', methods: ['GET'])] - #[Security("is_granted('edit', comment.getProject()) and is_granted('comments', comment.getProject())")] + #[IsGranted(new Expression("is_granted('edit', subject.getProject()) and is_granted('comments', subject.getProject())"), 'comment')] public function pinCommentAction(ProjectComment $comment, string $token, CsrfTokenManagerInterface $csrfTokenManager) { $projectId = $comment->getProject()->getId(); @@ -271,7 +272,8 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/create_team', name: 'project_team_create', methods: ['GET'])] - #[Security("is_granted('create_team') and is_granted('permissions', project)")] + #[IsGranted('create_team')] + #[IsGranted('permissions', 'project')] public function createDefaultTeamAction(Project $project, TeamRepository $teamRepository) { $defaultTeam = $teamRepository->findOneBy(['name' => $project->getName()]); @@ -295,7 +297,7 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/activities/{page}', defaults: ['page' => 1], name: 'project_activities', methods: ['GET', 'POST'])] - #[Security("is_granted('view', project)")] + #[IsGranted('view', 'project')] public function activitiesAction(Project $project, int $page, ActivityRepository $activityRepository) { $query = new ActivityQuery(); @@ -319,7 +321,7 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/details', name: 'project_details', methods: ['GET', 'POST'])] - #[Security("is_granted('view', project)")] + #[IsGranted('view', 'project')] public function detailsAction(Project $project, TeamRepository $teamRepository, ProjectRateRepository $rateRepository, ProjectStatisticService $statisticService, CsrfTokenManagerInterface $csrfTokenManager) { $event = new ProjectMetaDefinitionEvent($project); @@ -380,14 +382,14 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/rate/{rate}', name: 'admin_project_rate_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', project)")] + #[IsGranted('edit', 'project')] public function editRateAction(Project $project, ProjectRate $rate, Request $request, ProjectRateRepository $repository): Response { return $this->rateFormAction($project, $rate, $request, $repository, $this->generateUrl('admin_project_rate_edit', ['id' => $project->getId(), 'rate' => $rate->getId()])); } #[Route(path: '/{id}/rate', name: 'admin_project_rate_add', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', project)")] + #[IsGranted('edit', 'project')] public function addRateAction(Project $project, Request $request, ProjectRateRepository $repository): Response { $rate = new ProjectRate(); @@ -424,7 +426,7 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/edit', name: 'admin_project_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', project)")] + #[IsGranted('edit', 'project')] public function editAction(Project $project, Request $request) { $editForm = $this->createEditForm($project); @@ -449,7 +451,7 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/duplicate/{token}', name: 'admin_project_duplicate', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', project)")] + #[IsGranted('edit', 'project')] public function duplicateAction(Project $project, string $token, ProjectDuplicationService $projectDuplicationService, CsrfTokenManagerInterface $csrfTokenManager) { if (!$csrfTokenManager->isTokenValid(new CsrfToken('project.duplicate', $token))) { @@ -468,7 +470,7 @@ final class ProjectController extends AbstractController } #[Route(path: '/{id}/delete', name: 'admin_project_delete', methods: ['GET', 'POST'])] - #[Security("is_granted('delete', project)")] + #[IsGranted('delete', 'project')] public function deleteAction(Project $project, Request $request, ProjectStatisticService $statisticService) { $stats = $statisticService->getProjectStatistics($project); diff --git a/src/Controller/QuickEntryController.php b/src/Controller/QuickEntryController.php index 6ae14ee9..1d17ffad 100644 --- a/src/Controller/QuickEntryController.php +++ b/src/Controller/QuickEntryController.php @@ -17,15 +17,15 @@ use App\Repository\Query\TimesheetQuery; use App\Repository\TimesheetRepository; use App\Timesheet\TimesheetService; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Controller used to enter times in weekly form. */ #[Route(path: '/quick_entry')] -#[Security("is_granted('quick-entry')")] +#[IsGranted('quick-entry')] final class QuickEntryController extends AbstractController { public function __construct(private SystemConfiguration $configuration, private TimesheetService $timesheetService, private TimesheetRepository $repository) diff --git a/src/Controller/Reporting/CustomerMonthlyProjectsController.php b/src/Controller/Reporting/CustomerMonthlyProjectsController.php index 8ebc516c..f0a8ca84 100644 --- a/src/Controller/Reporting/CustomerMonthlyProjectsController.php +++ b/src/Controller/Reporting/CustomerMonthlyProjectsController.php @@ -18,13 +18,14 @@ use App\Reporting\CustomerMonthlyProjects\CustomerMonthlyProjectsRepository; use App\Repository\Query\UserQuery; use App\Repository\UserRepository; use PhpOffice\PhpSpreadsheet\Reader\Html; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/reporting/customer/monthly_projects')] -#[Security("is_granted('report:customer') and is_granted('report:other')")] +#[IsGranted('report:customer')] +#[IsGranted('report:other')] final class CustomerMonthlyProjectsController extends AbstractController { #[Route(path: '/view', name: 'report_customer_monthly_projects', methods: ['GET', 'POST'])] diff --git a/src/Controller/Reporting/ProjectDateRangeController.php b/src/Controller/Reporting/ProjectDateRangeController.php index 343e8f72..d3b53fc0 100644 --- a/src/Controller/Reporting/ProjectDateRangeController.php +++ b/src/Controller/Reporting/ProjectDateRangeController.php @@ -14,14 +14,16 @@ use App\Form\Model\DateRange; use App\Project\ProjectStatisticService; use App\Reporting\ProjectDateRange\ProjectDateRangeForm; use App\Reporting\ProjectDateRange\ProjectDateRangeQuery; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; final class ProjectDateRangeController extends AbstractController { #[Route(path: '/reporting/project_daterange', name: 'report_project_daterange', methods: ['GET', 'POST'])] - #[Security("is_granted('report:project') and is_granted('budget_any', 'project')")] + #[IsGranted('report:project')] + #[IsGranted(new Expression("is_granted('budget_any', 'project')"))] public function __invoke(Request $request, ProjectStatisticService $service) { $dateFactory = $this->getDateTimeFactory(); diff --git a/src/Controller/Reporting/ProjectDetailsController.php b/src/Controller/Reporting/ProjectDetailsController.php index 9bd09439..774607c5 100644 --- a/src/Controller/Reporting/ProjectDetailsController.php +++ b/src/Controller/Reporting/ProjectDetailsController.php @@ -14,14 +14,16 @@ use App\Project\ProjectStatisticService; use App\Reporting\ProjectDetails\ProjectDetailsForm; use App\Reporting\ProjectDetails\ProjectDetailsQuery; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; final class ProjectDetailsController extends AbstractController { #[Route(path: '/reporting/project_details', name: 'report_project_details', methods: ['GET'])] - #[Security("is_granted('report:project') and is_granted('details', 'project')")] + #[IsGranted('report:project')] + #[IsGranted(new Expression("is_granted('details', 'project')"))] public function __invoke(Request $request, ProjectStatisticService $service) { $dateFactory = $this->getDateTimeFactory(); diff --git a/src/Controller/Reporting/ProjectInactiveController.php b/src/Controller/Reporting/ProjectInactiveController.php index ae8cbe91..90bbe252 100644 --- a/src/Controller/Reporting/ProjectInactiveController.php +++ b/src/Controller/Reporting/ProjectInactiveController.php @@ -13,14 +13,16 @@ use App\Controller\AbstractController; use App\Project\ProjectStatisticService; use App\Reporting\ProjectInactive\ProjectInactiveForm; use App\Reporting\ProjectInactive\ProjectInactiveQuery; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; final class ProjectInactiveController extends AbstractController { #[Route(path: '/reporting/project_inactive', name: 'report_project_inactive', methods: ['GET', 'POST'])] - #[Security("is_granted('report:project') and is_granted('budget_any', 'project')")] + #[IsGranted('report:project')] + #[IsGranted(new Expression("is_granted('budget_any', 'project')"))] public function __invoke(Request $request, ProjectStatisticService $service) { $dateFactory = $this->getDateTimeFactory(); diff --git a/src/Controller/Reporting/ProjectViewController.php b/src/Controller/Reporting/ProjectViewController.php index 2b2a4b71..d7461a6d 100644 --- a/src/Controller/Reporting/ProjectViewController.php +++ b/src/Controller/Reporting/ProjectViewController.php @@ -13,14 +13,16 @@ use App\Controller\AbstractController; use App\Project\ProjectStatisticService; use App\Reporting\ProjectView\ProjectViewForm; use App\Reporting\ProjectView\ProjectViewQuery; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; +use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; final class ProjectViewController extends AbstractController { #[Route(path: '/reporting/project_view', name: 'report_project_view', methods: ['GET', 'POST'])] - #[Security("is_granted('report:project') and is_granted('budget_any', 'project')")] + #[IsGranted('report:project')] + #[IsGranted(new Expression("is_granted('budget_any', 'project')"))] public function __invoke(Request $request, ProjectStatisticService $service) { $dateFactory = $this->getDateTimeFactory(); diff --git a/src/Controller/Reporting/ReportUsersMonthController.php b/src/Controller/Reporting/ReportUsersMonthController.php index 8ca2d5ab..38a7321b 100644 --- a/src/Controller/Reporting/ReportUsersMonthController.php +++ b/src/Controller/Reporting/ReportUsersMonthController.php @@ -19,13 +19,13 @@ use App\Repository\Query\UserQuery; use App\Repository\UserRepository; use App\Timesheet\TimesheetStatisticService; use PhpOffice\PhpSpreadsheet\Reader\Html; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/reporting/users')] -#[Security("is_granted('report:other')")] +#[IsGranted('report:other')] final class ReportUsersMonthController extends AbstractController { #[Route(path: '/month', name: 'report_monthly_users', methods: ['GET', 'POST'])] diff --git a/src/Controller/Reporting/ReportUsersWeekController.php b/src/Controller/Reporting/ReportUsersWeekController.php index a96f62bc..f4c7bcba 100644 --- a/src/Controller/Reporting/ReportUsersWeekController.php +++ b/src/Controller/Reporting/ReportUsersWeekController.php @@ -19,13 +19,13 @@ use App\Repository\Query\UserQuery; use App\Repository\UserRepository; use App\Timesheet\TimesheetStatisticService; use PhpOffice\PhpSpreadsheet\Reader\Html; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/reporting/users')] -#[Security("is_granted('report:other')")] +#[IsGranted('report:other')] final class ReportUsersWeekController extends AbstractController { #[Route(path: '/week', name: 'report_weekly_users', methods: ['GET', 'POST'])] diff --git a/src/Controller/Reporting/ReportUsersYearController.php b/src/Controller/Reporting/ReportUsersYearController.php index 35fb4544..20806468 100644 --- a/src/Controller/Reporting/ReportUsersYearController.php +++ b/src/Controller/Reporting/ReportUsersYearController.php @@ -21,13 +21,13 @@ use App\Repository\UserRepository; use App\Timesheet\TimesheetStatisticService; use Exception; use PhpOffice\PhpSpreadsheet\Reader\Html; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/reporting/users')] -#[Security("is_granted('report:other')")] +#[IsGranted('report:other')] final class ReportUsersYearController extends AbstractController { /** diff --git a/src/Controller/Reporting/UserMonthController.php b/src/Controller/Reporting/UserMonthController.php index 47048ba3..ff0bab89 100644 --- a/src/Controller/Reporting/UserMonthController.php +++ b/src/Controller/Reporting/UserMonthController.php @@ -13,14 +13,14 @@ use App\Model\DailyStatistic; use App\Reporting\MonthByUser\MonthByUser; use App\Reporting\MonthByUser\MonthByUserForm; use Exception; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/reporting/user')] -#[Security("is_granted('report:user')")] +#[IsGranted('report:user')] final class UserMonthController extends AbstractUserReportController { /** diff --git a/src/Controller/Reporting/UserWeekController.php b/src/Controller/Reporting/UserWeekController.php index ed9122c5..1fd5c91a 100644 --- a/src/Controller/Reporting/UserWeekController.php +++ b/src/Controller/Reporting/UserWeekController.php @@ -13,14 +13,14 @@ use App\Model\DailyStatistic; use App\Reporting\WeekByUser\WeekByUser; use App\Reporting\WeekByUser\WeekByUserForm; use Exception; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/reporting/user')] -#[Security("is_granted('report:user')")] +#[IsGranted('report:user')] final class UserWeekController extends AbstractUserReportController { /** diff --git a/src/Controller/Reporting/UserYearController.php b/src/Controller/Reporting/UserYearController.php index 082ac1b3..1e0a6058 100644 --- a/src/Controller/Reporting/UserYearController.php +++ b/src/Controller/Reporting/UserYearController.php @@ -17,14 +17,14 @@ use App\Reporting\YearByUser\YearByUser; use App\Reporting\YearByUser\YearByUserForm; use DateTime; use Exception; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/reporting/user')] -#[Security("is_granted('report:user')")] +#[IsGranted('report:user')] final class UserYearController extends AbstractUserReportController { /** diff --git a/src/Controller/ReportingController.php b/src/Controller/ReportingController.php index 6d5d9708..e9bcd39d 100644 --- a/src/Controller/ReportingController.php +++ b/src/Controller/ReportingController.php @@ -11,15 +11,15 @@ namespace App\Controller; use App\Reporting\ReportingService; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Controller used to render reports. */ #[Route(path: '/reporting')] -#[Security("is_granted('view_reporting')")] +#[IsGranted('view_reporting')] final class ReportingController extends AbstractController { #[Route(path: '/', name: 'reporting', methods: ['GET'])] diff --git a/src/Controller/SystemConfigurationController.php b/src/Controller/SystemConfigurationController.php index e2d4215a..69a7145b 100644 --- a/src/Controller/SystemConfigurationController.php +++ b/src/Controller/SystemConfigurationController.php @@ -36,7 +36,6 @@ use App\Utils\PageSetup; use App\Validator\Constraints\ColorChoices; use App\Validator\Constraints\DateTimeFormat; use App\Validator\Constraints\TimeFormat; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Extension\Core\Type\CountryType; use Symfony\Component\Form\Extension\Core\Type\CurrencyType; @@ -47,6 +46,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotNull; @@ -57,7 +57,8 @@ use Symfony\Component\Validator\Constraints\Regex; * Controller used for executing system relevant tasks. */ #[Route(path: '/admin/system-config')] -#[Security("is_granted('IS_AUTHENTICATED_FULLY') and is_granted('system_configuration')")] +#[IsGranted('IS_AUTHENTICATED_FULLY')] +#[IsGranted('system_configuration')] final class SystemConfigurationController extends AbstractController { public function __construct(private EventDispatcherInterface $eventDispatcher, private ConfigurationRepository $repository, private SystemConfiguration $systemConfiguration, private LockdownService $lockdownService) diff --git a/src/Controller/TagController.php b/src/Controller/TagController.php index fd702532..b18400b8 100644 --- a/src/Controller/TagController.php +++ b/src/Controller/TagController.php @@ -18,14 +18,14 @@ use App\Repository\Query\TagQuery; use App\Repository\TagRepository; use App\Utils\DataTable; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/admin/tags')] -#[Security("is_granted('view_tag')")] +#[IsGranted('view_tag')] final class TagController extends AbstractController { /** @@ -76,7 +76,7 @@ final class TagController extends AbstractController } #[Route(path: '/{id}/edit', name: 'tags_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('manage_tag')")] + #[IsGranted('manage_tag')] public function editAction(Tag $tag, TagRepository $repository, Request $request) { $editForm = $this->createForm(TagEditForm::class, $tag, [ @@ -108,7 +108,7 @@ final class TagController extends AbstractController } #[Route(path: '/create', name: 'tags_create', methods: ['GET', 'POST'])] - #[Security("is_granted('manage_tag')")] + #[IsGranted('manage_tag')] public function createAction(TagRepository $repository, Request $request) { $tag = new Tag(); @@ -142,7 +142,7 @@ final class TagController extends AbstractController } #[Route(path: '/multi-delete', name: 'tags_multi_delete', methods: ['POST'])] - #[Security("is_granted('delete_tag')")] + #[IsGranted('delete_tag')] public function multiDelete(TagRepository $repository, Request $request) { $form = $this->getMultiUpdateForm($repository); diff --git a/src/Controller/TeamController.php b/src/Controller/TeamController.php index 346770c3..6d1e23d3 100644 --- a/src/Controller/TeamController.php +++ b/src/Controller/TeamController.php @@ -18,14 +18,14 @@ use App\Repository\Query\TeamQuery; use App\Repository\TeamRepository; use App\Utils\DataTable; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/admin/teams')] -#[Security("is_granted('view_team')")] +#[IsGranted('view_team')] final class TeamController extends AbstractController { public function __construct(private TeamRepository $repository) @@ -81,14 +81,15 @@ final class TeamController extends AbstractController * @return Response */ #[Route(path: '/create', name: 'admin_team_create', methods: ['GET', 'POST'])] - #[Security("is_granted('create_team')")] + #[IsGranted('create_team')] public function createTeam(Request $request): Response { return $this->renderEditScreen(new Team(''), $request, true); } #[Route(path: '/{id}/duplicate', name: 'team_duplicate', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', team) and is_granted('create_team')")] + #[IsGranted('create_team')] + #[IsGranted('edit', 'team')] public function duplicateTeam(Team $team, Request $request) { $newTeam = clone $team; @@ -103,14 +104,14 @@ final class TeamController extends AbstractController } #[Route(path: '/{id}/edit', name: 'admin_team_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', team)")] + #[IsGranted('edit', 'team')] public function editAction(Team $team, Request $request) { return $this->renderEditScreen($team, $request); } #[Route(path: '/{id}/edit_member', name: 'admin_team_member', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', team)")] + #[IsGranted('edit', 'team')] public function editMemberAction(Team $team, Request $request) { $editForm = $this->createForm(TeamEditForm::class, $team, [ diff --git a/src/Controller/TimesheetAbstractController.php b/src/Controller/TimesheetAbstractController.php index b770ea1e..ae65db2d 100644 --- a/src/Controller/TimesheetAbstractController.php +++ b/src/Controller/TimesheetAbstractController.php @@ -167,14 +167,13 @@ abstract class TimesheetAbstractController extends AbstractController protected function create(Request $request): Response { - $entry = $this->service->createNewTimesheet($this->getUser()); + $entry = $this->service->createNewTimesheet($this->getUser(), $request); $preForm = $this->createFormForGetRequest(TimesheetPreCreateForm::class, $entry, [ 'include_user' => $this->includeUserInForms('create'), ]); $preForm->submit($request->query->all(), false); - $this->service->prepareNewTimesheet($entry, $request); $createForm = $this->getCreateForm($entry); $createForm->handleRequest($request); diff --git a/src/Controller/TimesheetController.php b/src/Controller/TimesheetController.php index e27b1d52..63259388 100644 --- a/src/Controller/TimesheetController.php +++ b/src/Controller/TimesheetController.php @@ -13,19 +13,19 @@ use App\Entity\Timesheet; use App\Event\TimesheetMetaDisplayEvent; use App\Export\ServiceExport; use App\Form\TimesheetEditForm; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/timesheet')] -#[Security("is_granted('view_own_timesheet')")] +#[IsGranted('view_own_timesheet')] final class TimesheetController extends TimesheetAbstractController { #[Route(path: '/', defaults: ['page' => 1], name: 'timesheet', methods: ['GET'])] #[Route(path: '/page/{page}', requirements: ['page' => '[1-9]\d*'], name: 'timesheet_paginated', methods: ['GET'])] - #[Security("is_granted('view_own_timesheet')")] + #[IsGranted('view_own_timesheet')] public function indexAction(int $page, Request $request): Response { $query = $this->createDefaultQuery(); @@ -35,42 +35,42 @@ final class TimesheetController extends TimesheetAbstractController } #[Route(path: '/export/', name: 'timesheet_export', methods: ['GET', 'POST'])] - #[Security("is_granted('export_own_timesheet')")] + #[IsGranted('export_own_timesheet')] public function exportAction(Request $request, ServiceExport $serviceExport): Response { return $this->export($request, $serviceExport); } #[Route(path: '/{id}/edit', name: 'timesheet_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', entry)")] + #[IsGranted('edit', 'entry')] public function editAction(Timesheet $entry, Request $request): Response { return $this->edit($entry, $request); } #[Route(path: '/{id}/duplicate', name: 'timesheet_duplicate', methods: ['GET', 'POST'])] - #[Security("is_granted('duplicate', entry)")] + #[IsGranted('duplicate', 'entry')] public function duplicateAction(Timesheet $entry, Request $request): Response { return $this->duplicate($entry, $request); } #[Route(path: '/multi-update', name: 'timesheet_multi_update', methods: ['POST'])] - #[Security("is_granted('edit_own_timesheet')")] + #[IsGranted('edit_own_timesheet')] public function multiUpdateAction(Request $request): Response { return $this->multiUpdate($request); } #[Route(path: '/multi-delete', name: 'timesheet_multi_delete', methods: ['POST'])] - #[Security("is_granted('delete_own_timesheet')")] + #[IsGranted('delete_own_timesheet')] public function multiDeleteAction(Request $request): Response { return $this->multiDelete($request); } #[Route(path: '/create', name: 'timesheet_create', methods: ['GET', 'POST'])] - #[Security("is_granted('create_own_timesheet')")] + #[IsGranted('create_own_timesheet')] public function createAction(Request $request): Response { return $this->create($request); diff --git a/src/Controller/TimesheetTeamController.php b/src/Controller/TimesheetTeamController.php index d0981362..50169250 100644 --- a/src/Controller/TimesheetTeamController.php +++ b/src/Controller/TimesheetTeamController.php @@ -21,19 +21,19 @@ use App\Form\TimesheetMultiUserEditForm; use App\Repository\Query\TimesheetQuery; use App\Utils\PageSetup; use Doctrine\Common\Collections\ArrayCollection; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/team/timesheet')] -#[Security("is_granted('view_other_timesheet')")] +#[IsGranted('view_other_timesheet')] final class TimesheetTeamController extends TimesheetAbstractController { #[Route(path: '/', defaults: ['page' => 1], name: 'admin_timesheet', methods: ['GET'])] #[Route(path: '/page/{page}', requirements: ['page' => '[1-9]\d*'], name: 'admin_timesheet_paginated', methods: ['GET'])] - #[Security("is_granted('view_other_timesheet')")] + #[IsGranted('view_other_timesheet')] public function indexAction(int $page, Request $request): Response { $query = $this->createDefaultQuery(); @@ -43,35 +43,35 @@ final class TimesheetTeamController extends TimesheetAbstractController } #[Route(path: '/export/', name: 'admin_timesheet_export', methods: ['GET', 'POST'])] - #[Security("is_granted('export_other_timesheet')")] + #[IsGranted('export_other_timesheet')] public function exportAction(Request $request, ServiceExport $serviceExport): Response { return $this->export($request, $serviceExport); } #[Route(path: '/{id}/edit', name: 'admin_timesheet_edit', methods: ['GET', 'POST'])] - #[Security("is_granted('edit', entry)")] + #[IsGranted('edit', 'entry')] public function editAction(Timesheet $entry, Request $request): Response { return $this->edit($entry, $request); } #[Route(path: '/{id}/duplicate', name: 'admin_timesheet_duplicate', methods: ['GET', 'POST'])] - #[Security("is_granted('duplicate', entry)")] + #[IsGranted('duplicate', 'entry')] public function duplicateAction(Timesheet $entry, Request $request): Response { return $this->duplicate($entry, $request); } #[Route(path: '/create', name: 'admin_timesheet_create', methods: ['GET', 'POST'])] - #[Security("is_granted('create_other_timesheet')")] + #[IsGranted('create_other_timesheet')] public function createAction(Request $request): Response { return $this->create($request); } #[Route(path: '/create_mu', name: 'admin_timesheet_create_multiuser', methods: ['GET', 'POST'])] - #[Security("is_granted('create_other_timesheet')")] + #[IsGranted('create_other_timesheet')] public function createForMultiUserAction(Request $request): Response { $entry = new MultiUserTimesheet(); @@ -150,14 +150,14 @@ final class TimesheetTeamController extends TimesheetAbstractController } #[Route(path: '/multi-update', name: 'admin_timesheet_multi_update', methods: ['POST'])] - #[Security("is_granted('edit_other_timesheet')")] + #[IsGranted('edit_other_timesheet')] public function multiUpdateAction(Request $request): Response { return $this->multiUpdate($request); } #[Route(path: '/multi-delete', name: 'admin_timesheet_multi_delete', methods: ['POST'])] - #[Security("is_granted('delete_other_timesheet')")] + #[IsGranted('delete_other_timesheet')] public function multiDeleteAction(Request $request): Response { return $this->multiDelete($request); diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index e35ae0a7..fa6d7fcd 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -25,19 +25,20 @@ use App\Repository\UserRepository; use App\User\UserService; use App\Utils\DataTable; use App\Utils\PageSetup; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; /** * Controller used to manage users in the admin part of the site. */ #[Route(path: '/admin/user')] -#[Security("is_granted('IS_AUTHENTICATED_FULLY') and is_granted('view_user')")] +#[IsGranted('IS_AUTHENTICATED_FULLY')] +#[IsGranted('view_user')] final class UserController extends AbstractController { public function __construct(private UserPasswordHasherInterface $passwordHasher, private UserRepository $repository, private EventDispatcherInterface $dispatcher) @@ -110,7 +111,7 @@ final class UserController extends AbstractController } #[Route(path: '/create', name: 'admin_user_create', methods: ['GET', 'POST'])] - #[Security("is_granted('create_user')")] + #[IsGranted('create_user')] public function createAction(Request $request, SystemConfiguration $config, UserRepository $userRepository): Response { $user = $this->createNewDefaultUser($config); @@ -139,7 +140,7 @@ final class UserController extends AbstractController } #[Route(path: '/{id}/delete', name: 'admin_user_delete', methods: ['GET', 'POST'])] - #[Security("is_granted('delete', userToDelete)")] + #[IsGranted('delete', 'userToDelete')] public function deleteAction(User $userToDelete, Request $request, TimesheetRepository $repository, UserService $userService): Response { // $userToDelete MUST not be called $user, as $user is always the current user! @@ -191,7 +192,7 @@ final class UserController extends AbstractController } #[Route(path: '/export', name: 'user_export', methods: ['GET'])] - #[Security("is_granted('view_user')")] + #[IsGranted('view_user')] public function exportAction(Request $request, UserExporter $exporter) { $query = new UserQuery(); diff --git a/src/Controller/WidgetController.php b/src/Controller/WidgetController.php index 02cda44e..3ad83953 100644 --- a/src/Controller/WidgetController.php +++ b/src/Controller/WidgetController.php @@ -9,16 +9,16 @@ namespace App\Controller; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/widgets')] -#[Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")] +#[IsGranted('IS_AUTHENTICATED_REMEMBERED')] final class WidgetController extends AbstractController { #[Route(path: '/working-time/{year}/{week}', requirements: ['year' => '[1-9]\d*', 'week' => '[0-9]\d*'], name: 'widgets_working_time_chart', methods: ['GET'])] - #[Security("is_granted('view_own_timesheet')")] + #[IsGranted('view_own_timesheet')] public function workingtimechartAction($year, $week): Response { return $this->render('widget/paginatedworkingtimechart.html.twig', [ diff --git a/src/Controller/WizardController.php b/src/Controller/WizardController.php index 0810a6ab..9e944ea3 100644 --- a/src/Controller/WizardController.php +++ b/src/Controller/WizardController.php @@ -15,18 +15,18 @@ use App\Form\Type\LanguageType; use App\Form\Type\SkinType; use App\Form\Type\TimezoneType; use App\User\UserService; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; #[Route(path: '/wizard')] -#[Security("is_granted('IS_AUTHENTICATED_FULLY')")] +#[IsGranted('IS_AUTHENTICATED_FULLY')] final class WizardController extends AbstractController { #[Route(path: '/{wizard}', name: 'wizard', methods: ['GET', 'POST'])] - #[Security("is_granted('view_own_timesheet')")] + #[IsGranted('view_own_timesheet')] public function wizard(Request $request, UserService $userService, string $wizard): Response { $user = $this->getUser(); diff --git a/src/DataFixtures/InvoiceFixtures.php b/src/DataFixtures/InvoiceFixtures.php index ff665b72..330382e4 100644 --- a/src/DataFixtures/InvoiceFixtures.php +++ b/src/DataFixtures/InvoiceFixtures.php @@ -92,7 +92,7 @@ final class InvoiceFixtures extends Fixture ]; } - protected function generatePaymentDetails(Generator $faker): string + private function generatePaymentDetails(Generator $faker): string { return 'Acme Bank' . PHP_EOL . @@ -101,7 +101,7 @@ final class InvoiceFixtures extends Fixture ; } - protected function generateContact(Generator $faker): string + private function generateContact(Generator $faker): string { return 'Phone: ' . $faker->phoneNumber() . PHP_EOL . @@ -110,7 +110,7 @@ final class InvoiceFixtures extends Fixture ; } - protected function generateAddress(Generator $faker): string + private function generateAddress(Generator $faker): string { return $faker->streetAddress() . PHP_EOL . diff --git a/src/DataFixtures/TeamFixtures.php b/src/DataFixtures/TeamFixtures.php index 7bbddad2..ddc2ea04 100644 --- a/src/DataFixtures/TeamFixtures.php +++ b/src/DataFixtures/TeamFixtures.php @@ -40,7 +40,7 @@ final class TeamFixtures extends Fixture * @param ObjectManager $manager * @return array */ - protected function getAllUsers(ObjectManager $manager): array + private function getAllUsers(ObjectManager $manager): array { $all = []; /** @var User[] $entries */ @@ -56,7 +56,7 @@ final class TeamFixtures extends Fixture * @param ObjectManager $manager * @return array */ - protected function getAllProjects(ObjectManager $manager): array + private function getAllProjects(ObjectManager $manager): array { $all = []; diff --git a/src/DataFixtures/TimesheetFixtures.php b/src/DataFixtures/TimesheetFixtures.php index 8d54080c..99cea4c9 100644 --- a/src/DataFixtures/TimesheetFixtures.php +++ b/src/DataFixtures/TimesheetFixtures.php @@ -117,6 +117,7 @@ final class TimesheetFixtures extends Fixture implements FixtureGroupInterface } $allTags = $this->getAllTags($manager); + /** @var array $entries */ $entries = $this->findRandom($manager, Timesheet::class, min($all, self::ADD_TAGS_MAX_ENTRIES)); foreach ($entries as $temp) { $tagAmount = rand(0, self::MAX_TAG_PER_ENTRY); @@ -132,9 +133,17 @@ final class TimesheetFixtures extends Fixture implements FixtureGroupInterface $manager->clear(); } - private function findRandom(ObjectManager $manager, string $class, int $amount) + /** + * @template T of object + * @param ObjectManager $manager + * @param class-string $class + * @param int $amount + * @return array + */ + private function findRandom(ObjectManager $manager, string $class, int $amount): array { $qb = $manager->getRepository($class)->createQueryBuilder('entity'); + /** @var array $limits */ $limits = $qb ->select('MIN(entity.id)', 'MAX(entity.id)') ->getQuery() @@ -150,18 +159,17 @@ final class TimesheetFixtures extends Fixture implements FixtureGroupInterface $qb = $manager->getRepository($class)->createQueryBuilder('entity'); - return $qb - ->where($qb->expr()->in('entity.id', $ids)) - ->setMaxResults($amount) - ->getQuery() - ->getResult(); + /** @var array $result */ + $result = $qb->where($qb->expr()->in('entity.id', $ids))->setMaxResults($amount)->getQuery()->getResult(); + + return $result; } /** * @param ObjectManager $manager * @return array */ - protected function getAllTags(ObjectManager $manager): array + private function getAllTags(ObjectManager $manager): array { return $this->findRandom($manager, Tag::class, 50); } @@ -170,7 +178,7 @@ final class TimesheetFixtures extends Fixture implements FixtureGroupInterface * @param ObjectManager $manager * @return array */ - protected function getAllUsers(ObjectManager $manager): array + private function getAllUsers(ObjectManager $manager): array { $all = []; /** @var User[] $entries */ @@ -186,7 +194,7 @@ final class TimesheetFixtures extends Fixture implements FixtureGroupInterface * @param ObjectManager $manager * @return array */ - protected function getAllProjects(ObjectManager $manager): array + private function getAllProjects(ObjectManager $manager): array { return $this->findRandom($manager, Project::class, 50); } @@ -195,12 +203,12 @@ final class TimesheetFixtures extends Fixture implements FixtureGroupInterface * @param ObjectManager $manager * @return array */ - protected function getAllActivities(ObjectManager $manager): array + private function getAllActivities(ObjectManager $manager): array { return $this->findRandom($manager, Activity::class, 50); } - private function createTimesheetEntry(User $user, Activity $activity, Project $project, ?string $description, bool $setEndDate) + private function createTimesheetEntry(User $user, Activity $activity, Project $project, ?string $description, bool $setEndDate): Timesheet { $start = $this->getRandomFirstDay(); $start = $start->modify('- ' . (rand(1, 86400)) . ' seconds'); diff --git a/src/DataFixtures/UserFixtures.php b/src/DataFixtures/UserFixtures.php index 52b649d9..2e8e3688 100644 --- a/src/DataFixtures/UserFixtures.php +++ b/src/DataFixtures/UserFixtures.php @@ -59,10 +59,8 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface /** * Default users for all test cases - * - * @param ObjectManager $manager */ - private function loadDefaultAccounts(ObjectManager $manager) + private function loadDefaultAccounts(ObjectManager $manager): void { $allUsers = $this->getUserDefinition(); foreach ($allUsers as $userData) { @@ -74,8 +72,8 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface $user->setRoles([$userData[4]]); $user->setAvatar($userData[5]); $user->setEnabled($userData[6]); - $user->setPassword($this->passwordHasher->hashPassword($user, self::DEFAULT_PASSWORD)); - $user->setApiToken($this->passwordHasher->hashPassword($user, self::DEFAULT_API_TOKEN)); + $user->setPassword($this->passwordHasher->hashPassword($user, $userData[8])); + $user->setApiToken($this->passwordHasher->hashPassword($user, $userData[9])); $manager->persist($user); $prefs = $this->getUserPreferences($user, $userData[7]); @@ -117,11 +115,9 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface } /** - * Generate randomized test users, which don't have API access. - * - * @param ObjectManager $manager + * Generate randomized test users, without API access. */ - private function loadTestUsers(ObjectManager $manager) + private function loadTestUsers(ObjectManager $manager): void { $faker = Factory::create(); $existingName = []; @@ -161,10 +157,7 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface $manager->clear(); } - /** - * @return array - */ - protected function getUserDefinition(): array + private function getUserDefinition(): array { // alias = $userData[0] // title = $userData[1] @@ -174,6 +167,8 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface // avatar = $userData[5] // enabled = $userData[6] // timezone = $userData[7] + // password = $userData[8] + // api = $userData[9] return [ [ @@ -185,6 +180,20 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface self::DEFAULT_AVATAR, true, 'America/Vancouver', + self::DEFAULT_PASSWORD, + self::DEFAULT_API_TOKEN, + ], + [ + 'John Doe', + 'Developer', + 'user', + 'user@example.com', + User::ROLE_USER, + self::DEFAULT_AVATAR, + true, + 'America/Vancouver', + 'password', + 'password', ], // inactive user to test login [ @@ -196,6 +205,8 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface self::DEFAULT_AVATAR, false, 'Australia/Sydney', + self::DEFAULT_PASSWORD, + self::DEFAULT_API_TOKEN, ], [ 'Tony Maier', @@ -206,6 +217,20 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface 'https://en.gravatar.com/userimage/3533186/bf2163b1dd23f3107a028af0195624e9.jpeg', true, 'Asia/Bangkok', + self::DEFAULT_PASSWORD, + self::DEFAULT_API_TOKEN, + ], + [ + 'Tony Maier', + 'Head of Sales', + 'teamlead', + 'teamlead@example.com', + User::ROLE_TEAMLEAD, + 'https://en.gravatar.com/userimage/3533186/bf2163b1dd23f3107a028af0195624e9.jpeg', + true, + 'Asia/Bangkok', + 'password', + 'password', ], // no avatar to test default image macro [ @@ -217,6 +242,20 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface null, true, 'Europe/London', + self::DEFAULT_PASSWORD, + self::DEFAULT_API_TOKEN, + ], + [ + 'Anna Smith', + 'Administrator', + 'administrator', + 'administrator@example.com', + User::ROLE_ADMIN, + null, + true, + 'Europe/London', + 'password', + 'password', ], // no alias to test twig username macro [ @@ -228,7 +267,21 @@ final class UserFixtures extends Fixture implements FixtureGroupInterface '/touch-icon-192x192.png', true, 'Europe/Berlin', - ] + self::DEFAULT_PASSWORD, + self::DEFAULT_API_TOKEN, + ], + [ + null, + 'Super Administrator', + 'super_admin', + 'super_admin@example.com', + User::ROLE_SUPER_ADMIN, + '/touch-icon-192x192.png', + true, + 'Europe/Berlin', + 'password', + 'password', + ], ]; } } diff --git a/src/Entity/Customer.php b/src/Entity/Customer.php index 16ab4252..4ef9b3d0 100644 --- a/src/Entity/Customer.php +++ b/src/Entity/Customer.php @@ -107,7 +107,7 @@ class Customer implements EntityWithMetaFields, EntityWithBudget #[Serializer\Expose] #[Serializer\Groups(['Customer'])] #[Exporter\Expose(label: 'currency')] - private string $currency = self::DEFAULT_CURRENCY; + private ?string $currency = self::DEFAULT_CURRENCY; #[ORM\Column(name: 'phone', type: 'string', length: 30, nullable: true)] #[Assert\Length(max: 30)] #[Serializer\Expose] @@ -197,11 +197,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->id; } - public function setName(?string $name): Customer + public function setName(?string $name): void { $this->name = $name; - - return $this; } public function getName(): ?string @@ -209,11 +207,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->name; } - public function setNumber(?string $number): Customer + public function setNumber(?string $number): void { $this->number = $number; - - return $this; } public function getNumber(): ?string @@ -221,11 +217,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->number; } - public function setComment(?string $comment): Customer + public function setComment(?string $comment): void { $this->comment = $comment; - - return $this; } public function getComment(): ?string @@ -233,11 +227,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->comment; } - public function setVisible(bool $visible): Customer + public function setVisible(bool $visible): void { $this->visible = $visible; - - return $this; } public function isVisible(): bool @@ -255,11 +247,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->billable; } - public function setCompany(?string $company): Customer + public function setCompany(?string $company): void { $this->company = $company; - - return $this; } public function getCompany(): ?string @@ -272,18 +262,14 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->vatId; } - public function setVatId(?string $vatId): Customer + public function setVatId(?string $vatId): void { $this->vatId = $vatId; - - return $this; } - public function setContact(?string $contact): Customer + public function setContact(?string $contact): void { $this->contact = $contact; - - return $this; } public function getContact(): ?string @@ -291,11 +277,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->contact; } - public function setAddress(?string $address): Customer + public function setAddress(?string $address): void { $this->address = $address; - - return $this; } public function getAddress(): ?string @@ -303,11 +287,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->address; } - public function setCountry(?string $country): Customer + public function setCountry(?string $country): void { $this->country = $country; - - return $this; } public function getCountry(): ?string @@ -315,23 +297,19 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->country; } - public function setCurrency(string $currency): Customer + public function setCurrency(?string $currency): void { $this->currency = $currency; - - return $this; } - public function getCurrency(): string + public function getCurrency(): ?string { return $this->currency; } - public function setPhone(?string $phone): Customer + public function setPhone(?string $phone): void { $this->phone = $phone; - - return $this; } public function getPhone(): ?string @@ -339,11 +317,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->phone; } - public function setFax(?string $fax): Customer + public function setFax(?string $fax): void { $this->fax = $fax; - - return $this; } public function getFax(): ?string @@ -351,11 +327,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->fax; } - public function setMobile(?string $mobile): Customer + public function setMobile(?string $mobile): void { $this->mobile = $mobile; - - return $this; } public function getMobile(): ?string @@ -363,11 +337,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->mobile; } - public function setEmail(?string $mail): Customer + public function setEmail(?string $mail): void { $this->email = $mail; - - return $this; } public function getEmail(): ?string @@ -375,11 +347,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->email; } - public function setHomepage(?string $homepage): Customer + public function setHomepage(?string $homepage): void { $this->homepage = $homepage; - - return $this; } public function getHomepage(): ?string @@ -387,11 +357,9 @@ class Customer implements EntityWithMetaFields, EntityWithBudget return $this->homepage; } - public function setTimezone(string $timezone): Customer + public function setTimezone(?string $timezone): void { $this->timezone = $timezone; - - return $this; } public function getTimezone(): ?string diff --git a/src/Entity/Timesheet.php b/src/Entity/Timesheet.php index ac751bf2..0ab12cba 100644 --- a/src/Entity/Timesheet.php +++ b/src/Entity/Timesheet.php @@ -90,6 +90,8 @@ class Timesheet implements EntityWithMetaFields, ExportableItem #[Assert\NotNull] private ?DateTime $date = null; /** + * Time records start date-time. + * * Attention: Accessor MUST be used, otherwise date will be serialized in UTC. */ #[ORM\Column(name: 'start_time', type: 'datetime', nullable: false)] @@ -100,6 +102,8 @@ class Timesheet implements EntityWithMetaFields, ExportableItem #[Serializer\Accessor(getter: 'getBegin')] private ?DateTime $begin = null; /** + * Time records end date-time. + * * Attention: Accessor MUST be used, otherwise date will be serialized in UTC. */ #[ORM\Column(name: 'end_time', type: 'datetime', nullable: true)] diff --git a/src/Entity/User.php b/src/Entity/User.php index eb7c3ebd..9acbd5a2 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -165,7 +165,7 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas #[ORM\Column(name: 'email', type: 'string', length: 180, nullable: false)] #[Assert\NotBlank(groups: ['Registration', 'UserCreate', 'Profile'])] #[Assert\Length(min: 2, max: 180)] - #[Assert\Email(groups: ['Registration', 'UserCreate', 'Profile'])] + #[Assert\Email(mode: 'html5', groups: ['Registration', 'UserCreate', 'Profile'])] private ?string $email = null; #[ORM\Column(name: 'account', type: 'string', length: 30, nullable: true)] #[Assert\Length(max: 30, groups: ['Registration', 'UserCreate', 'Profile'])] diff --git a/src/EventSubscriber/MenuBuilderSubscriber.php b/src/EventSubscriber/MenuBuilderSubscriber.php index 7fa16903..9876b402 100644 --- a/src/EventSubscriber/MenuBuilderSubscriber.php +++ b/src/EventSubscriber/MenuBuilderSubscriber.php @@ -14,9 +14,9 @@ use App\Event\ConfigureMainMenuEvent; use App\Utils\MenuItemModel; use KevinPapst\TablerBundle\Event\MenuEvent; use KevinPapst\TablerBundle\Model\MenuItemInterface; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Security\Core\Security; /** * Class MenuBuilder configures the main navigation. diff --git a/src/EventSubscriber/MenuFavoritesSubscriber.php b/src/EventSubscriber/MenuFavoritesSubscriber.php index de52cdb3..41b5f050 100644 --- a/src/EventSubscriber/MenuFavoritesSubscriber.php +++ b/src/EventSubscriber/MenuFavoritesSubscriber.php @@ -12,8 +12,8 @@ namespace App\EventSubscriber; use App\Entity\User; use App\Event\ConfigureMainMenuEvent; use App\Utils\MenuItemModel; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Security\Core\Security; final class MenuFavoritesSubscriber implements EventSubscriberInterface { diff --git a/src/EventSubscriber/UserDetailsSubscriber.php b/src/EventSubscriber/UserDetailsSubscriber.php index ca47205a..6a25b036 100644 --- a/src/EventSubscriber/UserDetailsSubscriber.php +++ b/src/EventSubscriber/UserDetailsSubscriber.php @@ -12,9 +12,9 @@ namespace App\EventSubscriber; use App\Entity\User; use App\Utils\MenuItemModel; use KevinPapst\TablerBundle\Event\UserDetailsEvent; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Symfony\Component\Security\Core\Security; /** * @internal diff --git a/src/Export/Base/AbstractSpreadsheetRenderer.php b/src/Export/Base/AbstractSpreadsheetRenderer.php index 58ac27fe..abfd7ffb 100644 --- a/src/Export/Base/AbstractSpreadsheetRenderer.php +++ b/src/Export/Base/AbstractSpreadsheetRenderer.php @@ -29,11 +29,11 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\Border; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; -use Symfony\Component\Security\Core\Security; use Symfony\Contracts\Translation\TranslatorInterface; /** diff --git a/src/Form/Extension/UserExtension.php b/src/Form/Extension/UserExtension.php index 647a09c3..854f01f0 100644 --- a/src/Form/Extension/UserExtension.php +++ b/src/Form/Extension/UserExtension.php @@ -10,10 +10,10 @@ namespace App\Form\Extension; use App\Entity\User; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Security\Core\Security; final class UserExtension extends AbstractTypeExtension { diff --git a/src/Form/TimesheetPreCreateForm.php b/src/Form/TimesheetPreCreateForm.php index d1af5fea..f5a08874 100644 --- a/src/Form/TimesheetPreCreateForm.php +++ b/src/Form/TimesheetPreCreateForm.php @@ -10,6 +10,7 @@ namespace App\Form; use App\Form\Type\DescriptionType; +use App\Form\Type\MetaFieldsCollectionType; use App\Form\Type\TagsInputType; use App\Form\Type\UserType; use Symfony\Component\Form\AbstractType; @@ -29,6 +30,7 @@ final class TimesheetPreCreateForm extends AbstractType $this->addActivity($builder, null, null, ['required' => false]); $builder->add('description', DescriptionType::class, ['required' => false]); $builder->add('tags', TagsInputType::class, ['required' => false]); + $builder->add('metaFields', MetaFieldsCollectionType::class); if ($options['include_user']) { $builder->add('user', UserType::class, ['required' => false]); } diff --git a/src/Form/Type/QuickEntryTimesheetType.php b/src/Form/Type/QuickEntryTimesheetType.php index 96c059aa..b9986ea9 100644 --- a/src/Form/Type/QuickEntryTimesheetType.php +++ b/src/Form/Type/QuickEntryTimesheetType.php @@ -10,13 +10,13 @@ namespace App\Form\Type; use App\Entity\Timesheet; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Security\Core\Security; final class QuickEntryTimesheetType extends AbstractType { diff --git a/src/Invoice/InvoiceModel.php b/src/Invoice/InvoiceModel.php index 66028d52..01f46a58 100644 --- a/src/Invoice/InvoiceModel.php +++ b/src/Invoice/InvoiceModel.php @@ -229,12 +229,11 @@ final class InvoiceModel public function getCurrency(): string { - if (null === $this->getCustomer()) { - // this should be set from the configuration - return Customer::DEFAULT_CURRENCY; + if (null !== $this->getCustomer() && $this->getCustomer()->getCurrency() !== null) { + return $this->getCustomer()->getCurrency(); } - return $this->getCustomer()->getCurrency(); + return Customer::DEFAULT_CURRENCY; } public function toArray(): array diff --git a/src/Timesheet/FavoriteRecordService.php b/src/Timesheet/FavoriteRecordService.php index 9e7b66bb..3fbdfae0 100644 --- a/src/Timesheet/FavoriteRecordService.php +++ b/src/Timesheet/FavoriteRecordService.php @@ -62,7 +62,7 @@ final class FavoriteRecordService $bookmark = new Bookmark(); $bookmark->setUser($user); $bookmark->setType('favorite'); - $bookmark->setName('timesheet'); + $bookmark->setName('recent'); } return $bookmark; diff --git a/src/Twig/LocaleFormatExtensions.php b/src/Twig/LocaleFormatExtensions.php index 3eda7548..a66e6f6e 100644 --- a/src/Twig/LocaleFormatExtensions.php +++ b/src/Twig/LocaleFormatExtensions.php @@ -17,7 +17,7 @@ use App\Utils\FormFormatConverter; use App\Utils\JavascriptFormatConverter; use App\Utils\LocaleFormatter; use DateTime; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Contracts\Translation\LocaleAwareInterface; use Twig\Extension\AbstractExtension; use Twig\TwigFilter; diff --git a/src/Twig/Runtime/WidgetExtension.php b/src/Twig/Runtime/WidgetExtension.php index 0ac4620e..524e3549 100644 --- a/src/Twig/Runtime/WidgetExtension.php +++ b/src/Twig/Runtime/WidgetExtension.php @@ -13,7 +13,7 @@ use App\Entity\User; use App\Widget\WidgetException; use App\Widget\WidgetInterface; use App\Widget\WidgetService; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Twig\Environment; use Twig\Extension\RuntimeExtensionInterface; diff --git a/src/Utils/ProfileManager.php b/src/Utils/ProfileManager.php index f7edb35e..1bef1287 100644 --- a/src/Utils/ProfileManager.php +++ b/src/Utils/ProfileManager.php @@ -11,6 +11,7 @@ namespace App\Utils; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\Session\SessionInterface; final class ProfileManager { @@ -52,7 +53,7 @@ final class ProfileManager return $profile; } - public function setProfile(Session $session, string $profile): void + public function setProfile(SessionInterface $session, string $profile): void { if ($profile === self::PROFILE_MOBILE) { $session->set(self::SESSION_PROFILE, $profile); diff --git a/src/Validator/Constraints/ColorChoices.php b/src/Validator/Constraints/ColorChoices.php index ecdb5722..798c400b 100644 --- a/src/Validator/Constraints/ColorChoices.php +++ b/src/Validator/Constraints/ColorChoices.php @@ -16,7 +16,7 @@ final class ColorChoices extends Constraint public const COLOR_CHOICES_ERROR = 'ui5hffg-dsfef3-1234-5678-2g8jkfr56d84'; public const COLOR_CHOICES_NAME_ERROR = 'ui5hffg-dsfef3-1234-5679-2g8jkfr56d84'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::COLOR_CHOICES_ERROR => 'COLOR_CHOICES_ERROR', self::COLOR_CHOICES_NAME_ERROR => 'COLOR_CHOICES_NAME_ERROR', ]; diff --git a/src/Validator/Constraints/DateTimeFormat.php b/src/Validator/Constraints/DateTimeFormat.php index 0ecf53a6..e2a470a0 100644 --- a/src/Validator/Constraints/DateTimeFormat.php +++ b/src/Validator/Constraints/DateTimeFormat.php @@ -15,7 +15,7 @@ final class DateTimeFormat extends Constraint { public const INVALID_FORMAT = 'kimai-datetime-00'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::INVALID_FORMAT => 'The given value is not a valid datetime format.', ]; diff --git a/src/Validator/Constraints/HexColor.php b/src/Validator/Constraints/HexColor.php index 49f438b6..fe10c71c 100644 --- a/src/Validator/Constraints/HexColor.php +++ b/src/Validator/Constraints/HexColor.php @@ -16,7 +16,7 @@ final class HexColor extends Constraint { public const HEX_COLOR_ERROR = 'xd5hffg-dsfef3-426a-83d7-2g8jkfr56d84'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::HEX_COLOR_ERROR => 'HEX_COLOR_ERROR', ]; diff --git a/src/Validator/Constraints/Project.php b/src/Validator/Constraints/Project.php index 0b3e8bab..0e851900 100644 --- a/src/Validator/Constraints/Project.php +++ b/src/Validator/Constraints/Project.php @@ -16,7 +16,7 @@ final class Project extends Constraint { public const END_BEFORE_BEGIN_ERROR = 'kimai-project-00'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::END_BEFORE_BEGIN_ERROR => 'End date must not be earlier then start date.', ]; diff --git a/src/Validator/Constraints/Role.php b/src/Validator/Constraints/Role.php index f1ec6860..6aca2889 100644 --- a/src/Validator/Constraints/Role.php +++ b/src/Validator/Constraints/Role.php @@ -16,7 +16,7 @@ final class Role extends Constraint { public const ROLE_ERROR = 'xd5hffg-dsfef3-426a-83d7-1f2d33hs5d84'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::ROLE_ERROR => 'ROLE_ERROR', ]; diff --git a/src/Validator/Constraints/RoleName.php b/src/Validator/Constraints/RoleName.php index dda1de0d..d89de264 100644 --- a/src/Validator/Constraints/RoleName.php +++ b/src/Validator/Constraints/RoleName.php @@ -16,7 +16,7 @@ final class RoleName extends Constraint { public const ROLE_NAME_ERROR = 'xd5hffg-dsfef3-426a-83d7-1f2d33hs5d85'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::ROLE_NAME_ERROR => 'ROLE_NAME_ERROR', ]; diff --git a/src/Validator/Constraints/Team.php b/src/Validator/Constraints/Team.php index cb4ae321..441a0008 100644 --- a/src/Validator/Constraints/Team.php +++ b/src/Validator/Constraints/Team.php @@ -16,7 +16,7 @@ final class Team extends Constraint { public const MISSING_TEAMLEAD = 'kimai-team-001'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::MISSING_TEAMLEAD => 'At least one team leader must be assigned to the team.', ]; diff --git a/src/Validator/Constraints/TimeFormat.php b/src/Validator/Constraints/TimeFormat.php index 40e1e1c3..4a81983a 100644 --- a/src/Validator/Constraints/TimeFormat.php +++ b/src/Validator/Constraints/TimeFormat.php @@ -15,7 +15,7 @@ final class TimeFormat extends Constraint { public const INVALID_FORMAT = 'kimai-time-00'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::INVALID_FORMAT => 'The given value is not a valid time.', ]; diff --git a/src/Validator/Constraints/TimesheetBasic.php b/src/Validator/Constraints/TimesheetBasic.php index 47ce19bc..b5fccbf8 100644 --- a/src/Validator/Constraints/TimesheetBasic.php +++ b/src/Validator/Constraints/TimesheetBasic.php @@ -23,7 +23,7 @@ final class TimesheetBasic extends TimesheetConstraint public const PROJECT_ALREADY_ENDED = 'kimai-timesheet-92'; public const PROJECT_DISALLOWS_GLOBAL_ACTIVITY = 'kimai-timesheet-93'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::MISSING_BEGIN_ERROR => 'You must submit a begin date.', self::END_BEFORE_BEGIN_ERROR => 'End date must not be earlier then start date.', self::MISSING_ACTIVITY_ERROR => 'An activity needs to be selected.', diff --git a/src/Validator/Constraints/TimesheetExported.php b/src/Validator/Constraints/TimesheetExported.php index f3767df4..df37d914 100644 --- a/src/Validator/Constraints/TimesheetExported.php +++ b/src/Validator/Constraints/TimesheetExported.php @@ -13,7 +13,7 @@ final class TimesheetExported extends TimesheetConstraint { public const TIMESHEET_EXPORTED = 'kimai-timesheet-exported-01'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::TIMESHEET_EXPORTED => 'This timesheet is already exported.', ]; diff --git a/src/Validator/Constraints/TimesheetExportedValidator.php b/src/Validator/Constraints/TimesheetExportedValidator.php index 9978e281..179daec4 100644 --- a/src/Validator/Constraints/TimesheetExportedValidator.php +++ b/src/Validator/Constraints/TimesheetExportedValidator.php @@ -10,7 +10,7 @@ namespace App\Validator\Constraints; use App\Entity\Timesheet as TimesheetEntity; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; diff --git a/src/Validator/Constraints/TimesheetFutureTimes.php b/src/Validator/Constraints/TimesheetFutureTimes.php index b40286cc..d052cfe1 100644 --- a/src/Validator/Constraints/TimesheetFutureTimes.php +++ b/src/Validator/Constraints/TimesheetFutureTimes.php @@ -13,7 +13,7 @@ final class TimesheetFutureTimes extends TimesheetConstraint { public const BEGIN_IN_FUTURE_ERROR = 'kimai-timesheet-future-times-01'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::BEGIN_IN_FUTURE_ERROR => 'The begin date cannot be in the future.', ]; diff --git a/src/Validator/Constraints/TimesheetLockdown.php b/src/Validator/Constraints/TimesheetLockdown.php index 49521bf2..1ba70425 100644 --- a/src/Validator/Constraints/TimesheetLockdown.php +++ b/src/Validator/Constraints/TimesheetLockdown.php @@ -13,7 +13,7 @@ final class TimesheetLockdown extends TimesheetConstraint { public const PERIOD_LOCKED = 'kimai-timesheet-lockdown-01'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::PERIOD_LOCKED => 'This period is locked, please choose a later date.', ]; diff --git a/src/Validator/Constraints/TimesheetLockdownValidator.php b/src/Validator/Constraints/TimesheetLockdownValidator.php index 22254415..4a01508a 100644 --- a/src/Validator/Constraints/TimesheetLockdownValidator.php +++ b/src/Validator/Constraints/TimesheetLockdownValidator.php @@ -11,7 +11,7 @@ namespace App\Validator\Constraints; use App\Entity\Timesheet as TimesheetEntity; use App\Timesheet\LockdownService; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; diff --git a/src/Validator/Constraints/TimesheetLongRunning.php b/src/Validator/Constraints/TimesheetLongRunning.php index faac2e46..537eb882 100644 --- a/src/Validator/Constraints/TimesheetLongRunning.php +++ b/src/Validator/Constraints/TimesheetLongRunning.php @@ -14,7 +14,7 @@ final class TimesheetLongRunning extends TimesheetConstraint public const LONG_RUNNING = 'kimai-timesheet-long-running-01'; public const MAXIMUM = 'kimai-timesheet-long-running-02'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::LONG_RUNNING => 'TIMESHEET_LONG_RUNNING', self::MAXIMUM => 'MAXIMUM', ]; diff --git a/src/Validator/Constraints/TimesheetMultiUpdate.php b/src/Validator/Constraints/TimesheetMultiUpdate.php index 46d01a44..8b3c0c8e 100644 --- a/src/Validator/Constraints/TimesheetMultiUpdate.php +++ b/src/Validator/Constraints/TimesheetMultiUpdate.php @@ -22,7 +22,7 @@ final class TimesheetMultiUpdate extends Constraint public const DISABLED_CUSTOMER_ERROR = 'ts-multi-update-89'; public const HOURLY_RATE_FIXED_RATE = 'ts-multi-update-90'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::MISSING_ACTIVITY_ERROR => 'You need to choose an activity, if the project should be changed.', self::MISSING_PROJECT_ERROR => 'A project needs to be selected.', self::ACTIVITY_PROJECT_MISMATCH_ERROR => 'Project mismatch: chosen project does not match the activity project.', diff --git a/src/Validator/Constraints/TimesheetMultiUser.php b/src/Validator/Constraints/TimesheetMultiUser.php index 48907d06..f9c8c969 100644 --- a/src/Validator/Constraints/TimesheetMultiUser.php +++ b/src/Validator/Constraints/TimesheetMultiUser.php @@ -16,7 +16,7 @@ final class TimesheetMultiUser extends Constraint { public const MISSING_USER_OR_TEAM = 'ts-multi-user-01'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::MISSING_USER_OR_TEAM => 'You must select at least one user or team.', ]; diff --git a/src/Validator/Constraints/TimesheetOverlapping.php b/src/Validator/Constraints/TimesheetOverlapping.php index 1dec1469..35ff6eba 100644 --- a/src/Validator/Constraints/TimesheetOverlapping.php +++ b/src/Validator/Constraints/TimesheetOverlapping.php @@ -13,7 +13,7 @@ final class TimesheetOverlapping extends TimesheetConstraint { public const RECORD_OVERLAPPING = 'kimai-timesheet-overlapping-01'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::RECORD_OVERLAPPING => 'You already have an entry for this time.', ]; diff --git a/src/Validator/Constraints/TimesheetRestart.php b/src/Validator/Constraints/TimesheetRestart.php index 91a19912..751c66d0 100644 --- a/src/Validator/Constraints/TimesheetRestart.php +++ b/src/Validator/Constraints/TimesheetRestart.php @@ -13,7 +13,7 @@ final class TimesheetRestart extends TimesheetConstraint { public const START_DISALLOWED = 'kimai-timesheet-restart-01'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::START_DISALLOWED => 'You are not allowed to start this timesheet record.', ]; diff --git a/src/Validator/Constraints/TimesheetRestartValidator.php b/src/Validator/Constraints/TimesheetRestartValidator.php index 30c1e9a1..4333bcba 100644 --- a/src/Validator/Constraints/TimesheetRestartValidator.php +++ b/src/Validator/Constraints/TimesheetRestartValidator.php @@ -11,7 +11,7 @@ namespace App\Validator\Constraints; use App\Entity\Timesheet as TimesheetEntity; use App\Timesheet\TrackingModeService; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; diff --git a/src/Validator/Constraints/TimesheetZeroDuration.php b/src/Validator/Constraints/TimesheetZeroDuration.php index cbdd4565..16bde215 100644 --- a/src/Validator/Constraints/TimesheetZeroDuration.php +++ b/src/Validator/Constraints/TimesheetZeroDuration.php @@ -13,7 +13,7 @@ final class TimesheetZeroDuration extends TimesheetConstraint { public const ZERO_DURATION_ERROR = 'kimai-timesheet-zero-duration-01'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::ZERO_DURATION_ERROR => 'Duration cannot be zero.', ]; diff --git a/src/Validator/Constraints/User.php b/src/Validator/Constraints/User.php index 41584a72..0bcfcc8c 100644 --- a/src/Validator/Constraints/User.php +++ b/src/Validator/Constraints/User.php @@ -19,7 +19,7 @@ final class User extends Constraint public const USER_EXISTING_EMAIL_AS_NAME = 'kimai-user-02'; public const USER_EXISTING_NAME_AS_EMAIL = 'kimai-user-03'; - protected static $errorNames = [ + protected const ERROR_NAMES = [ self::USER_EXISTING_EMAIL => 'The email is already used.', self::USER_EXISTING_NAME => 'The username is already used.', self::USER_EXISTING_EMAIL_AS_NAME => 'An equal username is already used.', diff --git a/symfony.lock b/symfony.lock index d1ff8086..33194aac 100644 --- a/symfony.lock +++ b/symfony.lock @@ -379,15 +379,6 @@ "sebastian/version": { "version": "2.0.1" }, - "sensio/framework-extra-bundle": { - "version": "4.0", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "master", - "version": "4.0", - "ref": "aaddfdf43cdecd4cf91f992052d76c2cadc04543" - } - }, "setasign/fpdi": { "version": "1.6.2" }, diff --git a/templates/invoice/renderer/default.pdf.twig b/templates/invoice/renderer/default.pdf.twig index ee6173a0..3cfbe1b9 100644 --- a/templates/invoice/renderer/default.pdf.twig +++ b/templates/invoice/renderer/default.pdf.twig @@ -32,10 +32,10 @@ {{ 'contact'|trans }}: - {{ model.template.contact|nl2str(' – ') }} + {{ model.template.contact|nl2str(' – ') }}
{{ 'invoice_bank_account'|trans }}: - {{ model.template.paymentDetails|nl2str(' – ') }} + {{ model.template.paymentDetails|nl2str(' – ') }} {{ 'export.page_of'|trans({'%page%': '{PAGENO}', '%pages%': '{nb}'}) }} diff --git a/templates/invoice/renderer/invoice.html.twig b/templates/invoice/renderer/invoice.html.twig index 3c8dbd56..5ade51cf 100644 --- a/templates/invoice/renderer/invoice.html.twig +++ b/templates/invoice/renderer/invoice.html.twig @@ -138,11 +138,11 @@

- {{ 'address'|trans }}: {{ model.template.company }} – {{ model.template.address|nl2str(' – ') }} + {{ 'address'|trans }}: {{ model.template.company }} – {{ model.template.address|nl2str(' – ') }}
- {{ 'invoice_bank_account'|trans }}: {{ model.template.paymentDetails|nl2str(' – ') }} + {{ 'invoice_bank_account'|trans }}: {{ model.template.paymentDetails|nl2str(' – ') }}
- {{ 'contact'|trans }}: {{ model.template.contact|nl2str(' – ') }} + {{ 'contact'|trans }}: {{ model.template.contact|nl2str(' – ') }}

{% endblock %} diff --git a/templates/invoice/renderer/service-date.pdf.twig b/templates/invoice/renderer/service-date.pdf.twig index 3b6e02c4..de14028f 100644 --- a/templates/invoice/renderer/service-date.pdf.twig +++ b/templates/invoice/renderer/service-date.pdf.twig @@ -18,7 +18,7 @@
- {{ model.template.company }} – {{ model.template.address|nl2str(' – ') }} + {{ model.template.company }} – {{ model.template.address|nl2str(' – ') }} {% if model.template.vatId is not empty %} – {{ 'vat_id'|trans }}: {{ model.template.vatId }} {% endif %} diff --git a/templates/user/stats.html.twig b/templates/user/stats.html.twig index c6895df6..d0ff6dd2 100644 --- a/templates/user/stats.html.twig +++ b/templates/user/stats.html.twig @@ -18,11 +18,11 @@ } %} {% if user.accountNumber is not empty %} {% set datagrid = datagrid|merge({ - 'account_number' : (user.accountNumber ?? '–'), + 'account_number' : (user.accountNumber ?? '–'), }) %} {% endif %} {% set datagrid = datagrid|merge({ - 'profile.first_entry' : (firstTimesheet is not null ? firstTimesheet|date_short : '–'), + 'profile.first_entry' : (firstTimesheet is not null ? firstTimesheet|date_short : '–'), 'profile.registration_date' : user.registeredAt|date_short, }) %} {% set seeOwnRate = false %} diff --git a/tests/API/ApiDocControllerTest.php b/tests/API/ApiDocControllerTest.php index bba4b4ba..3e4e67c7 100644 --- a/tests/API/ApiDocControllerTest.php +++ b/tests/API/ApiDocControllerTest.php @@ -110,7 +110,7 @@ class ApiDocControllerTest extends ControllerBaseTest $this->assertArrayHasKey('security', $json); $this->assertArrayHasKey('X-AUTH-USER', $json['security'][0]); - $this->assertArrayHasKey('X-AUTH-TOKEN', $json['security'][1]); + $this->assertArrayHasKey('X-AUTH-TOKEN', $json['security'][0]); $this->assertArrayHasKey('components', $json); $this->assertArrayHasKey('schemas', $json['components']); diff --git a/tests/API/ProjectControllerTest.php b/tests/API/ProjectControllerTest.php index b093bc32..ce4f4970 100644 --- a/tests/API/ProjectControllerTest.php +++ b/tests/API/ProjectControllerTest.php @@ -111,25 +111,45 @@ class ProjectControllerTest extends APIControllerBaseTest $customer = $em->getRepository(Customer::class)->find(1); - $customer2 = (new Customer('first one'))->setVisible(false)->setCountry('de')->setTimezone('Europe/Berlin'); + $customer2 = new Customer('first one'); + $customer2->setVisible(false); + $customer2->setCountry('de'); + $customer2->setTimezone('Europe/Berlin'); $em->persist($customer2); - $customer3 = (new Customer('second one'))->setCountry('at')->setTimezone('Europe/Vienna'); + $customer3 = new Customer('second one'); + $customer3->setCountry('at'); + $customer3->setTimezone('Europe/Vienna'); $em->persist($customer3); - $project = (new Project())->setName('first')->setVisible(false)->setCustomer($customer2); + $project = new Project(); + $project->setName('first'); + $project->setVisible(false); + $project->setCustomer($customer2); $em->persist($project); - $project = (new Project())->setName('second')->setVisible(false)->setCustomer($customer); + $project = new Project(); + $project->setName('second'); + $project->setVisible(false); + $project->setCustomer($customer); $em->persist($project); - $project = (new Project())->setName('third')->setVisible(true)->setCustomer($customer2); + $project = new Project(); + $project->setName('third'); + $project->setVisible(true); + $project->setCustomer($customer2); $em->persist($project); - $project = (new Project())->setName('fourth')->setVisible(true)->setCustomer($customer3); + $project = new Project(); + $project->setName('fourth'); + $project->setVisible(true); + $project->setCustomer($customer3); $em->persist($project); - $project = (new Project())->setName('fifth')->setVisible(true)->setCustomer($customer); + $project = new Project(); + $project->setName('fifth'); + $project->setVisible(true); + $project->setCustomer($customer); // add meta fields $meta = new ProjectMeta(); @@ -227,25 +247,23 @@ class ProjectControllerTest extends APIControllerBaseTest $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); $em = $this->getEntityManager(); - $customer = (new Customer('first one')) - ->setVisible(true) - ->setCountry('de') - ->setTimezone('Europe/Berlin') - ; + $customer = new Customer('first one'); + $customer->setVisible(true); + $customer->setCountry('de'); + $customer->setTimezone('Europe/Berlin'); $em->persist($customer); $orderDate = new \DateTime('2019-11-29 14:35:17', new \DateTimeZone('Pacific/Tongatapu')); $startDate = new \DateTime('2020-01-07 18:19:20', new \DateTimeZone('Pacific/Tongatapu')); $endDate = new \DateTime('2021-03-23 00:00:01', new \DateTimeZone('Pacific/Tongatapu')); - $project = (new Project()) - ->setName('first') - ->setVisible(true) - ->setCustomer($customer) - ->setOrderDate($orderDate) - ->setStart($startDate) - ->setEnd($endDate) - ; + $project = new Project(); + $project->setName('first'); + $project->setVisible(true); + $project->setCustomer($customer); + $project->setOrderDate($orderDate); + $project->setStart($startDate); + $project->setEnd($endDate); $em->persist($project); $em->flush(); diff --git a/tests/API/Serializer/ValidationFailedExceptionErrorHandlerTest.php b/tests/API/Serializer/ValidationFailedExceptionErrorHandlerTest.php index 67123f44..526a87b1 100644 --- a/tests/API/Serializer/ValidationFailedExceptionErrorHandlerTest.php +++ b/tests/API/Serializer/ValidationFailedExceptionErrorHandlerTest.php @@ -16,8 +16,8 @@ use JMS\Serializer\GraphNavigatorInterface; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\SerializationContext; use PHPUnit\Framework\TestCase; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\ErrorHandler\Exception\FlattenException; -use Symfony\Component\Security\Core\Security; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Contracts\Translation\TranslatorInterface; diff --git a/tests/API/TimesheetControllerTest.php b/tests/API/TimesheetControllerTest.php index 9ca9e342..ca5befd1 100644 --- a/tests/API/TimesheetControllerTest.php +++ b/tests/API/TimesheetControllerTest.php @@ -467,11 +467,19 @@ class TimesheetControllerTest extends APIControllerBaseTest $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); $em = $this->getEntityManager(); - $customer = (new Customer('foo-bar-1'))->setVisible(false)->setCountry('DE')->setTimezone('Europe/Berlin'); + $customer = new Customer('foo-bar-1'); + $customer->setVisible(false); + $customer->setCountry('DE'); + $customer->setTimezone('Europe/Berlin'); $em->persist($customer); - $project = (new Project())->setName('foo-bar-2')->setVisible(true)->setCustomer($customer); + $project = new Project(); + $project->setName('foo-bar-2'); + $project->setVisible(true); + $project->setCustomer($customer); $em->persist($project); - $activity = (new Activity())->setName('foo-bar-3')->setVisible(true); + $activity = new Activity(); + $activity->setName('foo-bar-3'); + $activity->setVisible(true); $em->persist($activity); $em->flush(); @@ -493,11 +501,19 @@ class TimesheetControllerTest extends APIControllerBaseTest $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); $em = $this->getEntityManager(); - $customer = (new Customer('foo-bar-1'))->setVisible(true)->setCountry('DE')->setTimezone('Europe/Berlin'); + $customer = new Customer('foo-bar-1'); + $customer->setVisible(true); + $customer->setCountry('DE'); + $customer->setTimezone('Europe/Berlin'); $em->persist($customer); - $project = (new Project())->setName('foo-bar-2')->setVisible(true)->setCustomer($customer); + $project = new Project(); + $project->setName('foo-bar-2'); + $project->setVisible(true); + $project->setCustomer($customer); $em->persist($project); - $activity = (new Activity())->setName('foo-bar-3')->setVisible(false); + $activity = new Activity(); + $activity->setName('foo-bar-3'); + $activity->setVisible(false); $em->persist($activity); $em->flush(); @@ -517,12 +533,17 @@ class TimesheetControllerTest extends APIControllerBaseTest $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); $em = $this->getEntityManager(); - $customer = (new Customer('foo-bar-1'))->setCountry('DE')->setTimezone('Europe/Berlin'); + $customer = new Customer('foo-bar-1'); + $customer->setCountry('DE'); + $customer->setTimezone('Europe/Berlin'); $customer->setBillable(false); $em->persist($customer); - $project = (new Project())->setName('foo-bar-2')->setCustomer($customer); + $project = new Project(); + $project->setName('foo-bar-2'); + $project->setCustomer($customer); $em->persist($project); - $activity = (new Activity())->setName('foo-bar-3'); + $activity = new Activity(); + $activity->setName('foo-bar-3'); $em->persist($activity); $em->flush(); @@ -547,12 +568,17 @@ class TimesheetControllerTest extends APIControllerBaseTest $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); $em = $this->getEntityManager(); - $customer = (new Customer('foo-bar-1'))->setCountry('DE')->setTimezone('Europe/Berlin'); + $customer = new Customer('foo-bar-1'); + $customer->setCountry('DE'); + $customer->setTimezone('Europe/Berlin'); $customer->setBillable(false); $em->persist($customer); - $project = (new Project())->setName('foo-bar-2')->setCustomer($customer); + $project = new Project(); + $project->setName('foo-bar-2'); + $project->setCustomer($customer); $em->persist($project); - $activity = (new Activity())->setName('foo-bar-3'); + $activity = new Activity(); + $activity->setName('foo-bar-3'); $em->persist($activity); $em->flush(); diff --git a/tests/Controller/Auth/SamlControllerTest.php b/tests/Controller/Auth/SamlControllerTest.php index 497c89fa..37eef1b9 100644 --- a/tests/Controller/Auth/SamlControllerTest.php +++ b/tests/Controller/Auth/SamlControllerTest.php @@ -18,11 +18,11 @@ use App\Tests\Mocks\Saml\SamlAuthFactoryFactory; use App\Tests\Mocks\SystemConfigurationFactory; use OneLogin\Saml2\Auth; use PHPUnit\Framework\TestCase; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Symfony\Component\Security\Core\Security; /** * @group integration diff --git a/tests/DependencyInjection/Compiler/ExportServiceCompilerPassTest.php b/tests/DependencyInjection/Compiler/ExportServiceCompilerPassTest.php new file mode 100644 index 00000000..eeac830e --- /dev/null +++ b/tests/DependencyInjection/Compiler/ExportServiceCompilerPassTest.php @@ -0,0 +1,69 @@ +setParameter('kimai.export.documents', []); // TODO we could test that as well + + $definition = new Definition(ServiceExport::class); + $container->setDefinition(ServiceExport::class, $definition); + + $renderers = [CsvRenderer::class, HtmlRenderer::class]; + foreach ($renderers as $renderer) { + $container->register($renderer)->addTag(Kernel::TAG_EXPORT_RENDERER); + } + + $exporters = [PDFRenderer::class, XlsxRenderer::class]; + foreach ($exporters as $exporter) { + $container->register($exporter)->addTag(Kernel::TAG_TIMESHEET_EXPORTER); + } + + $repositories = [TimesheetExportRepository::class]; + foreach ($repositories as $repository) { + $container->register($repository)->addTag(Kernel::TAG_EXPORT_REPOSITORY); + } + + return $container; + } + + public function testCallsAreAdded(): void + { + $container = $this->getContainer(); + $sut = new ExportServiceCompilerPass(); + $sut->process($container); + + $definition = $container->findDefinition(ServiceExport::class); + $methods = $definition->getMethodCalls(); + + self::assertCount(5, $methods); + self::assertTrue($definition->hasMethodCall('addRenderer')); + self::assertTrue($definition->hasMethodCall('addTimesheetExporter')); + self::assertTrue($definition->hasMethodCall('addExportRepository')); + } +} diff --git a/tests/DependencyInjection/Compiler/InvoiceServiceCompilerPassTest.php b/tests/DependencyInjection/Compiler/InvoiceServiceCompilerPassTest.php new file mode 100644 index 00000000..6b61e35f --- /dev/null +++ b/tests/DependencyInjection/Compiler/InvoiceServiceCompilerPassTest.php @@ -0,0 +1,76 @@ +setDefinition(ServiceInvoice::class, $definition); + + $renderers = [DocxRenderer::class]; + foreach ($renderers as $renderer) { + $container->register($renderer)->addTag(Kernel::TAG_INVOICE_RENDERER); + } + + $numberGenerators = [DateNumberGenerator::class, ConfigurableNumberGenerator::class]; + foreach ($numberGenerators as $numberGenerator) { + $container->register($numberGenerator)->addTag(Kernel::TAG_INVOICE_NUMBER_GENERATOR); + } + + $calculators = [DefaultCalculator::class, UserInvoiceCalculator::class, ShortInvoiceCalculator::class]; + foreach ($calculators as $calculator) { + $container->register($calculator)->addTag(Kernel::TAG_INVOICE_CALCULATOR); + } + + $repositories = [TimesheetInvoiceItemRepository::class]; + foreach ($repositories as $repository) { + $container->register($repository)->addTag(Kernel::TAG_INVOICE_REPOSITORY); + } + + return $container; + } + + public function testCallsAreAdded(): void + { + $container = $this->getContainer(); + $sut = new InvoiceServiceCompilerPass(); + $sut->process($container); + + $definition = $container->findDefinition(ServiceInvoice::class); + $methods = $definition->getMethodCalls(); + + self::assertCount(7, $methods); + self::assertTrue($definition->hasMethodCall('addRenderer')); + self::assertTrue($definition->hasMethodCall('addNumberGenerator')); + self::assertTrue($definition->hasMethodCall('addCalculator')); + self::assertTrue($definition->hasMethodCall('addInvoiceItemRepository')); + } +} diff --git a/tests/DependencyInjection/Compiler/TwigContextCompilerPassTest.php b/tests/DependencyInjection/Compiler/TwigContextCompilerPassTest.php new file mode 100644 index 00000000..4a9ca45c --- /dev/null +++ b/tests/DependencyInjection/Compiler/TwigContextCompilerPassTest.php @@ -0,0 +1,65 @@ +setParameter('kimai.invoice.documents', []); // TODO we could test that as well + $container->setParameter('kimai.export.documents', []); // TODO we could test that as well + + $definition = new Definition('twig'); + $container->setDefinition('twig', $definition); + + $definition = new Definition('twig.loader.native_filesystem'); + $container->setDefinition('twig.loader.native_filesystem', $definition); + + $definition = new Definition(ServiceExport::class); + $container->setDefinition(ServiceExport::class, $definition); + + $definition = new Definition(Context::class); + $container->setDefinition(Context::class, $definition); + + $definition = new Definition(Configuration::class); + $container->setDefinition(Configuration::class, $definition); + + return $container; + } + + public function testCallsAreAdded(): void + { + $container = $this->getContainer(); + $sut = new TwigContextCompilerPass(); + $sut->process($container); + + $definition = $container->findDefinition('twig'); + $methods = $definition->getMethodCalls(); + + self::assertCount(2, $methods); + self::assertTrue($definition->hasMethodCall('addGlobal')); + self::assertEquals('addGlobal', $methods[0][0]); + self::assertEquals('kimai_context', $methods[0][1][0]); + self::assertEquals('addGlobal', $methods[1][0]); + self::assertEquals('kimai_config', $methods[1][1][0]); + } +} diff --git a/tests/DependencyInjection/Compiler/WidgetCompilerPassTest.php b/tests/DependencyInjection/Compiler/WidgetCompilerPassTest.php new file mode 100644 index 00000000..d3a266ab --- /dev/null +++ b/tests/DependencyInjection/Compiler/WidgetCompilerPassTest.php @@ -0,0 +1,53 @@ +setDefinition(WidgetService::class, $definition); + + $widgets = [ActiveTimesheets::class, ActiveUsersMonth::class]; + foreach ($widgets as $widget) { + $container->register($widget)->addTag(Kernel::TAG_WIDGET); + } + + return $container; + } + + public function testCallsAreAdded(): void + { + $container = $this->getContainer(); + $sut = new WidgetCompilerPass(); + $sut->process($container); + + $definition = $container->findDefinition(WidgetService::class); + $methods = $definition->getMethodCalls(); + + self::assertCount(2, $methods); + self::assertTrue($definition->hasMethodCall('registerWidget')); + } +} diff --git a/tests/Entity/CustomerTest.php b/tests/Entity/CustomerTest.php index 724d4d93..8d836fbe 100644 --- a/tests/Entity/CustomerTest.php +++ b/tests/Entity/CustomerTest.php @@ -65,7 +65,7 @@ class CustomerTest extends AbstractEntityTest self::assertEquals('foo-bar', $sut->getName()); self::assertEquals('foo-bar', (string) $sut); - self::assertInstanceOf(Customer::class, $sut->setVisible(false)); + $sut->setVisible(false); self::assertFalse($sut->isVisible()); $sut->setVisible(false); @@ -73,7 +73,7 @@ class CustomerTest extends AbstractEntityTest $sut->setVisible(true); self::assertTrue($sut->isVisible()); - self::assertInstanceOf(Customer::class, $sut->setComment('hello world')); + $sut->setComment('hello world'); self::assertEquals('hello world', $sut->getComment()); self::assertFalse($sut->hasColor()); @@ -85,35 +85,38 @@ class CustomerTest extends AbstractEntityTest self::assertNull($sut->getColor()); self::assertFalse($sut->hasColor()); - self::assertInstanceOf(Customer::class, $sut->setCompany('test company')); + $sut->setCompany('test company'); self::assertEquals('test company', $sut->getCompany()); - self::assertInstanceOf(Customer::class, $sut->setContact('test contact')); + $sut->setContact('test contact'); self::assertEquals('test contact', $sut->getContact()); - self::assertInstanceOf(Customer::class, $sut->setPhone('0123456789')); + $sut->setPhone('0123456789'); self::assertEquals('0123456789', $sut->getPhone()); - self::assertInstanceOf(Customer::class, $sut->setFax('asdfghjkl')); + $sut->setFax('asdfghjkl'); self::assertEquals('asdfghjkl', $sut->getFax()); - self::assertInstanceOf(Customer::class, $sut->setMobile('76576534')); + $sut->setMobile('76576534'); self::assertEquals('76576534', $sut->getMobile()); - self::assertInstanceOf(Customer::class, $sut->setEmail('test@example.com')); + $sut->setEmail('test@example.com'); self::assertEquals('test@example.com', $sut->getEmail()); - self::assertInstanceOf(Customer::class, $sut->setHomepage('https://www.example.com')); + $sut->setHomepage('https://www.example.com'); self::assertEquals('https://www.example.com', $sut->getHomepage()); - self::assertInstanceOf(Customer::class, $sut->setVatId('ID 1234567890')); + $sut->setVatId('ID 1234567890'); self::assertEquals('ID 1234567890', $sut->getVatId()); - self::assertInstanceOf(Customer::class, $sut->setCountry(null)); + $sut->setCountry(null); self::assertNull($sut->getCountry()); - self::assertInstanceOf(Customer::class, $sut->setCurrency('USD')); + $sut->setCurrency('USD'); self::assertEquals('USD', $sut->getCurrency()); + + $sut->setCurrency(null); + self::assertNull($sut->getCurrency()); } public function testMetaFields() diff --git a/tests/Entity/TimesheetValidationTest.php b/tests/Entity/TimesheetValidationTest.php index 86397a8a..dd3685f5 100644 --- a/tests/Entity/TimesheetValidationTest.php +++ b/tests/Entity/TimesheetValidationTest.php @@ -50,11 +50,9 @@ class TimesheetValidationTest extends KernelTestCase $project->setCustomer(new Customer('foo')); $entity = new Timesheet(); - $entity - ->setUser(new User()) - ->setProject($project) - ->setBegin(new \DateTime()) - ; + $entity->setUser(new User()); + $entity->setProject($project); + $entity->setBegin(new \DateTime()); $this->assertHasViolationForField($entity, 'activity'); } @@ -62,11 +60,9 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationNeedsProject() { $entity = new Timesheet(); - $entity - ->setUser(new User()) - ->setActivity(new Activity()) - ->setBegin(new \DateTime()) - ; + $entity->setUser(new User()); + $entity->setActivity(new Activity()); + $entity->setBegin(new \DateTime()); $this->assertHasViolationForField($entity, 'project'); } @@ -79,29 +75,30 @@ class TimesheetValidationTest extends KernelTestCase $activity = (new Activity())->setName('hello-world')->setProject($project); $entity = new Timesheet(); - $entity - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project2) - ->setBegin(new \DateTime()) - ; + $entity->setUser(new User()); + $entity->setActivity($activity); + $entity->setProject($project2); + $entity->setBegin(new \DateTime()); $this->assertHasViolationForField($entity, 'project'); } public function testValidationCustomerInvisible() { - $customer = (new Customer('foo'))->setVisible(false); - $project = (new Project())->setName('foo')->setCustomer($customer); - $activity = (new Activity())->setName('hello-world')->setProject($project); + $customer = new Customer('foo'); + $customer->setVisible(false); + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); $entity = new Timesheet(); - $entity - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ; + $entity->setUser(new User()); + $entity->setActivity($activity); + $entity->setProject($project); + $entity->setBegin(new \DateTime()); $this->assertHasViolationForField($entity, 'customer'); } @@ -109,13 +106,11 @@ class TimesheetValidationTest extends KernelTestCase private function createStoppedTimesheet(Project $project, Activity $activity, ?int $id = null): Timesheet { $entity = new Timesheet(); - $entity - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ->setEnd(new \DateTime()) - ; + $entity->setUser(new User()); + $entity->setActivity($activity); + $entity->setProject($project); + $entity->setBegin(new \DateTime()); + $entity->setEnd(new \DateTime()); if ($id !== null) { $o = new \ReflectionClass($entity); @@ -130,9 +125,14 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationCustomerInvisibleDoesNotTriggerOnStoppedEntities() { - $customer = (new Customer('foo'))->setVisible(false); - $project = (new Project())->setName('foo')->setCustomer($customer); - $activity = (new Activity())->setName('hello-world')->setProject($project); + $customer = new Customer('foo'); + $customer->setVisible(false); + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); $entity = $this->createStoppedTimesheet($project, $activity, 99); @@ -141,9 +141,14 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationCustomerInvisibleDoesTriggerOnNewEntities() { - $customer = (new Customer('foo'))->setVisible(false); - $project = (new Project())->setName('foo')->setCustomer($customer); - $activity = (new Activity())->setName('hello-world')->setProject($project); + $customer = new Customer('foo'); + $customer->setVisible(false); + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); $entity = $this->createStoppedTimesheet($project, $activity); @@ -157,12 +162,10 @@ class TimesheetValidationTest extends KernelTestCase $activity = (new Activity())->setName('hello-world')->setProject($project); $entity = new Timesheet(); - $entity - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ; + $entity->setUser(new User()); + $entity->setActivity($activity); + $entity->setProject($project); + $entity->setBegin(new \DateTime()); $this->assertHasViolationForField($entity, 'project'); } @@ -196,12 +199,10 @@ class TimesheetValidationTest extends KernelTestCase $activity = (new Activity())->setName('hello-world')->setProject($project)->setVisible(false); $entity = new Timesheet(); - $entity - ->setUser(new User()) - ->setActivity($activity) - ->setProject($project) - ->setBegin(new \DateTime()) - ; + $entity->setUser(new User()); + $entity->setActivity($activity); + $entity->setProject($project); + $entity->setBegin(new \DateTime()); $this->assertHasViolationForField($entity, 'activity'); } @@ -209,8 +210,13 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationActivityInvisibleDoesNotTriggerOnStoppedEntities() { $customer = new Customer('foo'); - $project = (new Project())->setName('foo')->setCustomer($customer); - $activity = (new Activity())->setName('hello-world')->setProject($project)->setVisible(false); + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); + $activity->setVisible(false); $entity = $this->createStoppedTimesheet($project, $activity, 2); @@ -220,8 +226,13 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationActivityInvisibleDoesTriggerOnNewEntities() { $customer = new Customer('foo'); - $project = (new Project())->setName('foo')->setCustomer($customer); - $activity = (new Activity())->setName('hello-world')->setProject($project)->setVisible(false); + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); + $activity->setVisible(false); $entity = $this->createStoppedTimesheet($project, $activity); diff --git a/tests/Export/Renderer/AbstractRendererTest.php b/tests/Export/Renderer/AbstractRendererTest.php index 46969cbe..f92e179a 100644 --- a/tests/Export/Renderer/AbstractRendererTest.php +++ b/tests/Export/Renderer/AbstractRendererTest.php @@ -30,10 +30,10 @@ use App\Export\TimesheetExportInterface; use App\Repository\Query\TimesheetQuery; use App\Twig\LocaleFormatExtensions; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\Extension\Core\Type\TextType; -use Symfony\Component\Security\Core\Security; use Symfony\Contracts\Translation\TranslatorInterface; abstract class AbstractRendererTest extends KernelTestCase diff --git a/tests/Export/Timesheet/AbstractRendererTest.php b/tests/Export/Timesheet/AbstractRendererTest.php index 503f1dce..25b6fbe9 100644 --- a/tests/Export/Timesheet/AbstractRendererTest.php +++ b/tests/Export/Timesheet/AbstractRendererTest.php @@ -29,10 +29,10 @@ use App\Export\TimesheetExportInterface; use App\Repository\Query\TimesheetQuery; use App\Twig\LocaleFormatExtensions; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\Extension\Core\Type\TextType; -use Symfony\Component\Security\Core\Security; use Symfony\Contracts\Translation\TranslatorInterface; abstract class AbstractRendererTest extends KernelTestCase diff --git a/tests/Form/Type/QuickEntryTimesheetTypeTest.php b/tests/Form/Type/QuickEntryTimesheetTypeTest.php index 1bf23d65..ebfb0448 100644 --- a/tests/Form/Type/QuickEntryTimesheetTypeTest.php +++ b/tests/Form/Type/QuickEntryTimesheetTypeTest.php @@ -12,9 +12,9 @@ namespace App\Tests\Form\Type; use App\Entity\Timesheet; use App\Entity\User; use App\Form\Type\QuickEntryTimesheetType; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\PreloadedExtension; use Symfony\Component\Form\Test\TypeTestCase; -use Symfony\Component\Security\Core\Security; /** * @covers \App\Form\Type\QuickEntryTimesheetType diff --git a/tests/Twig/LocaleFormatExtensionsTest.php b/tests/Twig/LocaleFormatExtensionsTest.php index 76f327c9..eff472ea 100644 --- a/tests/Twig/LocaleFormatExtensionsTest.php +++ b/tests/Twig/LocaleFormatExtensionsTest.php @@ -15,8 +15,8 @@ use App\Entity\User; use App\Entity\UserPreference; use App\Twig\LocaleFormatExtensions; use PHPUnit\Framework\TestCase; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Intl\Util\IntlTestHelper; -use Symfony\Component\Security\Core\Security; use Twig\TwigFilter; use Twig\TwigFunction; use Twig\TwigTest; diff --git a/tests/Twig/Runtime/WidgetExtensionTest.php b/tests/Twig/Runtime/WidgetExtensionTest.php index 11c2b37d..8eb9b7fb 100644 --- a/tests/Twig/Runtime/WidgetExtensionTest.php +++ b/tests/Twig/Runtime/WidgetExtensionTest.php @@ -14,10 +14,10 @@ use App\Twig\Runtime\WidgetExtension; use App\Widget\Type\More; use App\Widget\WidgetService; use PHPUnit\Framework\TestCase; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Security; use Twig\Environment; /** diff --git a/tests/Validator/Constraints/ColorChoicesValidatorTest.php b/tests/Validator/Constraints/ColorChoicesValidatorTest.php index 806bf11c..8e5617b0 100644 --- a/tests/Validator/Constraints/ColorChoicesValidatorTest.php +++ b/tests/Validator/Constraints/ColorChoicesValidatorTest.php @@ -18,10 +18,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\ColorChoices * @covers \App\Validator\Constraints\ColorChoicesValidator + * @extends ConstraintValidatorTestCase */ class ColorChoicesValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): ColorChoicesValidator { return new ColorChoicesValidator(); } diff --git a/tests/Validator/Constraints/DateTimeFormatValidatorTest.php b/tests/Validator/Constraints/DateTimeFormatValidatorTest.php index dfc0e414..0de579da 100644 --- a/tests/Validator/Constraints/DateTimeFormatValidatorTest.php +++ b/tests/Validator/Constraints/DateTimeFormatValidatorTest.php @@ -18,10 +18,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\DateTimeFormat * @covers \App\Validator\Constraints\DateTimeFormatValidator + * @extends ConstraintValidatorTestCase */ class DateTimeFormatValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): DateTimeFormatValidator { return new DateTimeFormatValidator(); } diff --git a/tests/Validator/Constraints/DurationValidatorTest.php b/tests/Validator/Constraints/DurationValidatorTest.php index 648aebd0..7a766918 100644 --- a/tests/Validator/Constraints/DurationValidatorTest.php +++ b/tests/Validator/Constraints/DurationValidatorTest.php @@ -19,10 +19,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\Duration * @covers \App\Validator\Constraints\DurationValidator + * @extends ConstraintValidatorTestCase */ class DurationValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): DurationValidator { return new DurationValidator(); } diff --git a/tests/Validator/Constraints/HexColorValidatorTest.php b/tests/Validator/Constraints/HexColorValidatorTest.php index 3be0f1a9..80fcc40b 100644 --- a/tests/Validator/Constraints/HexColorValidatorTest.php +++ b/tests/Validator/Constraints/HexColorValidatorTest.php @@ -18,10 +18,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\HexColor * @covers \App\Validator\Constraints\HexColorValidator + * @extends ConstraintValidatorTestCase */ class HexColorValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): HexColorValidator { return new HexColorValidator(); } diff --git a/tests/Validator/Constraints/ProjectValidatorTest.php b/tests/Validator/Constraints/ProjectValidatorTest.php index cd21e0d2..7e204946 100644 --- a/tests/Validator/Constraints/ProjectValidatorTest.php +++ b/tests/Validator/Constraints/ProjectValidatorTest.php @@ -19,10 +19,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\Project * @covers \App\Validator\Constraints\ProjectValidator + * @extends ConstraintValidatorTestCase */ class ProjectValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): ProjectValidator { return new ProjectValidator(); } diff --git a/tests/Validator/Constraints/QuickEntryModelValidatorTest.php b/tests/Validator/Constraints/QuickEntryModelValidatorTest.php index e1e71d0e..ceb7cf85 100644 --- a/tests/Validator/Constraints/QuickEntryModelValidatorTest.php +++ b/tests/Validator/Constraints/QuickEntryModelValidatorTest.php @@ -22,10 +22,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\QuickEntryModel * @covers \App\Validator\Constraints\QuickEntryModelValidator + * @extends ConstraintValidatorTestCase */ class QuickEntryModelValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): QuickEntryModelValidator { return new QuickEntryModelValidator(); } diff --git a/tests/Validator/Constraints/QuickEntryTimesheetValidatorTest.php b/tests/Validator/Constraints/QuickEntryTimesheetValidatorTest.php index 31dc8792..1d37f3c6 100644 --- a/tests/Validator/Constraints/QuickEntryTimesheetValidatorTest.php +++ b/tests/Validator/Constraints/QuickEntryTimesheetValidatorTest.php @@ -14,23 +14,24 @@ use App\Entity\Timesheet; use App\Validator\Constraints\QuickEntryTimesheet; use App\Validator\Constraints\QuickEntryTimesheetValidator; use App\Validator\Constraints\TimesheetBasic; -use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\ConstraintValidatorInterface; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\QuickEntryTimesheet * @covers \App\Validator\Constraints\QuickEntryTimesheetValidator + * @extends ConstraintValidatorTestCase */ class QuickEntryTimesheetValidatorTest extends ConstraintValidatorTestCase { - protected function createConstraint(): Constraint + protected function createConstraint(): QuickEntryTimesheet { return new QuickEntryTimesheet(); } - protected function createValidator() + protected function createValidator(): ConstraintValidatorInterface { return new QuickEntryTimesheetValidator([new TimesheetBasic()]); } diff --git a/tests/Validator/Constraints/RoleNameValidatorTest.php b/tests/Validator/Constraints/RoleNameValidatorTest.php index 13a887af..f9247519 100644 --- a/tests/Validator/Constraints/RoleNameValidatorTest.php +++ b/tests/Validator/Constraints/RoleNameValidatorTest.php @@ -20,6 +20,7 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\RoleName * @covers \App\Validator\Constraints\RoleNameValidator + * @extends ConstraintValidatorTestCase */ class RoleNameValidatorTest extends ConstraintValidatorTestCase { diff --git a/tests/Validator/Constraints/RoleValidatorTest.php b/tests/Validator/Constraints/RoleValidatorTest.php index 43ca5dcc..e55ffcc3 100644 --- a/tests/Validator/Constraints/RoleValidatorTest.php +++ b/tests/Validator/Constraints/RoleValidatorTest.php @@ -20,10 +20,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\Role * @covers \App\Validator\Constraints\RoleValidator + * @extends ConstraintValidatorTestCase */ class RoleValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): RoleValidator { $factory = new RoleServiceFactory($this); $roleService = $factory->create(); diff --git a/tests/Validator/Constraints/TeamValidatorTest.php b/tests/Validator/Constraints/TeamValidatorTest.php index ce041c5e..6a0f5467 100644 --- a/tests/Validator/Constraints/TeamValidatorTest.php +++ b/tests/Validator/Constraints/TeamValidatorTest.php @@ -21,10 +21,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\Team * @covers \App\Validator\Constraints\TeamValidator + * @extends ConstraintValidatorTestCase */ class TeamValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TeamValidator { return new TeamValidator(); } @@ -33,7 +34,7 @@ class TeamValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate('foo', new NotBlank()); + $this->validator->validate('foo', new NotBlank()); // @phpstan-ignore-line } public function testMissingTeamlead() diff --git a/tests/Validator/Constraints/TimeFormatValidatorTest.php b/tests/Validator/Constraints/TimeFormatValidatorTest.php index 4745e61d..e21af9ae 100644 --- a/tests/Validator/Constraints/TimeFormatValidatorTest.php +++ b/tests/Validator/Constraints/TimeFormatValidatorTest.php @@ -19,10 +19,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimeFormat * @covers \App\Validator\Constraints\TimeFormatValidator + * @extends ConstraintValidatorTestCase */ class TimeFormatValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimeFormatValidator { return new TimeFormatValidator(); } diff --git a/tests/Validator/Constraints/TimesheetBasicValidatorTest.php b/tests/Validator/Constraints/TimesheetBasicValidatorTest.php index 72c29297..e411e950 100644 --- a/tests/Validator/Constraints/TimesheetBasicValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetBasicValidatorTest.php @@ -23,15 +23,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetBasic * @covers \App\Validator\Constraints\TimesheetBasicValidator + * @extends ConstraintValidatorTestCase */ class TimesheetBasicValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimesheetBasicValidator { return $this->createMyValidator(); } - protected function createMyValidator() + protected function createMyValidator(): TimesheetBasicValidator { $configuration = SystemConfigurationFactory::createStub(['timesheet' => ['rules' => ['require_activity' => true]]]); diff --git a/tests/Validator/Constraints/TimesheetBudgetUsedValidatorTest.php b/tests/Validator/Constraints/TimesheetBudgetUsedValidatorTest.php index 53c6cf22..1f311af5 100644 --- a/tests/Validator/Constraints/TimesheetBudgetUsedValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetBudgetUsedValidatorTest.php @@ -40,10 +40,14 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetBudgetUsed * @covers \App\Validator\Constraints\TimesheetBudgetUsedValidator + * @extends ConstraintValidatorTestCase */ class TimesheetBudgetUsedValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator(bool $isAllowed = false, ?ActivityBudgetStatisticModel $activityStatisticModel = null, ?ProjectBudgetStatisticModel $projectStatisticModel = null, ?CustomerBudgetStatisticModel $customerStatisticModel = null, ?array $rawData = null, ?Rate $rate = null) + /** + * @param array|null $rawData + */ + protected function createValidator(bool $isAllowed = false, ?ActivityBudgetStatisticModel $activityStatisticModel = null, ?ProjectBudgetStatisticModel $projectStatisticModel = null, ?CustomerBudgetStatisticModel $customerStatisticModel = null, ?array $rawData = null, ?Rate $rate = null): TimesheetBudgetUsedValidator { $configuration = SystemConfigurationFactory::createStub(['timesheet' => ['rules' => ['allow_overbooking_budget' => $isAllowed]]]); @@ -117,7 +121,7 @@ class TimesheetBudgetUsedValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate('foo', new TimesheetBudgetUsed()); + $this->validator->validate('foo', new TimesheetBudgetUsed()); // @phpstan-ignore-line } public function testWithMissingEnd() diff --git a/tests/Validator/Constraints/TimesheetExportedValidatorTest.php b/tests/Validator/Constraints/TimesheetExportedValidatorTest.php index 14e2ded2..00a4a184 100644 --- a/tests/Validator/Constraints/TimesheetExportedValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetExportedValidatorTest.php @@ -13,7 +13,7 @@ use App\Entity\Timesheet; use App\Entity\User; use App\Validator\Constraints\TimesheetExported; use App\Validator\Constraints\TimesheetExportedValidator; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; @@ -21,15 +21,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetExported * @covers \App\Validator\Constraints\TimesheetExportedValidator + * @extends ConstraintValidatorTestCase */ class TimesheetExportedValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimesheetExportedValidator { return $this->createMyValidator(true); } - protected function createMyValidator(bool $allowEdit) + protected function createMyValidator(bool $allowEdit): TimesheetExportedValidator { $auth = $this->createMock(Security::class); $auth->method('getUser')->willReturn(new User()); @@ -58,7 +59,7 @@ class TimesheetExportedValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetExported(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetExported(['message' => 'myMessage'])); // @phpstan-ignore-line } public function testTriggersOnMissingPermission() diff --git a/tests/Validator/Constraints/TimesheetFutureTimesValidatorTest.php b/tests/Validator/Constraints/TimesheetFutureTimesValidatorTest.php index 1db91c94..8825a855 100644 --- a/tests/Validator/Constraints/TimesheetFutureTimesValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetFutureTimesValidatorTest.php @@ -21,15 +21,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetFutureTimes * @covers \App\Validator\Constraints\TimesheetFutureTimesValidator + * @extends ConstraintValidatorTestCase */ class TimesheetFutureTimesValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimesheetFutureTimesValidator { return $this->createMyValidator(false); } - protected function createMyValidator(bool $allowFutureTimes = false) + protected function createMyValidator(bool $allowFutureTimes = false): TimesheetFutureTimesValidator { $loader = $this->createMock(ConfigLoaderInterface::class); $config = SystemConfigurationFactory::create($loader, [ @@ -59,7 +60,7 @@ class TimesheetFutureTimesValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetFutureTimes(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetFutureTimes(['message' => 'myMessage'])); // @phpstan-ignore-line } public function testFutureBeginIsDisallowed() diff --git a/tests/Validator/Constraints/TimesheetLockdownValidatorTest.php b/tests/Validator/Constraints/TimesheetLockdownValidatorTest.php index 2263a4c0..23be83d3 100644 --- a/tests/Validator/Constraints/TimesheetLockdownValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetLockdownValidatorTest.php @@ -16,7 +16,7 @@ use App\Tests\Mocks\SystemConfigurationFactory; use App\Timesheet\LockdownService; use App\Validator\Constraints\TimesheetLockdown; use App\Validator\Constraints\TimesheetLockdownValidator; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; @@ -24,15 +24,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetLockdown * @covers \App\Validator\Constraints\TimesheetLockdownValidator + * @extends ConstraintValidatorTestCase */ class TimesheetLockdownValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimesheetLockdownValidator { return $this->createMyValidator(false, false, null, null, null); } - protected function createMyValidator(bool $allowOverwriteFull, bool $allowOverwriteGrace, ?string $start, ?string $end, ?string $grace) + protected function createMyValidator(bool $allowOverwriteFull, bool $allowOverwriteGrace, ?string $start, ?string $end, ?string $grace): TimesheetLockdownValidator { $auth = $this->createMock(Security::class); $auth->method('getUser')->willReturn(new User()); @@ -74,7 +75,7 @@ class TimesheetLockdownValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetLockdown(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetLockdown(['message' => 'myMessage'])); // @phpstan-ignore-line } public function testValidatorWithoutNowConstraint() diff --git a/tests/Validator/Constraints/TimesheetLongRunningValidatorTest.php b/tests/Validator/Constraints/TimesheetLongRunningValidatorTest.php index b18dd6ca..33e138c4 100644 --- a/tests/Validator/Constraints/TimesheetLongRunningValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetLongRunningValidatorTest.php @@ -21,15 +21,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetLongRunning * @covers \App\Validator\Constraints\TimesheetLongRunningValidator + * @extends ConstraintValidatorTestCase */ class TimesheetLongRunningValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimesheetLongRunningValidator { return $this->createMyValidator(120); } - protected function createMyValidator(int $minutes) + protected function createMyValidator(int $minutes): TimesheetLongRunningValidator { $loader = $this->createMock(ConfigLoaderInterface::class); $config = SystemConfigurationFactory::create($loader, [ @@ -54,7 +55,7 @@ class TimesheetLongRunningValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetLongRunning(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetLongRunning(['message' => 'myMessage'])); // @phpstan-ignore-line } public function testLongRunningTriggers() diff --git a/tests/Validator/Constraints/TimesheetMultiUpdateValidatorTest.php b/tests/Validator/Constraints/TimesheetMultiUpdateValidatorTest.php index 52577501..442c7976 100644 --- a/tests/Validator/Constraints/TimesheetMultiUpdateValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetMultiUpdateValidatorTest.php @@ -22,10 +22,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetMultiUpdate * @covers \App\Validator\Constraints\TimesheetMultiUpdateValidator + * @extends ConstraintValidatorTestCase */ class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator($isGranted = true) + protected function createValidator(): TimesheetMultiUpdateValidator { return new TimesheetMultiUpdateValidator(); } diff --git a/tests/Validator/Constraints/TimesheetMultiUserValidatorTest.php b/tests/Validator/Constraints/TimesheetMultiUserValidatorTest.php index 132f7707..09ee4e50 100644 --- a/tests/Validator/Constraints/TimesheetMultiUserValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetMultiUserValidatorTest.php @@ -19,10 +19,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetMultiUser * @covers \App\Validator\Constraints\TimesheetMultiUserValidator + * @extends ConstraintValidatorTestCase */ class TimesheetMultiUserValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator($isGranted = true) + protected function createValidator(): TimesheetMultiUserValidator { return new TimesheetMultiUserValidator(); } diff --git a/tests/Validator/Constraints/TimesheetOverlappingValidatorTest.php b/tests/Validator/Constraints/TimesheetOverlappingValidatorTest.php index cab1c5c4..0dbc1fbf 100644 --- a/tests/Validator/Constraints/TimesheetOverlappingValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetOverlappingValidatorTest.php @@ -22,15 +22,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetOverlapping * @covers \App\Validator\Constraints\TimesheetOverlappingValidator + * @extends ConstraintValidatorTestCase */ class TimesheetOverlappingValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimesheetOverlappingValidator { return $this->createMyValidator(false, true); } - protected function createMyValidator(bool $allowOverlappingRecords = false, bool $hasRecords = true) + protected function createMyValidator(bool $allowOverlappingRecords = false, bool $hasRecords = true): TimesheetOverlappingValidator { $loader = $this->createMock(ConfigLoaderInterface::class); $config = SystemConfigurationFactory::create($loader, [ @@ -57,7 +58,7 @@ class TimesheetOverlappingValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetOverlapping(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetOverlapping(['message' => 'myMessage'])); // @phpstan-ignore-line } public function testOverlappingDisallowedWithRecords() diff --git a/tests/Validator/Constraints/TimesheetRestartValidatorTest.php b/tests/Validator/Constraints/TimesheetRestartValidatorTest.php index 539c9f30..2e1605fb 100644 --- a/tests/Validator/Constraints/TimesheetRestartValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetRestartValidatorTest.php @@ -18,7 +18,7 @@ use App\Tests\Mocks\TrackingModeServiceFactory; use App\Validator\Constraints\TimesheetOverlapping; use App\Validator\Constraints\TimesheetRestart; use App\Validator\Constraints\TimesheetRestartValidator; -use Symfony\Component\Security\Core\Security; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; @@ -26,15 +26,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetRestart * @covers \App\Validator\Constraints\TimesheetRestartValidator + * @extends ConstraintValidatorTestCase */ class TimesheetRestartValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimesheetRestartValidator { return $this->createMyValidator(false, 'default'); } - protected function createMyValidator(bool $allowed, string $trackingMode) + protected function createMyValidator(bool $allowed, string $trackingMode): TimesheetRestartValidator { $auth = $this->createMock(Security::class); $auth->method('getUser')->willReturn(new User()); @@ -56,7 +57,7 @@ class TimesheetRestartValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetOverlapping(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetOverlapping(['message' => 'myMessage'])); // @phpstan-ignore-line } /** diff --git a/tests/Validator/Constraints/TimesheetValidatorTest.php b/tests/Validator/Constraints/TimesheetValidatorTest.php index 3d73570f..ce1230cc 100644 --- a/tests/Validator/Constraints/TimesheetValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetValidatorTest.php @@ -19,15 +19,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\Timesheet * @covers \App\Validator\Constraints\TimesheetValidator + * @extends ConstraintValidatorTestCase */ class TimesheetValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimesheetValidator { return $this->createMyValidator(); } - protected function createMyValidator(bool $isGranted = true) + protected function createMyValidator(bool $isGranted = true): TimesheetValidator { return new TimesheetValidator([]); } @@ -43,6 +44,6 @@ class TimesheetValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetConstraint(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetConstraint(['message' => 'myMessage'])); // @phpstan-ignore-line } } diff --git a/tests/Validator/Constraints/TimesheetZeroDurationValidatorTest.php b/tests/Validator/Constraints/TimesheetZeroDurationValidatorTest.php index b2e43b22..9ce027f6 100644 --- a/tests/Validator/Constraints/TimesheetZeroDurationValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetZeroDurationValidatorTest.php @@ -21,15 +21,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\TimesheetZeroDuration * @covers \App\Validator\Constraints\TimesheetZeroDurationValidator + * @extends ConstraintValidatorTestCase */ class TimesheetZeroDurationValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): TimesheetZeroDurationValidator { return $this->createMyValidator(false); } - protected function createMyValidator(bool $allowZeroDuration = false) + protected function createMyValidator(bool $allowZeroDuration = false): TimesheetZeroDurationValidator { $loader = $this->createMock(ConfigLoaderInterface::class); $config = SystemConfigurationFactory::create($loader, [ @@ -54,7 +55,7 @@ class TimesheetZeroDurationValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetZeroDuration(['message' => 'Duration cannot be zero.'])); + $this->validator->validate(new NotBlank(), new TimesheetZeroDuration(['message' => 'Duration cannot be zero.'])); // @phpstan-ignore-line } private function prepareTimesheet() diff --git a/tests/Validator/Constraints/UserValidatorTest.php b/tests/Validator/Constraints/UserValidatorTest.php index 9905a66c..a65f8f3d 100644 --- a/tests/Validator/Constraints/UserValidatorTest.php +++ b/tests/Validator/Constraints/UserValidatorTest.php @@ -21,10 +21,11 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** * @covers \App\Validator\Constraints\User * @covers \App\Validator\Constraints\UserValidator + * @extends ConstraintValidatorTestCase */ class UserValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator() + protected function createValidator(): UserValidator { $userService = $this->createMock(UserService::class); @@ -35,19 +36,19 @@ class UserValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate('foo', new NotBlank()); + $this->validator->validate('foo', new NotBlank()); // @phpstan-ignore-line } public function testNullIsValid() { - $this->validator->validate(null, new User(['message' => 'myMessage'])); + $this->validator->validate(null, new User(['message' => 'myMessage'])); // @phpstan-ignore-line $this->assertNoViolation(); } public function testNonUserIsValid() { - $this->validator->validate(new TestUserEntity(), new User(['message' => 'myMessage'])); + $this->validator->validate(new TestUserEntity(), new User(['message' => 'myMessage'])); // @phpstan-ignore-line $this->assertNoViolation(); } diff --git a/tests/phpstan.neon b/tests/phpstan.neon index 4e907935..7645d611 100644 --- a/tests/phpstan.neon +++ b/tests/phpstan.neon @@ -10982,11 +10982,6 @@ parameters: count: 6 path: Utils/StringHelperTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\ColorChoicesValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/ColorChoicesValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\ColorChoicesValidatorTest\\:\\:getInvalidColors\\(\\) has no return type specified\\.$#" count: 1 @@ -11012,11 +11007,6 @@ parameters: count: 1 path: Validator/Constraints/ColorChoicesValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\DateTimeFormatValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/DateTimeFormatValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\DateTimeFormatValidatorTest\\:\\:getInvalidData\\(\\) has no return type specified\\.$#" count: 1 @@ -11042,11 +11032,6 @@ parameters: count: 1 path: Validator/Constraints/DateTimeFormatValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\DurationValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/DurationValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\DurationValidatorTest\\:\\:getInvalidData\\(\\) has no return type specified\\.$#" count: 1 @@ -11082,11 +11067,6 @@ parameters: count: 1 path: Validator/Constraints/DurationValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\HexColorValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/HexColorValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\HexColorValidatorTest\\:\\:getInvalidColors\\(\\) has no return type specified\\.$#" count: 1 @@ -11117,11 +11097,6 @@ parameters: count: 1 path: Validator/Constraints/HexColorValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\ProjectValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/ProjectValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\ProjectValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11137,11 +11112,6 @@ parameters: count: 1 path: Validator/Constraints/ProjectValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\QuickEntryModelValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/QuickEntryModelValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\QuickEntryModelValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11177,11 +11147,6 @@ parameters: count: 1 path: Validator/Constraints/QuickEntryModelValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\QuickEntryTimesheetValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/QuickEntryTimesheetValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\QuickEntryTimesheetValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11202,11 +11167,6 @@ parameters: count: 1 path: Validator/Constraints/RoleValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\RoleValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/RoleValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\RoleValidatorTest\\:\\:getInvalidRoles\\(\\) has no return type specified\\.$#" count: 1 @@ -11237,11 +11197,6 @@ parameters: count: 1 path: Validator/Constraints/RoleValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TeamValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TeamValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TeamValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11252,11 +11207,6 @@ parameters: count: 1 path: Validator/Constraints/TeamValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimeFormatValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimeFormatValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimeFormatValidatorTest\\:\\:getInvalidTimes\\(\\) has no return type specified\\.$#" count: 1 @@ -11292,16 +11242,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetBasicValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetBasicValidatorTest\\:\\:createMyValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetBasicValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetBasicValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetBasicValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetBasicValidatorTest\\:\\:getProjectStartEndTestData\\(\\) has no return type specified\\.$#" count: 1 @@ -11357,16 +11297,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetBasicValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetBudgetUsedValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetBudgetUsedValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetBudgetUsedValidatorTest\\:\\:createValidator\\(\\) has parameter \\$rawData with no value type specified in iterable type array\\.$#" - count: 1 - path: Validator/Constraints/TimesheetBudgetUsedValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetBudgetUsedValidatorTest\\:\\:getViolationTestData\\(\\) has no return type specified\\.$#" count: 1 @@ -11422,16 +11352,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetBudgetUsedValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetExportedValidatorTest\\:\\:createMyValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetExportedValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetExportedValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetExportedValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetExportedValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11467,16 +11387,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetExportedValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetFutureTimesValidatorTest\\:\\:createMyValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetFutureTimesValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetFutureTimesValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetFutureTimesValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetFutureTimesValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11497,16 +11407,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetFutureTimesValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetLockdownValidatorTest\\:\\:createMyValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetLockdownValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetLockdownValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetLockdownValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetLockdownValidatorTest\\:\\:getConfigTestData\\(\\) has no return type specified\\.$#" count: 1 @@ -11557,16 +11457,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetLockdownValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetLongRunningValidatorTest\\:\\:createMyValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetLongRunningValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetLongRunningValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetLongRunningValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetLongRunningValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11612,16 +11502,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetLongRunningValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetMultiUpdateValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetMultiUpdateValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetMultiUpdateValidatorTest\\:\\:createValidator\\(\\) has parameter \\$isGranted with no type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetMultiUpdateValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetMultiUpdateValidatorTest\\:\\:testActivityWithoutProject\\(\\) has no return type specified\\.$#" count: 1 @@ -11652,16 +11532,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetMultiUpdateValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetMultiUserValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetMultiUserValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetMultiUserValidatorTest\\:\\:createValidator\\(\\) has parameter \\$isGranted with no type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetMultiUserValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetMultiUserValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11672,16 +11542,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetMultiUserValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetOverlappingValidatorTest\\:\\:createMyValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetOverlappingValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetOverlappingValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetOverlappingValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetOverlappingValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11712,16 +11572,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetOverlappingValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetRestartValidatorTest\\:\\:createMyValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetRestartValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetRestartValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetRestartValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetRestartValidatorTest\\:\\:getTestData\\(\\) has no return type specified\\.$#" count: 1 @@ -11742,16 +11592,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetRestartValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetValidatorTest\\:\\:createMyValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1 @@ -11762,16 +11602,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetZeroDurationValidatorTest\\:\\:createMyValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetZeroDurationValidatorTest.php - - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetZeroDurationValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/TimesheetZeroDurationValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\TimesheetZeroDurationValidatorTest\\:\\:prepareTimesheet\\(\\) has no return type specified\\.$#" count: 1 @@ -11797,11 +11627,6 @@ parameters: count: 1 path: Validator/Constraints/TimesheetZeroDurationValidatorTest.php - - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\UserValidatorTest\\:\\:createValidator\\(\\) has no return type specified\\.$#" - count: 1 - path: Validator/Constraints/UserValidatorTest.php - - message: "#^Method App\\\\Tests\\\\Validator\\\\Constraints\\\\UserValidatorTest\\:\\:testConstraintIsInvalid\\(\\) has no return type specified\\.$#" count: 1