Skip to content

Commit 1b89f32

Browse files
committed
feat: update to PHPStan 2 and PHP 8.4
1 parent 27497f3 commit 1b89f32

13 files changed

+89
-109
lines changed

.github/workflows/tests.yml

+4-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
---
12
name: Tests
23

34
on:
@@ -18,16 +19,8 @@ jobs:
1819
strategy:
1920
fail-fast: false
2021
matrix:
21-
php: [8.1, 8.2, 8.3]
22-
laravel: ['^10.0', '^11.0']
23-
include:
24-
- laravel: ^10.0
25-
testbench: ^8.0
26-
- laravel: ^11.0
27-
testbench: ^9.0
28-
exclude:
29-
- php: 8.1
30-
laravel: '^11.0'
22+
php: [8.4]
23+
laravel: ['^11.0']
3124
name: PHP${{ matrix.php }} - Laravel${{ matrix.laravel }}
3225
runs-on: ubuntu-latest
3326
steps:
@@ -57,7 +50,7 @@ jobs:
5750
restore-keys: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-
5851

5952
- name: Install dependencies from composer.json
60-
run: composer update --with='laravel/framework:${{ matrix.laravel }}' --with='orchestra/testbench:${{ matrix.testbench }}' --no-interaction --no-progress
53+
run: composer update --with='laravel/framework:${{ matrix.laravel }}' --no-interaction --no-progress
6154

6255
- name: Check PSR-4 mapping
6356
run: composer dump-autoload --optimize --strict-psr

composer.json

+7-8
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,17 @@
4040
}
4141
},
4242
"require": {
43-
"php": "^8.1",
43+
"php": "^8.4",
4444
"godruoyi/php-snowflake": "^3.0",
45-
"illuminate/contracts": "^10.0|^11.0",
46-
"illuminate/database": "^10.0|^11.0",
47-
"illuminate/support": "^10.0|^11.0",
48-
"illuminate/validation": "^10.0|^11.0",
49-
"phpstan/phpstan": "^1.11"
45+
"illuminate/contracts": "^11.0",
46+
"illuminate/database": "^11.0",
47+
"illuminate/support": "^11.0",
48+
"illuminate/validation": "^11.0"
5049
},
5150
"require-dev": {
52-
"larastan/larastan": "^2.9",
51+
"larastan/larastan": "^3.0",
5352
"laravel/pint": "^1.16.2",
54-
"orchestra/testbench": "^8.0|^9.0",
53+
"orchestra/testbench": "^9.0",
5554
"pestphp/pest": "^2.34"
5655
},
5756
"extra": {

phpstan.neon.dist

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ parameters:
44
level: max
55
paths:
66
- src
7+
- workbench/app

src/Concerns/HasSnowflakes.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ public function newUniqueId(): string
4040
/** @inheritDoc */
4141
public function resolveRouteBindingQuery($query, $value, $field = null)
4242
{
43+
if (! is_numeric($value)) {
44+
return parent::resolveRouteBindingQuery($query, $value, $field);
45+
}
46+
4347
$field ??= $this->getRouteKeyName();
4448

4549
if (in_array($field, $this->uniqueIds(), true) && ! Str::isSnowflake($value)) {
46-
throw (new ModelNotFoundException())->setModel($this::class, $value);
50+
throw new ModelNotFoundException()->setModel($this::class, (string) $value);
4751
}
4852

4953
return parent::resolveRouteBindingQuery($query, $value, $field);

src/Macros/BlueprintMacros.php

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CalebDW\Laraflake\Macros;
6+
7+
use Illuminate\Database\Eloquent\Model;
8+
use Illuminate\Database\Schema\Blueprint;
9+
use Illuminate\Database\Schema\ColumnDefinition;
10+
11+
class BlueprintMacros
12+
{
13+
public static function boot(): void
14+
{
15+
Blueprint::macro('snowflake', function (string $column = 'id'): ColumnDefinition {
16+
return $this->unsignedBigInteger($column);
17+
});
18+
19+
Blueprint::macro('foreignSnowflake', function (string $column): ColumnDefinition {
20+
return $this->foreignId($column);
21+
});
22+
23+
Blueprint::macro('foreignSnowflakeFor', function (string $model, ?string $column = null): ColumnDefinition {
24+
/** @var class-string<Model> $model */
25+
return $this->foreignSnowflake($column ?? (new $model())->getForeignKey());
26+
});
27+
}
28+
}

src/Macros/RuleMacros.php

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CalebDW\Laraflake\Macros;
6+
7+
use CalebDW\Laraflake\Rules\Snowflake as SnowflakeRule;
8+
use Illuminate\Validation\Rule;
9+
10+
class RuleMacros
11+
{
12+
public static function boot(): void
13+
{
14+
Rule::macro('snowflake', fn () => new SnowflakeRule());
15+
}
16+
}

src/Mixins/StrMixin.php src/Macros/StrMacros.php

+9-14
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,33 @@
22

33
declare(strict_types=1);
44

5-
namespace CalebDW\Laraflake\Mixins;
5+
namespace CalebDW\Laraflake\Macros;
66

77
use CalebDW\Laraflake\Facades\Snowflake;
8-
use Closure;
98
use Illuminate\Support\Str;
109

11-
/** @mixin \Illuminate\Support\Str */
12-
class StrMixin
10+
class StrMacros
1311
{
14-
/** @return Closure(): string */
15-
public function snowflake(): Closure
12+
public static function boot(): void
1613
{
17-
return fn (): string => Snowflake::id();
18-
}
14+
Str::macro('snowflake', fn (): string => Snowflake::id());
1915

20-
/** @return Closure(mixed): bool */
21-
public function isSnowflake(): Closure
22-
{
23-
return function (mixed $value): bool {
16+
Str::macro('isSnowflake', function (mixed $value): bool {
2417
if (! is_numeric($value)) {
2518
return false;
2619
}
2720

2821
$value = Str::of((string) $value)
2922
->rtrim('.0')
3023
->rtrim('.')
31-
->toString();
24+
->value();
3225

3326
if (Str::contains($value, '.')) {
3427
return false;
3528
}
3629

30+
assert(is_numeric($value));
31+
3732
$maxSnowflakeValue = '9223372036854775807';
3833

3934
if (bccomp($value, '0') < 0 || bccomp($value, $maxSnowflakeValue, 1) > 0) {
@@ -43,6 +38,6 @@ public function isSnowflake(): Closure
4338
$parsed = Snowflake::parseId($value);
4439

4540
return count(array_filter($parsed)) === count($parsed);
46-
};
41+
});
4742
}
4843
}

src/Mixins/BlueprintMixin.php

-40
This file was deleted.

src/Mixins/RuleMixin.php

-19
This file was deleted.

src/ServiceProvider.php

+11-13
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
namespace CalebDW\Laraflake;
66

7-
use CalebDW\Laraflake\Mixins\BlueprintMixin;
8-
use CalebDW\Laraflake\Mixins\RuleMixin;
9-
use CalebDW\Laraflake\Mixins\StrMixin;
7+
use CalebDW\Laraflake\Macros\BlueprintMacros;
8+
use CalebDW\Laraflake\Macros\RuleMacros;
9+
use CalebDW\Laraflake\Macros\StrMacros;
1010
use Composer\InstalledVersions;
1111
use Godruoyi\Snowflake\FileLockResolver;
1212
use Godruoyi\Snowflake\LaravelSequenceResolver;
@@ -18,11 +18,9 @@
1818
use Godruoyi\Snowflake\Sonyflake;
1919
use Godruoyi\Snowflake\SwooleSequenceResolver;
2020
use Illuminate\Contracts\Cache\Repository;
21-
use Illuminate\Database\Schema\Blueprint;
21+
use Illuminate\Contracts\Foundation\Application;
2222
use Illuminate\Foundation\Console\AboutCommand;
2323
use Illuminate\Support\ServiceProvider as IlluminateServiceProvider;
24-
use Illuminate\Support\Str;
25-
use Illuminate\Validation\Rule;
2624
use InvalidArgumentException;
2725

2826
/**
@@ -50,7 +48,7 @@ public function boot(): void
5048
{
5149
$this->publishes([__DIR__ . '/../config/laraflake.php' => config_path('laraflake.php')]);
5250

53-
$this->registerMixins();
51+
$this->registerMacros();
5452

5553
AboutCommand::add('Laraflake', function () {
5654
/** @var LaraflakeConfig $config */
@@ -76,17 +74,17 @@ public function boot(): void
7674
}
7775

7876
/** Register custom mixins. */
79-
protected function registerMixins(): void
77+
protected function registerMacros(): void
8078
{
81-
Blueprint::mixin(new BlueprintMixin());
82-
Str::mixin(new StrMixin());
83-
Rule::mixin(new RuleMixin());
79+
BlueprintMacros::boot();
80+
RuleMacros::boot();
81+
StrMacros::boot();
8482
}
8583

8684
/** Register the Snowflake singleton. */
8785
protected function registerSnowflake(): void
8886
{
89-
$this->app->singleton(Snowflake::class, function ($app) {
87+
$this->app->singleton(Snowflake::class, function (Application $app) {
9088
/** @var LaraflakeConfig $config */
9189
$config = config('laraflake');
9290

@@ -103,7 +101,7 @@ protected function registerSnowflake(): void
103101
/** Bind the Snowflake sequence resolver. */
104102
protected function registerSequenceResolver(): void
105103
{
106-
$this->app->bind(SequenceResolver::class, function ($app) {
104+
$this->app->bind(SequenceResolver::class, function (Application $app) {
107105
if (! $app->has('cache.store')) {
108106
return new RandomSequenceResolver();
109107
}

tests/Feature/HasSnowflakesTest.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,14 @@
5252
->assertSee(test()->post->title);
5353
});
5454

55-
it('throws exception for invalid snowflake', function () {
55+
it('throws exception for invalid snowflake', function ($value) {
5656
test()->withoutExceptionHandling();
5757

58-
test()->get('/users-id/invalid');
59-
})->throws(ModelNotFoundException::class);
58+
test()->get("/users-id/{$value}");
59+
})->with([
60+
'non-numeric',
61+
'9999999999999999999',
62+
])->throws(ModelNotFoundException::class);
6063

6164
it('throws exception for non-unique field', function () {
6265
test()->withoutExceptionHandling();

workbench/app/Models/Post.php

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public function uniqueIds(): array
2525
return ['slug'];
2626
}
2727

28+
/** @return BelongsTo<User, $this> */
2829
public function user(): BelongsTo
2930
{
3031
return $this->belongsTo(User::class);

workbench/app/Models/User.php

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class User extends Model
1414

1515
protected $guarded = [];
1616

17+
/** @return HasMany<Post, $this> */
1718
public function posts(): HasMany
1819
{
1920
return $this->hasMany(Post::class);

0 commit comments

Comments
 (0)