From 0d9fdade9a3ccf8f6a942b9ec07bd98967de8051 Mon Sep 17 00:00:00 2001 From: Bob van de Vijver Date: Fri, 26 Sep 2025 20:13:41 +0200 Subject: [PATCH 1/4] Complete migration to bolt namespace --- README.md | 5 ++++- composer.json | 7 +++++-- src/Extension.php | 2 +- src/WeatherWidget.php | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1d6772c..7492bfc 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # Bolt Weather Widget + Bolt Extension: A simple Dashboard Widget that displays the current weather. So you don't actually need to go outside or open the curtains. +> This repository was forked from [bobdenotter/weatherwidget](https://github.com/bobdenotter/weatherwidget) and updated to be used with newer versions of [bolt/core](https://github.com/bolt/core). + Installation: ```bash -composer require bobdenotter/weatherwidget +composer require bolt/weatherwidget ``` diff --git a/composer.json b/composer.json index a06ad8b..3d1b77f 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,9 @@ "type": "bolt-extension", "license": "MIT", "authors": [ + { + "name": "Bolt developers" + }, { "name": "Bob den Otter", "email": "bob@twokings.nl" @@ -18,7 +21,7 @@ }, "autoload": { "psr-4": { - "BobdenOtter\\WeatherWidget\\": "src/" + "Bolt\\WeatherWidget\\": "src/" } }, "replace": { @@ -27,7 +30,7 @@ "minimum-stability": "dev", "prefer-stable": true, "extra": { - "entrypoint": "BobdenOtter\\WeatherWidget\\Extension", + "entrypoint": "Bolt\\WeatherWidget\\Extension", "screenshots": [ "screenshots/widget.png" ] diff --git a/src/Extension.php b/src/Extension.php index 3d550c2..3609ddb 100644 --- a/src/Extension.php +++ b/src/Extension.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace BobdenOtter\WeatherWidget; +namespace Bolt\WeatherWidget; use Bolt\Extension\BaseExtension; diff --git a/src/WeatherWidget.php b/src/WeatherWidget.php index 9030bd1..26e7bd3 100644 --- a/src/WeatherWidget.php +++ b/src/WeatherWidget.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace BobdenOtter\WeatherWidget; +namespace Bolt\WeatherWidget; use Bolt\Widget\BaseWidget; use Bolt\Widget\CacheAwareInterface; From 279ec9d1c4efa2b2672df2453ebaabea1c3fe429 Mon Sep 17 00:00:00 2001 From: Bob van de Vijver Date: Fri, 26 Sep 2025 20:14:53 +0200 Subject: [PATCH 2/4] Upgrade ECS to be in sync with bolt/core --- composer.json | 12 +++-- easy-coding-standard.yml | 100 --------------------------------------- ecs.php | 79 +++++++++++++++++++++++++++++++ src/WeatherWidget.php | 12 ++++- 4 files changed, 98 insertions(+), 105 deletions(-) delete mode 100644 easy-coding-standard.yml create mode 100644 ecs.php diff --git a/composer.json b/composer.json index 3d1b77f..0eff2dd 100644 --- a/composer.json +++ b/composer.json @@ -13,11 +13,11 @@ } ], "require": { - "php": ">=7.1.3" + "php": ">=8.1" }, "require-dev": { - "bolt/core": "^4.0.0", - "symplify/easy-coding-standard": "^6.0" + "bolt/core": "^5 || ^6", + "symplify/easy-coding-standard": "^12.5" }, "autoload": { "psr-4": { @@ -34,5 +34,11 @@ "screenshots": [ "screenshots/widget.png" ] + }, + "config": { + "allow-plugins": { + "symfony/flex": false, + "drupol/composer-packages": false + } } } diff --git a/easy-coding-standard.yml b/easy-coding-standard.yml deleted file mode 100644 index 6e0ef26..0000000 --- a/easy-coding-standard.yml +++ /dev/null @@ -1,100 +0,0 @@ -imports: - - { resource: 'vendor/symplify/easy-coding-standard/config/set/clean-code.yaml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/set/common.yaml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/set/php70.yaml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/set/php71.yaml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/set/psr2.yaml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/set/psr12.yaml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/set/symfony.yaml' } - - { resource: 'vendor/symplify/easy-coding-standard/config/set/symfony-risky.yaml' } - -services: - # most of these services are taken from symplify.yml - # see https://github.com/Symplify/Symplify/blob/master/ecs.yml - - # PHP 5.5 - Symplify\CodingStandard\Fixer\Php\ClassStringToClassConstantFixer: ~ - - # Control Structures - Symplify\CodingStandard\Fixer\Property\ArrayPropertyDefaultValueFixer: ~ - Symplify\CodingStandard\Fixer\ArrayNotation\StandaloneLineInMultilineArrayFixer: ~ - Symplify\CodingStandard\Fixer\ControlStructure\RequireFollowedByAbsolutePathFixer: ~ - - # Spaces - Symplify\CodingStandard\Fixer\Strict\BlankLineAfterStrictTypesFixer: ~ - - # Comments - Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousDocBlockWhitespaceFixer: ~ - - # Naming - PhpCsFixer\Fixer\PhpUnit\PhpUnitMethodCasingFixer: ~ - - # Debug - Symplify\CodingStandard\Sniffs\Debug\DebugFunctionCallSniff: ~ - Symplify\CodingStandard\Sniffs\Debug\CommentedOutCodeSniff: ~ - - # final classes - PhpCsFixer\Fixer\ClassNotation\FinalInternalClassFixer: ~ - - # multibyte - PhpCsFixer\Fixer\Alias\MbStrFunctionsFixer: ~ - - # psr - PhpCsFixer\Fixer\Basic\Psr0Fixer: ~ - PhpCsFixer\Fixer\Basic\Psr4Fixer: ~ - - PhpCsFixer\Fixer\CastNotation\LowercaseCastFixer: ~ - PhpCsFixer\Fixer\CastNotation\ShortScalarCastFixer: ~ - PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer: ~ - PhpCsFixer\Fixer\Import\NoLeadingImportSlashFixer: ~ - PhpCsFixer\Fixer\Import\OrderedImportsFixer: - importsOrder: - - 'class' - - 'const' - - 'function' - PhpCsFixer\Fixer\LanguageConstruct\DeclareEqualNormalizeFixer: - space: 'none' - PhpCsFixer\Fixer\Operator\NewWithBracesFixer: ~ - PhpCsFixer\Fixer\Basic\BracesFixer: - 'allow_single_line_closure': false - 'position_after_functions_and_oop_constructs': 'next' - 'position_after_control_structures': 'same' - 'position_after_anonymous_constructs': 'same' - - PhpCsFixer\Fixer\ClassNotation\NoBlankLinesAfterClassOpeningFixer: ~ - PhpCsFixer\Fixer\ClassNotation\VisibilityRequiredFixer: - elements: - - 'const' - - 'method' - - 'property' - PhpCsFixer\Fixer\Operator\TernaryOperatorSpacesFixer: ~ - PhpCsFixer\Fixer\FunctionNotation\ReturnTypeDeclarationFixer: ~ - PhpCsFixer\Fixer\Whitespace\NoTrailingWhitespaceFixer: ~ - - PhpCsFixer\Fixer\Semicolon\NoSinglelineWhitespaceBeforeSemicolonsFixer: ~ - PhpCsFixer\Fixer\ArrayNotation\NoWhitespaceBeforeCommaInArrayFixer: ~ - PhpCsFixer\Fixer\ArrayNotation\WhitespaceAfterCommaInArrayFixer: ~ - - #remove useless phpdoc - PhpCsFixer\Fixer\FunctionNotation\PhpdocToReturnTypeFixer: ~ - PhpCsFixer\Fixer\Import\FullyQualifiedStrictTypesFixer: ~ - PhpCsFixer\Fixer\Phpdoc\NoSuperfluousPhpdocTagsFixer: ~ - - #please yoda no - SlevomatCodingStandard\Sniffs\ControlStructures\DisallowYodaComparisonSniff: ~ - -parameters: - cache_directory: var/cache/ecs - skip: - PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer: ~ - PhpCsFixer\Fixer\ClassNotation\OrderedClassElementsFixer: ~ - PhpCsFixer\Fixer\ControlStructure\YodaStyleFixer: ~ - PhpCsFixer\Fixer\Operator\ConcatSpaceFixer: ~ - PhpCsFixer\Fixer\Operator\IncrementStyleFixer: ~ - PhpCsFixer\Fixer\Operator\UnaryOperatorSpacesFixer: ~ - PhpCsFixer\Fixer\Phpdoc\PhpdocAnnotationWithoutDotFixer: ~ - PhpCsFixer\Fixer\Phpdoc\PhpdocSummaryFixer: ~ - PhpCsFixer\Fixer\Whitespace\BlankLineBeforeStatementFixer: ~ - SlevomatCodingStandard\Sniffs\TypeHints\TypeHintDeclarationSniff: ~ - Symplify\CodingStandard\Sniffs\Debug\CommentedOutCodeSniff: ~ #to be removed before beta release - Symplify\CodingStandard\Sniffs\Debug\DebugFunctionCallSniff: ~ #to be removed before beta release diff --git a/ecs.php b/ecs.php new file mode 100644 index 0000000..f0c27b7 --- /dev/null +++ b/ecs.php @@ -0,0 +1,79 @@ +withPaths([__DIR__ . '/src',]) + ->withRules([ + StandaloneLineInMultilineArrayFixer::class, + BlankLineAfterStrictTypesFixer::class, + PhpUnitMethodCasingFixer::class, + FinalInternalClassFixer::class, + MbStrFunctionsFixer::class, + LowercaseCastFixer::class, + ShortScalarCastFixer::class, + BlankLineAfterOpeningTagFixer::class, + NoLeadingImportSlashFixer::class, + NoBlankLinesAfterClassOpeningFixer::class, + TernaryOperatorSpacesFixer::class, + ReturnTypeDeclarationFixer::class, + NoTrailingWhitespaceFixer::class, + NoSinglelineWhitespaceBeforeSemicolonsFixer::class, + NoWhitespaceBeforeCommaInArrayFixer::class, + WhitespaceAfterCommaInArrayFixer::class, + PhpdocToReturnTypeFixer::class, + FullyQualifiedStrictTypesFixer::class, + NoSuperfluousPhpdocTagsFixer::class, + ]) + ->withConfiguredRule(OrderedImportsFixer::class, [ + 'imports_order' => ['class', 'const', 'function'], + ]) + ->withConfiguredRule(DeclareEqualNormalizeFixer::class, [ + 'space' => 'none', + ]) + ->withConfiguredRule(VisibilityRequiredFixer::class, [ + 'elements' => ['const', 'method', 'property'], + ]) + ->withConfiguredRule(PhpdocLineSpanFixer::class, [ + 'property' => 'single', + ]) + ->withSkip([ + OrderedClassElementsFixer::class => null, + IncrementStyleFixer::class => null, + PhpdocSummaryFixer::class => null, + PhpdocAlignFixer::class => null, + ConcatSpaceFixer::class => null, + ]) + ->withPreparedSets(psr12: true, common: true, cleanCode: true); diff --git a/src/WeatherWidget.php b/src/WeatherWidget.php index 26e7bd3..655ec25 100644 --- a/src/WeatherWidget.php +++ b/src/WeatherWidget.php @@ -20,11 +20,17 @@ class WeatherWidget extends BaseWidget implements TwigAwareInterface, CacheAware use StopwatchTrait; protected $name = 'Weather Widget'; + protected $target = AdditionalTarget::WIDGET_BACK_DASHBOARD_ASIDE_TOP; + protected $priority = 200; + protected $template = '@weather-widget/weather.html.twig'; + protected $zone = RequestZone::BACKEND; + protected $cacheDuration = 1800; + protected $location = ''; public function run(array $params = []): ?string @@ -35,7 +41,9 @@ public function run(array $params = []): ?string return null; } - return parent::run(['weather' => $weather]); + return parent::run([ + 'weather' => $weather, + ]); } private function getWeather(): array @@ -51,7 +59,7 @@ private function getWeather(): array $client = HttpClient::create(); $result = $client->request('GET', $url, $curlOptions)->getContent(); if (mb_substr_count($result, '|') === 9) { - $details = explode('|', trim($result)); + $details = explode('|', mb_trim($result)); } } catch (\Throwable $e) { dump($this->getName() . ' exception: ' . $e->getMessage()); From 2ee50a39847993644a4100f6a34fce548573a7e3 Mon Sep 17 00:00:00 2001 From: Bob van de Vijver Date: Fri, 26 Sep 2025 20:44:26 +0200 Subject: [PATCH 3/4] Add rector/phpstan and resolve found issues --- composer.json | 2 ++ phpstan.neon | 8 ++++++++ rector.php | 20 ++++++++++++++++++++ src/WeatherWidget.php | 14 ++++++++++---- 4 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 phpstan.neon create mode 100644 rector.php diff --git a/composer.json b/composer.json index 0eff2dd..061666e 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,8 @@ }, "require-dev": { "bolt/core": "^5 || ^6", + "phpstan/phpstan": "2.1.28", + "rector/rector": "2.1.7", "symplify/easy-coding-standard": "^12.5" }, "autoload": { diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..e5f9e2a --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,8 @@ +parameters: + level: 8 + + paths: + - src + + treatPhpDocTypesAsCertain: false + reportUnmatchedIgnoredErrors: true diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..fde83fa --- /dev/null +++ b/rector.php @@ -0,0 +1,20 @@ +withCache('./var/cache/rector', FileCacheStorage::class) + ->withPaths(['./src']) + ->withImportNames() + ->withParallel(timeoutSeconds: 180, jobSize: 10) + ->withPhpSets() + ->withPreparedSets( + typeDeclarations: true, + ) + ->withComposerBased( + twig: true, + symfony: true, + ); diff --git a/src/WeatherWidget.php b/src/WeatherWidget.php index 655ec25..1d6e2a6 100644 --- a/src/WeatherWidget.php +++ b/src/WeatherWidget.php @@ -4,6 +4,7 @@ namespace Bolt\WeatherWidget; +use Bolt\Extension\BaseExtension; use Bolt\Widget\BaseWidget; use Bolt\Widget\CacheAwareInterface; use Bolt\Widget\CacheTrait; @@ -13,6 +14,7 @@ use Bolt\Widget\StopwatchTrait; use Bolt\Widget\TwigAwareInterface; use Symfony\Component\HttpClient\HttpClient; +use Throwable; class WeatherWidget extends BaseWidget implements TwigAwareInterface, CacheAwareInterface, StopwatchAwareInterface { @@ -31,8 +33,9 @@ class WeatherWidget extends BaseWidget implements TwigAwareInterface, CacheAware protected $cacheDuration = 1800; - protected $location = ''; - + /** + * @param array $params + */ public function run(array $params = []): ?string { $weather = $this->getWeather(); @@ -46,6 +49,9 @@ public function run(array $params = []): ?string ]); } + /** + * @return string[] + */ private function getWeather(): array { $url = 'https://wttr.in/' . $this->getLocation() . '?format=%c|%C|%h|%t|%w|%l|%m|%M|%p|%P'; @@ -61,7 +67,7 @@ private function getWeather(): array if (mb_substr_count($result, '|') === 9) { $details = explode('|', mb_trim($result)); } - } catch (\Throwable $e) { + } catch (Throwable $e) { dump($this->getName() . ' exception: ' . $e->getMessage()); // Do nothing, fall through to empty array } @@ -71,7 +77,7 @@ private function getWeather(): array private function getLocation(): string { - if (! $this->extension) { + if (! $this->extension instanceof BaseExtension) { return ''; } From 4b366526c6fc5622f049fb3bbf8199143af5ec0f Mon Sep 17 00:00:00 2001 From: Bob van de Vijver Date: Fri, 26 Sep 2025 20:45:03 +0200 Subject: [PATCH 4/4] Add github actions --- .github/workflows/code_analysis.yaml | 66 ++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .github/workflows/code_analysis.yaml diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml new file mode 100644 index 0000000..1f4bb7b --- /dev/null +++ b/.github/workflows/code_analysis.yaml @@ -0,0 +1,66 @@ +name: Code Analysis + +on: + pull_request: null + push: + branches: + - main + +jobs: + rector_analysis: + name: Rector analysis + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: shivammathur/setup-php@v2 + with: + php-version: 8.4 + extensions: json, mbstring, pdo, curl, pdo_sqlite + coverage: none + tools: symfony-cli + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - run: composer install --no-progress --ansi + + - run: vendor/bin/rector process -n --no-progress-bar --ansi + + code_analysis: + strategy: + fail-fast: false + matrix: + php-version: ['8.1', '8.2', '8.3', '8.4'] + actions: + - + name: Coding Standard + # tip: add "--ansi" to commands in CI to make them full of colors + run: vendor/bin/ecs check src --ansi + + - + name: PHPStan + run: vendor/bin/phpstan analyse --ansi + + - + name: Check composer.json and composer.lock + run: composer validate --strict --ansi + + name: ${{ matrix.actions.name }} - PHP ${{ matrix.php-version }} + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + # see https://github.com/shivammathur/setup-php + - uses: shivammathur/setup-php@v2 + with: + # test the lowest version, to make sure checks pass on it + php-version: ${{ matrix.php-version }} + extensions: json, mbstring, pdo, curl, pdo_sqlite + coverage: none + tools: symfony-cli + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - run: composer install --no-progress --ansi + + - run: ${{ matrix.actions.run }}