From 2ced1038afa9f87c435b3c46fb1b531cdd251c53 Mon Sep 17 00:00:00 2001 From: Joel Male Date: Sat, 6 Jun 2026 16:02:16 +1000 Subject: [PATCH] feat: add PHPStan level 5 with zero errors - Install phpstan/phpstan, add phpstan.neon at level 5 targeting PHP 8.3 - Add phpstan-bootstrap.php stubs for Laravel helper functions (app, config, config_path, app_path, session) unavailable in standalone packages - Fix CartCondition::setOrder() - removed incorrect @return int (method is void) - Fix CartCondition::getCalculatedValue() - removed incorrect @return mixed PHPDoc - Fix Cart::condition() - remove redundant instanceof check the type system already guarantees - Fix Cart::fireEvent() - remove array_values() on already-list literal array - Fix ItemCollection - add @property annotations for magic __get properties - Fix ItemCollection::getAssociatedModel() - correct @return bool to @return mixed - Fix ItemCollection::getConditions() - remove dead is_array && !instanceof check - Fix Validator - add @method stub so PHPStan resolves make() through __callStatic - Add ignoreErrors for trait.unused (HasCart designed for external Livewire use) - Add ignoreErrors for round() mode mismatch (PHPStan 2.x PHP 8.4 stubs bug) - Add phpstan step to CI (PHP 8.3 only, matches phpVersion config) --- .github/workflows/tests.yml | 4 +++ composer.json | 3 +- composer.lock | 70 ++++++++++++++++++++++++++++++++++-- phpstan-bootstrap.php | 42 ++++++++++++++++++++++ phpstan.neon | 14 ++++++++ src/Cart.php | 6 +--- src/CartCondition.php | 8 ++--- src/ItemCollection.php | 14 ++++++-- src/Validators/Validator.php | 3 ++ 9 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 phpstan-bootstrap.php create mode 100644 phpstan.neon diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6c7685e..2a79d56 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,3 +37,7 @@ jobs: - name: Execute tests run: vendor/bin/pest + + - name: Static analysis + run: vendor/bin/phpstan analyse --no-progress + if: matrix.php == '8.3' diff --git a/composer.json b/composer.json index 7248399..d0ee455 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "mockery/mockery": "^2.0", "laravel/pint": "^1.21", "pestphp/pest": "^4.7", - "larapack/dd": "dev-master" + "larapack/dd": "dev-master", + "phpstan/phpstan": "2.2.x-dev" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index c12f801..477801f 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": "36458db92bb67aee0a12a15f588349b4", + "content-hash": "56b40d3f17cc40f1b62c3f71a3601af7", "packages": [ { "name": "brick/math", @@ -6518,6 +6518,71 @@ }, "time": "2026-05-25T15:58:15+00:00" }, + { + "name": "phpstan/phpstan", + "version": "2.2.x-dev", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5c0bbadd35255710f7d2402cd6213a0bc34cfa34", + "reference": "5c0bbadd35255710f7d2402cd6213a0bc34cfa34", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "default-branch": true, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-06-05T16:36:10+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "12.5.x-dev", @@ -8189,7 +8254,8 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { - "larapack/dd": 20 + "larapack/dd": 20, + "phpstan/phpstan": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/phpstan-bootstrap.php b/phpstan-bootstrap.php new file mode 100644 index 0000000..48daf68 --- /dev/null +++ b/phpstan-bootstrap.php @@ -0,0 +1,42 @@ +getConditions(); if ($condition->getOrder() === 0) { @@ -735,6 +731,6 @@ protected function fireEvent(string $name, ?string $type = null, mixed $data = n $eventData[$type] = $data; } - return $this->events->dispatch('LaravelCart.' . $name, array_values([$eventData, $this]), true); + return $this->events->dispatch('LaravelCart.' . $name, [$eventData, $this], true); } } diff --git a/src/CartCondition.php b/src/CartCondition.php index 0908655..bb671ee 100644 --- a/src/CartCondition.php +++ b/src/CartCondition.php @@ -105,13 +105,11 @@ public function setValue($value): void } /** - * Set the order to apply this condition. If no argument order is applied we return 0 as - * indicator that no assignment has been made + * Set the order to apply this condition. * * @param int $order - * @return int */ - public function setOrder($order = 1) + public function setOrder($order = 1): void { $this->args['order'] = $order; } @@ -139,8 +137,6 @@ public function applyCondition($totalOrSubTotalOrPrice) /** * get the calculated value of this condition supplied by the subtotal|price - * - * @return mixed */ public function getCalculatedValue($totalOrSubTotalOrPrice = null): int|float { diff --git a/src/ItemCollection.php b/src/ItemCollection.php index 9d1d6d5..43b1474 100644 --- a/src/ItemCollection.php +++ b/src/ItemCollection.php @@ -5,6 +5,14 @@ use Illuminate\Support\Collection; use Wearepixel\Cart\Helpers\Helpers; +/** + * @property mixed $id + * @property string $name + * @property float|int $price + * @property int|float $quantity + * @property array $attributes + * @property mixed $conditions + */ class ItemCollection extends Collection { /** @@ -46,7 +54,7 @@ public function __get($name) /** * return the associated model of an item * - * @return bool + * @return mixed */ protected function getAssociatedModel() { @@ -97,7 +105,7 @@ public function getConditions() // check if we're already an array of CartConditions foreach ($conditions as $key => $condition) { - if ($condition instanceof CartCondition) { + if (is_object($condition) && $condition instanceof CartCondition) { return $conditions; } } @@ -105,7 +113,7 @@ public function getConditions() $hasSubArray = false; foreach ($conditions as $key => $condition) { - if (is_array($condition) && ! $condition instanceof CartCondition) { + if (is_array($condition)) { $hasSubArray = true; $conditionsArray[] = new CartCondition($condition); } elseif ($condition instanceof CartCondition) { diff --git a/src/Validators/Validator.php b/src/Validators/Validator.php index 0a3db44..5fa5060 100644 --- a/src/Validators/Validator.php +++ b/src/Validators/Validator.php @@ -7,6 +7,9 @@ use Illuminate\Translation\FileLoader; use Illuminate\Translation\Translator; +/** + * @method static \Illuminate\Validation\Validator make(array $data, array $rules, array $messages = [], array $attributes = []) + */ abstract class Validator { protected static $factory;