From 9897377b46332e36e9c72a65122e8630dcd0a54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sun, 15 Oct 2023 23:31:58 +0000 Subject: [PATCH 01/17] Prepare PHPStan --- .github/workflows/back-end.yml | 5 ++++- phpstan.neon.dist | 16 ++++++++++++++++ src/Actions/Actions.php | 3 +++ src/Columns/Columns.php | 3 +++ src/Fields/Fields.php | 3 +++ src/Filters/Filters.php | 3 +++ src/Models/Medium.php | 2 ++ src/Navigation/Item.php | 6 ++++++ src/Widgets/Widgets.php | 3 +++ 9 files changed, 43 insertions(+), 1 deletion(-) diff --git a/.github/workflows/back-end.yml b/.github/workflows/back-end.yml index bbf0080db..e3f432763 100644 --- a/.github/workflows/back-end.yml +++ b/.github/workflows/back-end.yml @@ -135,9 +135,12 @@ jobs: name: "Search for $this->$this typo 🐌" run: | ! git grep --line-number -e '\$this\s*->\s*\$this' -- ':!:*/back-end\.yml' + - + name: "Install orchestra/testbench" + run: "composer require --dev orchestra/testbench" - name: "Perform static analysis" - run: "true TODO || composer exec -- phpstan analyze --level=5 src/" + run: "composer exec -- phpstan || true 'Annotate only'" coding_standards: name: "4️⃣ Coding Standards" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 96ad334f8..9787b6313 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -10,5 +10,21 @@ parameters: - database/ - routes/ level: 5 + checkAlwaysTrueCheckTypeFunctionCall: true + checkAlwaysTrueInstanceof: true + checkAlwaysTrueStrictComparison: true + checkAlwaysTrueLooseComparison: true + checkClassCaseSensitivity: false + checkDynamicProperties: true + checkExplicitMixed: false + checkImplicitMixed: false + checkExplicitMixedMissingReturn: true + checkFunctionNameCase: true + checkInternalClassCaseSensitivity: true ignoreErrors: - '#^Unsafe usage of new static#' + # Tricky readonlys + - '#Assign it in the constructor\.$#' + - '#is assigned outside of the constructor\.$#' + # View vs. View contract + - '#render\(\) should return Illuminate\\View\\View but#' diff --git a/src/Actions/Actions.php b/src/Actions/Actions.php index 297bf2e8b..51a552e29 100644 --- a/src/Actions/Actions.php +++ b/src/Actions/Actions.php @@ -7,6 +7,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Traits\ForwardsCalls; +/** + * @mixin \Illuminate\Support\Collection + */ class Actions { use ForwardsCalls; diff --git a/src/Columns/Columns.php b/src/Columns/Columns.php index a33db1d79..fc44b7774 100644 --- a/src/Columns/Columns.php +++ b/src/Columns/Columns.php @@ -8,6 +8,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Traits\ForwardsCalls; +/** + * @mixin \Illuminate\Support\Collection + */ class Columns { use ForwardsCalls; diff --git a/src/Fields/Fields.php b/src/Fields/Fields.php index fbb7e2a2f..2ec3d2baf 100644 --- a/src/Fields/Fields.php +++ b/src/Fields/Fields.php @@ -8,6 +8,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Traits\ForwardsCalls; +/** + * @mixin \Illuminate\Support\Collection + */ class Fields { use ForwardsCalls; diff --git a/src/Filters/Filters.php b/src/Filters/Filters.php index b7f11d15d..a7dfae7b6 100644 --- a/src/Filters/Filters.php +++ b/src/Filters/Filters.php @@ -8,6 +8,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Traits\ForwardsCalls; +/** + * @mixin \Illuminate\Support\Collection + */ class Filters { use ForwardsCalls; diff --git a/src/Models/Medium.php b/src/Models/Medium.php index f1f392db2..681b04ecb 100644 --- a/src/Models/Medium.php +++ b/src/Models/Medium.php @@ -152,6 +152,8 @@ public function user(): BelongsTo /** * Determine if the file is image. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function isImage(): Attribute { diff --git a/src/Navigation/Item.php b/src/Navigation/Item.php index 76e68d8ab..3d83c9450 100644 --- a/src/Navigation/Item.php +++ b/src/Navigation/Item.php @@ -6,6 +6,12 @@ use Cone\Root\Traits\Makeable; use Illuminate\Support\Facades\URL; +/** + * @property string $url + * @property string $label + * @property string $icon + * @property string $group + */ class Item { use HasAttributes; diff --git a/src/Widgets/Widgets.php b/src/Widgets/Widgets.php index bff732c21..6bf2a6f49 100644 --- a/src/Widgets/Widgets.php +++ b/src/Widgets/Widgets.php @@ -6,6 +6,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Traits\ForwardsCalls; +/** + * @mixin \Illuminate\Support\Collection + */ class Widgets { use ForwardsCalls; From 27eaa632174ff18ee5d7ef986fc716b4a7a7f4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Mon, 16 Oct 2023 00:23:04 +0000 Subject: [PATCH 02/17] Fix many problems --- phpstan.neon.dist | 10 +++++++--- src/Fields/BelongsTo.php | 4 ++++ src/Fields/BelongsToMany.php | 4 ++++ src/Fields/Boolean.php | 2 +- src/Fields/Fieldset.php | 10 +++++----- src/Fields/HasMany.php | 3 +++ src/Fields/HasOne.php | 3 +++ src/Fields/HasOneOrMany.php | 4 ++++ src/Fields/Meta.php | 3 +++ src/Fields/MorphMany.php | 3 +++ src/Fields/MorphOne.php | 4 ++++ src/Fields/MorphOneOrMany.php | 4 ++++ src/Fields/MorphTo.php | 3 +++ src/Fields/MorphToMany.php | 3 +++ src/Fields/Relation.php | 5 +++++ src/Resources/Resources.php | 3 +++ src/Support/Slug.php | 2 +- 17 files changed, 60 insertions(+), 10 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 9787b6313..9312cf752 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,7 +7,8 @@ parameters: paths: - src/ - config/ - - database/ +# TODO +# - database/ - routes/ level: 5 checkAlwaysTrueCheckTypeFunctionCall: true @@ -23,8 +24,11 @@ parameters: checkInternalClassCaseSensitivity: true ignoreErrors: - '#^Unsafe usage of new static#' + # --- TODO-s --- # Tricky readonlys - '#Assign it in the constructor\.$#' - '#is assigned outside of the constructor\.$#' - # View vs. View contract - - '#render\(\) should return Illuminate\\View\\View but#' + # X vs. X contract + - '#but returns Illuminate\\Contracts\\#' + # SoftDeletes + - '#(\$forceDeleting|::withTrashed|::onlyTrashed|::trashed|::restore)#' diff --git a/src/Fields/BelongsTo.php b/src/Fields/BelongsTo.php index 4fd871e0e..b8b738525 100644 --- a/src/Fields/BelongsTo.php +++ b/src/Fields/BelongsTo.php @@ -6,6 +6,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo as EloquentRelation; use Illuminate\Http\Request; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\BelongsTo + * @extends \Cone\Root\Fields\Relation + */ class BelongsTo extends Relation { /** diff --git a/src/Fields/BelongsToMany.php b/src/Fields/BelongsToMany.php index a87749eb6..0da2da62d 100644 --- a/src/Fields/BelongsToMany.php +++ b/src/Fields/BelongsToMany.php @@ -9,6 +9,10 @@ use Illuminate\Http\Request; use Illuminate\Support\Arr; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\BelongsToMany + * @extends \Cone\Root\Fields\Relation + */ class BelongsToMany extends Relation { use ResolvesFields; diff --git a/src/Fields/Boolean.php b/src/Fields/Boolean.php index 7fe4b5e4a..91ceac618 100644 --- a/src/Fields/Boolean.php +++ b/src/Fields/Boolean.php @@ -27,7 +27,7 @@ public function __construct(string $label, string $modelAttribute = null) */ public function getValueForHydrate(Request $request): mixed { - return $request->boolean([$this->getRequestKey()]); + return $request->boolean($this->getRequestKey()); } /** diff --git a/src/Fields/Fieldset.php b/src/Fields/Fieldset.php index 694be62d7..141d9cf39 100644 --- a/src/Fields/Fieldset.php +++ b/src/Fields/Fieldset.php @@ -31,8 +31,8 @@ protected function resolveField(Request $request, Field $field): void */ public function persist(Request $request, Model $model, mixed $value): void { - $this->resolveFields($request)->each(static function (Field $field) use ($request): void { - $field->persist($request, $field->getValueForHydrate($request)); + $this->resolveFields($request)->each(static function (Field $field) use ($request, $model): void { + $field->persist($request, $model, $field->getValueForHydrate($request)); }); } @@ -41,8 +41,8 @@ public function persist(Request $request, Model $model, mixed $value): void */ public function resolveHydrate(Request $request, Model $model, mixed $value): void { - $this->resolveFields($request)->each(static function (Field $field) use ($request): void { - $field->resolveHydrate($request, $field->getValueForHydrate($request)); + $this->resolveFields($request)->each(static function (Field $field) use ($request, $model): void { + $field->resolveHydrate($request, $model, $field->getValueForHydrate($request)); }); } @@ -77,7 +77,7 @@ public function toValidate(Request $request, Model $model): array { return array_merge( parent::toValidate($request, $model), - $this->resolveFields($request)->mapToValidate($request) + $this->resolveFields($request)->mapToValidate($request, $model) ); } } diff --git a/src/Fields/HasMany.php b/src/Fields/HasMany.php index 1ff452803..8ac39e6a3 100644 --- a/src/Fields/HasMany.php +++ b/src/Fields/HasMany.php @@ -6,6 +6,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany as EloquentRelation; +/** + * @extends \Cone\Root\Fields\HasOneOrMany<\Illuminate\Database\Eloquent\Relations\HasMany> + */ class HasMany extends HasOneOrMany { /** diff --git a/src/Fields/HasOne.php b/src/Fields/HasOne.php index cd071702f..e6bda9b29 100644 --- a/src/Fields/HasOne.php +++ b/src/Fields/HasOne.php @@ -5,6 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasOne as EloquentRelation; +/** + * @extends \Cone\Root\Fields\HasOneOrMany<\Illuminate\Database\Eloquent\Relations\HasOne> + */ class HasOne extends HasOneOrMany { /** diff --git a/src/Fields/HasOneOrMany.php b/src/Fields/HasOneOrMany.php index 01a6c894a..478082d7c 100644 --- a/src/Fields/HasOneOrMany.php +++ b/src/Fields/HasOneOrMany.php @@ -7,6 +7,10 @@ use Illuminate\Http\Request; use Illuminate\Support\Arr; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\HasOneOrMany + * @extends \Cone\Root\Fields\Relation + */ abstract class HasOneOrMany extends Relation { /** diff --git a/src/Fields/Meta.php b/src/Fields/Meta.php index 37e72eecf..83339a9a4 100644 --- a/src/Fields/Meta.php +++ b/src/Fields/Meta.php @@ -9,6 +9,9 @@ use Illuminate\Database\Eloquent\Relations\MorphOne as EloquentRelation; use Illuminate\Http\Request; +/** + * @extends \Cone\Root\Fields\MorphOne<\Illuminate\Database\Eloquent\Relations\MorphOne> + */ class Meta extends MorphOne { /** diff --git a/src/Fields/MorphMany.php b/src/Fields/MorphMany.php index 2fa0385e2..7da69d4e3 100644 --- a/src/Fields/MorphMany.php +++ b/src/Fields/MorphMany.php @@ -5,6 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphMany as EloquentRelation; +/** + * @extends \Cone\Root\Fields\MorphOneOrMany<\Illuminate\Database\Eloquent\Relations\MorphMany> + */ class MorphMany extends MorphOneOrMany { /** diff --git a/src/Fields/MorphOne.php b/src/Fields/MorphOne.php index d17f7ace5..dfb4babda 100644 --- a/src/Fields/MorphOne.php +++ b/src/Fields/MorphOne.php @@ -5,6 +5,10 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphOne as EloquentRelation; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\MorphOne + * @extends \Cone\Root\Fields\MorphOneOrMany + */ class MorphOne extends MorphOneOrMany { /** diff --git a/src/Fields/MorphOneOrMany.php b/src/Fields/MorphOneOrMany.php index ab928ed59..77a1290ed 100644 --- a/src/Fields/MorphOneOrMany.php +++ b/src/Fields/MorphOneOrMany.php @@ -5,6 +5,10 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphOneOrMany as EloquentRelation; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\MorphOneOrMany + * @extends \Cone\Root\Fields\HasOneOrMany + */ abstract class MorphOneOrMany extends HasOneOrMany { /** diff --git a/src/Fields/MorphTo.php b/src/Fields/MorphTo.php index 36a155e6d..afb094bb9 100644 --- a/src/Fields/MorphTo.php +++ b/src/Fields/MorphTo.php @@ -5,6 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphTo as EloquentRelation; +/** + * @extends \Cone\Root\Fields\BelongsTo<\Illuminate\Database\Eloquent\Relations\MorphTo> + */ class MorphTo extends BelongsTo { /** diff --git a/src/Fields/MorphToMany.php b/src/Fields/MorphToMany.php index 8e3581438..5c98ffa25 100644 --- a/src/Fields/MorphToMany.php +++ b/src/Fields/MorphToMany.php @@ -5,6 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany as EloquentRelation; +/** + * @extends \Cone\Root\Fields\BelongsToMany<\Illuminate\Database\Eloquent\Relations\MorphToMany> + */ class MorphToMany extends BelongsToMany { /** diff --git a/src/Fields/Relation.php b/src/Fields/Relation.php index 3bea00693..fdd80a23a 100644 --- a/src/Fields/Relation.php +++ b/src/Fields/Relation.php @@ -10,6 +10,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\Relation + */ abstract class Relation extends Field { /** @@ -72,6 +75,8 @@ public static function scopeQuery(Closure $callback): void /** * Get the relation instance. + * + * @phpstan-return TRelation */ public function getRelation(Model $model): EloquentRelation { diff --git a/src/Resources/Resources.php b/src/Resources/Resources.php index c62d96063..fb50cb44c 100644 --- a/src/Resources/Resources.php +++ b/src/Resources/Resources.php @@ -9,6 +9,9 @@ use Illuminate\Support\Traits\ForwardsCalls; use Throwable; +/** + * @mixin \Illuminate\Support\Collection + */ class Resources { use ForwardsCalls; diff --git a/src/Support/Slug.php b/src/Support/Slug.php index 6768d4010..cc3be40ac 100644 --- a/src/Support/Slug.php +++ b/src/Support/Slug.php @@ -152,7 +152,7 @@ static function (Builder $query): Builder { $value = is_null($match) ? $value : preg_replace_callback( sprintf('/%s([\d]+)?$/', preg_quote($this->separator)), static function (array $match): string { - return str_replace($match[1], ((int) $match[1]) + 1, $match[0]); + return str_replace($match[1], (string)(((int) $match[1]) + 1), $match[0]); }, $match ); From 277d790f2cb8024253c4308e16af342160f6971c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Mon, 16 Oct 2023 00:26:19 +0000 Subject: [PATCH 03/17] Fix CS --- src/Fields/BelongsTo.php | 1 + src/Fields/BelongsToMany.php | 1 + src/Fields/HasOneOrMany.php | 1 + src/Fields/MorphOne.php | 1 + src/Fields/MorphOneOrMany.php | 1 + src/Support/Slug.php | 2 +- 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Fields/BelongsTo.php b/src/Fields/BelongsTo.php index b8b738525..c247595eb 100644 --- a/src/Fields/BelongsTo.php +++ b/src/Fields/BelongsTo.php @@ -8,6 +8,7 @@ /** * @template TRelation of \Illuminate\Database\Eloquent\Relations\BelongsTo + * * @extends \Cone\Root\Fields\Relation */ class BelongsTo extends Relation diff --git a/src/Fields/BelongsToMany.php b/src/Fields/BelongsToMany.php index 0da2da62d..a3fbf2e27 100644 --- a/src/Fields/BelongsToMany.php +++ b/src/Fields/BelongsToMany.php @@ -11,6 +11,7 @@ /** * @template TRelation of \Illuminate\Database\Eloquent\Relations\BelongsToMany + * * @extends \Cone\Root\Fields\Relation */ class BelongsToMany extends Relation diff --git a/src/Fields/HasOneOrMany.php b/src/Fields/HasOneOrMany.php index 478082d7c..f58d318b1 100644 --- a/src/Fields/HasOneOrMany.php +++ b/src/Fields/HasOneOrMany.php @@ -9,6 +9,7 @@ /** * @template TRelation of \Illuminate\Database\Eloquent\Relations\HasOneOrMany + * * @extends \Cone\Root\Fields\Relation */ abstract class HasOneOrMany extends Relation diff --git a/src/Fields/MorphOne.php b/src/Fields/MorphOne.php index dfb4babda..e2776f772 100644 --- a/src/Fields/MorphOne.php +++ b/src/Fields/MorphOne.php @@ -7,6 +7,7 @@ /** * @template TRelation of \Illuminate\Database\Eloquent\Relations\MorphOne + * * @extends \Cone\Root\Fields\MorphOneOrMany */ class MorphOne extends MorphOneOrMany diff --git a/src/Fields/MorphOneOrMany.php b/src/Fields/MorphOneOrMany.php index 77a1290ed..9ad8d3c48 100644 --- a/src/Fields/MorphOneOrMany.php +++ b/src/Fields/MorphOneOrMany.php @@ -7,6 +7,7 @@ /** * @template TRelation of \Illuminate\Database\Eloquent\Relations\MorphOneOrMany + * * @extends \Cone\Root\Fields\HasOneOrMany */ abstract class MorphOneOrMany extends HasOneOrMany diff --git a/src/Support/Slug.php b/src/Support/Slug.php index cc3be40ac..7e9822ba3 100644 --- a/src/Support/Slug.php +++ b/src/Support/Slug.php @@ -152,7 +152,7 @@ static function (Builder $query): Builder { $value = is_null($match) ? $value : preg_replace_callback( sprintf('/%s([\d]+)?$/', preg_quote($this->separator)), static function (array $match): string { - return str_replace($match[1], (string)(((int) $match[1]) + 1), $match[0]); + return str_replace($match[1], (string) (((int) $match[1]) + 1), $match[0]); }, $match ); From a9dddb9e49fd8617cf46450f74716fcf213cfb13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sat, 21 Oct 2023 02:54:20 +0000 Subject: [PATCH 04/17] Rebase --- .github/workflows/back-end.yml | 5 +- phpstan.neon.dist | 22 ++++- src/Fields/BelongsTo.php | 5 + src/Fields/BelongsToMany.php | 5 + src/Fields/HasMany.php | 3 + src/Fields/HasOne.php | 3 + src/Fields/HasOneOrMany.php | 5 + src/Fields/Meta.php | 3 + src/Fields/MorphMany.php | 3 + src/Fields/MorphOne.php | 5 + src/Fields/MorphOneOrMany.php | 5 + src/Fields/MorphTo.php | 3 + src/Fields/MorphToMany.php | 3 + src/Fields/Relation.php | 5 + src/Models/Medium.php | 2 + src/Navigation/Item.php | 6 ++ src/Support/Slug.php | 170 +++++++++++++++++++++++++++++++++ src/Widgets/Widgets.php | 3 + 18 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 src/Support/Slug.php diff --git a/.github/workflows/back-end.yml b/.github/workflows/back-end.yml index bbf0080db..e3f432763 100644 --- a/.github/workflows/back-end.yml +++ b/.github/workflows/back-end.yml @@ -135,9 +135,12 @@ jobs: name: "Search for $this->$this typo 🐌" run: | ! git grep --line-number -e '\$this\s*->\s*\$this' -- ':!:*/back-end\.yml' + - + name: "Install orchestra/testbench" + run: "composer require --dev orchestra/testbench" - name: "Perform static analysis" - run: "true TODO || composer exec -- phpstan analyze --level=5 src/" + run: "composer exec -- phpstan || true 'Annotate only'" coding_standards: name: "4️⃣ Coding Standards" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 96ad334f8..9312cf752 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,8 +7,28 @@ parameters: paths: - src/ - config/ - - database/ +# TODO +# - database/ - routes/ level: 5 + checkAlwaysTrueCheckTypeFunctionCall: true + checkAlwaysTrueInstanceof: true + checkAlwaysTrueStrictComparison: true + checkAlwaysTrueLooseComparison: true + checkClassCaseSensitivity: false + checkDynamicProperties: true + checkExplicitMixed: false + checkImplicitMixed: false + checkExplicitMixedMissingReturn: true + checkFunctionNameCase: true + checkInternalClassCaseSensitivity: true ignoreErrors: - '#^Unsafe usage of new static#' + # --- TODO-s --- + # Tricky readonlys + - '#Assign it in the constructor\.$#' + - '#is assigned outside of the constructor\.$#' + # X vs. X contract + - '#but returns Illuminate\\Contracts\\#' + # SoftDeletes + - '#(\$forceDeleting|::withTrashed|::onlyTrashed|::trashed|::restore)#' diff --git a/src/Fields/BelongsTo.php b/src/Fields/BelongsTo.php index 4fd871e0e..c247595eb 100644 --- a/src/Fields/BelongsTo.php +++ b/src/Fields/BelongsTo.php @@ -6,6 +6,11 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo as EloquentRelation; use Illuminate\Http\Request; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\BelongsTo + * + * @extends \Cone\Root\Fields\Relation + */ class BelongsTo extends Relation { /** diff --git a/src/Fields/BelongsToMany.php b/src/Fields/BelongsToMany.php index a87749eb6..a3fbf2e27 100644 --- a/src/Fields/BelongsToMany.php +++ b/src/Fields/BelongsToMany.php @@ -9,6 +9,11 @@ use Illuminate\Http\Request; use Illuminate\Support\Arr; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\BelongsToMany + * + * @extends \Cone\Root\Fields\Relation + */ class BelongsToMany extends Relation { use ResolvesFields; diff --git a/src/Fields/HasMany.php b/src/Fields/HasMany.php index 1ff452803..8ac39e6a3 100644 --- a/src/Fields/HasMany.php +++ b/src/Fields/HasMany.php @@ -6,6 +6,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany as EloquentRelation; +/** + * @extends \Cone\Root\Fields\HasOneOrMany<\Illuminate\Database\Eloquent\Relations\HasMany> + */ class HasMany extends HasOneOrMany { /** diff --git a/src/Fields/HasOne.php b/src/Fields/HasOne.php index cd071702f..e6bda9b29 100644 --- a/src/Fields/HasOne.php +++ b/src/Fields/HasOne.php @@ -5,6 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasOne as EloquentRelation; +/** + * @extends \Cone\Root\Fields\HasOneOrMany<\Illuminate\Database\Eloquent\Relations\HasOne> + */ class HasOne extends HasOneOrMany { /** diff --git a/src/Fields/HasOneOrMany.php b/src/Fields/HasOneOrMany.php index 01a6c894a..f58d318b1 100644 --- a/src/Fields/HasOneOrMany.php +++ b/src/Fields/HasOneOrMany.php @@ -7,6 +7,11 @@ use Illuminate\Http\Request; use Illuminate\Support\Arr; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\HasOneOrMany + * + * @extends \Cone\Root\Fields\Relation + */ abstract class HasOneOrMany extends Relation { /** diff --git a/src/Fields/Meta.php b/src/Fields/Meta.php index 37e72eecf..83339a9a4 100644 --- a/src/Fields/Meta.php +++ b/src/Fields/Meta.php @@ -9,6 +9,9 @@ use Illuminate\Database\Eloquent\Relations\MorphOne as EloquentRelation; use Illuminate\Http\Request; +/** + * @extends \Cone\Root\Fields\MorphOne<\Illuminate\Database\Eloquent\Relations\MorphOne> + */ class Meta extends MorphOne { /** diff --git a/src/Fields/MorphMany.php b/src/Fields/MorphMany.php index 2fa0385e2..7da69d4e3 100644 --- a/src/Fields/MorphMany.php +++ b/src/Fields/MorphMany.php @@ -5,6 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphMany as EloquentRelation; +/** + * @extends \Cone\Root\Fields\MorphOneOrMany<\Illuminate\Database\Eloquent\Relations\MorphMany> + */ class MorphMany extends MorphOneOrMany { /** diff --git a/src/Fields/MorphOne.php b/src/Fields/MorphOne.php index d17f7ace5..e2776f772 100644 --- a/src/Fields/MorphOne.php +++ b/src/Fields/MorphOne.php @@ -5,6 +5,11 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphOne as EloquentRelation; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\MorphOne + * + * @extends \Cone\Root\Fields\MorphOneOrMany + */ class MorphOne extends MorphOneOrMany { /** diff --git a/src/Fields/MorphOneOrMany.php b/src/Fields/MorphOneOrMany.php index ab928ed59..9ad8d3c48 100644 --- a/src/Fields/MorphOneOrMany.php +++ b/src/Fields/MorphOneOrMany.php @@ -5,6 +5,11 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphOneOrMany as EloquentRelation; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\MorphOneOrMany + * + * @extends \Cone\Root\Fields\HasOneOrMany + */ abstract class MorphOneOrMany extends HasOneOrMany { /** diff --git a/src/Fields/MorphTo.php b/src/Fields/MorphTo.php index 36a155e6d..afb094bb9 100644 --- a/src/Fields/MorphTo.php +++ b/src/Fields/MorphTo.php @@ -5,6 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphTo as EloquentRelation; +/** + * @extends \Cone\Root\Fields\BelongsTo<\Illuminate\Database\Eloquent\Relations\MorphTo> + */ class MorphTo extends BelongsTo { /** diff --git a/src/Fields/MorphToMany.php b/src/Fields/MorphToMany.php index 8e3581438..5c98ffa25 100644 --- a/src/Fields/MorphToMany.php +++ b/src/Fields/MorphToMany.php @@ -5,6 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany as EloquentRelation; +/** + * @extends \Cone\Root\Fields\BelongsToMany<\Illuminate\Database\Eloquent\Relations\MorphToMany> + */ class MorphToMany extends BelongsToMany { /** diff --git a/src/Fields/Relation.php b/src/Fields/Relation.php index 3bea00693..fdd80a23a 100644 --- a/src/Fields/Relation.php +++ b/src/Fields/Relation.php @@ -10,6 +10,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Str; +/** + * @template TRelation of \Illuminate\Database\Eloquent\Relations\Relation + */ abstract class Relation extends Field { /** @@ -72,6 +75,8 @@ public static function scopeQuery(Closure $callback): void /** * Get the relation instance. + * + * @phpstan-return TRelation */ public function getRelation(Model $model): EloquentRelation { diff --git a/src/Models/Medium.php b/src/Models/Medium.php index f1f392db2..681b04ecb 100644 --- a/src/Models/Medium.php +++ b/src/Models/Medium.php @@ -152,6 +152,8 @@ public function user(): BelongsTo /** * Determine if the file is image. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function isImage(): Attribute { diff --git a/src/Navigation/Item.php b/src/Navigation/Item.php index 76e68d8ab..3d83c9450 100644 --- a/src/Navigation/Item.php +++ b/src/Navigation/Item.php @@ -6,6 +6,12 @@ use Cone\Root\Traits\Makeable; use Illuminate\Support\Facades\URL; +/** + * @property string $url + * @property string $label + * @property string $icon + * @property string $group + */ class Item { use HasAttributes; diff --git a/src/Support/Slug.php b/src/Support/Slug.php new file mode 100644 index 000000000..7e9822ba3 --- /dev/null +++ b/src/Support/Slug.php @@ -0,0 +1,170 @@ +model = $model; + } + + /** + * Set the "from" property. + */ + public function from(array|string $attributes): static + { + $this->from = (array) $attributes; + + return $this; + } + + /** + * Set the "to" property + */ + public function to(string $attribute): static + { + $this->to = $attribute; + + return $this; + } + + /** + * Set the "unique" property. + */ + public function unique(bool $value = true): static + { + $this->unique = $value; + + return $this; + } + + /** + * Set the "fresh" property. + */ + public function fresh(bool $value = true): static + { + $this->fresh = $value; + + return $this; + } + + /** + * Set the "resolver" property. + */ + public function generateUsing(Closure $callback): static + { + $this->resolver = $callback; + + return $this; + } + + /** + * Generate the slug. + */ + public function generate(): string + { + $this->from ??= ['id']; + $this->to ??= 'slug'; + $this->separator ??= '-'; + $this->unique ??= false; + $this->fresh ??= false; + + if (! is_null($this->model->getAttribute($this->to)) && ! $this->fresh) { + return $this->model->getAttribute($this->to); + } + + $value = Str::of(implode($this->separator, $this->model->only($this->from))) + ->slug($this->separator) + ->value(); + + if (! is_null($this->resolver)) { + return call_user_func_array($this->resolver, [$this, $value]); + } + + if (! $this->unique) { + return $value; + } + + $match = $this->model + ->newQuery() + ->when( + in_array(SoftDeletes::class, class_uses_recursive($this->model)), + static function (Builder $query): Builder { + return $query->withTrashed(); + } + ) + ->whereRaw(sprintf( + "`%s` regexp '^%s(%s[\\\\d]+)?$'", + $this->to, + preg_quote($value), + preg_quote($this->separator) + )) + ->orderByDesc($this->to) + ->limit(1) + ->value($this->to); + + $value = is_null($match) ? $value : preg_replace_callback( + sprintf('/%s([\d]+)?$/', preg_quote($this->separator)), + static function (array $match): string { + return str_replace($match[1], (string) (((int) $match[1]) + 1), $match[0]); + }, + $match + ); + + return $value === $match ? sprintf('%s%s1', $value, $this->separator) : $value; + } + + /** + * Get the string representation of the slug. + */ + public function __toString(): string + { + return $this->generate(); + } +} diff --git a/src/Widgets/Widgets.php b/src/Widgets/Widgets.php index bff732c21..6bf2a6f49 100644 --- a/src/Widgets/Widgets.php +++ b/src/Widgets/Widgets.php @@ -6,6 +6,9 @@ use Illuminate\Support\Collection; use Illuminate\Support\Traits\ForwardsCalls; +/** + * @mixin \Illuminate\Support\Collection + */ class Widgets { use ForwardsCalls; From 2ececb03f3f2634d9415f7b5beeeca856489e155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sat, 21 Oct 2023 02:55:48 +0000 Subject: [PATCH 05/17] fix --- src/Support/Slug.php | 170 ------------------------------------------- 1 file changed, 170 deletions(-) delete mode 100644 src/Support/Slug.php diff --git a/src/Support/Slug.php b/src/Support/Slug.php deleted file mode 100644 index 7e9822ba3..000000000 --- a/src/Support/Slug.php +++ /dev/null @@ -1,170 +0,0 @@ -model = $model; - } - - /** - * Set the "from" property. - */ - public function from(array|string $attributes): static - { - $this->from = (array) $attributes; - - return $this; - } - - /** - * Set the "to" property - */ - public function to(string $attribute): static - { - $this->to = $attribute; - - return $this; - } - - /** - * Set the "unique" property. - */ - public function unique(bool $value = true): static - { - $this->unique = $value; - - return $this; - } - - /** - * Set the "fresh" property. - */ - public function fresh(bool $value = true): static - { - $this->fresh = $value; - - return $this; - } - - /** - * Set the "resolver" property. - */ - public function generateUsing(Closure $callback): static - { - $this->resolver = $callback; - - return $this; - } - - /** - * Generate the slug. - */ - public function generate(): string - { - $this->from ??= ['id']; - $this->to ??= 'slug'; - $this->separator ??= '-'; - $this->unique ??= false; - $this->fresh ??= false; - - if (! is_null($this->model->getAttribute($this->to)) && ! $this->fresh) { - return $this->model->getAttribute($this->to); - } - - $value = Str::of(implode($this->separator, $this->model->only($this->from))) - ->slug($this->separator) - ->value(); - - if (! is_null($this->resolver)) { - return call_user_func_array($this->resolver, [$this, $value]); - } - - if (! $this->unique) { - return $value; - } - - $match = $this->model - ->newQuery() - ->when( - in_array(SoftDeletes::class, class_uses_recursive($this->model)), - static function (Builder $query): Builder { - return $query->withTrashed(); - } - ) - ->whereRaw(sprintf( - "`%s` regexp '^%s(%s[\\\\d]+)?$'", - $this->to, - preg_quote($value), - preg_quote($this->separator) - )) - ->orderByDesc($this->to) - ->limit(1) - ->value($this->to); - - $value = is_null($match) ? $value : preg_replace_callback( - sprintf('/%s([\d]+)?$/', preg_quote($this->separator)), - static function (array $match): string { - return str_replace($match[1], (string) (((int) $match[1]) + 1), $match[0]); - }, - $match - ); - - return $value === $match ? sprintf('%s%s1', $value, $this->separator) : $value; - } - - /** - * Get the string representation of the slug. - */ - public function __toString(): string - { - return $this->generate(); - } -} From f3886e108b61ff92384327f0d7b251d5a07204af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sat, 21 Oct 2023 03:07:09 +0000 Subject: [PATCH 06/17] fix --- src/Fields/Fieldset.php | 2 +- src/Fields/File.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Fields/Fieldset.php b/src/Fields/Fieldset.php index 59b105f59..141d9cf39 100644 --- a/src/Fields/Fieldset.php +++ b/src/Fields/Fieldset.php @@ -77,7 +77,7 @@ public function toValidate(Request $request, Model $model): array { return array_merge( parent::toValidate($request, $model), - $this->resolveFields($request)->mapToValidate($request) + $this->resolveFields($request)->mapToValidate($request, $model) ); } } diff --git a/src/Fields/File.php b/src/Fields/File.php index c62fa5a86..7f57aa9ff 100644 --- a/src/Fields/File.php +++ b/src/Fields/File.php @@ -222,6 +222,8 @@ protected function prune(Request $request, Model $model, array $keys): int */ public function toOption(Request $request, Model $model, Model $related): array { + /** @var \Cone\Root\Fields\File $related */ + $option = parent::toOption($request, $model, $related); $name = sprintf( From ef11498d4133a65b373508fd10ad12118f54612f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sat, 21 Oct 2023 03:13:24 +0000 Subject: [PATCH 07/17] fix --- src/Fields/File.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Fields/File.php b/src/Fields/File.php index 7f57aa9ff..b3c48b7eb 100644 --- a/src/Fields/File.php +++ b/src/Fields/File.php @@ -222,8 +222,6 @@ protected function prune(Request $request, Model $model, array $keys): int */ public function toOption(Request $request, Model $model, Model $related): array { - /** @var \Cone\Root\Fields\File $related */ - $option = parent::toOption($request, $model, $related); $name = sprintf( @@ -235,6 +233,8 @@ public function toOption(Request $request, Model $model, Model $related): array $option['attrs']->merge(['name' => $name]); + /** @var \Cone\Root\Fields\File $related */ + return array_merge($option, [ 'file_name' => $related->file_name, 'is_image' => $related->isImage, From 44f79d4efdb53c24b5460cc3987747136c71526f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sat, 21 Oct 2023 03:15:52 +0000 Subject: [PATCH 08/17] fix --- src/Fields/File.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Fields/File.php b/src/Fields/File.php index b3c48b7eb..187375b2b 100644 --- a/src/Fields/File.php +++ b/src/Fields/File.php @@ -233,7 +233,7 @@ public function toOption(Request $request, Model $model, Model $related): array $option['attrs']->merge(['name' => $name]); - /** @var \Cone\Root\Fields\File $related */ + /** @var \Cone\Root\Models\Medium $related */ return array_merge($option, [ 'file_name' => $related->file_name, From 355215fd42b8991330b860c36923aca2e8f5fdc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sat, 21 Oct 2023 03:24:11 +0000 Subject: [PATCH 09/17] fix --- src/Fields/Slug.php | 3 ++- src/Http/Controllers/ActionController.php | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Fields/Slug.php b/src/Fields/Slug.php index 49966bf10..44fb50763 100644 --- a/src/Fields/Slug.php +++ b/src/Fields/Slug.php @@ -5,6 +5,7 @@ use Closure; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Http\Request; use Illuminate\Support\Str; use Illuminate\Validation\Rule; @@ -152,7 +153,7 @@ static function (Builder $query): Builder { $value = is_null($match) ? $value : preg_replace_callback( sprintf('/%s([\d]+)?$/', preg_quote($this->separator)), static function (array $match): string { - return str_replace($match[1], ((int) $match[1]) + 1, $match[0]); + return str_replace($match[1], (string) (((int) $match[1]) + 1), $match[0]); }, $match ); diff --git a/src/Http/Controllers/ActionController.php b/src/Http/Controllers/ActionController.php index 6d0c4c6df..4f0421e1a 100644 --- a/src/Http/Controllers/ActionController.php +++ b/src/Http/Controllers/ActionController.php @@ -13,6 +13,7 @@ class ActionController extends Controller */ public function __invoke(Request $request): RedirectResponse { + /** @var \Cone\Root\Actions\Action $action */ $action = $request->route('rootAction'); Gate::allowIf($action->authorized($request)); From a7703fbf8ca39a4a563c1ed1b6650ef62700ebe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Sat, 21 Oct 2023 02:47:58 +0000 Subject: [PATCH 10/17] Prepare PHPStan --- phpstan.neon.dist | 3 --- 1 file changed, 3 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 9312cf752..eee11b917 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -25,9 +25,6 @@ parameters: ignoreErrors: - '#^Unsafe usage of new static#' # --- TODO-s --- - # Tricky readonlys - - '#Assign it in the constructor\.$#' - - '#is assigned outside of the constructor\.$#' # X vs. X contract - '#but returns Illuminate\\Contracts\\#' # SoftDeletes From 99119d43d9457a1cffc85875a245d47da68101f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Wed, 25 Oct 2023 13:32:31 +0000 Subject: [PATCH 11/17] wip --- .gitattributes | 2 +- .github/workflows/reusable-integrity.yml | 2 +- phpstan.neon.dist | 3 +++ src/Fields/File.php | 6 +++++- src/Fields/Meta.php | 2 ++ tests/phpstan/MetaDataModel.php | 16 ++++++++++++++++ 6 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 tests/phpstan/MetaDataModel.php diff --git a/.gitattributes b/.gitattributes index 1b44d6dc0..6f9cb471f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,7 +12,7 @@ /js-tests export-ignore /phpstan.neon.dist export-ignore /phpunit.xml.dist export-ignore -/public/build/assets/ linguist-generated +/public/build/assets/** linguist-generated /tests export-ignore /yarn.lock export-ignore linguist-generated /vite.config.js export-ignore diff --git a/.github/workflows/reusable-integrity.yml b/.github/workflows/reusable-integrity.yml index 3a2a06f88..6f5e1c691 100644 --- a/.github/workflows/reusable-integrity.yml +++ b/.github/workflows/reusable-integrity.yml @@ -119,7 +119,7 @@ jobs: wget --secure-protocol=TLSv1_3 --max-redirect=1 --retry-on-host-error --retry-connrefused --tries=3 \ --no-verbose --output-document="${{ runner.temp }}/cloc/cloc" "${RELEASE_ASSET_URL}" { - git ls-files -- ':!:LICENSE' ':!:package-lock.json' >"${{ runner.temp }}/cloc/include-list" + git ls-files -- ':!:LICENSE' ':!:yarn.lock' >"${{ runner.temp }}/cloc/include-list" echo '```' perl "${{ runner.temp }}/cloc/cloc" --hide-rate \ --list-file="${{ runner.temp }}/cloc/include-list" \ diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 9312cf752..1bf86dd7f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,9 +1,12 @@ includes: - vendor/nunomaduro/larastan/extension.neon +# - phpstan-baseline.neon parameters: databaseMigrationsPath: - database/migrations/ - vendor/orchestra/testbench-core/laravel/migrations/ + scanFiles: + - tests/phpstan/MetaDataModel.php paths: - src/ - config/ diff --git a/src/Fields/File.php b/src/Fields/File.php index c62fa5a86..242872153 100644 --- a/src/Fields/File.php +++ b/src/Fields/File.php @@ -156,7 +156,9 @@ protected function stored(Request $request, Model $model, string $path): array call_user_func_array($this->storageResolver, [$request, $medium, $path]); } - $request->user()->uploads()->save($medium); + /** @var \Illuminate\Foundation\Auth\User&\Cone\Root\Interfaces\Models\User $user */ + $user = $request->user(); + $user->uploads()->save($medium); MoveFile::withChain($medium->convertible() ? [new PerformConversions($medium)] : []) ->dispatch($medium, $path, false); @@ -219,6 +221,8 @@ protected function prune(Request $request, Model $model, array $keys): int /** * Create a new method. + * + * @phpstan-param \Cone\Root\Models\Medium $related */ public function toOption(Request $request, Model $model, Model $related): array { diff --git a/src/Fields/Meta.php b/src/Fields/Meta.php index 83339a9a4..eb32b1388 100644 --- a/src/Fields/Meta.php +++ b/src/Fields/Meta.php @@ -25,6 +25,8 @@ class Meta extends MorphOne public function __construct(string $label, string $modelAttribute = null, Closure|string $relation = null) { $relation ??= function (Model $model): EloquentRelation { + /** @phpstan-var \App\Models\MetaDataModel $model */ + $related = $model->metaData()->getRelated(); return $model->metaData() diff --git a/tests/phpstan/MetaDataModel.php b/tests/phpstan/MetaDataModel.php new file mode 100644 index 000000000..e9a62c9e5 --- /dev/null +++ b/tests/phpstan/MetaDataModel.php @@ -0,0 +1,16 @@ + Date: Wed, 25 Oct 2023 14:08:33 +0000 Subject: [PATCH 12/17] fix --- phpstan.neon.dist | 4 +--- src/Fields/Fields.php | 1 + src/Fields/Meta.php | 2 +- src/Fields/Slug.php | 1 + src/Http/Controllers/ActionController.php | 1 + src/Http/Controllers/MediaController.php | 2 ++ src/Http/Controllers/RepeaterController.php | 2 ++ src/Http/Controllers/WidgetController.php | 1 + src/Models/Medium.php | 6 ++++++ src/Models/Notification.php | 8 ++++++++ src/RootServiceProvider.php | 5 ++++- src/Traits/AsRootUser.php | 2 ++ tests/phpstan/FieldWithRoute.php | 16 ++++++++++++++++ tests/phpstan/MetaDataModel.php | 2 +- 14 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 tests/phpstan/FieldWithRoute.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1bf86dd7f..437e0e65e 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,6 +6,7 @@ parameters: - database/migrations/ - vendor/orchestra/testbench-core/laravel/migrations/ scanFiles: + - tests/phpstan/FieldWithRoute.php - tests/phpstan/MetaDataModel.php paths: - src/ @@ -28,9 +29,6 @@ parameters: ignoreErrors: - '#^Unsafe usage of new static#' # --- TODO-s --- - # Tricky readonlys - - '#Assign it in the constructor\.$#' - - '#is assigned outside of the constructor\.$#' # X vs. X contract - '#but returns Illuminate\\Contracts\\#' # SoftDeletes diff --git a/src/Fields/Fields.php b/src/Fields/Fields.php index f456d3357..93ecb6c67 100644 --- a/src/Fields/Fields.php +++ b/src/Fields/Fields.php @@ -61,6 +61,7 @@ public function registerRoutes(Request $request, Router $router): void $router->prefix('fields')->group(function (Router $router) use ($request): void { $this->each(static function (Field $field) use ($request, $router): void { if (in_array(RegistersRoutes::class, class_uses_recursive($field))) { + /** @var \Tests\FieldWithRoute $field */ $field->registerRoutes($request, $router); } }); diff --git a/src/Fields/Meta.php b/src/Fields/Meta.php index 795bcf625..01a2ea475 100644 --- a/src/Fields/Meta.php +++ b/src/Fields/Meta.php @@ -24,7 +24,7 @@ class Meta extends MorphOne public function __construct(string $label, string $modelAttribute = null, Closure|string $relation = null) { $relation ??= function (Model $model): EloquentRelation { - /** @phpstan-var \App\Models\MetaDataModel $model */ + /** @phpstan-var \Tests\MetaDataModel $model */ $related = $model->metaData()->getRelated(); diff --git a/src/Fields/Slug.php b/src/Fields/Slug.php index 4f6b0385f..c71084c88 100644 --- a/src/Fields/Slug.php +++ b/src/Fields/Slug.php @@ -5,6 +5,7 @@ use Closure; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Http\Request; use Illuminate\Support\Str; use Illuminate\Validation\Rule; diff --git a/src/Http/Controllers/ActionController.php b/src/Http/Controllers/ActionController.php index 553a4b699..86c18089a 100644 --- a/src/Http/Controllers/ActionController.php +++ b/src/Http/Controllers/ActionController.php @@ -13,6 +13,7 @@ class ActionController extends Controller */ public function __invoke(Request $request): Response { + /** @var \Cone\Root\Actions\Action $action */ $action = $request->route('action'); Gate::allowIf($action->authorized($request)); diff --git a/src/Http/Controllers/MediaController.php b/src/Http/Controllers/MediaController.php index 332a54c1a..6c41485f1 100644 --- a/src/Http/Controllers/MediaController.php +++ b/src/Http/Controllers/MediaController.php @@ -13,8 +13,10 @@ class MediaController extends Controller */ public function __invoke(Request $request): JsonResponse { + /** @var \Cone\Root\Resources\Resource $resource */ $resource = $request->route('_resource'); + /** @var \Cone\Root\Fields\Media $field */ $field = $request->route('field'); // Gate::allowIf($field->authorized($request, $model)); diff --git a/src/Http/Controllers/RepeaterController.php b/src/Http/Controllers/RepeaterController.php index dec018670..80c69f132 100644 --- a/src/Http/Controllers/RepeaterController.php +++ b/src/Http/Controllers/RepeaterController.php @@ -12,8 +12,10 @@ class RepeaterController extends Controller */ public function __invoke(Request $request): JsonResponse { + /** @var \Cone\Root\Resources\Resource $resource */ $resource = $request->route('_resource'); + /** @var \Cone\Root\Fields\Repeater $field */ $field = $request->route('field'); // Gate::allowIf($field->authorized($request, $model)); diff --git a/src/Http/Controllers/WidgetController.php b/src/Http/Controllers/WidgetController.php index 5bc7d33a2..19fac5f4a 100644 --- a/src/Http/Controllers/WidgetController.php +++ b/src/Http/Controllers/WidgetController.php @@ -13,6 +13,7 @@ class WidgetController extends Controller */ public function __invoke(Request $request): Response { + /** @var \Cone\Root\Widgets\Widget $widget */ $widget = $request->route('rootWidget'); Gate::allowIf($widget->authorized($request)); diff --git a/src/Models/Medium.php b/src/Models/Medium.php index 8bedc7e1d..c98bc5033 100644 --- a/src/Models/Medium.php +++ b/src/Models/Medium.php @@ -166,6 +166,8 @@ protected function isImage(): Attribute /** * Get the conversion URLs. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute, never> */ protected function urls(): Attribute { @@ -184,6 +186,8 @@ function (array $urls, string $conversion): array { /** * Get the formatted size attribute. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function formattedSize(): Attribute { @@ -204,6 +208,8 @@ protected function formattedSize(): Attribute /** * Get the dimensions attribute. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function dimensions(): Attribute { diff --git a/src/Models/Notification.php b/src/Models/Notification.php index f3780000c..086dfdede 100644 --- a/src/Models/Notification.php +++ b/src/Models/Notification.php @@ -54,6 +54,8 @@ public static function getProxiedInterface(): string /** * Get the subject attribute. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function subject(): Attribute { @@ -64,6 +66,8 @@ protected function subject(): Attribute /** * Get the formatted created at attribute. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function formattedCreatedAt(): Attribute { @@ -74,6 +78,8 @@ protected function formattedCreatedAt(): Attribute /** * Get the formatted created at attribute. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function isRead(): Attribute { @@ -84,6 +90,8 @@ protected function isRead(): Attribute /** * Get the URL attribute. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function url(): Attribute { diff --git a/src/RootServiceProvider.php b/src/RootServiceProvider.php index dee0143cb..a79fe6182 100644 --- a/src/RootServiceProvider.php +++ b/src/RootServiceProvider.php @@ -122,7 +122,10 @@ protected function registerRoutes(): void }); $this->app['router']->bind('resourceModel', function (string $id, Route $route): Model { - return $route->parameter('resource')->resolveRouteBinding($this->app['request'], $id); + /** @var \Cone\Root\Resources\Resource $resource */ + $resource = $route->parameter('resource'); + + return $resource->resolveRouteBinding($this->app['request'], $id); }); $this->app['router'] diff --git a/src/Traits/AsRootUser.php b/src/Traits/AsRootUser.php index 7225f0c3c..1fe3da8f7 100644 --- a/src/Traits/AsRootUser.php +++ b/src/Traits/AsRootUser.php @@ -39,6 +39,8 @@ public function rootNotifications(): MorphMany /** * Get the avatar attribute. + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function avatar(): Attribute { diff --git a/tests/phpstan/FieldWithRoute.php b/tests/phpstan/FieldWithRoute.php new file mode 100644 index 000000000..07ce0955a --- /dev/null +++ b/tests/phpstan/FieldWithRoute.php @@ -0,0 +1,16 @@ + Date: Wed, 25 Oct 2023 14:16:23 +0000 Subject: [PATCH 13/17] Fix CS --- src/Fields/File.php | 1 - src/Fields/Meta.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Fields/File.php b/src/Fields/File.php index 8ea014ae4..e27184e85 100644 --- a/src/Fields/File.php +++ b/src/Fields/File.php @@ -227,7 +227,6 @@ protected function prune(Request $request, Model $model, array $keys): int public function toOption(Request $request, Model $model, Model $related): array { /** @var \Cone\Root\Models\Medium $related */ - $option = parent::toOption($request, $model, $related); $name = sprintf( diff --git a/src/Fields/Meta.php b/src/Fields/Meta.php index 01a2ea475..40cacc089 100644 --- a/src/Fields/Meta.php +++ b/src/Fields/Meta.php @@ -25,7 +25,6 @@ public function __construct(string $label, string $modelAttribute = null, Closur { $relation ??= function (Model $model): EloquentRelation { /** @phpstan-var \Tests\MetaDataModel $model */ - $related = $model->metaData()->getRelated(); return $model->metaData() From 85330e1de7576f0445eae66c3962075df7d0881b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Wed, 25 Oct 2023 14:23:39 +0000 Subject: [PATCH 14/17] fix --- src/Fields/File.php | 2 +- tests/phpstan/MetaDataModel.php | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Fields/File.php b/src/Fields/File.php index e27184e85..416dde4dc 100644 --- a/src/Fields/File.php +++ b/src/Fields/File.php @@ -205,7 +205,7 @@ public function persist(Request $request, Model $model, mixed $value): void /** * Prune the related models. */ - protected function prune(Request $request, Model $model, array $keys): int + public function prune(Request $request, Model $model, array $keys): int { $count = 0; diff --git a/tests/phpstan/MetaDataModel.php b/tests/phpstan/MetaDataModel.php index 4c39b50a1..19a23c025 100644 --- a/tests/phpstan/MetaDataModel.php +++ b/tests/phpstan/MetaDataModel.php @@ -8,9 +8,4 @@ class MetaDataModel extends Model { use HasMetaData; - - /** - * The Blade template. - */ - protected string $template = 'meta.field'; } From f1bfb8f955fc3c7df8f5e538a26699d8fd8055b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Wed, 25 Oct 2023 19:49:25 +0000 Subject: [PATCH 15/17] Remove TODO-s --- database/factories/MediumFactory.php | 2 +- database/factories/MetaFactory.php | 2 +- database/factories/NotificationFactory.php | 2 +- phpstan.neon.dist | 10 ++++------ 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/database/factories/MediumFactory.php b/database/factories/MediumFactory.php index a327d9da7..56e02ccd3 100644 --- a/database/factories/MediumFactory.php +++ b/database/factories/MediumFactory.php @@ -12,7 +12,7 @@ class MediumFactory extends Factory /** * The name of the factory's corresponding model. * - * @var string + * @var class-string<\Cone\Root\Models\Medium> */ protected $model = Medium::class; diff --git a/database/factories/MetaFactory.php b/database/factories/MetaFactory.php index 38e125d8e..6a80cf8d0 100644 --- a/database/factories/MetaFactory.php +++ b/database/factories/MetaFactory.php @@ -11,7 +11,7 @@ class MetaFactory extends Factory /** * The name of the factory's corresponding model. * - * @var string + * @var class-string<\Cone\Root\Models\Meta> */ protected $model = Meta::class; diff --git a/database/factories/NotificationFactory.php b/database/factories/NotificationFactory.php index b48cc4028..796bedb6f 100644 --- a/database/factories/NotificationFactory.php +++ b/database/factories/NotificationFactory.php @@ -11,7 +11,7 @@ class NotificationFactory extends Factory /** * The name of the factory's corresponding model. * - * @var string + * @var class-string<\Cone\Root\Models\Notification> */ protected $model = Notification::class; diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 437e0e65e..93c9993a5 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,6 +1,6 @@ includes: - vendor/nunomaduro/larastan/extension.neon -# - phpstan-baseline.neon + - phpstan-baseline.neon parameters: databaseMigrationsPath: - database/migrations/ @@ -11,8 +11,7 @@ parameters: paths: - src/ - config/ -# TODO -# - database/ + - database/ - routes/ level: 5 checkAlwaysTrueCheckTypeFunctionCall: true @@ -28,8 +27,7 @@ parameters: checkInternalClassCaseSensitivity: true ignoreErrors: - '#^Unsafe usage of new static#' - # --- TODO-s --- - # X vs. X contract - - '#but returns Illuminate\\Contracts\\#' + # Illuminate\View\View vs. Illuminate\Contracts\View\View + - '#^Method Cone\\\S+::render\(\) should return Illuminate\\View\\View but returns Illuminate\\Contracts\\View\\View\.$#' # SoftDeletes - '#(\$forceDeleting|::withTrashed|::onlyTrashed|::trashed|::restore)#' From 72dc07b8f736307883bd597db7156e457178cdaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Wed, 25 Oct 2023 19:52:46 +0000 Subject: [PATCH 16/17] comment out baseline --- phpstan.neon.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 93c9993a5..ec37703e9 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,6 +1,6 @@ includes: - vendor/nunomaduro/larastan/extension.neon - - phpstan-baseline.neon + #- phpstan-baseline.neon parameters: databaseMigrationsPath: - database/migrations/ From 3802c021f648454640fbb3c2760a6907c2e7f0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sz=C3=A9pe?= Date: Tue, 19 Dec 2023 15:01:54 +0100 Subject: [PATCH 17/17] Update phpstan.neon.dist --- phpstan.neon.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index ec37703e9..056db9ba0 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ includes: - - vendor/nunomaduro/larastan/extension.neon + - vendor/larastan/larastan/extension.neon #- phpstan-baseline.neon parameters: databaseMigrationsPath: