Skip to content

Commit fbde435

Browse files
authored
Merge pull request #25 from laravelcm/patch-fix
feat: fix slug generation and add new tests
2 parents 98fd039 + 825e38c commit fbde435

23 files changed

+144
-110
lines changed

.github/workflows/phpstan.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ jobs:
4444
run: composer install --prefer-dist --no-interaction
4545

4646
- name: Run PHPStan
47-
run: composer stan
47+
run: composer types

composer.json

+6-5
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@
4242
"spatie/laravel-translatable": "^6.5.0"
4343
},
4444
"require-dev": {
45-
"laravel/pint": "^1.13",
4645
"larastan/larastan": "^2.0",
46+
"laravel/pint": "^1.13",
4747
"orchestra/testbench": "^8.0|^9.0",
48-
"pestphp/pest": "^2.18"
48+
"pestphp/pest": "^2.18",
49+
"spatie/test-time": "^1.3"
4950
},
5051
"autoload": {
5152
"psr-4": {
@@ -59,9 +60,9 @@
5960
}
6061
},
6162
"scripts": {
62-
"pest": "./vendor/bin/pest",
63-
"pint": "./vendor/bin/pint",
64-
"stan": "./vendor/bin/phpstan analyse --memory-limit=2g"
63+
"test": "./vendor/bin/pest",
64+
"lint": "./vendor/bin/pint",
65+
"types": "./vendor/bin/phpstan analyse --memory-limit=2g"
6566
},
6667
"config": {
6768
"sort-packages": true,

database/migrations/create_plan_features_table.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
use Illuminate\Database\Schema\Blueprint;
77
use Illuminate\Support\Facades\Schema;
88

9-
return new class () extends Migration {
9+
return new class extends Migration
10+
{
1011
public function up(): void
1112
{
1213
Schema::create(config('laravel-subscriptions.tables.features'), function (Blueprint $table): void {

database/migrations/create_plan_subscription_usage_table.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
use Illuminate\Database\Schema\Blueprint;
77
use Illuminate\Support\Facades\Schema;
88

9-
return new class () extends Migration {
9+
return new class extends Migration
10+
{
1011
public function up(): void
1112
{
1213
Schema::create(config('laravel-subscriptions.tables.subscription_usage'), function (Blueprint $table): void {

database/migrations/create_plan_subscriptions_table.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
use Illuminate\Database\Schema\Blueprint;
77
use Illuminate\Support\Facades\Schema;
88

9-
return new class () extends Migration {
9+
return new class extends Migration
10+
{
1011
public function up(): void
1112
{
1213
Schema::create(config('laravel-subscriptions.tables.subscriptions'), function (Blueprint $table): void {

database/migrations/create_plans_table.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
use Illuminate\Support\Facades\Schema;
88
use Laravelcm\Subscriptions\Interval;
99

10-
return new class () extends Migration {
10+
return new class extends Migration
11+
{
1112
public function up(): void
1213
{
1314
Schema::create(config('laravel-subscriptions.tables.plans'), function (Blueprint $table): void {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Database\Migrations\Migration;
6+
use Illuminate\Database\Schema\Blueprint;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
return new class extends Migration
10+
{
11+
public function up(): void
12+
{
13+
Schema::table(config('laravel-subscriptions.tables.subscriptions'), function (Blueprint $table): void {
14+
$table->dropUnique(config('laravel-subscriptions.tables.subscriptions') . '_slug_unique');
15+
});
16+
}
17+
};

pint.json

+7-33
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,14 @@
11
{
2-
"preset": "psr12",
2+
"preset": "laravel",
33
"rules": {
4-
"align_multiline_comment": true,
4+
"concat_space": {
5+
"spacing": "one"
6+
},
57
"array_indentation": true,
68
"array_syntax": true,
7-
"blank_line_after_namespace": true,
8-
"blank_line_after_opening_tag": true,
9-
"combine_consecutive_issets": true,
10-
"combine_consecutive_unsets": true,
11-
"concat_space": true,
12-
"declare_parentheses": true,
9+
"blank_line_before_statement": true,
1310
"declare_strict_types": true,
14-
"explicit_string_variable": true,
15-
"final_internal_class": false,
16-
"fully_qualified_strict_types": true,
17-
"global_namespace_import": {
18-
"import_classes": true,
19-
"import_constants": true,
20-
"import_functions": true
21-
},
22-
"is_null": true,
23-
"lambda_not_used_import": true,
24-
"logical_operators": true,
25-
"mb_str_functions": true,
26-
"method_chaining_indentation": true,
27-
"modernize_strpos": true,
28-
"new_with_braces": true,
29-
"no_empty_comment": true,
30-
"not_operator_with_space": true,
31-
"ordered_traits": true,
32-
"protected_to_private": true,
33-
"simplified_if_return": true,
34-
"strict_comparison": true,
35-
"ternary_to_null_coalescing": true,
36-
"trim_array_spaces": true,
37-
"use_arrow_functions": true,
38-
"void_return": true
11+
"declare_parentheses": true,
12+
"ordered_traits": true
3913
}
4014
}

src/Models/Feature.php

+5-7
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,20 @@
55
namespace Laravelcm\Subscriptions\Models;
66

77
use Carbon\Carbon;
8-
use Illuminate\Database\Eloquent\Model;
98
use Illuminate\Database\Eloquent\Factories\HasFactory;
10-
use Illuminate\Database\Eloquent\SoftDeletes;
9+
use Illuminate\Database\Eloquent\Model;
1110
use Illuminate\Database\Eloquent\Relations\HasMany;
12-
use Laravelcm\Subscriptions\Traits\HasSlug;
13-
use Laravelcm\Subscriptions\Traits\HasTranslations;
11+
use Illuminate\Database\Eloquent\SoftDeletes;
1412
use Laravelcm\Subscriptions\Services\Period;
1513
use Laravelcm\Subscriptions\Traits\BelongsToPlan;
14+
use Laravelcm\Subscriptions\Traits\HasSlug;
15+
use Laravelcm\Subscriptions\Traits\HasTranslations;
1616
use Spatie\EloquentSortable\Sortable;
1717
use Spatie\EloquentSortable\SortableTrait;
1818
use Spatie\Sluggable\SlugOptions;
1919

2020
/**
21-
* Laravelcm\Subscriptions\Models\PlanFeature.
22-
*
23-
* @property int $id
21+
* @property-read int|string $id
2422
* @property string $slug
2523
* @property array $title
2624
* @property array $description

src/Models/Plan.php

+6-20
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,18 @@
44

55
namespace Laravelcm\Subscriptions\Models;
66

7+
use Illuminate\Database\Eloquent\Factories\HasFactory;
78
use Illuminate\Database\Eloquent\Model;
8-
use Illuminate\Database\Eloquent\SoftDeletes;
99
use Illuminate\Database\Eloquent\Relations\HasMany;
10-
use Illuminate\Database\Eloquent\Factories\HasFactory;
10+
use Illuminate\Database\Eloquent\SoftDeletes;
1111
use Laravelcm\Subscriptions\Traits\HasSlug;
1212
use Laravelcm\Subscriptions\Traits\HasTranslations;
13+
use Spatie\EloquentSortable\Sortable;
1314
use Spatie\EloquentSortable\SortableTrait;
1415
use Spatie\Sluggable\SlugOptions;
15-
use Spatie\EloquentSortable\Sortable;
1616

1717
/**
18-
* Laravelcm\Subscriptions\Models\Plan.
19-
*
20-
* @property int $id
18+
* @property-read int|string $id
2119
* @property string $slug
2220
* @property array $name
2321
* @property array $description
@@ -96,22 +94,9 @@ class Plan extends Model implements Sortable
9694
];
9795

9896
protected $casts = [
99-
'slug' => 'string',
10097
'is_active' => 'boolean',
10198
'price' => 'float',
10299
'signup_fee' => 'float',
103-
'currency' => 'string',
104-
'trial_period' => 'integer',
105-
'trial_interval' => 'string',
106-
'invoice_period' => 'integer',
107-
'invoice_interval' => 'string',
108-
'grace_period' => 'integer',
109-
'grace_interval' => 'string',
110-
'prorate_day' => 'integer',
111-
'prorate_period' => 'integer',
112-
'prorate_extend_due' => 'integer',
113-
'active_subscribers_limit' => 'integer',
114-
'sort_order' => 'integer',
115100
'deleted_at' => 'datetime',
116101
];
117102

@@ -149,7 +134,8 @@ public function getSlugOptions(): SlugOptions
149134
return SlugOptions::create()
150135
->doNotGenerateSlugsOnUpdate()
151136
->generateSlugsFrom('name')
152-
->saveSlugsTo('slug');
137+
->saveSlugsTo('slug')
138+
->allowDuplicateSlugs();
153139
}
154140

155141
public function features(): HasMany

src/Models/Subscription.php

+5-7
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020
use Spatie\Sluggable\SlugOptions;
2121

2222
/**
23-
* Laravelcm\Subscriptions\Models\Subscription.
24-
*
25-
* @property int $id
23+
* @property-read int|string $id
2624
* @property string $subscriber_type
2725
* @property string $slug
2826
* @property array $title
@@ -104,7 +102,7 @@ class Subscription extends Model
104102
'description',
105103
];
106104

107-
public function getTable(): string
105+
public function getTable()
108106
{
109107
return config('laravel-subscriptions.tables.subscriptions');
110108
}
@@ -114,7 +112,7 @@ protected static function boot(): void
114112
parent::boot();
115113

116114
static::creating(function (self $model): void {
117-
if ( ! $model->starts_at || ! $model->ends_at) {
115+
if (! $model->starts_at || ! $model->ends_at) {
118116
$model->setNewPeriod();
119117
}
120118
});
@@ -367,7 +365,7 @@ public function canUseFeature(string $featureSlug): bool
367365

368366
// If the feature value is zero, let's return false since
369367
// there's no uses available. (useful to disable countable features)
370-
if ( ! $usage || $usage->expired() || $featureValue === null || $featureValue === '0' || $featureValue === 'false') {
368+
if (! $usage || $usage->expired() || $featureValue === null || $featureValue === '0' || $featureValue === 'false') {
371369
return false;
372370
}
373371

@@ -382,7 +380,7 @@ public function getFeatureUsage(string $featureSlug): int
382380
{
383381
$usage = $this->usage()->byFeatureSlug($featureSlug)->first();
384382

385-
return ( ! $usage || $usage->expired()) ? 0 : $usage->used;
383+
return (! $usage || $usage->expired()) ? 0 : $usage->used;
386384
}
387385

388386
/**

src/Models/SubscriptionUsage.php

+6-9
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,14 @@
55
namespace Laravelcm\Subscriptions\Models;
66

77
use Carbon\Carbon;
8-
use Illuminate\Database\Eloquent\Model;
98
use Illuminate\Database\Eloquent\Builder;
10-
use Illuminate\Database\Eloquent\SoftDeletes;
11-
use Illuminate\Database\Eloquent\Relations\BelongsTo;
129
use Illuminate\Database\Eloquent\Factories\HasFactory;
10+
use Illuminate\Database\Eloquent\Model;
11+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
12+
use Illuminate\Database\Eloquent\SoftDeletes;
1313

1414
/**
15-
* Laravelcm\Subscriptions\Models\SubscriptionUsage.
16-
*
17-
* @property int $id
15+
* @property-read int|string $id
1816
* @property int $used
1917
* @property Carbon|null $valid_until
2018
* @property Carbon|null $created_at
@@ -32,7 +30,6 @@
3230
* @method static \Illuminate\Database\Eloquent\Builder|\Laravelcm\Subscriptions\Models\SubscriptionUsage whereUpdatedAt($value)
3331
* @method static \Illuminate\Database\Eloquent\Builder|\Laravelcm\Subscriptions\Models\SubscriptionUsage whereUsed($value)
3432
* @method static \Illuminate\Database\Eloquent\Builder|\Laravelcm\Subscriptions\Models\SubscriptionUsage whereValidUntil($value)
35-
*
3633
*/
3734
class SubscriptionUsage extends Model
3835
{
@@ -70,14 +67,14 @@ public function subscription(): BelongsTo
7067
public function scopeByFeatureSlug(Builder $builder, string $featureSlug): Builder
7168
{
7269
$model = config('laravel-subscriptions.models.feature', Feature::class);
73-
$feature = tap(new $model())->where('slug', $featureSlug)->first();
70+
$feature = $model::where('slug', $featureSlug)->first();
7471

7572
return $builder->where('feature_id', $feature ? $feature->getKey() : null);
7673
}
7774

7875
public function expired(): bool
7976
{
80-
if ( ! $this->valid_until) {
77+
if (! $this->valid_until) {
8178
return false;
8279
}
8380

src/Services/Period.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ public function __construct(string $interval = 'month', int $count = 1, ?Carbon
2828

2929
if (empty($start)) {
3030
$this->start = Carbon::now();
31-
} elseif ( ! $start instanceof Carbon) {
31+
} elseif (! $start instanceof Carbon) {
3232
$this->start = new Carbon($start);
3333
} else {
3434
$this->start = $start;
3535
}
3636

3737
$this->period = $count;
3838
$start = clone $this->start;
39-
$method = 'add'.ucfirst($this->interval).'s';
39+
$method = 'add' . ucfirst($this->interval) . 's';
4040
$this->end = $start->{$method}($this->period);
4141
}
4242

src/SubscriptionServiceProvider.php

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public function configurePackage(Package $package): void
1919
'create_plan_features_table',
2020
'create_plan_subscriptions_table',
2121
'create_plan_subscription_usage_table',
22+
'remove_unique_slug_on_subscriptions_table',
2223
])
2324
->hasInstallCommand(function (InstallCommand $command): void {
2425
$command

src/Traits/HasPlanSubscriptions.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
use Carbon\Carbon;
88
use Illuminate\Database\Eloquent\Collection;
99
use Illuminate\Database\Eloquent\Relations\MorphMany;
10-
use Laravelcm\Subscriptions\Models\Subscription;
1110
use Laravelcm\Subscriptions\Models\Plan;
11+
use Laravelcm\Subscriptions\Models\Subscription;
1212
use Laravelcm\Subscriptions\Services\Period;
1313

1414
trait HasPlanSubscriptions
@@ -22,8 +22,6 @@ protected static function bootHasSubscriptions(): void
2222

2323
/**
2424
* The subscriber may have many plan subscriptions.
25-
*
26-
* @return MorphMany
2725
*/
2826
public function planSubscriptions(): MorphMany
2927
{
@@ -42,7 +40,7 @@ public function activePlanSubscriptions(): Collection
4240

4341
public function planSubscription(string $subscriptionSlug): ?Subscription
4442
{
45-
return $this->planSubscriptions()->where('slug', $subscriptionSlug)->first();
43+
return $this->planSubscriptions()->where('slug', 'like', '%' . $subscriptionSlug . '%')->first();
4644
}
4745

4846
public function subscribedPlans(): Collection

src/Traits/HasSlug.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ protected static function bootHasSlug(): void
1717
static::creating(function (Model $model): void {
1818
if ($model->exists && $model->getSlugOptions()->generateSlugsOnUpdate) {
1919
$model->generateSlugOnUpdate();
20-
} elseif ( ! $model->exists && $model->getSlugOptions()->generateSlugsOnCreate) {
20+
} elseif (! $model->exists && $model->getSlugOptions()->generateSlugsOnCreate) {
2121
$model->generateSlugOnCreate();
2222
}
2323
});

0 commit comments

Comments
 (0)