From 7e367803fcc62ed6f4ca89d51766e5ee5b34e050 Mon Sep 17 00:00:00 2001 From: Snider Date: Thu, 29 Jan 2026 23:09:27 +0000 Subject: [PATCH] fix: resolve static analysis issues and bump PHPStan to level 1 - Replace \Log:: with proper Log facade imports in Channel.php and EncryptArrayObject.php - Remove unnecessary null coalescing on $_GET/$_POST superglobals in Input.php - Add @property annotations to SeoMetadata and ImageOptimization models - Add @property-read annotations for Livewire computed properties in ConfigPanel and WorkspaceConfig - Bump PHPStan level from 0 to 1 - Remove Log facade from Psalm suppressions (now properly imported) Co-Authored-By: Claude Opus 4.5 --- phpstan.neon | 2 +- psalm.xml | 2 -- src/Core/Config/Models/Channel.php | 3 ++- .../Config/View/Modal/Admin/ConfigPanel.php | 7 +++++++ .../View/Modal/Admin/WorkspaceConfig.php | 11 ++++++++++ src/Core/Crypt/EncryptArrayObject.php | 5 +++-- src/Core/Input/Input.php | 4 ++-- src/Core/Media/Image/ImageOptimization.php | 17 ++++++++++++++++ src/Core/Seo/SeoMetadata.php | 20 +++++++++++++++++++ 9 files changed, 63 insertions(+), 8 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index f628907..2ab5346 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,7 @@ parameters: paths: - src - level: 0 + level: 1 ignoreErrors: - '#Unsafe usage of new static#' - '#env\(\).*outside of the config directory#' diff --git a/psalm.xml b/psalm.xml index 7d23bb2..b4e4aff 100644 --- a/psalm.xml +++ b/psalm.xml @@ -31,8 +31,6 @@ - - diff --git a/src/Core/Config/Models/Channel.php b/src/Core/Config/Models/Channel.php index 5d2d34f..4ac8996 100644 --- a/src/Core/Config/Models/Channel.php +++ b/src/Core/Config/Models/Channel.php @@ -15,6 +15,7 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Support\Facades\Log; /** * Configuration channel (voice/context substrate). @@ -123,7 +124,7 @@ class Channel extends Model while ($current->parent_id !== null) { if (isset($seen[$current->parent_id])) { - \Log::error('Circular reference detected in channel inheritance', [ + Log::error('Circular reference detected in channel inheritance', [ 'channel_id' => $this->id, 'cycle_at' => $current->parent_id, ]); diff --git a/src/Core/Config/View/Modal/Admin/ConfigPanel.php b/src/Core/Config/View/Modal/Admin/ConfigPanel.php index 0899053..290be2a 100644 --- a/src/Core/Config/View/Modal/Admin/ConfigPanel.php +++ b/src/Core/Config/View/Modal/Admin/ConfigPanel.php @@ -19,6 +19,13 @@ use Livewire\Attributes\Computed; use Livewire\Attributes\Url; use Livewire\Component; +/** + * Configuration panel for managing config keys and values. + * + * @property-read ConfigProfile $activeProfile + * @property-read array $categories + * @property-read \Illuminate\Database\Eloquent\Collection $workspaces + */ class ConfigPanel extends Component { #[Url] diff --git a/src/Core/Config/View/Modal/Admin/WorkspaceConfig.php b/src/Core/Config/View/Modal/Admin/WorkspaceConfig.php index 8b373ad..bcacfe9 100644 --- a/src/Core/Config/View/Modal/Admin/WorkspaceConfig.php +++ b/src/Core/Config/View/Modal/Admin/WorkspaceConfig.php @@ -19,6 +19,17 @@ use Livewire\Attributes\Computed; use Livewire\Attributes\On; use Livewire\Component; +/** + * Workspace configuration panel. + * + * @property-read int $depth + * @property-read array $namespaces + * @property-read ConfigProfile|null $workspaceProfile + * @property-read ConfigProfile $systemProfile + * @property-read object|null $workspace + * @property-read string $prefix + * @property-read array $tabs + */ class WorkspaceConfig extends Component { public ?string $path = null; diff --git a/src/Core/Crypt/EncryptArrayObject.php b/src/Core/Crypt/EncryptArrayObject.php index 0e90a84..3533124 100644 --- a/src/Core/Crypt/EncryptArrayObject.php +++ b/src/Core/Crypt/EncryptArrayObject.php @@ -14,6 +14,7 @@ namespace Core\Crypt; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; use Illuminate\Database\Eloquent\Casts\ArrayObject; use Illuminate\Support\Facades\Crypt; +use Illuminate\Support\Facades\Log; /** * Cast for storing encrypted array data as ArrayObject. @@ -36,7 +37,7 @@ class EncryptArrayObject implements CastsAttributes try { $decrypted = Crypt::decryptString($attributes[$key]); } catch (\Illuminate\Contracts\Encryption\DecryptException $e) { - \Log::warning('Failed to decrypt array object', ['key' => $key, 'error' => $e->getMessage()]); + Log::warning('Failed to decrypt array object', ['key' => $key, 'error' => $e->getMessage()]); return null; } @@ -44,7 +45,7 @@ class EncryptArrayObject implements CastsAttributes $decoded = json_decode($decrypted, true); if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) { - \Log::warning('Failed to decode encrypted array', ['key' => $key, 'error' => json_last_error_msg()]); + Log::warning('Failed to decode encrypted array', ['key' => $key, 'error' => json_last_error_msg()]); return null; } diff --git a/src/Core/Input/Input.php b/src/Core/Input/Input.php index 5231efb..7f2bd0c 100644 --- a/src/Core/Input/Input.php +++ b/src/Core/Input/Input.php @@ -22,8 +22,8 @@ class Input { $sanitiser = new Sanitiser; - $_GET = $sanitiser->filter($_GET ?? []); - $_POST = $sanitiser->filter($_POST ?? []); + $_GET = $sanitiser->filter($_GET); + $_POST = $sanitiser->filter($_POST); return Request::capture(); } diff --git a/src/Core/Media/Image/ImageOptimization.php b/src/Core/Media/Image/ImageOptimization.php index 1e9cdff..e30c242 100644 --- a/src/Core/Media/Image/ImageOptimization.php +++ b/src/Core/Media/Image/ImageOptimization.php @@ -16,6 +16,23 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\MorphTo; +/** + * Image optimisation record. + * + * @property int $id + * @property string $path + * @property string|null $original_path + * @property int $original_size + * @property int $optimized_size + * @property int $percentage_saved + * @property string|null $driver + * @property int|null $quality + * @property int|null $workspace_id + * @property string|null $optimizable_type + * @property int|null $optimizable_id + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + */ class ImageOptimization extends Model { use HasFactory; diff --git a/src/Core/Seo/SeoMetadata.php b/src/Core/Seo/SeoMetadata.php index 4eb3481..471653f 100644 --- a/src/Core/Seo/SeoMetadata.php +++ b/src/Core/Seo/SeoMetadata.php @@ -14,6 +14,26 @@ namespace Core\Seo; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphTo; +/** + * SEO metadata for any model. + * + * @property int $id + * @property string $seoable_type + * @property int $seoable_id + * @property string|null $title + * @property string|null $description + * @property string|null $canonical_url + * @property array|null $og_data + * @property array|null $twitter_data + * @property array|null $schema_markup + * @property string|null $robots + * @property string|null $focus_keyword + * @property int|null $seo_score + * @property array|null $seo_issues + * @property array|null $seo_suggestions + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + */ class SeoMetadata extends Model { protected $table = 'seo_metadata';