From 1f03f33f4a0b11120bffb0cd1740b2283130b139 Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Tue, 23 Apr 2024 15:25:58 +0200 Subject: [PATCH 1/8] chore: cleaning up code for craft 5 Signed-off-by: Fred Carlsen --- src/controllers/DefaultController.php | 11 ----- src/models/BeamModel.php | 63 +++++++-------------------- src/services/BeamService.php | 49 ++++++++++++++------- 3 files changed, 48 insertions(+), 75 deletions(-) diff --git a/src/controllers/DefaultController.php b/src/controllers/DefaultController.php index bc18472..03baf42 100644 --- a/src/controllers/DefaultController.php +++ b/src/controllers/DefaultController.php @@ -24,19 +24,8 @@ class DefaultController extends Controller { - // Protected Properties - // ========================================================================= - - /** - * @var bool|array Allows anonymous access to this controller's actions. - * The actions must be in 'kebab-case' - * @access protected - */ protected array|int|bool $allowAnonymous = ['index']; - // Public Methods - // ========================================================================= - /** * @return mixed * @throws NotFoundHttpException diff --git a/src/models/BeamModel.php b/src/models/BeamModel.php index db7aa80..959de57 100644 --- a/src/models/BeamModel.php +++ b/src/models/BeamModel.php @@ -22,26 +22,11 @@ */ class BeamModel extends Model { - // Public Properties - // ========================================================================= - - /** @var array */ - public $header = []; - - /** @var array */ - public $content = []; - - /** @var array */ - public $rows = []; - - /** @var string */ - public $filename = 'output'; - - /** @var string */ - public $sheetName = 'Sheet'; - - // Public Methods - // ========================================================================= + public array $header = []; + public array $content = []; + public array $rows = []; + public string $filename = 'output'; + public string $sheetName = 'Sheet'; public function init(): void { @@ -52,12 +37,7 @@ public function init(): void } } - /** - * @param array $content - * - * @return $this - */ - public function append(array $content = []) + public function append(array $content = []): static { if (isset($content[0]) && !\is_array($content[0])) { $content = [$content]; @@ -68,31 +48,26 @@ public function append(array $content = []) return $this; } - public function setHeader($headers = []) + public function setHeader(array $headers = []): static { $this->header = $headers; return $this; } - public function getContent() + public function getContent(): array { return $this->content; } - /** - * @param $content - * - * @return $this - */ - public function setContent($content) + public function setContent(array $content): static { $this->content = $content; return $this; } - public function getConfig() + public function getConfig(): array { return [ 'header' => $this->header, @@ -107,39 +82,31 @@ public function getFilename($ext = null) return "$filename.$ext"; } - public function setFilename($filename = null) + public function setFilename($filename = null): static { $this->filename = $filename; return $this; } - public function csv($filename = null) + public function csv($filename = null): void { if ($filename) { $this->filename = $filename; } - return Beam::$plugin->beamService->csv($this); + Beam::$plugin->beamService->csv($this); } - public function xlsx($filename = null) + public function xlsx($filename = null): void { if ($filename) { $this->filename = $filename; } - return Beam::$plugin->beamService->xlsx($this); - } - - public function html() - { - + Beam::$plugin->beamService->xlsx($this); } - /** - * @inheritdoc - */ public function rules(): array { return [ diff --git a/src/services/BeamService.php b/src/services/BeamService.php index c1a978e..626cd13 100644 --- a/src/services/BeamService.php +++ b/src/services/BeamService.php @@ -22,6 +22,11 @@ use League\Csv\Reader; use superbig\beam\models\BeamModel; use XLSXWriter; +use yii\base\ErrorException; +use yii\base\Exception; +use yii\base\ExitException; +use yii\base\InvalidConfigException; +use yii\base\InvalidRouteException; use yii\web\Response; /** @@ -31,9 +36,6 @@ */ class BeamService extends Component { - // Public Methods - // ========================================================================= - public function create($config = []) { $model = new BeamModel($config); @@ -44,16 +46,16 @@ public function create($config = []) /** * @param BeamModel $model * - * @return null + * @return void * @throws \League\Csv\CannotInsertRecord */ - public function csv(BeamModel $model) + public function csv(BeamModel $model): void { $header = $model->header; $content = $model->content; if (empty($header) && empty($content)) { - return null; + return; } $csv = Writer::createFromString(''); @@ -76,19 +78,20 @@ public function csv(BeamModel $model) } /** - * @param BeamModel $model - * - * @return null - * @throws \yii\base\Exception + * @throws ErrorException + * @throws Exception + * @throws ExitException + * @throws InvalidConfigException + * @throws InvalidRouteException */ - public function xlsx(BeamModel $model) + public function xlsx(BeamModel $model): void { $tempPath = Craft::$app->path->getTempPath() . DIRECTORY_SEPARATOR . 'beam' . DIRECTORY_SEPARATOR; $header = $model->header; $content = $model->content; if (empty($header) && empty($content)) { - return null; + return; } if (!file_exists($tempPath) && !is_dir($tempPath)) { @@ -122,13 +125,20 @@ public function xlsx(BeamModel $model) $this->writeAndRedirect($writer->writeToString(), $model->getFilename('xlsx'), $mimeType); } - public function downloadHash($fileHash = null) + /** + * @param $fileHash + * @return array|bool + * @throws Exception + * @throws InvalidConfigException + */ + public function downloadHash($fileHash = null): array | bool { $hash = Craft::$app->getSecurity()->validateData($fileHash); if (!$hash) { return false; } + $config = $this->unhashConfig($hash); $config['path'] = Craft::$app->path->getTempPath() . DIRECTORY_SEPARATOR . 'beam' . DIRECTORY_SEPARATOR . $config['tempFilename']; @@ -136,7 +146,14 @@ public function downloadHash($fileHash = null) return $config; } - private function writeAndRedirect($content, $filename, $mimeType) + /** + * @throws InvalidRouteException + * @throws InvalidConfigException + * @throws ErrorException + * @throws Exception + * @throws ExitException + */ + private function writeAndRedirect(string $content, string $filename, string $mimeType): void { $tempPath = Craft::$app->path->getTempPath() . DIRECTORY_SEPARATOR . 'beam' . DIRECTORY_SEPARATOR; $tempFilename = StringHelper::randomString(12) . "-{$filename}"; @@ -156,7 +173,7 @@ private function writeAndRedirect($content, $filename, $mimeType) Craft::$app->getResponse()->redirect($url); - return Craft::$app->end(); + Craft::$app->end(); } public function hashConfig($config = []): string @@ -182,7 +199,7 @@ public function unhashConfig(string $hash): array return $config; } - private function normalizeCellFormat(string $type) { + private function normalizeCellFormat(string $type): string { $types = [ 'number' => 'integer', 'date' => 'date', From aaa987b83477b05e9cd50ca875d234ac2ae16f37 Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Tue, 23 Apr 2024 15:26:19 +0200 Subject: [PATCH 2/8] fix: fix string concat issue in readme example Signed-off-by: Fred Carlsen --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ddebd0..8f70846 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ To set the header of the file (the first row): To set the filename: ```twig {% set currentDate = now|date('Y-m-d') %} -{% do beam.setFilename('report-#{currentDate}') %} +{% do beam.setFilename("report-#{currentDate}") %} ``` To overwrite the content: From 601eb7df340dc80f8aa27e87d078c6f4de675608 Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Tue, 23 Apr 2024 15:26:53 +0200 Subject: [PATCH 3/8] chore: preparing quality tooling for craft 5 Signed-off-by: Fred Carlsen --- composer.json | 5 +++++ ecs.php | 14 ++++++++++++++ phpstan.neon | 6 ++++++ 3 files changed, 25 insertions(+) create mode 100644 ecs.php create mode 100644 phpstan.neon diff --git a/composer.json b/composer.json index 29a2709..b018ea9 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,11 @@ "league/csv": "^8.1|^9.0", "mk-j/php_xlsxwriter": "^0.38.0" }, + "require-dev": { + "craftcms/ecs": "dev-main", + "craftcms/phpstan": "dev-main", + "craftcms/rector": "dev-main" + }, "repositories": [ { "type": "composer", diff --git a/ecs.php b/ecs.php new file mode 100644 index 0000000..7b09884 --- /dev/null +++ b/ecs.php @@ -0,0 +1,14 @@ +paths([ + __DIR__ . '/src', + __FILE__, + ]); + + $ecsConfig->parallel(); + $ecsConfig->sets([SetList::CRAFT_CMS_4]); +}; \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..8bc0882 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,6 @@ +includes: + - %currentWorkingDirectory%/vendor/craftcms/phpstan/phpstan.neon +parameters: + level: 5 + paths: + - src \ No newline at end of file From 3520f3ecb342bd6f42055e3002a719feb2b9ff49 Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Tue, 23 Apr 2024 20:53:06 +0200 Subject: [PATCH 4/8] chore: craft 5 support Signed-off-by: Fred Carlsen --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index b018ea9..15fe4ba 100644 --- a/composer.json +++ b/composer.json @@ -22,9 +22,9 @@ } ], "require": { - "craftcms/cms": "^4.0.0", - "league/csv": "^8.1|^9.0", - "mk-j/php_xlsxwriter": "^0.38.0" + "craftcms/cms": "^5.0.0", + "league/csv": "^9.0", + "mk-j/php_xlsxwriter": "^0.39.0" }, "require-dev": { "craftcms/ecs": "dev-main", From 20fd4af2b5f118a3ef6e7b6250a5e5dd2ba450b9 Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Tue, 23 Apr 2024 21:55:10 +0200 Subject: [PATCH 5/8] 5.0.0 Signed-off-by: Fred Carlsen --- CHANGELOG.md | 5 +++++ composer.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f03f2f7..aa610bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## 5.0.0 - 2024-04-23 + +### Added +- Craft 5 support + ## 3.0.0 - 2022-10-03 ### Added diff --git a/composer.json b/composer.json index 15fe4ba..fb95819 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "superbig/craft3-beam", "description": "Generate CSVs and XLS files in your templates", "type": "craft-plugin", - "version": "3.0.0", + "version": "5.0.0", "keywords": [ "craft", "cms", From 8b581ef26afcdf75db180e765d4aa53974767edb Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Wed, 24 Apr 2024 09:20:36 +0200 Subject: [PATCH 6/8] chore: add code analysis workflows Signed-off-by: Fred Carlsen --- .github/workflows/code-analysis.yaml | 37 ++++++++++++++++++++++++++++ composer.json | 5 ++++ 2 files changed, 42 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..a07f0f4 --- /dev/null +++ b/.github/workflows/code-analysis.yaml @@ -0,0 +1,37 @@ +name: Code Analysis + +on: + pull_request: + workflow_dispatch: +permissions: + contents: read +jobs: + code_analysis: + strategy: + fail-fast: false + matrix: + actions: + - name: 'PHPStan' + run: composer phpstan + - name: 'Coding Standards' + run: composer check-cs + name: ${{ matrix.actions.name }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: /tmp/composer-cache + key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }} + - name: Setup PHP + id: setup-php + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + extensions: 'ctype,curl,dom,iconv,imagick,intl,json,mbstring,openssl,pcre,pdo,reflection,spl,zip' + ini-values: post_max_size=256M, max_execution_time=180, memory_limit=512M + tools: composer:v2 + - name: Install Composer dependencies + run: composer install --no-interaction --no-ansi --no-progress + - run: ${{ matrix.actions.run }} \ No newline at end of file diff --git a/composer.json b/composer.json index fb95819..3bac1d0 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,11 @@ "superbig\\beam\\": "src/" } }, + "scripts": { + "phpstan": "phpstan --ansi --memory-limit=1G", + "check-cs": "ecs check --ansi", + "fix-cs": "ecs check --fix --ansi" + }, "extra": { "name": "Beam", "handle": "beam", From 9fa1677bcfb5dcb432decd8b4e91b494acc040dc Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Wed, 24 Apr 2024 09:26:45 +0200 Subject: [PATCH 7/8] fixup! chore: add code analysis workflows Signed-off-by: Fred Carlsen --- composer.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/composer.json b/composer.json index 3bac1d0..1cd4032 100644 --- a/composer.json +++ b/composer.json @@ -47,6 +47,14 @@ "check-cs": "ecs check --ansi", "fix-cs": "ecs check --fix --ansi" }, + "config": { + "allow-plugins": { + "craftcms/plugin-installer": true, + "yiisoft/yii2-composer": true + }, + "optimize-autoloader": true, + "sort-packages": true + }, "extra": { "name": "Beam", "handle": "beam", From ac8b7434954c7ded225e2797b378db0ec900549b Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Wed, 24 Apr 2024 11:18:20 +0200 Subject: [PATCH 8/8] fix: code issues Signed-off-by: Fred Carlsen --- ecs.php | 2 +- src/Beam.php | 18 ++++++------- src/controllers/DefaultController.php | 9 +++---- src/models/BeamModel.php | 7 +++-- src/services/BeamService.php | 38 +++++++++++++-------------- src/variables/BeamVariable.php | 4 +-- 6 files changed, 35 insertions(+), 43 deletions(-) diff --git a/ecs.php b/ecs.php index 7b09884..b5fe0ae 100644 --- a/ecs.php +++ b/ecs.php @@ -11,4 +11,4 @@ $ecsConfig->parallel(); $ecsConfig->sets([SetList::CRAFT_CMS_4]); -}; \ No newline at end of file +}; diff --git a/src/Beam.php b/src/Beam.php index 2b17ca6..5d9b93d 100644 --- a/src/Beam.php +++ b/src/Beam.php @@ -10,16 +10,14 @@ namespace superbig\beam; -use superbig\beam\services\BeamService as BeamServiceService; -use superbig\beam\variables\BeamVariable; - use Craft; use craft\base\Plugin; -use craft\services\Plugins; -use craft\events\PluginEvent; -use craft\web\UrlManager; -use craft\web\twig\variables\CraftVariable; + use craft\events\RegisterUrlRulesEvent; +use craft\web\twig\variables\CraftVariable; +use craft\web\UrlManager; +use superbig\beam\services\BeamService as BeamServiceService; +use superbig\beam\variables\BeamVariable; use yii\base\Event; @@ -56,7 +54,7 @@ public function init() Event::on( UrlManager::class, UrlManager::EVENT_REGISTER_SITE_URL_RULES, - function (RegisterUrlRulesEvent $event) { + function(RegisterUrlRulesEvent $event) { $event->rules['beam/download'] = 'beam/default'; } ); @@ -64,7 +62,7 @@ function (RegisterUrlRulesEvent $event) { Event::on( UrlManager::class, UrlManager::EVENT_REGISTER_CP_URL_RULES, - function (RegisterUrlRulesEvent $event) { + function(RegisterUrlRulesEvent $event) { $event->rules['beam/download'] = 'beam/default'; } ); @@ -72,7 +70,7 @@ function (RegisterUrlRulesEvent $event) { Event::on( CraftVariable::class, CraftVariable::EVENT_INIT, - function (Event $event) { + function(Event $event) { /** @var CraftVariable $variable */ $variable = $event->sender; $variable->set('beam', BeamVariable::class); diff --git a/src/controllers/DefaultController.php b/src/controllers/DefaultController.php index 03baf42..4d1adb7 100644 --- a/src/controllers/DefaultController.php +++ b/src/controllers/DefaultController.php @@ -10,10 +10,10 @@ namespace superbig\beam\controllers; -use superbig\beam\Beam; - use Craft; + use craft\web\Controller; +use superbig\beam\Beam; use yii\web\NotFoundHttpException; /** @@ -23,7 +23,6 @@ */ class DefaultController extends Controller { - protected array|int|bool $allowAnonymous = ['index']; /** @@ -34,7 +33,7 @@ class DefaultController extends Controller public function actionIndex() { $request = Craft::$app->getRequest(); - $hash = $request->getRequiredParam('hash'); + $hash = $request->getRequiredParam('hash'); $config = Beam::$plugin->beamService->downloadHash($hash); @@ -42,7 +41,7 @@ public function actionIndex() throw new NotFoundHttpException(); } - $path = $config['path']; + $path = $config['path']; $filename = $config['filename']; return Craft::$app->getResponse()->sendFile($path, $filename, [ diff --git a/src/models/BeamModel.php b/src/models/BeamModel.php index 959de57..3646c67 100644 --- a/src/models/BeamModel.php +++ b/src/models/BeamModel.php @@ -10,11 +10,10 @@ namespace superbig\beam\models; -use superbig\beam\Beam; - -use Craft; use craft\base\Model; +use superbig\beam\Beam; + /** * @author Superbig * @package Beam @@ -71,7 +70,7 @@ public function getConfig(): array { return [ 'header' => $this->header, - 'rows' => $this->content, + 'rows' => $this->content, ]; } diff --git a/src/services/BeamService.php b/src/services/BeamService.php index 626cd13..43bb66e 100644 --- a/src/services/BeamService.php +++ b/src/services/BeamService.php @@ -10,16 +10,14 @@ namespace superbig\beam\services; +use Craft; +use craft\base\Component; use craft\helpers\FileHelper; -use craft\helpers\Path; use craft\helpers\StringHelper; -use craft\helpers\UrlHelper; -use superbig\beam\Beam; -use Craft; -use craft\base\Component; +use craft\helpers\UrlHelper; use League\Csv\Writer; -use League\Csv\Reader; +use superbig\beam\Beam; use superbig\beam\models\BeamModel; use XLSXWriter; use yii\base\ErrorException; @@ -27,7 +25,6 @@ use yii\base\ExitException; use yii\base\InvalidConfigException; use yii\base\InvalidRouteException; -use yii\web\Response; /** * @author Superbig @@ -51,7 +48,7 @@ public function create($config = []) */ public function csv(BeamModel $model): void { - $header = $model->header; + $header = $model->header; $content = $model->content; if (empty($header) && empty($content)) { @@ -87,8 +84,8 @@ public function csv(BeamModel $model): void public function xlsx(BeamModel $model): void { $tempPath = Craft::$app->path->getTempPath() . DIRECTORY_SEPARATOR . 'beam' . DIRECTORY_SEPARATOR; - $header = $model->header; - $content = $model->content; + $header = $model->header; + $content = $model->content; if (empty($header) && empty($content)) { return; @@ -99,7 +96,7 @@ public function xlsx(BeamModel $model): void } // Load the CSV document from a string - $writer = new XLSXWriter(); + $writer = new XLSXWriter(); $sheetName = !empty($model->sheetName) ? $model->sheetName : 'Sheet'; if (!empty($header)) { @@ -155,17 +152,17 @@ public function downloadHash($fileHash = null): array | bool */ private function writeAndRedirect(string $content, string $filename, string $mimeType): void { - $tempPath = Craft::$app->path->getTempPath() . DIRECTORY_SEPARATOR . 'beam' . DIRECTORY_SEPARATOR; + $tempPath = Craft::$app->path->getTempPath() . DIRECTORY_SEPARATOR . 'beam' . DIRECTORY_SEPARATOR; $tempFilename = StringHelper::randomString(12) . "-{$filename}"; - $config = [ - 'filename' => $filename, + $config = [ + 'filename' => $filename, 'tempFilename' => $tempFilename, - 'mimeType' => $mimeType, + 'mimeType' => $mimeType, ]; $hashConfig = $this->hashConfig($config); $verifyHash = Craft::$app->getSecurity()->hashData($hashConfig); - $url = UrlHelper::siteUrl('beam/download', [ + $url = UrlHelper::siteUrl('beam/download', [ 'hash' => $verifyHash, ]); @@ -188,18 +185,19 @@ public function unhashConfig(string $hash): array $config = base64_decode($hash); $config = explode('||', $config); - list ($filename, $tempFilename, $mimeType) = $config; + list($filename, $tempFilename, $mimeType) = $config; $config = [ - 'filename' => $filename, + 'filename' => $filename, 'tempFilename' => $tempFilename, - 'mimeType' => $mimeType, + 'mimeType' => $mimeType, ]; return $config; } - private function normalizeCellFormat(string $type): string { + private function normalizeCellFormat(string $type): string + { $types = [ 'number' => 'integer', 'date' => 'date', diff --git a/src/variables/BeamVariable.php b/src/variables/BeamVariable.php index f42e137..cfb2189 100644 --- a/src/variables/BeamVariable.php +++ b/src/variables/BeamVariable.php @@ -12,8 +12,6 @@ use superbig\beam\Beam; -use Craft; - /** * @author Superbig * @package Beam @@ -29,7 +27,7 @@ class BeamVariable * * @return null */ - public function create ($options = []) + public function create($options = []) { return Beam::$plugin->beamService->create($options); }