From ad2a95283ce739528799e338d1b38687d96ae2d6 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 11:37:02 -0400 Subject: [PATCH 01/28] larastan/phpstan --- .gitattributes | 1 + composer.json | 2 ++ phpstan.neon.dist | 7 +++++++ 3 files changed, 10 insertions(+) create mode 100644 phpstan.neon.dist diff --git a/.gitattributes b/.gitattributes index 887616f4e4..f85540ef05 100644 --- a/.gitattributes +++ b/.gitattributes @@ -17,6 +17,7 @@ .travis.yml export-ignore CONTRIBUTING.md export-ignore jest.config.js export-ignore +phpstan.neon.dist export-ignore phpunit.bat export-ignore phpunit.xml.dist export-ignore SECURITY.md export-ignore diff --git a/composer.json b/composer.json index 557e1ae5e4..d84c9a1e0b 100644 --- a/composer.json +++ b/composer.json @@ -45,11 +45,13 @@ "doctrine/dbal": "^3.6", "fakerphp/faker": "~1.10", "google/cloud-translate": "^1.6", + "larastan/larastan": "^3.10", "laravel/pao": "^1.1", "laravel/pint": "1.16.0", "laravel/socialite": "^5.28", "mockery/mockery": "^1.6.10", "orchestra/testbench": "^10.8 || ^11.0", + "phpstan/phpstan": "^2.2", "phpunit/phpunit": "^12.5.23", "spatie/laravel-ray": "^1.43.6" }, diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000000..e49c724c0a --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,7 @@ +includes: + - vendor/larastan/larastan/extension.neon + +parameters: + level: 0 + paths: + - src From 614978fcfb22d53895be8b4ea930c44f92085f40 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 11:50:29 -0400 Subject: [PATCH 02/28] Fix PHPStan new.static errors with @phpstan-consistent-constructor Marks classes whose constructor is compatible across their subclass hierarchy, so PHPStan can verify new static() calls are safe. Co-Authored-By: Claude Sonnet 5 --- src/Assets/AssetFolder.php | 3 +++ src/Assets/AssetUploader.php | 3 +++ src/Assets/FileUploader.php | 3 +++ src/Auth/Eloquent/Role.php | 3 +++ src/Auth/Eloquent/UserGroup.php | 3 +++ src/CP/Column.php | 3 +++ src/CP/Navigation/CoreNav.php | 3 +++ src/CP/Navigation/NavPreferencesNormalizer.php | 3 +++ src/CP/Navigation/NavTransformer.php | 3 +++ src/Console/Composer/Lock.php | 3 +++ src/Console/Processes/Process.php | 3 +++ src/Data/BulkAugmentor.php | 3 +++ src/Data/DataCollection.php | 2 ++ src/Data/DataReferenceUpdater.php | 3 +++ src/Events/AddonSettingsSaving.php | 3 +++ src/Events/AssetContainerCreating.php | 3 +++ src/Events/AssetContainerDeleting.php | 3 +++ src/Events/AssetContainerSaving.php | 3 +++ src/Events/AssetCreating.php | 3 +++ src/Events/AssetDeleting.php | 3 +++ src/Events/AssetSaving.php | 3 +++ src/Events/BlueprintCreating.php | 3 +++ src/Events/BlueprintDeleting.php | 3 +++ src/Events/BlueprintSaving.php | 3 +++ src/Events/CollectionCreating.php | 3 +++ src/Events/CollectionDeleting.php | 3 +++ src/Events/CollectionSaving.php | 3 +++ src/Events/CollectionTreeSaving.php | 3 +++ src/Events/EntryCreating.php | 3 +++ src/Events/EntryDeleting.php | 3 +++ src/Events/EntrySaving.php | 3 +++ src/Events/FieldsetCreating.php | 3 +++ src/Events/FieldsetDeleting.php | 3 +++ src/Events/FieldsetSaving.php | 3 +++ src/Events/FormCreating.php | 3 +++ src/Events/FormDeleting.php | 3 +++ src/Events/FormSaving.php | 3 +++ src/Events/FormSubmitted.php | 3 +++ src/Events/GlobalSetCreating.php | 3 +++ src/Events/GlobalSetDeleting.php | 3 +++ src/Events/GlobalSetSaving.php | 3 +++ src/Events/GlobalVariablesCreating.php | 3 +++ src/Events/GlobalVariablesDeleting.php | 3 +++ src/Events/GlobalVariablesSaving.php | 3 +++ src/Events/NavCreating.php | 3 +++ src/Events/NavDeleting.php | 3 +++ src/Events/NavSaving.php | 3 +++ src/Events/NavTreeSaving.php | 3 +++ src/Events/RevisionSaving.php | 3 +++ src/Events/SubmissionCreating.php | 3 +++ src/Events/SubmissionSaving.php | 3 +++ src/Events/TaxonomyCreating.php | 3 +++ src/Events/TaxonomyDeleting.php | 3 +++ src/Events/TaxonomySaving.php | 3 +++ src/Events/TermCreating.php | 3 +++ src/Events/TermDeleting.php | 3 +++ src/Events/TermSaving.php | 3 +++ src/Events/UserCreating.php | 3 +++ src/Events/UserDeleting.php | 3 +++ src/Events/UserRegistering.php | 3 +++ src/Events/UserSaving.php | 3 +++ src/Fields/Field.php | 3 +++ src/Fields/Fields.php | 3 +++ src/Fields/Validator.php | 3 +++ src/Fields/Value.php | 3 +++ src/Forms/Exceptions/BlueprintUndefinedException.php | 3 +++ src/Forms/Uploaders/AssetsUploader.php | 3 +++ src/Forms/Uploaders/FilesUploader.php | 3 +++ src/GraphQL/Types/ArrayType.php | 3 +++ src/Markdown/Parser.php | 3 +++ src/Providers/CollectionsServiceProvider.php | 3 +++ src/Query/OrderBy.php | 3 +++ src/Revisions/Revision.php | 3 +++ src/Statamic.php | 3 +++ src/Support/FileCollection.php | 3 +++ src/View/Scaffolding/Emitters/AbstractSourceEmitter.php | 3 +++ src/Widgets/VueComponent.php | 3 +++ 77 files changed, 230 insertions(+) diff --git a/src/Assets/AssetFolder.php b/src/Assets/AssetFolder.php index e190d9f1b1..8b5133f4e1 100644 --- a/src/Assets/AssetFolder.php +++ b/src/Assets/AssetFolder.php @@ -14,6 +14,9 @@ use Statamic\Support\Str; use Statamic\Support\Traits\FluentlyGetsAndSets; +/** + * @phpstan-consistent-constructor + */ class AssetFolder implements Arrayable, ContainsQueryableValues, Contract { use FluentlyGetsAndSets; diff --git a/src/Assets/AssetUploader.php b/src/Assets/AssetUploader.php index e919129273..a2ae157693 100644 --- a/src/Assets/AssetUploader.php +++ b/src/Assets/AssetUploader.php @@ -9,6 +9,9 @@ use Statamic\Support\Str; use Symfony\Component\HttpFoundation\File\UploadedFile; +/** + * @phpstan-consistent-constructor + */ class AssetUploader extends Uploader { private $asset; diff --git a/src/Assets/FileUploader.php b/src/Assets/FileUploader.php index 58a1e3f086..97461cb9d6 100644 --- a/src/Assets/FileUploader.php +++ b/src/Assets/FileUploader.php @@ -6,6 +6,9 @@ use Statamic\Facades\AssetContainer; use Symfony\Component\HttpFoundation\File\UploadedFile; +/** + * @phpstan-consistent-constructor + */ class FileUploader extends Uploader { protected $container; diff --git a/src/Auth/Eloquent/Role.php b/src/Auth/Eloquent/Role.php index 1c2672e127..e2d3b1909d 100644 --- a/src/Auth/Eloquent/Role.php +++ b/src/Auth/Eloquent/Role.php @@ -4,6 +4,9 @@ use Statamic\Auth\File\Role as FileRole; +/** + * @phpstan-consistent-constructor + */ class Role extends FileRole { protected $model; diff --git a/src/Auth/Eloquent/UserGroup.php b/src/Auth/Eloquent/UserGroup.php index e75268b5c8..9b02ba6490 100644 --- a/src/Auth/Eloquent/UserGroup.php +++ b/src/Auth/Eloquent/UserGroup.php @@ -6,6 +6,9 @@ use Statamic\Auth\File\UserGroup as FileUserGroup; use Statamic\Facades\User; +/** + * @phpstan-consistent-constructor + */ class UserGroup extends FileUserGroup { protected $model; diff --git a/src/CP/Column.php b/src/CP/Column.php index 0bf83d59a5..78b662623a 100644 --- a/src/CP/Column.php +++ b/src/CP/Column.php @@ -5,6 +5,9 @@ use Statamic\Support\Str; use Statamic\Support\Traits\FluentlyGetsAndSets; +/** + * @phpstan-consistent-constructor + */ class Column { use FluentlyGetsAndSets; diff --git a/src/CP/Navigation/CoreNav.php b/src/CP/Navigation/CoreNav.php index 7aba785ce8..036e622cd1 100644 --- a/src/CP/Navigation/CoreNav.php +++ b/src/CP/Navigation/CoreNav.php @@ -25,6 +25,9 @@ use Statamic\Facades\Utility; use Statamic\Statamic; +/** + * @phpstan-consistent-constructor + */ class CoreNav { /** diff --git a/src/CP/Navigation/NavPreferencesNormalizer.php b/src/CP/Navigation/NavPreferencesNormalizer.php index 5d12eab177..82318c342f 100644 --- a/src/CP/Navigation/NavPreferencesNormalizer.php +++ b/src/CP/Navigation/NavPreferencesNormalizer.php @@ -6,6 +6,9 @@ use Statamic\Support\Arr; use Statamic\Support\Str; +/** + * @phpstan-consistent-constructor + */ class NavPreferencesNormalizer { protected $preferences; diff --git a/src/CP/Navigation/NavTransformer.php b/src/CP/Navigation/NavTransformer.php index 67f9114827..9fece64d4c 100644 --- a/src/CP/Navigation/NavTransformer.php +++ b/src/CP/Navigation/NavTransformer.php @@ -8,6 +8,9 @@ use Statamic\Support\Arr; use Statamic\Support\Str; +/** + * @phpstan-consistent-constructor + */ class NavTransformer { protected $coreNav; diff --git a/src/Console/Composer/Lock.php b/src/Console/Composer/Lock.php index 7ba5a77319..764fef5c07 100644 --- a/src/Console/Composer/Lock.php +++ b/src/Console/Composer/Lock.php @@ -9,6 +9,9 @@ use Statamic\Facades\Path; use Statamic\UpdateScripts\UpdateScript; +/** + * @phpstan-consistent-constructor + */ class Lock { protected $files; diff --git a/src/Console/Processes/Process.php b/src/Console/Processes/Process.php index dd30262973..b59e9c8547 100644 --- a/src/Console/Processes/Process.php +++ b/src/Console/Processes/Process.php @@ -12,6 +12,9 @@ use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\Process as SymfonyProcess; +/** + * @phpstan-consistent-constructor + */ class Process { const CACHE_EXPIRY_MINUTES = 10; diff --git a/src/Data/BulkAugmentor.php b/src/Data/BulkAugmentor.php index 018b1b52c2..9e5ef00505 100644 --- a/src/Data/BulkAugmentor.php +++ b/src/Data/BulkAugmentor.php @@ -5,6 +5,9 @@ use Statamic\Contracts\Data\Augmentable; use Statamic\Contracts\Data\BulkAugmentable; +/** + * @phpstan-consistent-constructor + */ class BulkAugmentor { private $isTree = false; diff --git a/src/Data/DataCollection.php b/src/Data/DataCollection.php index 76a5434aa4..2cbad8df46 100644 --- a/src/Data/DataCollection.php +++ b/src/Data/DataCollection.php @@ -13,6 +13,8 @@ /** * An abstract collection of data types. + * + * @phpstan-consistent-constructor */ class DataCollection extends IlluminateCollection { diff --git a/src/Data/DataReferenceUpdater.php b/src/Data/DataReferenceUpdater.php index 1eaaf2974f..8f861c9012 100644 --- a/src/Data/DataReferenceUpdater.php +++ b/src/Data/DataReferenceUpdater.php @@ -7,6 +7,9 @@ use Statamic\Git\Subscriber as GitSubscriber; use Statamic\Support\Arr; +/** + * @phpstan-consistent-constructor + */ abstract class DataReferenceUpdater { /** diff --git a/src/Events/AddonSettingsSaving.php b/src/Events/AddonSettingsSaving.php index 0d2b91534c..a854555758 100644 --- a/src/Events/AddonSettingsSaving.php +++ b/src/Events/AddonSettingsSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class AddonSettingsSaving extends Event { public function __construct(public $settings) diff --git a/src/Events/AssetContainerCreating.php b/src/Events/AssetContainerCreating.php index a621cdfd63..35a7661b37 100644 --- a/src/Events/AssetContainerCreating.php +++ b/src/Events/AssetContainerCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class AssetContainerCreating extends Event { public function __construct(public $container) diff --git a/src/Events/AssetContainerDeleting.php b/src/Events/AssetContainerDeleting.php index 2f0d790809..41eb66629c 100644 --- a/src/Events/AssetContainerDeleting.php +++ b/src/Events/AssetContainerDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class AssetContainerDeleting extends Event { public function __construct(public $container) diff --git a/src/Events/AssetContainerSaving.php b/src/Events/AssetContainerSaving.php index f71c924074..5793d02255 100644 --- a/src/Events/AssetContainerSaving.php +++ b/src/Events/AssetContainerSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class AssetContainerSaving extends Event { public function __construct(public $container) diff --git a/src/Events/AssetCreating.php b/src/Events/AssetCreating.php index a375c80c9b..a5cf9e264f 100644 --- a/src/Events/AssetCreating.php +++ b/src/Events/AssetCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class AssetCreating extends Event { public function __construct(public $asset) diff --git a/src/Events/AssetDeleting.php b/src/Events/AssetDeleting.php index 2eadb47767..a12777bd6e 100644 --- a/src/Events/AssetDeleting.php +++ b/src/Events/AssetDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class AssetDeleting extends Event { public function __construct(public $asset) diff --git a/src/Events/AssetSaving.php b/src/Events/AssetSaving.php index 535f75b938..b5370525d6 100644 --- a/src/Events/AssetSaving.php +++ b/src/Events/AssetSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class AssetSaving extends Event { public function __construct(public $asset) diff --git a/src/Events/BlueprintCreating.php b/src/Events/BlueprintCreating.php index 44425253d5..ba615a4843 100644 --- a/src/Events/BlueprintCreating.php +++ b/src/Events/BlueprintCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class BlueprintCreating extends Event { public function __construct(public $blueprint) diff --git a/src/Events/BlueprintDeleting.php b/src/Events/BlueprintDeleting.php index 9d3b3f8330..37568d28b3 100644 --- a/src/Events/BlueprintDeleting.php +++ b/src/Events/BlueprintDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class BlueprintDeleting extends Event { public function __construct(public $blueprint) diff --git a/src/Events/BlueprintSaving.php b/src/Events/BlueprintSaving.php index 1129baa2b9..dd82e2f04b 100644 --- a/src/Events/BlueprintSaving.php +++ b/src/Events/BlueprintSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class BlueprintSaving extends Event { public function __construct(public $blueprint) diff --git a/src/Events/CollectionCreating.php b/src/Events/CollectionCreating.php index f60b8588a2..7b350d493a 100644 --- a/src/Events/CollectionCreating.php +++ b/src/Events/CollectionCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class CollectionCreating extends Event { public function __construct(public $collection) diff --git a/src/Events/CollectionDeleting.php b/src/Events/CollectionDeleting.php index d216bf6043..3b45121c2e 100644 --- a/src/Events/CollectionDeleting.php +++ b/src/Events/CollectionDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class CollectionDeleting extends Event { public function __construct(public $collection) diff --git a/src/Events/CollectionSaving.php b/src/Events/CollectionSaving.php index 4d02803683..1496be50f5 100644 --- a/src/Events/CollectionSaving.php +++ b/src/Events/CollectionSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class CollectionSaving extends Event { public function __construct(public $collection) diff --git a/src/Events/CollectionTreeSaving.php b/src/Events/CollectionTreeSaving.php index 27be32b9d3..14151a436b 100644 --- a/src/Events/CollectionTreeSaving.php +++ b/src/Events/CollectionTreeSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class CollectionTreeSaving extends Event { public function __construct(public $tree) diff --git a/src/Events/EntryCreating.php b/src/Events/EntryCreating.php index 9e6c782611..355e9a3350 100644 --- a/src/Events/EntryCreating.php +++ b/src/Events/EntryCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class EntryCreating extends Event { public function __construct(public $entry) diff --git a/src/Events/EntryDeleting.php b/src/Events/EntryDeleting.php index 8d62b8104c..056a6ebd5e 100644 --- a/src/Events/EntryDeleting.php +++ b/src/Events/EntryDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class EntryDeleting extends Event { public function __construct(public $entry) diff --git a/src/Events/EntrySaving.php b/src/Events/EntrySaving.php index 06539c14a1..bfc6a2ca2c 100644 --- a/src/Events/EntrySaving.php +++ b/src/Events/EntrySaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class EntrySaving extends Event { public function __construct(public $entry) diff --git a/src/Events/FieldsetCreating.php b/src/Events/FieldsetCreating.php index a26fd6d306..f913c41ee9 100644 --- a/src/Events/FieldsetCreating.php +++ b/src/Events/FieldsetCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class FieldsetCreating extends Event { public function __construct(public $fieldset) diff --git a/src/Events/FieldsetDeleting.php b/src/Events/FieldsetDeleting.php index af09dcbfab..e70d8b863b 100644 --- a/src/Events/FieldsetDeleting.php +++ b/src/Events/FieldsetDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class FieldsetDeleting extends Event { public function __construct(public $fieldset) diff --git a/src/Events/FieldsetSaving.php b/src/Events/FieldsetSaving.php index ef7ed93113..0feea9cbf6 100644 --- a/src/Events/FieldsetSaving.php +++ b/src/Events/FieldsetSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class FieldsetSaving extends Event { public function __construct(public $fieldset) diff --git a/src/Events/FormCreating.php b/src/Events/FormCreating.php index e9a86eefdd..3b404779f4 100644 --- a/src/Events/FormCreating.php +++ b/src/Events/FormCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class FormCreating extends Event { public function __construct(public $form) diff --git a/src/Events/FormDeleting.php b/src/Events/FormDeleting.php index 35745cfd34..3d991e068b 100644 --- a/src/Events/FormDeleting.php +++ b/src/Events/FormDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class FormDeleting extends Event { public function __construct(public $form) diff --git a/src/Events/FormSaving.php b/src/Events/FormSaving.php index 513f818485..058c535fc0 100644 --- a/src/Events/FormSaving.php +++ b/src/Events/FormSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class FormSaving extends Event { public function __construct(public $form) diff --git a/src/Events/FormSubmitted.php b/src/Events/FormSubmitted.php index cb81358b3c..f03780d662 100644 --- a/src/Events/FormSubmitted.php +++ b/src/Events/FormSubmitted.php @@ -4,6 +4,9 @@ use Statamic\Contracts\Forms\Submission; +/** + * @phpstan-consistent-constructor + */ class FormSubmitted extends Event { public function __construct(public Submission $submission) diff --git a/src/Events/GlobalSetCreating.php b/src/Events/GlobalSetCreating.php index 5d535df8f6..576a1d9973 100644 --- a/src/Events/GlobalSetCreating.php +++ b/src/Events/GlobalSetCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class GlobalSetCreating extends Event { public function __construct(public $globals) diff --git a/src/Events/GlobalSetDeleting.php b/src/Events/GlobalSetDeleting.php index 570098c1f9..7db7336f5c 100644 --- a/src/Events/GlobalSetDeleting.php +++ b/src/Events/GlobalSetDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class GlobalSetDeleting extends Event { public function __construct(public $globals) diff --git a/src/Events/GlobalSetSaving.php b/src/Events/GlobalSetSaving.php index 1a3b3e6352..d8797dbfda 100644 --- a/src/Events/GlobalSetSaving.php +++ b/src/Events/GlobalSetSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class GlobalSetSaving extends Event { public function __construct(public $globals) diff --git a/src/Events/GlobalVariablesCreating.php b/src/Events/GlobalVariablesCreating.php index 630a25633f..d231c27536 100644 --- a/src/Events/GlobalVariablesCreating.php +++ b/src/Events/GlobalVariablesCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class GlobalVariablesCreating extends Event { public function __construct(public $variables) diff --git a/src/Events/GlobalVariablesDeleting.php b/src/Events/GlobalVariablesDeleting.php index 69c24b3f47..3427092cf6 100644 --- a/src/Events/GlobalVariablesDeleting.php +++ b/src/Events/GlobalVariablesDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class GlobalVariablesDeleting extends Event { public function __construct(public $variables) diff --git a/src/Events/GlobalVariablesSaving.php b/src/Events/GlobalVariablesSaving.php index 594ea22bc2..7cd18bbfc9 100644 --- a/src/Events/GlobalVariablesSaving.php +++ b/src/Events/GlobalVariablesSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class GlobalVariablesSaving extends Event { public function __construct(public $variables) diff --git a/src/Events/NavCreating.php b/src/Events/NavCreating.php index ada7d791e3..7f68d7afc3 100644 --- a/src/Events/NavCreating.php +++ b/src/Events/NavCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class NavCreating extends Event { public function __construct(public $nav) diff --git a/src/Events/NavDeleting.php b/src/Events/NavDeleting.php index d64882ffc7..26cbc52fbc 100644 --- a/src/Events/NavDeleting.php +++ b/src/Events/NavDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class NavDeleting extends Event { public function __construct(public $nav) diff --git a/src/Events/NavSaving.php b/src/Events/NavSaving.php index 8ae6accbef..a7852f248b 100644 --- a/src/Events/NavSaving.php +++ b/src/Events/NavSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class NavSaving extends Event { public function __construct(public $nav) diff --git a/src/Events/NavTreeSaving.php b/src/Events/NavTreeSaving.php index 58b117e7ab..3b5b47fb06 100644 --- a/src/Events/NavTreeSaving.php +++ b/src/Events/NavTreeSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class NavTreeSaving extends Event { public function __construct(public $tree) diff --git a/src/Events/RevisionSaving.php b/src/Events/RevisionSaving.php index 8d295b2f00..2ae55ff96c 100644 --- a/src/Events/RevisionSaving.php +++ b/src/Events/RevisionSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class RevisionSaving extends Event { public function __construct(public $revision) diff --git a/src/Events/SubmissionCreating.php b/src/Events/SubmissionCreating.php index a7ad5c930b..cd2015d69f 100644 --- a/src/Events/SubmissionCreating.php +++ b/src/Events/SubmissionCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class SubmissionCreating extends Event { public function __construct(public $submission) diff --git a/src/Events/SubmissionSaving.php b/src/Events/SubmissionSaving.php index e632a22fd4..732eb80e60 100644 --- a/src/Events/SubmissionSaving.php +++ b/src/Events/SubmissionSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class SubmissionSaving extends Event { public function __construct(public $submission) diff --git a/src/Events/TaxonomyCreating.php b/src/Events/TaxonomyCreating.php index 2f869eb4be..3602fd766b 100644 --- a/src/Events/TaxonomyCreating.php +++ b/src/Events/TaxonomyCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class TaxonomyCreating extends Event { public function __construct(public $taxonomy) diff --git a/src/Events/TaxonomyDeleting.php b/src/Events/TaxonomyDeleting.php index b157a192e8..81d3b0a29b 100644 --- a/src/Events/TaxonomyDeleting.php +++ b/src/Events/TaxonomyDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class TaxonomyDeleting extends Event { public function __construct(public $taxonomy) diff --git a/src/Events/TaxonomySaving.php b/src/Events/TaxonomySaving.php index fc1ac3e656..c95daaa05e 100644 --- a/src/Events/TaxonomySaving.php +++ b/src/Events/TaxonomySaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class TaxonomySaving extends Event { public function __construct(public $taxonomy) diff --git a/src/Events/TermCreating.php b/src/Events/TermCreating.php index d8432b528a..56aad9a805 100644 --- a/src/Events/TermCreating.php +++ b/src/Events/TermCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class TermCreating extends Event { public function __construct(public $term) diff --git a/src/Events/TermDeleting.php b/src/Events/TermDeleting.php index 179a701788..422d7b0375 100644 --- a/src/Events/TermDeleting.php +++ b/src/Events/TermDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class TermDeleting extends Event { public function __construct(public $term) diff --git a/src/Events/TermSaving.php b/src/Events/TermSaving.php index da2d86d5a4..1db28d7de5 100644 --- a/src/Events/TermSaving.php +++ b/src/Events/TermSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class TermSaving extends Event { public function __construct(public $term) diff --git a/src/Events/UserCreating.php b/src/Events/UserCreating.php index 55989dc3e4..e6346c7a33 100644 --- a/src/Events/UserCreating.php +++ b/src/Events/UserCreating.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class UserCreating extends Event { public function __construct(public $user) diff --git a/src/Events/UserDeleting.php b/src/Events/UserDeleting.php index 40192e48ae..0921fba427 100644 --- a/src/Events/UserDeleting.php +++ b/src/Events/UserDeleting.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class UserDeleting extends Event { public function __construct(public $user) diff --git a/src/Events/UserRegistering.php b/src/Events/UserRegistering.php index e9c8d51321..33be8f2569 100644 --- a/src/Events/UserRegistering.php +++ b/src/Events/UserRegistering.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class UserRegistering extends Event { public function __construct(public $user) diff --git a/src/Events/UserSaving.php b/src/Events/UserSaving.php index b42a063152..c52f34e898 100644 --- a/src/Events/UserSaving.php +++ b/src/Events/UserSaving.php @@ -2,6 +2,9 @@ namespace Statamic\Events; +/** + * @phpstan-consistent-constructor + */ class UserSaving extends Event { public function __construct(public $user) diff --git a/src/Fields/Field.php b/src/Fields/Field.php index a731e62ed7..2af853df88 100644 --- a/src/Fields/Field.php +++ b/src/Fields/Field.php @@ -16,6 +16,9 @@ use function Statamic\trans as __; +/** + * @phpstan-consistent-constructor + */ class Field implements Arrayable { protected $handle; diff --git a/src/Fields/Fields.php b/src/Fields/Fields.php index 054c14361d..f6707b5086 100644 --- a/src/Fields/Fields.php +++ b/src/Fields/Fields.php @@ -10,6 +10,9 @@ use Statamic\Facades\Fieldset as FieldsetRepository; use Statamic\Support\Arr; +/** + * @phpstan-consistent-constructor + */ class Fields { protected $items; diff --git a/src/Fields/Validator.php b/src/Fields/Validator.php index 2f6c4d9398..394d759379 100644 --- a/src/Fields/Validator.php +++ b/src/Fields/Validator.php @@ -6,6 +6,9 @@ use Statamic\Support\Arr; use Statamic\Support\Str; +/** + * @phpstan-consistent-constructor + */ class Validator { protected $fields; diff --git a/src/Fields/Value.php b/src/Fields/Value.php index 5ac457691e..6a93a8b3cb 100644 --- a/src/Fields/Value.php +++ b/src/Fields/Value.php @@ -15,6 +15,9 @@ use Statamic\View\Cascade; use Traversable; +/** + * @phpstan-consistent-constructor + */ class Value implements ArrayAccess, IteratorAggregate, JsonSerializable { private $resolver; diff --git a/src/Forms/Exceptions/BlueprintUndefinedException.php b/src/Forms/Exceptions/BlueprintUndefinedException.php index 15a687e99b..bd9bd407da 100644 --- a/src/Forms/Exceptions/BlueprintUndefinedException.php +++ b/src/Forms/Exceptions/BlueprintUndefinedException.php @@ -9,6 +9,9 @@ use Statamic\Forms\Form; use Statamic\Statamic; +/** + * @phpstan-consistent-constructor + */ class BlueprintUndefinedException extends LogicException implements ProvidesSolution { protected $form; diff --git a/src/Forms/Uploaders/AssetsUploader.php b/src/Forms/Uploaders/AssetsUploader.php index 1c4341ebf3..c583604ad7 100644 --- a/src/Forms/Uploaders/AssetsUploader.php +++ b/src/Forms/Uploaders/AssetsUploader.php @@ -9,6 +9,9 @@ use Statamic\Fieldtypes\Assets\UndefinedContainerException; use Statamic\Support\Arr; +/** + * @phpstan-consistent-constructor + */ class AssetsUploader { protected $config; diff --git a/src/Forms/Uploaders/FilesUploader.php b/src/Forms/Uploaders/FilesUploader.php index 5a575b39e0..619580c36d 100644 --- a/src/Forms/Uploaders/FilesUploader.php +++ b/src/Forms/Uploaders/FilesUploader.php @@ -5,6 +5,9 @@ use Statamic\Assets\FileUploader; use Statamic\Support\Arr; +/** + * @phpstan-consistent-constructor + */ class FilesUploader { protected $config; diff --git a/src/GraphQL/Types/ArrayType.php b/src/GraphQL/Types/ArrayType.php index cdf8a13d3a..325712cabd 100644 --- a/src/GraphQL/Types/ArrayType.php +++ b/src/GraphQL/Types/ArrayType.php @@ -7,6 +7,9 @@ use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Contracts\TypeConvertible; +/** + * @phpstan-consistent-constructor + */ class ArrayType extends ScalarType implements TypeConvertible { const NAME = 'Array'; diff --git a/src/Markdown/Parser.php b/src/Markdown/Parser.php index 9c4a9aa760..a36640c900 100644 --- a/src/Markdown/Parser.php +++ b/src/Markdown/Parser.php @@ -9,6 +9,9 @@ use League\CommonMark\Extension\SmartPunct\SmartPunctExtension; use Statamic\Support\Arr; +/** + * @phpstan-consistent-constructor + */ class Parser { use Macroable; diff --git a/src/Providers/CollectionsServiceProvider.php b/src/Providers/CollectionsServiceProvider.php index 14cc476b5c..b20d73783d 100644 --- a/src/Providers/CollectionsServiceProvider.php +++ b/src/Providers/CollectionsServiceProvider.php @@ -7,6 +7,9 @@ use Illuminate\Support\ServiceProvider; use Statamic\Contracts\Data\Augmentable; +/** + * @phpstan-consistent-constructor + */ class CollectionsServiceProvider extends ServiceProvider { /** diff --git a/src/Query/OrderBy.php b/src/Query/OrderBy.php index dce95d8897..d0e94b2339 100644 --- a/src/Query/OrderBy.php +++ b/src/Query/OrderBy.php @@ -2,6 +2,9 @@ namespace Statamic\Query; +/** + * @phpstan-consistent-constructor + */ class OrderBy { public $sort; diff --git a/src/Revisions/Revision.php b/src/Revisions/Revision.php index a804799ebd..94b660815d 100644 --- a/src/Revisions/Revision.php +++ b/src/Revisions/Revision.php @@ -16,6 +16,9 @@ use Statamic\Facades\Revision as Revisions; use Statamic\Support\Traits\FluentlyGetsAndSets; +/** + * @phpstan-consistent-constructor + */ class Revision implements Arrayable, ContainsQueryableValues, Contract { use ExistsAsFile, FluentlyGetsAndSets, TracksQueriedColumns, TracksQueriedRelations; diff --git a/src/Statamic.php b/src/Statamic.php index 67e9cf59ad..abb4e4d839 100644 --- a/src/Statamic.php +++ b/src/Statamic.php @@ -20,6 +20,9 @@ use Statamic\Support\TextDirection; use Statamic\Tags\FluentTag; +/** + * @phpstan-consistent-constructor + */ class Statamic { const CORE_SLUG = 'statamic'; diff --git a/src/Support/FileCollection.php b/src/Support/FileCollection.php index 5c6378b403..389ce19425 100644 --- a/src/Support/FileCollection.php +++ b/src/Support/FileCollection.php @@ -10,6 +10,9 @@ use Symfony\Component\Finder\Comparator\DateComparator; use Symfony\Component\Finder\Comparator\NumberComparator; +/** + * @phpstan-consistent-constructor + */ class FileCollection extends Collection { /** diff --git a/src/View/Scaffolding/Emitters/AbstractSourceEmitter.php b/src/View/Scaffolding/Emitters/AbstractSourceEmitter.php index e0cda8d476..c8a79b24dd 100644 --- a/src/View/Scaffolding/Emitters/AbstractSourceEmitter.php +++ b/src/View/Scaffolding/Emitters/AbstractSourceEmitter.php @@ -10,6 +10,9 @@ use Statamic\View\Scaffolding\TemplateGenerator; use Stringable; +/** + * @phpstan-consistent-constructor + */ abstract class AbstractSourceEmitter implements Stringable { protected static array $blueprintStack = []; diff --git a/src/Widgets/VueComponent.php b/src/Widgets/VueComponent.php index 9e6601a981..cdaa544b72 100644 --- a/src/Widgets/VueComponent.php +++ b/src/Widgets/VueComponent.php @@ -4,6 +4,9 @@ use Illuminate\Contracts\Support\Arrayable; +/** + * @phpstan-consistent-constructor + */ class VueComponent implements Arrayable { public function __construct(private string $name, private array $props = []) From 6c01c4cb3b98957380859e5097bceb2314e8ee35 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 11:50:33 -0400 Subject: [PATCH 03/28] Fix PHPStan method.staticCall errors with explicit facade return types Facade @method docblocks lacking a return type were resolved as instance methods instead of static ones. Co-Authored-By: Claude Sonnet 5 --- src/Facades/Taxonomy.php | 4 ++-- src/Facades/Term.php | 4 ++-- src/Facades/User.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Facades/Taxonomy.php b/src/Facades/Taxonomy.php index 1abd25406a..4da8bc96f7 100644 --- a/src/Facades/Taxonomy.php +++ b/src/Facades/Taxonomy.php @@ -16,8 +16,8 @@ * @method static void save(\Statamic\Contracts\Taxonomies\Taxonomy $taxonomy) * @method static void delete(\Statamic\Contracts\Taxonomies\Taxonomy $taxonomy) * @method static \Statamic\Contracts\Taxonomies\Taxonomy make(?string $handle = null) - * @method static addPreviewTargets(string $handle, array $targets) - * @method static additionalPreviewTargets(string $handle) + * @method static void addPreviewTargets(string $handle, array $targets) + * @method static \Illuminate\Support\Collection additionalPreviewTargets(string $handle) * * @see \Statamic\Stache\Repositories\TaxonomyRepository * @link \Statamic\Taxonomies\Taxonomy diff --git a/src/Facades/Term.php b/src/Facades/Term.php index 499e708999..4616d57d60 100644 --- a/src/Facades/Term.php +++ b/src/Facades/Term.php @@ -18,8 +18,8 @@ * @method static TermContract findOrMake($id) * @method static TermContract findOr($id, \Closure $callback) * @method static TermContract make(string $slug = null) - * @method static save($term) - * @method static delete($term) + * @method static void save($term) + * @method static void delete($term) * @method static TermQueryBuilder query() * @method static int entriesCount(Term $term) * @method static void substitute($item) diff --git a/src/Facades/User.php b/src/Facades/User.php index 2baae60478..b3fbeb261b 100644 --- a/src/Facades/User.php +++ b/src/Facades/User.php @@ -13,7 +13,7 @@ * @method static null|\Statamic\Contracts\Auth\User findByEmail(string $email) * @method static null|\Statamic\Contracts\Auth\User findByOAuthId(Provider $provider, string $id) * @method static \Statamic\Contracts\Auth\User findOrFail($id) - * @method static query() + * @method static \Statamic\Contracts\Query\Builder query() * @method static int count() * @method static null|\Statamic\Contracts\Auth\User current() * @method static null|\Statamic\Contracts\Auth\User fromUser($user) From f93c6b9869d244637c6c0e98bddccac9aa089ac8 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 11:50:37 -0400 Subject: [PATCH 04/28] Fix PHPStan method.notFound errors with @mixin/@var annotations Co-Authored-By: Claude Sonnet 5 --- src/Mixins/Router.php | 3 +++ src/Providers/AppServiceProvider.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/Mixins/Router.php b/src/Mixins/Router.php index 593af05d1f..7f359e2658 100644 --- a/src/Mixins/Router.php +++ b/src/Mixins/Router.php @@ -4,6 +4,9 @@ use Statamic\Http\Controllers\FrontendController; +/** + * @mixin \Illuminate\Routing\Router + */ class Router { public function statamic() diff --git a/src/Providers/AppServiceProvider.php b/src/Providers/AppServiceProvider.php index b9aa25e36e..4721714245 100644 --- a/src/Providers/AppServiceProvider.php +++ b/src/Providers/AppServiceProvider.php @@ -97,6 +97,7 @@ public function boot() ], 'statamic-scaffolding'); $this->app['redirect']->macro('cpRoute', function ($route, $parameters = []) { + /** @var \Illuminate\Routing\Redirector $this */ return $this->to(cp_route($route, $parameters)); }); @@ -366,6 +367,7 @@ private function registerElevatedSessionMacros() }); Session::macro('elevate', function () { + /** @var \Illuminate\Session\Store $this */ $this->put('statamic_elevated_session', now()->timestamp); $this->forget('statamic_elevated_session_verification_code'); }); From 2a139c889c3443912f573263633b32e593d06dd2 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 13:24:01 -0400 Subject: [PATCH 05/28] Ignore PHPStan errors from optional spatie/laravel-ignition integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spatie/laravel-ignition is never a real dependency of this package — it's an optional integration only present when the consuming Laravel app installs it, guarded by isIgnitionInstalled()/class_exists() checks in RuntimeParser.php. It can't be installed as a dev dependency either: this repo's Laravel 13/Symfony 8 requirements conflict with even the latest stable ignition release. Co-Authored-By: Claude Sonnet 5 --- phpstan.neon.dist | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e49c724c0a..4581c7cea5 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -5,3 +5,9 @@ parameters: level: 0 paths: - src + + ignoreErrors: + - + identifier: class.notFound + message: '#^(Class|Instantiated class) Spatie\\LaravelIgnition\\Exceptions\\(ViewException|ViewExceptionWithSolution) not found\.$#' + path: src/View/Antlers/Language/Runtime/RuntimeParser.php From b3d0e7fe4ba4531c900b8f937adf033a5939ee8c Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 13:24:12 -0400 Subject: [PATCH 06/28] Ignore PHPStan errors from optional composer/composer integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Statamic\Console\Composer\Scripts::preUpdateCmd() type-hints Composer\Script\Event purely for IDE/static-analysis benefit — the class is always available at runtime when Composer invokes the script, but composer/composer was never a real dependency of this package and isn't worth adding just for this type hint. Co-Authored-By: Claude Sonnet 5 --- phpstan.neon.dist | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 4581c7cea5..3aac0adf49 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -11,3 +11,9 @@ parameters: identifier: class.notFound message: '#^(Class|Instantiated class) Spatie\\LaravelIgnition\\Exceptions\\(ViewException|ViewExceptionWithSolution) not found\.$#' path: src/View/Antlers/Language/Runtime/RuntimeParser.php + + # composer/composer is an optional runtime integration (composer update hooks), not a real dependency. + - + identifier: class.notFound + message: '#^Parameter \$event of method Statamic\\Console\\Composer\\Scripts::preUpdateCmd\(\) has invalid type Composer\\Script\\Event\.$#' + path: src/Console/Composer/Scripts.php From e441ab7e56bdedd340a5aa1df6e58700e9901e13 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 13:24:36 -0400 Subject: [PATCH 07/28] Ignore PHPStan errors from optional barryvdh/laravel-debugbar integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit barryvdh/laravel-debugbar is never a real dependency of this package — Statamic's View/Debugbar/* classes only activate when the consuming app has it installed, guarded by class_exists()/isEnabled() checks. Most of the resulting errors are simple ignoreErrors entries, but PHPStan hard-refuses to ignore "extends/implements unknown class" errors (PerformanceCollector.php, VariableCollector.php) via ignoreErrors — it requires the symbol to actually resolve. Since those files also contain real logic worth analyzing, excludePaths would have thrown out too much; instead .phpstan/stubs/debugbar.php provides minimal empty-shell declarations (DataCollector, ConfigCollector, AssetProvider, Renderable, Resettable) via scanFiles, matching the real php-debugbar API surface just enough for PHPStan to resolve the class hierarchy. Co-Authored-By: Claude Sonnet 5 --- .phpstan/stubs/debugbar.php | 80 +++++++++++++++++++++++++++++++++++++ phpstan.neon.dist | 15 +++++++ 2 files changed, 95 insertions(+) create mode 100644 .phpstan/stubs/debugbar.php diff --git a/.phpstan/stubs/debugbar.php b/.phpstan/stubs/debugbar.php new file mode 100644 index 0000000000..3805b58226 --- /dev/null +++ b/.phpstan/stubs/debugbar.php @@ -0,0 +1,80 @@ +name = $name; + } + + public function reset(): void + { + // + } + + public function setData(array $data): void + { + // + } + + public function collect(): array + { + return []; + } + + public function getName(): string + { + return $this->name; + } + + public function getWidgets(): array + { + return []; + } +} diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 3aac0adf49..abd927068b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,6 +6,11 @@ parameters: paths: - src + # Symbol-only stubs for optional runtime integrations that this package + # never requires as real dependencies (see .phpstan/stubs/debugbar.php). + scanFiles: + - .phpstan/stubs/debugbar.php + ignoreErrors: - identifier: class.notFound @@ -17,3 +22,13 @@ parameters: identifier: class.notFound message: '#^Parameter \$event of method Statamic\\Console\\Composer\\Scripts::preUpdateCmd\(\) has invalid type Composer\\Script\\Event\.$#' path: src/Console/Composer/Scripts.php + + # barryvdh/laravel-debugbar is an optional runtime integration, guarded by class_exists()/isEnabled() checks. + - + identifier: class.notFound + message: '#^Caught class DebugBar\\DebugBarException not found\.$#' + path: src/Forms/Tags.php + - + identifier: function.notFound + message: '#^Function debug not found\.$#' + path: src/Modifiers/CoreModifiers.php From 45f64541a5307a3ec8bf346ee0df23573a291c6e Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 13:39:04 -0400 Subject: [PATCH 08/28] Remove dead UserCollection::extract() method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Statamic\Auth\UserService has never existed in this repo's git history (git log --all --follow -- "*UserService.php" returns nothing) — this line has been broken since the file was carried over from the pre-monorepo codebase in commit a817e268f14 (2017-11-21). extract() isn't part of the parent DataCollection contract, and has zero call sites anywhere in src/ or tests/, so it was silently dead (and PHP-fatal if ever called) rather than causing a visible bug. Co-Authored-By: Claude Sonnet 5 --- src/Auth/UserCollection.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Auth/UserCollection.php b/src/Auth/UserCollection.php index 1f3cae5412..186122b006 100644 --- a/src/Auth/UserCollection.php +++ b/src/Auth/UserCollection.php @@ -9,14 +9,4 @@ */ class UserCollection extends DataCollection { - /** - * Get the collection as an array. - * - * @param bool $supplement - * @return array - */ - public function extract($supplement = false) - { - return UserService::transform($this->items, $supplement); - } } From 4b286d0cf6a2714c6970b6d2c389af087f2ef7b4 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 13:40:06 -0400 Subject: [PATCH 09/28] Remove dead Statamic\View\Store container binding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Statamic\View\Store was deleted in commit ada5c2ea8d ("SSG fixes (#3562)", 2021-04-23), but the container binding for it in ViewServiceProvider::register() was never cleaned up afterward. No other reference to Statamic\View\Store exists in src/ or tests/ (the many other Store::class matches in the codebase are unrelated classes — Stache\Stores\*, Illuminate\Contracts\Cache\Store, etc.). Co-Authored-By: Claude Sonnet 5 --- src/Providers/ViewServiceProvider.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Providers/ViewServiceProvider.php b/src/Providers/ViewServiceProvider.php index 7024b87efc..0cac2e8768 100644 --- a/src/Providers/ViewServiceProvider.php +++ b/src/Providers/ViewServiceProvider.php @@ -26,7 +26,6 @@ use Statamic\View\Debugbar\AntlersProfiler\PerformanceCollector; use Statamic\View\Debugbar\AntlersProfiler\PerformanceTracer; use Statamic\View\Interop\Stacks; -use Statamic\View\Store; class ViewServiceProvider extends ServiceProvider { @@ -37,8 +36,6 @@ class ViewServiceProvider extends ServiceProvider */ public function register() { - $this->app->singleton(Store::class); - $this->app->singleton(Cascade::class, function ($app) { return new Cascade($app['request'], Site::current()); }); From d0227eaead0f6fbc503363958c0a53b255a36315 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 13:41:19 -0400 Subject: [PATCH 10/28] Remove dead Statamic\Taxonomies\TermTracker class Both Statamic\Events\Stache\RepositoryItemInserted and RepositoryItemRemoved, which TermTracker::subscribe()/insert()/ remove() depend on, were deleted in commit 7ceee82a5f ("Remove outdated events", 2020-07-09). TermTracker was never wired back up after that: EventServiceProvider has it commented out (// \Statamic\Taxonomies\TermTracker::class, // TODO), so subscribe() never runs and insert()/remove() are never invoked. No tests reference it. Its responsibility (tracking term associations) is already covered by the still-active src/Listeners/UpdateTermReferences.php. Co-Authored-By: Claude Sonnet 5 --- src/Taxonomies/TermTracker.php | 102 --------------------------------- 1 file changed, 102 deletions(-) delete mode 100644 src/Taxonomies/TermTracker.php diff --git a/src/Taxonomies/TermTracker.php b/src/Taxonomies/TermTracker.php deleted file mode 100644 index dda688c177..0000000000 --- a/src/Taxonomies/TermTracker.php +++ /dev/null @@ -1,102 +0,0 @@ -stache = $stache; - $this->taxonomyStache = $stache->taxonomies; - } - - /** - * Register the listeners for the subscriber. - * - * @param \Illuminate\Events\Dispatcher $events - */ - public function subscribe($events) - { - $events->listen(RepositoryItemInserted::class, self::class.'@insert'); - $events->listen(RepositoryItemRemoved::class, self::class.'@remove'); - } - - public function insert(RepositoryItemInserted $event) - { - if ($event->item instanceof TaxonomyContract) { - $this->updateLocalizedTermUris($event->item); - - return; - } - - if (! method_exists($event->item, 'isTaxonomizable') || ! $event->item->isTaxonomizable()) { - return; - } - - Taxonomy::all()->each(function ($taxonomy, $handle) use ($event) { - if ($event->item->has($handle)) { - try { - $this->addTerms($handle, $event->item); - } catch (\Exception $e) { - \Log::debug('There was a problem adding taxonomy terms to data with ID '.$event->item->id()); - \Log::debug($e->getMessage().PHP_EOL.$e->getTraceAsString()); - } - } - }); - } - - private function addTerms($taxonomy, $item) - { - // Don't do anything if there aren't any terms. - if (! $values = $item->get($taxonomy)) { - return; - } - - $this->taxonomyStache->syncAssociations( - $item->id(), - $taxonomy, - (array) $item->get($taxonomy) - ); - } - - private function updateLocalizedTermUris($taxonomy) - { - $terms = []; - - $this->taxonomyStache->clearLocalizedUris(); - - // Collect all the terms that have had their slugs localized. - foreach ($taxonomy->get('slugs', []) as $locale => $slugs) { - foreach ((array) $slugs as $slug => $localizedSlug) { - $terms[] = $slug; - } - } - - // Now that we have the terms (not concerned with the locales - // now) we can let the Stache sort out the respective URIs. - foreach (collect($terms)->unique() as $term) { - $this->taxonomyStache->addUris($taxonomy->basename(), $term); - } - } - - public function remove(RepositoryItemRemoved $event) - { - $this->taxonomyStache->removeData($event->id); - } -} From 061a4a07562495df64b2926c8c310d1fb4326e00 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 13:43:16 -0400 Subject: [PATCH 11/28] Remove unreachable Route branch from AddRequestMessage::label() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Statamic\Routing\Route was deleted wholesale in commit 15418847bd ("Rip out routing", 2020-01-27). instanceof UndefinedClass silently evaluates to false in PHP rather than throwing, so this branch was permanently unreachable rather than crashing anything. Confirmed cascadeContent() can never produce a Route today — its only producers (Http/Responses/DataResponse.php, FrontendController:: getLoadedRouteItem() via Data::find()/findByUri(), the password protection controller) all resolve to Data/Entry-style objects, never a Route instance. Co-Authored-By: Claude Sonnet 5 --- src/View/Debugbar/AddRequestMessage.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/View/Debugbar/AddRequestMessage.php b/src/View/Debugbar/AddRequestMessage.php index f3726721e8..7dcda1dab1 100644 --- a/src/View/Debugbar/AddRequestMessage.php +++ b/src/View/Debugbar/AddRequestMessage.php @@ -3,7 +3,6 @@ namespace Statamic\View\Debugbar; use Illuminate\Database\Eloquent\Model; -use Statamic\Routing\Route; use Statamic\View\Events\ViewRendered; class AddRequestMessage @@ -30,10 +29,6 @@ public function handle(ViewRendered $event) protected function label($item) { - if ($item instanceof Route) { - return 'Route '.$item->url(); - } - if ($item instanceof Model) { return class_basename($item).' '.$item->getKey(); } From b2c927c7e34c04be51e4ac72dce467428574ea53 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 14:10:07 -0400 Subject: [PATCH 12/28] Fix PHPStan method.void errors with stale @return void docblocks AssetContainer::save()/delete() and the Permission facade's boot() docblock were typed as void but the underlying methods actually return a value ($this|false, bool, and \Statamic\Auth\Permissions respectively). --- src/Assets/AssetContainer.php | 4 ++-- src/Facades/Permission.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Assets/AssetContainer.php b/src/Assets/AssetContainer.php index 35f5d4ecb5..d4bbbee5db 100644 --- a/src/Assets/AssetContainer.php +++ b/src/Assets/AssetContainer.php @@ -254,7 +254,7 @@ public function saveQuietly() /** * Save the container. * - * @return void + * @return $this|false */ public function save() { @@ -303,7 +303,7 @@ public function deleteQuietly() /** * Delete the container. * - * @return void + * @return bool */ public function delete() { diff --git a/src/Facades/Permission.php b/src/Facades/Permission.php index 00a32c8250..b12eb044e2 100644 --- a/src/Facades/Permission.php +++ b/src/Facades/Permission.php @@ -6,7 +6,7 @@ use Statamic\Auth\Permissions; /** - * @method static void boot() + * @method static \Statamic\Auth\Permissions boot() * @method static void extend(\Closure $callback) * @method static \Statamic\Auth\Permission make(string $value) * @method static \Statamic\Auth\Permission register(string $permission, \Closure $callback = null) From 57bde3bc4e4c0d490f07d783874d11e0e3a8d8c0 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 14:10:17 -0400 Subject: [PATCH 13/28] Fix PHPStan method.void errors by dropping pointless return These call genuinely void methods as their final statement (or, for failedValidation(), a method that unconditionally throws), so the return keyword served no purpose and PHPStan correctly flagged the result as unused. --- src/Auth/CorePermissions.php | 2 +- src/Console/Commands/FlatCamp.php | 2 +- src/GraphQL/Manager.php | 4 ++-- src/Http/Controllers/Concerns/HandlesLogins.php | 2 +- src/Http/Requests/FrontendFormRequest.php | 4 ++-- src/Http/Requests/UserLoginRequest.php | 4 ++-- src/Http/Requests/UserPasswordRequest.php | 4 ++-- src/Http/Requests/UserProfileRequest.php | 4 ++-- src/Http/Requests/UserRegisterRequest.php | 4 ++-- src/Support/Arr.php | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Auth/CorePermissions.php b/src/Auth/CorePermissions.php index 0fec10cb62..d0d3eeb125 100644 --- a/src/Auth/CorePermissions.php +++ b/src/Auth/CorePermissions.php @@ -267,6 +267,6 @@ protected function permission($permission) protected function group($name, $callback) { - return Permission::group($name, __('statamic::permissions.group_'.$name), $callback); + Permission::group($name, __('statamic::permissions.group_'.$name), $callback); } } diff --git a/src/Console/Commands/FlatCamp.php b/src/Console/Commands/FlatCamp.php index 22fee9d7fe..339cf8d570 100644 --- a/src/Console/Commands/FlatCamp.php +++ b/src/Console/Commands/FlatCamp.php @@ -63,7 +63,7 @@ class FlatCamp extends Command public function handle() { - return $this->comment(collect($this->quotes) + $this->comment(collect($this->quotes) ->map(fn ($quote) => $this->formatForConsole($quote)) ->random()); } diff --git a/src/GraphQL/Manager.php b/src/GraphQL/Manager.php index abf10241db..83e6be5893 100644 --- a/src/GraphQL/Manager.php +++ b/src/GraphQL/Manager.php @@ -23,12 +23,12 @@ public function getExtraTypeFields($type) public function addType($type) { - return GraphQL::addType($type); + GraphQL::addType($type); } public function addTypes($type) { - return GraphQL::addTypes($type); + GraphQL::addTypes($type); } public function type($type) diff --git a/src/Http/Controllers/Concerns/HandlesLogins.php b/src/Http/Controllers/Concerns/HandlesLogins.php index d6b76ff58b..e460d1afda 100644 --- a/src/Http/Controllers/Concerns/HandlesLogins.php +++ b/src/Http/Controllers/Concerns/HandlesLogins.php @@ -22,7 +22,7 @@ protected function handleTooManyLoginAttempts(Request $request) if ($this->hasTooManyLoginAttempts($request)) { $this->fireLockoutEvent($request); - return $this->sendLockoutResponse($request); + $this->sendLockoutResponse($request); } } diff --git a/src/Http/Requests/FrontendFormRequest.php b/src/Http/Requests/FrontendFormRequest.php index 795e042044..b720d576cd 100644 --- a/src/Http/Requests/FrontendFormRequest.php +++ b/src/Http/Requests/FrontendFormRequest.php @@ -74,7 +74,7 @@ protected function failedValidation(Validator $validator) throw (new ValidationException($validator, $response)); } - return parent::failedValidation($validator); + parent::failedValidation($validator); } private function extraRules($fields) @@ -122,7 +122,7 @@ public function validateResolved() // directly in a headless format. In that case, we'll just use the default lang. $site = ($previousUrl = $this->previousUrl()) ? Site::findByUrl($previousUrl) : null; - return $this->withLocale($site?->lang(), fn () => parent::validateResolved()); + $this->withLocale($site?->lang(), fn () => parent::validateResolved()); } private function previousUrl() diff --git a/src/Http/Requests/UserLoginRequest.php b/src/Http/Requests/UserLoginRequest.php index bb29122e1b..558625bb48 100644 --- a/src/Http/Requests/UserLoginRequest.php +++ b/src/Http/Requests/UserLoginRequest.php @@ -32,7 +32,7 @@ public function rules(): array protected function failedValidation(Validator $validator) { if ($this->isPrecognitive() || $this->wantsJson()) { - return parent::failedValidation($validator); + parent::failedValidation($validator); } if ($this->ajax()) { @@ -58,6 +58,6 @@ public function validateResolved() { $site = Site::findByUrl(LaravelURL::previous()) ?? Site::default(); - return $this->withLocale($site->lang(), fn () => parent::validateResolved()); + $this->withLocale($site->lang(), fn () => parent::validateResolved()); } } diff --git a/src/Http/Requests/UserPasswordRequest.php b/src/Http/Requests/UserPasswordRequest.php index d7cb084a50..bf7910ec3a 100644 --- a/src/Http/Requests/UserPasswordRequest.php +++ b/src/Http/Requests/UserPasswordRequest.php @@ -32,7 +32,7 @@ public function rules(): array protected function failedValidation(Validator $validator) { if ($this->isPrecognitive() || $this->wantsJson()) { - return parent::failedValidation($validator); + parent::failedValidation($validator); } if ($this->ajax()) { @@ -58,6 +58,6 @@ public function validateResolved() { $site = Site::findByUrl(LaravelURL::previous()) ?? Site::default(); - return $this->withLocale($site->lang(), fn () => parent::validateResolved()); + $this->withLocale($site->lang(), fn () => parent::validateResolved()); } } diff --git a/src/Http/Requests/UserProfileRequest.php b/src/Http/Requests/UserProfileRequest.php index e025e29f3b..22ab78d45d 100644 --- a/src/Http/Requests/UserProfileRequest.php +++ b/src/Http/Requests/UserProfileRequest.php @@ -27,7 +27,7 @@ public function authorize(): bool protected function failedValidation(Validator $validator) { if ($this->isPrecognitive() || $this->wantsJson()) { - return parent::failedValidation($validator); + parent::failedValidation($validator); } if ($this->ajax()) { @@ -77,7 +77,7 @@ public function validateResolved() { $site = Site::findByUrl(LaravelURL::previous()) ?? Site::default(); - return $this->withLocale($site->lang(), fn () => parent::validateResolved()); + $this->withLocale($site->lang(), fn () => parent::validateResolved()); } private function valuesWithoutAssetFields($fields) diff --git a/src/Http/Requests/UserRegisterRequest.php b/src/Http/Requests/UserRegisterRequest.php index f126573bc9..a2c4e4ee90 100644 --- a/src/Http/Requests/UserRegisterRequest.php +++ b/src/Http/Requests/UserRegisterRequest.php @@ -30,7 +30,7 @@ public function authorize(): bool protected function failedValidation(Validator $validator) { if ($this->isPrecognitive() || $this->wantsJson()) { - return parent::failedValidation($validator); + parent::failedValidation($validator); } if ($this->ajax()) { @@ -82,7 +82,7 @@ public function validateResolved() { $site = Site::findByUrl(LaravelURL::previous()) ?? Site::default(); - return $this->withLocale($site->lang(), fn () => parent::validateResolved()); + $this->withLocale($site->lang(), fn () => parent::validateResolved()); } private function valuesWithoutAssetFields($fields) diff --git a/src/Support/Arr.php b/src/Support/Arr.php index e522ee1963..664a4a3986 100644 --- a/src/Support/Arr.php +++ b/src/Support/Arr.php @@ -308,7 +308,7 @@ public static function pull(&$array, $key, $default = null) */ public static function forget(&$array, $keys) { - return IlluminateArr::forget($array, $keys); + IlluminateArr::forget($array, $keys); } /** From d2baef1577e949dbd844adc8717e319dfe7623f0 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 14:16:42 -0400 Subject: [PATCH 14/28] Fix PHPStan method.void/function.void errors in early-exit guard clauses SiteClear, CommitCommand, and InstallSsg each had a guard clause of the form 'if (...) { return $this->info(...); }' followed by more code. Since info()/error() are void, PHPStan flagged the return value as unused, but simply stripping return would have let execution fall through into the code the guard is meant to skip. Split each into a void call followed by a bare return to preserve the early exit. --- src/Console/Commands/InstallSsg.php | 4 +++- src/Console/Commands/SiteClear.php | 4 +++- src/Git/CommitCommand.php | 10 +++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Console/Commands/InstallSsg.php b/src/Console/Commands/InstallSsg.php index 404e5b1b45..1fc25ece01 100644 --- a/src/Console/Commands/InstallSsg.php +++ b/src/Console/Commands/InstallSsg.php @@ -39,7 +39,9 @@ class InstallSsg extends Command public function handle() { if (Composer::isInstalled('statamic/ssg')) { - return error('The Static Site Generator package is already installed.'); + error('The Static Site Generator package is already installed.'); + + return; } spin( diff --git a/src/Console/Commands/SiteClear.php b/src/Console/Commands/SiteClear.php index a4156378f4..28bd24035f 100644 --- a/src/Console/Commands/SiteClear.php +++ b/src/Console/Commands/SiteClear.php @@ -42,7 +42,9 @@ class SiteClear extends Command public function handle() { if ($this->shouldAbort()) { - return $this->info('Aborted successfully.'); + $this->info('Aborted successfully.'); + + return; } $this->files = app(Filesystem::class); diff --git a/src/Git/CommitCommand.php b/src/Git/CommitCommand.php index cefcadd9fe..ed944300e3 100644 --- a/src/Git/CommitCommand.php +++ b/src/Git/CommitCommand.php @@ -34,15 +34,19 @@ class CommitCommand extends Command public function handle() { if (! config('statamic.git.enabled')) { - return $this->info(__('statamic::messages.git_disabled')); + $this->info(__('statamic::messages.git_disabled')); + + return; } if (! Git::statuses()) { - return $this->info(__('statamic::messages.git_nothing_to_commit')); + $this->info(__('statamic::messages.git_nothing_to_commit')); + + return; } Git::commit(); - return $this->info(__('Content committed')); + $this->info(__('Content committed')); } } From 56c2803d68470eff391ef016c4798d080ed81bd6 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 15:13:32 -0400 Subject: [PATCH 15/28] Fix PHPStan staticProperty.notFound errors by declaring base properties Fieldtype::preloadable() and AbstractSourceEmitter's stack-cleanup logic both reference static::$property as an optional override point, but the base classes never declared the properties themselves - only some subclasses did (e.g. Relationship::$preloadable, Blade/AntlersSourceEmitter::$variableStack). Declared $preloadable untyped to match Relationship's untyped override. Declared $variableStack/$currentIterationVar with the same types (array/?string) as the Blade and Antlers subclasses - PHP requires a typed property override to match its parent's type exactly, so adding them untyped would have been a fatal error at runtime for those two subclasses. --- src/Fields/Fieldtype.php | 1 + src/View/Scaffolding/Emitters/AbstractSourceEmitter.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/Fields/Fieldtype.php b/src/Fields/Fieldtype.php index 4073e07563..2b8a67c5a5 100644 --- a/src/Fields/Fieldtype.php +++ b/src/Fields/Fieldtype.php @@ -22,6 +22,7 @@ abstract class Fieldtype implements Arrayable protected static $title; protected static $binding = 'fieldtypes'; + protected static $preloadable = null; protected $field; protected $localizable = true; diff --git a/src/View/Scaffolding/Emitters/AbstractSourceEmitter.php b/src/View/Scaffolding/Emitters/AbstractSourceEmitter.php index c8a79b24dd..903b5d7c23 100644 --- a/src/View/Scaffolding/Emitters/AbstractSourceEmitter.php +++ b/src/View/Scaffolding/Emitters/AbstractSourceEmitter.php @@ -16,6 +16,8 @@ abstract class AbstractSourceEmitter implements Stringable { protected static array $blueprintStack = []; + protected static array $variableStack = []; + protected static ?string $currentIterationVar = null; protected array $specialLoopVariables = [ 'key', 'value', From c5d8f02ab2d2b5a60d7ba0fbed752f9e155f3192 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 15:35:33 -0400 Subject: [PATCH 16/28] 2 spacse --- phpstan.neon.dist | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index abd927068b..161453acf7 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,34 +1,34 @@ includes: - - vendor/larastan/larastan/extension.neon + - vendor/larastan/larastan/extension.neon parameters: - level: 0 - paths: - - src + level: 0 + paths: + - src - # Symbol-only stubs for optional runtime integrations that this package - # never requires as real dependencies (see .phpstan/stubs/debugbar.php). - scanFiles: - - .phpstan/stubs/debugbar.php + # Symbol-only stubs for optional runtime integrations that this package + # never requires as real dependencies (see .phpstan/stubs/debugbar.php). + scanFiles: + - .phpstan/stubs/debugbar.php - ignoreErrors: - - - identifier: class.notFound - message: '#^(Class|Instantiated class) Spatie\\LaravelIgnition\\Exceptions\\(ViewException|ViewExceptionWithSolution) not found\.$#' - path: src/View/Antlers/Language/Runtime/RuntimeParser.php + ignoreErrors: + - + identifier: class.notFound + message: '#^(Class|Instantiated class) Spatie\\LaravelIgnition\\Exceptions\\(ViewException|ViewExceptionWithSolution) not found\.$#' + path: src/View/Antlers/Language/Runtime/RuntimeParser.php - # composer/composer is an optional runtime integration (composer update hooks), not a real dependency. - - - identifier: class.notFound - message: '#^Parameter \$event of method Statamic\\Console\\Composer\\Scripts::preUpdateCmd\(\) has invalid type Composer\\Script\\Event\.$#' - path: src/Console/Composer/Scripts.php + # composer/composer is an optional runtime integration (composer update hooks), not a real dependency. + - + identifier: class.notFound + message: '#^Parameter \$event of method Statamic\\Console\\Composer\\Scripts::preUpdateCmd\(\) has invalid type Composer\\Script\\Event\.$#' + path: src/Console/Composer/Scripts.php - # barryvdh/laravel-debugbar is an optional runtime integration, guarded by class_exists()/isEnabled() checks. - - - identifier: class.notFound - message: '#^Caught class DebugBar\\DebugBarException not found\.$#' - path: src/Forms/Tags.php - - - identifier: function.notFound - message: '#^Function debug not found\.$#' - path: src/Modifiers/CoreModifiers.php + # barryvdh/laravel-debugbar is an optional runtime integration, guarded by class_exists()/isEnabled() checks. + - + identifier: class.notFound + message: '#^Caught class DebugBar\\DebugBarException not found\.$#' + path: src/Forms/Tags.php + - + identifier: function.notFound + message: '#^Function debug not found\.$#' + path: src/Modifiers/CoreModifiers.php From 6851d6362c6c07b02155b28a7521e66b48454333 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 15:47:46 -0400 Subject: [PATCH 17/28] rename to phpstan.dist.neon --- .gitattributes | 2 +- .phpstan/stubs/debugbar.php | 2 +- phpstan.neon.dist => phpstan.dist.neon | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename phpstan.neon.dist => phpstan.dist.neon (100%) diff --git a/.gitattributes b/.gitattributes index f85540ef05..bbb245f903 100644 --- a/.gitattributes +++ b/.gitattributes @@ -17,7 +17,7 @@ .travis.yml export-ignore CONTRIBUTING.md export-ignore jest.config.js export-ignore -phpstan.neon.dist export-ignore +phpstan.dist.neon export-ignore phpunit.bat export-ignore phpunit.xml.dist export-ignore SECURITY.md export-ignore diff --git a/.phpstan/stubs/debugbar.php b/.phpstan/stubs/debugbar.php index 3805b58226..da2420b0ef 100644 --- a/.phpstan/stubs/debugbar.php +++ b/.phpstan/stubs/debugbar.php @@ -8,7 +8,7 @@ * * These declarations exist solely so PHPStan can resolve the * extends/implements relationships in that code (see scanFiles in - * phpstan.neon.dist) — they are never autoloaded or executed. + * phpstan.dist.neon) — they are never autoloaded or executed. * * Signatures mirror php-debugbar/php-debugbar ^3.8 (src/DataCollector/*). */ diff --git a/phpstan.neon.dist b/phpstan.dist.neon similarity index 100% rename from phpstan.neon.dist rename to phpstan.dist.neon From d9afe771787c3ef3fcd7e5347f98337dfd08f32d Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 16:01:04 -0400 Subject: [PATCH 18/28] workflow --- .github/workflows/phpstan.yml | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/phpstan.yml diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000000..b17fe0af57 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,53 @@ +name: PHPStan + +on: + pull_request: + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + phpstan: + name: PHPStan + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6 + with: + files: | + src/** + composer.json + phpstan.dist.neon + .phpstan/** + .github/workflows/phpstan.yml + + - name: Setup PHP + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 + if: steps.changed-files.outputs.any_modified == 'true' + with: + php-version: 8.5 + coverage: none + + - name: Install dependencies + uses: nick-invision/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 + if: steps.changed-files.outputs.any_modified == 'true' + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer update --prefer-stable --prefer-dist --no-interaction + + - name: Run PHPStan + if: steps.changed-files.outputs.any_modified == 'true' + run: vendor/bin/phpstan analyse --memory-limit=2G From 3e8f2de28a5f22c80dd04db571931fc3c5b2e8b0 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 16:03:38 -0400 Subject: [PATCH 19/28] rename to match "CodeQL / Analyze" check name --- .github/workflows/phpstan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index b17fe0af57..302695972d 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -11,7 +11,7 @@ concurrency: jobs: phpstan: - name: PHPStan + name: Analyze runs-on: ubuntu-latest permissions: contents: read From 42e56c81df7d0cbefb5484ad9d3d4023ff65f742 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 16:22:50 -0400 Subject: [PATCH 20/28] Fix PHPStan errors with stale docblocks and undeclared override points - Icon facade's sets() docblock claimed a required $name parameter, but the real IconManager::sets() takes none and returns all registered sets; all call sites already call it with no args. - TreeBranchType references static::NAME as an override point but never declares it itself, only its concrete subclasses do. Same pattern as the earlier Fieldtype::$preloadable fix. - NullIndex passed $this to NullSearchables's constructor, but NullSearchables has no constructor - the argument was silently discarded, not a real bug. Dropped the dead argument. --- src/Facades/Icon.php | 2 +- src/GraphQL/Types/TreeBranchType.php | 2 ++ src/Search/Null/NullIndex.php | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Facades/Icon.php b/src/Facades/Icon.php index 99d00b212b..c4d7af4988 100644 --- a/src/Facades/Icon.php +++ b/src/Facades/Icon.php @@ -9,7 +9,7 @@ /** * @method static void register(string $name, string $directory) - * @method static Collection sets(string $name) + * @method static Collection sets() * @method static IconSet get(string $name) * @method static IconSet default() * diff --git a/src/GraphQL/Types/TreeBranchType.php b/src/GraphQL/Types/TreeBranchType.php index 2a077c7502..e1f48a80de 100644 --- a/src/GraphQL/Types/TreeBranchType.php +++ b/src/GraphQL/Types/TreeBranchType.php @@ -6,6 +6,8 @@ abstract class TreeBranchType extends \Rebing\GraphQL\Support\Type { + const NAME = ''; + public function __construct() { $this->attributes['name'] = static::NAME; diff --git a/src/Search/Null/NullIndex.php b/src/Search/Null/NullIndex.php index 10ebc808ad..7f0c2b2e1e 100644 --- a/src/Search/Null/NullIndex.php +++ b/src/Search/Null/NullIndex.php @@ -34,6 +34,6 @@ protected function deleteIndex() public function searchables() { - return new NullSearchables($this); + return new NullSearchables(); } } From 5249e28dff64415627d786d6b3223e31d6fcc72d Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 16:24:59 -0400 Subject: [PATCH 21/28] Ignore PHPStan error from optional spatie/laravel-ignition ddd() helper Same situation as the existing Spatie\LaravelIgnition\Exceptions ignore entries: spatie/laravel-ignition is an optional runtime integration this package never requires as a real dependency, and ddd() is one of its global helpers (see https://github.com/spatie/laravel-ignition/blob/main/src/helpers.php). --- phpstan.dist.neon | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 161453acf7..b1637e3b1a 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -32,3 +32,9 @@ parameters: identifier: function.notFound message: '#^Function debug not found\.$#' path: src/Modifiers/CoreModifiers.php + + # spatie/laravel-ignition is an optional runtime integration; ddd() is one of its helpers. + - + identifier: function.notFound + message: '#^Function ddd not found\.$#' + path: src/Modifiers/CoreModifiers.php From 3ce13aaeef9a9a6b9941cab23b95e2e4bb1ef78c Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 16:43:21 -0400 Subject: [PATCH 22/28] Simplify dead dispatchNow fallback in AssetsGeneratePresets composer.json requires laravel/framework ^12.40.0 || ^13.0, and Dispatcher::dispatchSync() has existed since long before that floor. The method_exists() check (and its dispatchNow fallback, added in 2021 for Laravel versions this package no longer supports) always resolves to dispatchSync, so it can be simplified to a plain ternary. Also removes the now-unused Dispatcher import. --- src/Console/Commands/AssetsGeneratePresets.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Console/Commands/AssetsGeneratePresets.php b/src/Console/Commands/AssetsGeneratePresets.php index 328c49fe8a..c7133f97cc 100644 --- a/src/Console/Commands/AssetsGeneratePresets.php +++ b/src/Console/Commands/AssetsGeneratePresets.php @@ -3,7 +3,6 @@ namespace Statamic\Console\Commands; use Illuminate\Console\Command; -use Illuminate\Contracts\Bus\Dispatcher; use Illuminate\Support\Facades\Log; use Statamic\Console\RunsInPlease; use Statamic\Facades\AssetContainer; @@ -113,9 +112,7 @@ protected function generatePresets($container, ?string $filterPreset = null) $counts[$preset] = ($counts[$preset] ?? 0) + 1; $progress->label("Generating $preset for {$asset->basename()}..."); - $dispatchMethod = $this->shouldQueue - ? 'dispatch' - : (method_exists(Dispatcher::class, 'dispatchSync') ? 'dispatchSync' : 'dispatchNow'); + $dispatchMethod = $this->shouldQueue ? 'dispatch' : 'dispatchSync'; try { GeneratePresetImageManipulation::$dispatchMethod($asset, $preset); From fd839dae0407e6fe9de2bfaebeb61e9bc8cc426c Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 16:43:28 -0400 Subject: [PATCH 23/28] Ignore PHPStan error from Carbon's self::this() macro scope rebinding Carbon::macro('asVueComponent', ...) calls self::this() inside a static closure, which Carbon\Traits\Mixin rebinds into scope for macros at runtime (Mixin::this() is a real, protected static method). PHPStan can't follow that scope rebinding and sees it as an undefined static method on AppServiceProvider - confirmed via empirical repro, including testing Carbon's own official vendor/nesbot/carbon/extension.neon PHPStan extension, which does not resolve this either. --- phpstan.dist.neon | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/phpstan.dist.neon b/phpstan.dist.neon index b1637e3b1a..5abd425b18 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -38,3 +38,12 @@ parameters: identifier: function.notFound message: '#^Function ddd not found\.$#' path: src/Modifiers/CoreModifiers.php + + # self::this() inside the Carbon::macro() closure resolves to Carbon\Traits\Mixin::this(), + # a protected static method Carbon rebinds into scope for macros registered via Mixin - + # see vendor/nesbot/carbon/src/Carbon/Traits/Mixin.php. PHPStan can't follow the + # static-closure scope rebinding, so it thinks this() is being called on this class. + - + identifier: staticMethod.notFound + message: '#^Call to an undefined static method Statamic\\Providers\\AppServiceProvider::this\(\)\.$#' + path: src/Providers/AppServiceProvider.php From 4789b98bc3ae58ac40417401c376adb364999485 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 16:47:46 -0400 Subject: [PATCH 24/28] Clean up CollectionsServiceProvider: remove dead macros, use public API - Removed the getOrPut() macro: Laravel's Collection has had a native getOrPut() with identical behavior for years, so the macro is permanently unreachable (native methods intercept before macro dispatch). - Removed the pipe() macro: Laravel's Collection has had a native pipe() with an identical implementation since 5.2, long before this package's floor. - keyByWithKey() is kept untouched, since it's a public macro third-party addons could still be calling even though Statamic's own code doesn't use it anymore. Its calls into Collection's protected valueRetriever()/$items are now suppressed via a scoped ignoreErrors entry instead of being rewritten. - Everywhere else in the file, $this->items (protected) is replaced with $this->all() (public, returns the same value). --- phpstan.dist.neon | 13 ++++++ src/Providers/CollectionsServiceProvider.php | 43 +++----------------- 2 files changed, 18 insertions(+), 38 deletions(-) diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 5abd425b18..69ef22b390 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -47,3 +47,16 @@ parameters: identifier: staticMethod.notFound message: '#^Call to an undefined static method Statamic\\Providers\\AppServiceProvider::this\(\)\.$#' path: src/Providers/AppServiceProvider.php + + # keyByWithKey() is a public Collection macro kept for third-party/addon backward + # compatibility even though Statamic's own code no longer calls it, so its use of + # Collection's protected valueRetriever()/$items internals is left as-is rather than + # rewritten to public equivalents. + - + identifier: method.protected + message: '#^Call to protected method valueRetriever\(\) of class Illuminate\\Support\\Collection(<.*>)?\.$#' + path: src/Providers/CollectionsServiceProvider.php + - + identifier: property.protected + message: '#^Access to protected property Illuminate\\Support\\Collection::\$items\.$#' + path: src/Providers/CollectionsServiceProvider.php diff --git a/src/Providers/CollectionsServiceProvider.php b/src/Providers/CollectionsServiceProvider.php index b20d73783d..a46f4a1044 100644 --- a/src/Providers/CollectionsServiceProvider.php +++ b/src/Providers/CollectionsServiceProvider.php @@ -19,33 +19,12 @@ class CollectionsServiceProvider extends ServiceProvider */ public function register() { - $this->getOrPut(); $this->keyByWithKey(); $this->l10n(); - $this->pipe(); $this->transpose(); $this->toAugmentedArray(); } - /** - * Get a key from a collection if it exists, - * otherwise put a value in there and return it. - * - * @return void - */ - private function getOrPut() - { - Collection::macro('getOrPut', function ($key, $put) { - if ($this->has($key)) { - return $this->get($key); - } - - $this->put($key, $put); - - return $put; - }); - } - /** * The Laravel 5.3 way of doing keyBy. * @@ -84,7 +63,7 @@ private function l10n() * @param string $prefix This is for prefixing the keys for our addons. */ Collection::macro('localize', function ($prefix = null) { - return collect($this->items) + return collect($this->all()) ->filter(function ($item) { return pathinfo($item, PATHINFO_EXTENSION) == 'php'; }) @@ -97,18 +76,6 @@ private function l10n() }); } - /** - * Backport of the pipe method from 5.2. - * - * @return void - */ - private function pipe() - { - Collection::macro('pipe', function (callable $callback) { - return $callback($this); - }); - } - /** * "Transpose" a multidimensional array. * @@ -163,7 +130,7 @@ protected function toAugmentedArray() } return $value instanceof Arrayable ? $value->toArray() : $value; - }, $this->items); + }, $this->all()); }); Collection::macro('toDeferredAugmentedArray', function ($keys = null) { @@ -173,7 +140,7 @@ protected function toAugmentedArray() } return $value instanceof Arrayable ? $value->toArray() : $value; - }, $this->items); + }, $this->all()); }); Collection::macro('toAugmentedCollection', function ($keys = null) { @@ -183,7 +150,7 @@ protected function toAugmentedArray() } return $value instanceof Arrayable ? $value->toArray() : $value; - }, $this->items); + }, $this->all()); }); Collection::macro('toEvaluatedAugmentedArray', function ($keys = null) { @@ -193,7 +160,7 @@ protected function toAugmentedArray() } return $value instanceof Arrayable ? $value->toArray() : $value; - }, $this->items); + }, $this->all()); }); } } From 99084116fc4852dc19dca77d04f90bc19f13ceab Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 16:47:49 -0400 Subject: [PATCH 25/28] Use getEngine() instead of protected $engine in View::withoutExtractions macro Illuminate\View\View::getEngine() is a public method that returns the same protected $engine property this macro was accessing directly. --- src/Providers/ViewServiceProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Providers/ViewServiceProvider.php b/src/Providers/ViewServiceProvider.php index 0cac2e8768..a566131558 100644 --- a/src/Providers/ViewServiceProvider.php +++ b/src/Providers/ViewServiceProvider.php @@ -436,8 +436,8 @@ public function boot() }); View::macro('withoutExtractions', function () { - if ($this->engine instanceof Engine) { - $this->engine->withoutExtractions(); + if ($this->getEngine() instanceof Engine) { + $this->getEngine()->withoutExtractions(); } return $this; From ce7b7477cc23a9ba8dea99e4e680ea8c20800f6e Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 17:18:20 -0400 Subject: [PATCH 26/28] Add default case to repositoryHasBeenMigrated() switch The 19-case switch had no default, so an unmatched $repository would silently return null from a : bool-typed method - a TypeError risk if allRepositories()'s keys and this switch's cases ever drift out of sync. All 3 call sites currently only pass validated keys from allRepositories(), so this is unreachable today, but throwing (rather than returning false) means a future forgotten case fails loudly instead of being misread as "not migrated yet". --- src/Console/Commands/InstallEloquentDriver.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Console/Commands/InstallEloquentDriver.php b/src/Console/Commands/InstallEloquentDriver.php index 19b78c86ba..2e26e7d8fa 100644 --- a/src/Console/Commands/InstallEloquentDriver.php +++ b/src/Console/Commands/InstallEloquentDriver.php @@ -209,6 +209,9 @@ protected function repositoryHasBeenMigrated(string $repository): bool case 'tokens': return config('statamic.eloquent-driver.tokens.driver') === 'eloquent'; + + default: + throw new \LogicException("Unknown repository: {$repository}"); } } From 869e65bf210db47c6efd359d4dc7ff2d741ef3a6 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 17:23:59 -0400 Subject: [PATCH 27/28] Throw Flysystem's standard exceptions from GuzzleAdapter's stub methods mimeType(), lastModified(), fileSize(), listContents(), and visibility() were empty stubs that always crashed with a TypeError (no code path satisfies their strict return types). They had real HEAD-request-based implementations before the Flysystem v1->v3 migration (#5551), but were converted to stubs during that migration and never ported forward - the underlying head() request infrastructure this class still has today was left unused for these methods. Confirmed unreachable in Statamic's current usage (Glide skips validation for remote URLs; nothing in Flysystem's internals calls these for this adapter), so there's no working behavior to restore. Instead, throw Flysystem's own UnableToRetrieveMetadata/ UnableToListContents exceptions - the same contract other Flysystem adapters use to signal a genuinely unsupported operation, rather than crashing with a raw TypeError. --- src/Imaging/GuzzleAdapter.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Imaging/GuzzleAdapter.php b/src/Imaging/GuzzleAdapter.php index fb0562bd41..a7901dc111 100644 --- a/src/Imaging/GuzzleAdapter.php +++ b/src/Imaging/GuzzleAdapter.php @@ -11,7 +11,9 @@ use League\Flysystem\Config; use League\Flysystem\FileAttributes; use League\Flysystem\FilesystemAdapter; +use League\Flysystem\UnableToListContents; use League\Flysystem\UnableToReadFile; +use League\Flysystem\UnableToRetrieveMetadata; use Statamic\Exceptions\InvalidRemoteUrlException; class GuzzleAdapter implements FilesystemAdapter @@ -101,22 +103,22 @@ public function writeStream(string $path, $contents, Config $config): void public function mimeType(string $path): FileAttributes { - // + throw UnableToRetrieveMetadata::mimeType($path, 'Not supported by '.static::class); } public function lastModified(string $path): FileAttributes { - // + throw UnableToRetrieveMetadata::lastModified($path, 'Not supported by '.static::class); } public function fileSize(string $path): FileAttributes { - // + throw UnableToRetrieveMetadata::fileSize($path, 'Not supported by '.static::class); } public function listContents(string $path, bool $deep): iterable { - // + throw UnableToListContents::atLocation($path, $deep, new \RuntimeException('Not supported by '.static::class)); } public function move(string $source, string $destination, Config $config): void @@ -146,7 +148,7 @@ public function deleteDirectory(string $prefix): void public function visibility(string $path): FileAttributes { - // + throw UnableToRetrieveMetadata::visibility($path, 'Not supported by '.static::class); } /* From 9b4558079296398f7c9d49a130cd6352b7d47ebc Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 Jul 2026 17:34:45 -0400 Subject: [PATCH 28/28] Add PHPStan baseline in .phpstan/ to keep the config green as debt accrues The remaining 70 errors (return.missing, method.notFound, property.notFound, argument.unknown, etc.) are the abstract-pattern and BC-sensitive cases deliberately left unfixed throughout this branch - real, but requiring either a public API change or deeper design decisions outside today's scope. Baselining lets vendor/bin/phpstan analyse pass cleanly so the GitHub Actions check is actually enforceable going forward: new code introducing new errors will fail CI, while this known, already-triaged debt stays visible in .phpstan/baseline.neon rather than silently swallowed. Placed inside .phpstan/ instead of the repo root to avoid clutter - note PHPStan resolves a baseline's relative paths against its own directory, so it was generated directly at this location rather than moved after the fact. Co-Authored-By: Claude Sonnet 5 --- .phpstan/baseline.neon | 277 +++++++++++++++++++++++++++++++++++++++++ phpstan.dist.neon | 1 + 2 files changed, 278 insertions(+) create mode 100644 .phpstan/baseline.neon diff --git a/.phpstan/baseline.neon b/.phpstan/baseline.neon new file mode 100644 index 0000000000..527438b53c --- /dev/null +++ b/.phpstan/baseline.neon @@ -0,0 +1,277 @@ +parameters: + ignoreErrors: + - + message: '#^Method Statamic\\Auth\\Eloquent\\User\:\:mergePreferences\(\) should return \$this\(Statamic\\Auth\\Eloquent\\User\) but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../src/Auth/Eloquent/User.php + + - + message: '#^Method Statamic\\Auth\\Eloquent\\User\:\:setPreferences\(\) should return \$this\(Statamic\\Auth\\Eloquent\\User\) but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../src/Auth/Eloquent/User.php + + - + message: '#^Method Statamic\\Auth\\User\:\:getAuthIdentifierName\(\) should return string but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../src/Auth/User.php + + - + message: '#^Access to an undefined property Statamic\\Auth\\UserRepository\:\:\$roleRepository\.$#' + identifier: property.notFound + count: 1 + path: ../src/Auth/UserRepository.php + + - + message: '#^Access to an undefined property Statamic\\Auth\\UserRepository\:\:\$userGroupRepository\.$#' + identifier: property.notFound + count: 1 + path: ../src/Auth/UserRepository.php + + - + message: '#^Call to an undefined method Statamic\\Auth\\UserRepository\:\:query\(\)\.$#' + identifier: method.notFound + count: 2 + path: ../src/Auth/UserRepository.php + + - + message: '#^Unknown parameter \$editing in call to static method Statamic\\Facades\\CP\\Nav\:\:build\(\)\.$#' + identifier: argument.unknown + count: 1 + path: ../src/CP/Navigation/NavTransformer.php + + - + message: '#^Unknown parameter \$preferences in call to static method Statamic\\Facades\\CP\\Nav\:\:build\(\)\.$#' + identifier: argument.unknown + count: 1 + path: ../src/CP/Navigation/NavTransformer.php + + - + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static + count: 1 + path: ../src/Events/Event.php + + - + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static + count: 2 + path: ../src/Events/Subscriber.php + + - + message: '#^Called ''env'' outside of the config directory which returns null when the config is cached, use ''config''\.$#' + identifier: larastan.noEnvCallsOutsideOfConfig + count: 1 + path: ../src/Facades/Endpoint/Parse.php + + - + message: '#^Method Illuminate\\Contracts\\Validation\\DataAwareRule@anonymous/Fieldtypes/Bard\.php\:898\:\:setData\(\) should return \$this\(Illuminate\\Contracts\\Validation\\DataAwareRule@anonymous/Fieldtypes/Bard\.php\:898\) but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../src/Fieldtypes/Bard.php + + - + message: '#^Access to an undefined property Statamic\\Filesystem\\AbstractAdapter\:\:\$filesystem\.$#' + identifier: property.notFound + count: 13 + path: ../src/Filesystem/AbstractAdapter.php + + - + message: '#^Call to an undefined method Statamic\\Filesystem\\AbstractAdapter\:\:copyDirectory\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Filesystem/AbstractAdapter.php + + - + message: '#^Call to an undefined method Statamic\\Filesystem\\AbstractAdapter\:\:getFiles\(\)\.$#' + identifier: method.notFound + count: 3 + path: ../src/Filesystem/AbstractAdapter.php + + - + message: '#^Call to an undefined method Statamic\\Filesystem\\AbstractAdapter\:\:getFolders\(\)\.$#' + identifier: method.notFound + count: 2 + path: ../src/Filesystem/AbstractAdapter.php + + - + message: '#^Call to an undefined method Statamic\\Filesystem\\AbstractAdapter\:\:moveDirectory\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Filesystem/AbstractAdapter.php + + - + message: '#^Result of method Statamic\\Forms\\Form\:\:save\(\) \(void\) is used\.$#' + identifier: method.void + count: 1 + path: ../src/Forms/Form.php + + - + message: '#^Result of method Statamic\\Forms\\Submission\:\:save\(\) \(void\) is used\.$#' + identifier: method.void + count: 1 + path: ../src/Forms/Submission.php + + - + message: '#^Access to an undefined property Statamic\\Http\\Controllers\\API\\ApiController\:\:\$params\.$#' + identifier: property.notFound + count: 1 + path: ../src/Http/Controllers/API/ApiController.php + + - + message: '#^Unknown parameter \$editing in call to static method Statamic\\Facades\\CP\\Nav\:\:build\(\)\.$#' + identifier: argument.unknown + count: 1 + path: ../src/Http/Controllers/CP/Preferences/Nav/DefaultNavController.php + + - + message: '#^Unknown parameter \$preferences in call to static method Statamic\\Facades\\CP\\Nav\:\:build\(\)\.$#' + identifier: argument.unknown + count: 1 + path: ../src/Http/Controllers/CP/Preferences/Nav/DefaultNavController.php + + - + message: '#^Unknown parameter \$editing in call to static method Statamic\\Facades\\CP\\Nav\:\:build\(\)\.$#' + identifier: argument.unknown + count: 1 + path: ../src/Http/Controllers/CP/Preferences/Nav/RoleNavController.php + + - + message: '#^Unknown parameter \$preferences in call to static method Statamic\\Facades\\CP\\Nav\:\:build\(\)\.$#' + identifier: argument.unknown + count: 1 + path: ../src/Http/Controllers/CP/Preferences/Nav/RoleNavController.php + + - + message: '#^Access to an undefined property Statamic\\Imaging\\GlideManager\:\:\$cachePathPrefix\.$#' + identifier: property.notFound + count: 1 + path: ../src/Imaging/GlideManager.php + + - + message: '#^Access to an undefined property Statamic\\Imaging\\GlideManager\:\:\$sourcePathPrefix\.$#' + identifier: property.notFound + count: 1 + path: ../src/Imaging/GlideManager.php + + - + message: '#^Call to an undefined method Statamic\\Imaging\\GlideManager\:\:getAllParams\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Imaging/GlideManager.php + + - + message: '#^Call to an undefined method Statamic\\Imaging\\GlideManager\:\:getSourcePath\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Imaging/GlideManager.php + + - + message: '#^Called ''env'' outside of the config directory which returns null when the config is cached, use ''config''\.$#' + identifier: larastan.noEnvCallsOutsideOfConfig + count: 1 + path: ../src/Marketplace/Client.php + + - + message: '#^Call to an undefined method Statamic\\Providers\\AppServiceProvider\:\:sendElevatedSessionVerificationCode\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Providers/AppServiceProvider.php + + - + message: '#^Access to an undefined property Statamic\\Providers\\EventServiceProvider\:\:\$listeners\.$#' + identifier: property.notFound + count: 2 + path: ../src/Providers/EventServiceProvider.php + + - + message: '#^Call to an undefined method Statamic\\Stache\\Indexes\\Index\:\:getItemValue\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Stache/Indexes/Index.php + + - + message: '#^Access to an undefined property Statamic\\Stache\\Stores\\AggregateStore\:\:\$childStore\.$#' + identifier: property.notFound + count: 1 + path: ../src/Stache/Stores/AggregateStore.php + + - + message: '#^Call to an undefined method Statamic\\Stache\\Stores\\Store\:\:cacheItem\(\)\.$#' + identifier: method.notFound + count: 2 + path: ../src/Stache/Stores/Store.php + + - + message: '#^Call to an undefined method Statamic\\Stache\\Stores\\Store\:\:forgetItem\(\)\.$#' + identifier: method.notFound + count: 2 + path: ../src/Stache/Stores/Store.php + + - + message: '#^Call to an undefined method Statamic\\Stache\\Stores\\Store\:\:getKeyFromPath\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Stache/Stores/Store.php + + - + message: '#^Call to an undefined method Statamic\\Stache\\Stores\\Store\:\:makeItemFromFile\(\)\.$#' + identifier: method.notFound + count: 2 + path: ../src/Stache/Stores/Store.php + + - + message: '#^Method Statamic\\StaticCaching\\Cachers\\NullCacher\:\:getCachedPage\(\) should return Statamic\\StaticCaching\\Page but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../src/StaticCaching/Cachers/NullCacher.php + + - + message: '#^Call to an undefined method Statamic\\StaticCaching\\NoCache\\Region\:\:key\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/StaticCaching/NoCache/Region.php + + - + message: '#^Access to an undefined property Statamic\\Structures\\StructureRepository\:\:\$store\.$#' + identifier: property.notFound + count: 2 + path: ../src/Structures/StructureRepository.php + + - + message: '#^Call to an undefined method Statamic\\Support\\Manager\:\:createNullDriver\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Support/Manager.php + + - + message: '#^Access to an undefined property Statamic\\Testing\\AddonTestCase\:\:\$fakeStacheDirectory\.$#' + identifier: property.notFound + count: 1 + path: ../src/Testing/AddonTestCase.php + + - + message: '#^Call to an undefined method Statamic\\Testing\\AddonTestCase\:\:deleteFakeStacheDirectory\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Testing/AddonTestCase.php + + - + message: '#^Call to an undefined method Statamic\\Testing\\AddonTestCase\:\:preventSavingStacheItemsToDisk\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../src/Testing/AddonTestCase.php + + - + message: '#^Call to an undefined method Statamic\\View\\Scaffolding\\Emitters\\AbstractSourceEmitter\:\:getCountedVariable\(\)\.$#' + identifier: method.notFound + count: 2 + path: ../src/View/Scaffolding/Emitters/AbstractSourceEmitter.php + + - + message: '#^Call to an undefined method Statamic\\View\\Scaffolding\\Emitters\\AbstractSourceEmitter\:\:releaseCountedVariable\(\)\.$#' + identifier: method.notFound + count: 2 + path: ../src/View/Scaffolding/Emitters/AbstractSourceEmitter.php diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 69ef22b390..f15f7c292e 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -1,5 +1,6 @@ includes: - vendor/larastan/larastan/extension.neon + - .phpstan/baseline.neon parameters: level: 0