diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3cf33e9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,53 @@ +# Unix-style newlines with a newline ending every file +# copied from in2code/powermail +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +# TS/JS-Files +[*.{ts,js}] +indent_size = 2 + +# composer.json +# composer.json currently deviates from default by using 2 spaces indents +[composer.json] +indent_size = 2 + +# JSON-Files +[*.json] +indent_style = tab + +# ReST-Files (TYPO3 core convention is no longer 3 spaces, it is 4 spaces) +[*.{rst,rst.txt}] +indent_size = 4 +max_line_length = 80 + +# YAML-Files +[*.{yaml,yml}] +indent_size = 2 + +# package.json +# .travis.yml +[{package.json,.travis.yml}] +indent_size = 2 + +# TypoScript +[*.{typoscript,tsconfig}] +indent_size = 2 + +# XLF-Files +[*.xlf] +indent_style = tab + +# SQL-Files +[*.sql] +indent_style = tab +indent_size = 2 + +# .htaccess +[{_.htaccess,.htaccess}] +indent_style = tab diff --git a/.gitattributes b/.gitattributes index c9a6185..112f5cf 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,5 @@ *.gz filter=lfs diff=lfs merge=lfs -text +/.editorconfig export-ignore +/.github export-ignore +/.project export-ignore +/Tests export-ignore diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml new file mode 100644 index 0000000..76f3d0f --- /dev/null +++ b/.github/workflows/testing.yaml @@ -0,0 +1,102 @@ +# currently only testing with v12 and supported PHP versions for v12 (8.1-8.4) +# todo +# - execute "composer fix:php:cs" and uncomment "php-cs-fixer" job +# - fix TypoScript linter and uncomment jog +name: testing +on: + push: + branches-ignore: + - 'l10n_*' + pull_request: + branches-ignore: + - 'l10n_*' + +jobs: + php-lint: + name: "PHP linter" + runs-on: ubuntu-24.04 + steps: + - name: "Checkout" + uses: actions/checkout@v4 + - name: "Install PHP" + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php-version }}" + coverage: none + tools: composer:v2 + - name: "Run PHP lint" + run: "composer test:php:lint" + strategy: + fail-fast: false + matrix: + php-version: + - 8.1 + - 8.2 + - 8.3 + - 8.4 + #typoscript-lint: + # name: "TypoScript linter" + # runs-on: ubuntu-24.04 + # steps: + # - name: "Checkout" + # uses: actions/checkout@v4 + # - name: "Run TypoScript lint" + # uses: TYPO3-Continuous-Integration/TYPO3-CI-Typoscript-Lint@v1 + # with: + # files: "./Configuration" + # config_file: ".project/tests/typoscript-lint.yml" + #php-cs-fixer: + # name: "PHP CS Fixer" + # runs-on: ubuntu-24.04 + # needs: php-lint + # steps: + # - name: "Checkout" + # uses: actions/checkout@v4 + # - name: "Install PHP" + # uses: shivammathur/setup-php@v2 + # with: + # php-version: 8.1 + # - name: "Composer Install" + # run: "composer install" + # - name: "Run PHP CS Fixer" + # run: "composer test:php:cs" + phpstan: + name: "PHPstan" + runs-on: ubuntu-24.04 + needs: php-lint + steps: + - name: "Checkout" + uses: actions/checkout@v4 + - name: "Install PHP" + uses: shivammathur/setup-php@v2 + with: + php-version: 8.1 + - name: "Composer Install" + run: "composer install" + - name: "Run PHPstan" + run: "composer test:php:phpstan" + #unit-tests: + # name: "PHP Unit Tests" + # runs-on: ubuntu-24.04 + # needs: php-lint + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + # - name: "Install PHP" + # uses: shivammathur/setup-php@v2 + # with: + # php-version: "${{ matrix.php-version }}" + # coverage: none + # tools: composer:v2 + # - name: "Composer Install" + # run: "composer install" + # - name: "Run Unit Tests" + # run: "composer test:unit" + strategy: + fail-fast: false + matrix: + php-version: + - 8.1 + - 8.2 + - 8.3 + - 8.4 diff --git a/.project/tests/.php-cs-fixer.php b/.project/tests/.php-cs-fixer.php new file mode 100644 index 0000000..e2c1e18 --- /dev/null +++ b/.project/tests/.php-cs-fixer.php @@ -0,0 +1,111 @@ +in( + [ + __DIR__ . '/../../Classes', + __DIR__ . '/../../Tests', + __DIR__ . '/../../Configuration', + ] + ); +// Return a Code Sniffing configuration using +// all sniffers needed for PSR-2 +// and additionally: +// - Remove leading slashes in use clauses. +// - PHP single-line arrays should not have trailing comma. +// - Single-line whitespace before closing semicolon are prohibited. +// - Remove unused use statements in the PHP source code +// - Ensure Concatenation to have at least one whitespace around +// - Remove trailing whitespace at the end of blank lines. + +$config = new PhpCsFixer\Config(); + +return $config + ->setRiskyAllowed(true) + ->setRules([ + '@DoctrineAnnotation' => true, + '@PSR2' => true, + 'array_syntax' => ['syntax' => 'short'], + 'blank_line_after_opening_tag' => true, + 'braces' => ['allow_single_line_closure' => true], + 'cast_spaces' => ['space' => 'none'], + 'compact_nullable_typehint' => true, + 'concat_space' => ['spacing' => 'one'], + 'declare_equal_normalize' => ['space' => 'none'], + 'dir_constant' => true, + 'function_to_constant' => ['functions' => ['get_called_class', 'get_class', 'get_class_this', 'php_sapi_name', 'phpversion', 'pi']], + 'function_typehint_space' => true, + 'lowercase_cast' => true, + 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'], + 'modernize_strpos' => false, // different to https://github.com/TYPO3/typo3/blob/main/Build/php-cs-fixer.php + 'modernize_types_casting' => true, + 'native_function_casing' => true, + 'new_with_braces' => true, + 'no_alias_functions' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_null_property_initialization' => false, // different to https://github.com/TYPO3/typo3/blob/main/Build/php-cs-fixer.php + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_superfluous_elseif' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_whitespace_in_blank_line' => true, + 'ordered_imports' => true, + 'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']], + 'php_unit_mock_short_will_return' => true, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], + 'phpdoc_no_access' => true, + 'phpdoc_no_empty_return' => false, // different to https://github.com/TYPO3/typo3/blob/main/Build/php-cs-fixer.php + 'phpdoc_no_package' => true, + 'phpdoc_scalar' => true, + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], + 'return_type_declaration' => ['space_before' => 'none'], + 'single_quote' => true, + 'single_line_comment_style' => ['comment_types' => ['hash']], + 'single_trait_insert_per_statement' => true, + 'trailing_comma_in_multiline' => ['elements' => ['arrays']], + 'whitespace_after_comma_in_array' => true, + 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false], + ])->setFinder($finder); diff --git a/.project/tests/phpstan-baseline.neon b/.project/tests/phpstan-baseline.neon new file mode 100644 index 0000000..b3eda86 --- /dev/null +++ b/.project/tests/phpstan-baseline.neon @@ -0,0 +1,6 @@ +parameters: + ignoreErrors: + - + message: "#^Static method In2code\\\\PowermailCleaner\\\\Service\\\\TimeCalculationService\\:\\:getTodaysStart\\(\\) is unused\\.$#" + count: 1 + path: ../../Classes/Service/TimeCalculationService.php diff --git a/.project/tests/phpstan.neon b/.project/tests/phpstan.neon new file mode 100644 index 0000000..1daf4e9 --- /dev/null +++ b/.project/tests/phpstan.neon @@ -0,0 +1,14 @@ +# tests for v12 +# todo +# - some phpstan tests will fail due to classes being XCLASSed and the code using the original class, can be explicitly +# defined using @var, see Command/CleanupCommand.php +includes: + - phpstan-baseline.neon +parameters: + level: 5 + tmpDir: ../../.build/var/cache/phpstan + paths: + - ../../Classes + scanDirectories: + - ../../.build/vendor/in2code/powermail + - ../../.build/vendor/typo3 diff --git a/Classes/Command/CleanupCommand.php b/Classes/Command/CleanupCommand.php index 5966ca0..1418409 100644 --- a/Classes/Command/CleanupCommand.php +++ b/Classes/Command/CleanupCommand.php @@ -25,6 +25,7 @@ protected function configure(): void } protected function execute(InputInterface $input, OutputInterface $output): int { + /** @var \In2code\PowermailCleaner\Domain\Repository\MailRepository $mailRepository */ $mailRepository = GeneralUtility::makeInstance(MailRepository::class); $mailsToDelete = $mailRepository->findAllDeletionTimeStampOlderThan(time()); $mails = 0; @@ -36,4 +37,4 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->logger->info('Removed mails: ' . $mails); return Command::SUCCESS; } -} \ No newline at end of file +} diff --git a/Classes/Command/ForceCleanupCommand.php b/Classes/Command/ForceCleanupCommand.php index 84b0d53..0c4243f 100644 --- a/Classes/Command/ForceCleanupCommand.php +++ b/Classes/Command/ForceCleanupCommand.php @@ -32,6 +32,7 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { + /** @var \In2code\PowermailCleaner\Domain\Repository\MailRepository $mailRepository */ $mailRepository = GeneralUtility::makeInstance(MailRepository::class); // ToDo: calculate timestamp $timestamp = (time() - $input->getArgument('Retention days') * 86400); diff --git a/Classes/Command/InformReceiversCommand.php b/Classes/Command/InformReceiversCommand.php index 1d43d2e..d6395a4 100644 --- a/Classes/Command/InformReceiversCommand.php +++ b/Classes/Command/InformReceiversCommand.php @@ -41,11 +41,8 @@ public function __construct( ) { parent::__construct(); $this->powermailCleanerTyposcript = $this->getTypoScriptConfiguration(); - /** @var MailRepository $mailRepository */ $this->mailRepository = GeneralUtility::makeInstance(MailRepository::class); - /** @var FlexFormService $flexFormService */ $this->flexFormService = GeneralUtility::makeInstance(FlexFormService::class); - /** @var Mail $mail */ $this->mail = GeneralUtility::makeInstance(Mail::class); $this->timeCalculationService = GeneralUtility::makeInstance(TimeCalculationService::class); } @@ -119,7 +116,7 @@ private function getTypoScriptConfiguration(): array private function findReceivers(array $flexform): array { - /** @var ReceiverAddressService $receiverService */ + /** @var ReceiverAddressService $addressService */ $addressService = GeneralUtility::makeInstance(ReceiverAddressService::class, $this->mail, $flexform); return $addressService->getReceiverEmails(); } diff --git a/Classes/Controller/ModuleController.php b/Classes/Controller/ModuleController.php index 0f724e6..1a2b72b 100644 --- a/Classes/Controller/ModuleController.php +++ b/Classes/Controller/ModuleController.php @@ -12,15 +12,11 @@ */ class ModuleController extends \In2code\Powermail\Controller\ModuleController { - /** - * @param int $age - * @param int $pid - */ public function cleanupAction(): ResponseInterface { $age = null; $pid = null; - + if ($this->request->hasArgument('age')) { $age = $this->request->getArgument('age'); } diff --git a/Classes/Domain/Repository/MailRepository.php b/Classes/Domain/Repository/MailRepository.php index a8aee3a..30c74eb 100644 --- a/Classes/Domain/Repository/MailRepository.php +++ b/Classes/Domain/Repository/MailRepository.php @@ -155,7 +155,7 @@ public function findMailsOlderThan(int $timestamp): array /** * @param int $mailIdentifier - * @return QueryBuilder + * @return array * @throws Exception */ public function getAnswersWithFiles(int $mailIdentifier): array diff --git a/Classes/Service/TimeCalculationService.php b/Classes/Service/TimeCalculationService.php index 231c9e5..5e66985 100644 --- a/Classes/Service/TimeCalculationService.php +++ b/Classes/Service/TimeCalculationService.php @@ -15,8 +15,11 @@ public function calculateNotificationTimeframe(int $informReceiversBeforeDeletio return $notificationLimit; } + /** + * @todo Remove? Is not used + */ private static function getTodaysStart(): int { return strtotime('today', time()); } -} \ No newline at end of file +} diff --git a/Classes/Utility/FileUtility.php b/Classes/Utility/FileUtility.php index 0d5e2db..e963d4d 100644 --- a/Classes/Utility/FileUtility.php +++ b/Classes/Utility/FileUtility.php @@ -80,6 +80,7 @@ public static function hasSysfileReference(int $sysFileUid): bool public static function deleteFromFilesystem(string $identifier, ?ResourceStorage $storage): void { + $resourceBasePath = ''; if ($storage instanceof ResourceStorage) { $resourceBasePath = $storage->getConfiguration()['basePath']; } diff --git a/composer.json b/composer.json index 4463cea..01dfbc7 100644 --- a/composer.json +++ b/composer.json @@ -81,14 +81,10 @@ "friends-of-behat/mink-extension": "^2.7", "behat/mink-selenium2-driver": "^1.7", "friends-of-behat/mink-browserkit-driver": "^1.6", - "drevops/behat-screenshot": "^1.2" + "drevops/behat-screenshot": "^1.2", + "phpstan/phpstan": "^1.11.7", + "saschaegerer/phpstan-typo3": "^1.10.2" }, - "repositories": [ - { - "type": "git", - "url": "git@github.com:in2code-pro/powermail.git" - } - ], "autoload": { "psr-4": { "In2code\\PowermailCleaner\\": "Classes/" @@ -122,8 +118,11 @@ "test:behaviour": "behat --config Tests/Behavior/behat.ddev.yml", "test:behaviour:tag": "behat --config Tests/Behavior/behat.ddev.yml --tags", "test:behaviour:stop": "behat --config Tests/Behavior/behat.ddev.yml --stop-on-failure", - "test:php:cs": ".Build/bin/php-cs-fixer --version && .Build/bin/php-cs-fixer fix --dry-run --config=.project/tests/.php-cs-fixer.php --diff", + "test:php:cs": ".build/bin/php-cs-fixer --version && .build/bin/php-cs-fixer fix --dry-run --config=.project/tests/.php-cs-fixer.php --diff", + "fix:php:cs": ".build/bin/php-cs-fixer --version && .build/bin/php-cs-fixer fix --config=.project/tests/.php-cs-fixer.php --diff", "test:php:lint": "find *.php Classes Configuration Tests -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l", + "test:php:phpstan": "phpstan analyse -c .project/tests/phpstan.neon", + "test:php:phpstan:generate-baseline": "phpstan analyse -c .project/tests/phpstan.neon --generate-baseline .project/tests/phpstan-baseline.neon", "test:typoscript:lint": "typoscript-lint --config=.project/tests/typoscript-lint.yml", "test:unit": "phpunit -c phpunit.xml.dist" }