Skip to content

Commit 16f1006

Browse files
committed
feat:
- change model table names - set/get/remove preferences via enum or model
1 parent 1916356 commit 16f1006

11 files changed

+183
-48
lines changed

README.md

+8-5
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ php artisan vendor:publish --tag="laravel-preference-config"
7272
```php
7373
'db' => [
7474
'connection' => null, //string: the connection name to use
75-
], // null -> use defaults
75+
'preferences_table_name' => 'preferences',
76+
'user_preferences_table_name' => 'user_preferences',
77+
],
7678
'routes' => [
7779
'enabled' => false, // set true to register routes, more on that later
7880
'middlewares' => [
@@ -92,6 +94,8 @@ php artisan vendor:publish --tag="laravel-preference-config"
9294
]
9395
```
9496

97+
> Consider changing the base table names before running the migrations, if needed
98+
9599
Run the migrations with:
96100

97101
```bash
@@ -103,9 +107,8 @@ php artisan migrate
103107
### Concepts
104108

105109
Each preference has at least a name and a caster. For additional validation you can add you custom Rule object
106-
> The default caster supports all major primitives, enums, objects, as well as time/datetime/date and timestamp which get
107-
> converted
108-
> with `Carbon/Carbon`
110+
> The default caster supports all major primitives, enums, objects, as well as time/datetime/date and timestamp which
111+
> get converted with `Carbon/Carbon`
109112
110113
### Define your preferences
111114

@@ -375,7 +378,7 @@ which can all be accessed via the route name: {prefix}.{scope}.{group}.{index/ge
375378
`scope_id`: The unique identifier of the scope (e.g., a user's ID).
376379
`preference`: The value of the specific preference enum (e.g., General::LANGUAGE->value).
377380
`group`: A mapping of group names to their corresponding Enum classes. See config below
378-
`scope`: A mapping of scope names to their corresponding Eloquent model. See config below
381+
`scope`: A mapping of scope names to their corresponding Eloquent model. See config below
379382

380383
### Example
381384

config/user_preference.php

+8-6
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,24 @@
22

33
return [
44
'db' => [
5-
'connection' => null,
5+
'connection' => null,
6+
'preferences_table_name' => 'preferences',
7+
'user_preferences_table_name' => 'user_preferences',
68
],
79
'routes' => [
810
'enabled' => false,
911
'middlewares' => [
1012
'auth', // general middleware
11-
'user'=> 'verified', // optional, scoped middleware
12-
'user.general'=> 'verified' // optional, scoped & grouped middleware
13+
'user' => 'verified', // optional, scoped middleware
14+
'user.general' => 'verified' // optional, scoped & grouped middleware
1315
],
14-
'prefix' => 'preferences',
16+
'prefix' => 'preferences',
1517
'groups' => [
1618
//enum class list of preferences
1719
//'general'=>General::class
1820
],
19-
'scopes'=> [
20-
// as many preferenceable models as you want
21+
'scopes' => [
22+
// as many preferenceable models as you want
2123
'user' => \Illuminate\Auth\Authenticatable::class
2224
]
2325
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
use Matteoc99\LaravelPreference\Models\Preference;
7+
8+
return new class extends Migration {
9+
10+
public function up()
11+
{
12+
13+
$preferenceTable = (new Preference())->getTable();
14+
15+
Schema::table($preferenceTable, function (Blueprint $table) {
16+
$table->json('guard')->nullable();
17+
});
18+
}
19+
20+
public function down()
21+
{
22+
$preferenceTable = (new Preference())->getTable();
23+
24+
Schema::table($preferenceTable, function (Blueprint $table) {
25+
$table->dropColumn('guard');
26+
});
27+
}
28+
};

src/Contracts/PreferencePolicy.php

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Matteoc99\LaravelPreference\Contracts;
4+
5+
use Illuminate\Contracts\Auth\Authenticatable;
6+
use Matteoc99\LaravelPreference\Models\Preference;
7+
8+
interface PreferencePolicy
9+
{
10+
public function index(Authenticatable $user, Preference $preference, mixed $value): bool;
11+
12+
public function get(Authenticatable $user, Preference $preference, mixed $value): bool;
13+
14+
public function update(Authenticatable $user, Preference $preference, mixed $value): bool;
15+
16+
public function delete(Authenticatable $user, Preference $preference, mixed $value): bool;
17+
}

src/Models/BaseModel.php

+6
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,10 @@ public function toArrayOnly(array $keys): array
2424
return Arr::only($this->attributesToArray(), $keys);
2525
}
2626

27+
public function getTable()
28+
{
29+
return ConfigHelper::getDbTableName(get_class($this), parent::getTable());
30+
}
31+
32+
2733
}

src/Traits/HasPreferences.php

+31-21
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,19 @@ private function userPreferences(): MorphMany
3030
/**
3131
* Get a user's preference value or default if not set.
3232
*
33-
* @param PreferenceGroup $name
34-
* @param mixed|null $default Default value if preference not set.
33+
* @param PreferenceGroup|Preference $preference
34+
* @param mixed|null $default Default value if preference not set.
3535
*
3636
* @return mixed
37-
* @throws PreferenceNotFoundException|AuthorizationException
37+
* @throws AuthorizationException
38+
* @throws PreferenceNotFoundException
3839
*/
39-
public function getPreference(PreferenceGroup $name, mixed $default = null): mixed
40+
public function getPreference(PreferenceGroup|Preference $preference, mixed $default = null): mixed
4041
{
42+
4143
$this->authorize(PolicyAction::GET);
4244

43-
$preference = $this->validateAndRetrievePreference($name);
45+
$preference = $this->validateAndRetrievePreference($preference);
4446

4547
$userPreference = $this->userPreferences()->where('preference_id', $preference->id)->first();
4648

@@ -50,17 +52,18 @@ public function getPreference(PreferenceGroup $name, mixed $default = null): mix
5052
/**
5153
* Set or update a user's preference value.
5254
*
53-
* @param PreferenceGroup $name
54-
* @param mixed $value Value to set for the preference.
55+
* @param PreferenceGroup|Preference $preference
56+
* @param mixed $value Value to set for the preference.
5557
*
56-
* @throws PreferenceNotFoundException|AuthorizationException|ValidationException
58+
* @throws AuthorizationException
59+
* @throws PreferenceNotFoundException
60+
* @throws ValidationException
5761
*/
58-
public function setPreference(PreferenceGroup $name, mixed $value): void
62+
public function setPreference(PreferenceGroup|Preference $preference, mixed $value): void
5963
{
6064
$this->authorize(PolicyAction::UPDATE);
6165

62-
63-
$preference = $this->validateAndRetrievePreference($name);
66+
$preference = $this->validateAndRetrievePreference($preference);
6467

6568
$validator = Validator::make(['value' => $value], ['value' => $preference->getValidationRules()]);
6669

@@ -74,16 +77,18 @@ public function setPreference(PreferenceGroup $name, mixed $value): void
7477
/**
7578
* Remove a user's preference.
7679
*
77-
* @param PreferenceGroup $name
80+
* @param PreferenceGroup|Preference $preference
7881
*
7982
* @return int Number of deleted records.
80-
* @throws PreferenceNotFoundException|AuthorizationException
83+
* @throws AuthorizationException
84+
* @throws PreferenceNotFoundException
8185
*/
82-
public function removePreference(PreferenceGroup $name): int
86+
public function removePreference(PreferenceGroup|Preference $preference): int
8387
{
8488
$this->authorize(PolicyAction::DELETE);
8589

86-
$preference = $this->validateAndRetrievePreference($name);
90+
$preference = $this->validateAndRetrievePreference($preference);
91+
8792

8893
return $this->userPreferences()->where('preference_id', $preference->id)->delete();
8994
}
@@ -112,22 +117,27 @@ public function getPreferences(string $group = null): Collection
112117
/**
113118
* Validate existence of a preference and retrieve it.
114119
*
115-
* @param PreferenceGroup $name Preference name.
120+
* @param PreferenceGroup|Preference $preference Preference name.
116121
*
117122
* @return Preference
118123
* @throws PreferenceNotFoundException If preference not found.
119124
*/
120-
private function validateAndRetrievePreference(PreferenceGroup $name): Preference
125+
private function validateAndRetrievePreference(PreferenceGroup|Preference $preference): Preference
121126
{
122-
SerializeHelper::conformNameAndGroup($name, $group);
123127

124-
/**@var string $name * */
125-
$preference = Preference::where('group', $group)->where('name', $name)->first();
128+
if (!$preference instanceof Preference) {
129+
130+
SerializeHelper::conformNameAndGroup($preference, $group);
126131

132+
/**@var Preference $preference * */
133+
$preference = Preference::where('group', $group)->where('name', $preference)->first();
134+
}
127135
if (!$preference) {
128-
throw new PreferenceNotFoundException("Preference not found: $name in group $group");
136+
throw new PreferenceNotFoundException("Preference not found: $preference in group $group");
129137
}
130138

139+
//Todo Gate
140+
131141
return $preference;
132142
}
133143

src/Utils/ConfigHelper.php

+15-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Matteoc99\LaravelPreference\Utils;
44

55
use Illuminate\Support\Facades\Config;
6+
use Matteoc99\LaravelPreference\Models\Preference;
7+
use Matteoc99\LaravelPreference\Models\UserPreference;
68

79
class ConfigHelper
810
{
@@ -12,6 +14,17 @@ public static function getDbConnection(): null|string
1214
return Config::get('user_preference.db.connection');
1315
}
1416

17+
public static function getDbTableName(string $class, string $default = ''): string
18+
{
19+
$config = match ($class) {
20+
Preference::class => 'preferences_table_name',
21+
UserPreference::class => 'user_preferences_table_name',
22+
default => throw new \InvalidArgumentException("Unsupported class: $class"),
23+
};
24+
25+
return Config::get("user_preference.db.$config", $default);
26+
}
27+
1528
public static function areRoutesEnabled(): bool
1629
{
1730
return Config::get('user_preference.routes.enabled', false);
@@ -26,12 +39,12 @@ public static function getRoutePrefix(bool $dotted = true): string
2639

2740
public static function getGroup(string $groupName): string|null
2841
{
29-
return Config::get("user_preference.routes.groups.{$groupName}");
42+
return Config::get("user_preference.routes.groups.$groupName");
3043
}
3144

3245
public static function getScope(string $scopeName): string|null
3346
{
34-
return Config::get("user_preference.routes.scopes.{$scopeName}");
47+
return Config::get("user_preference.routes.scopes.$scopeName");
3548
}
3649

3750
public static function getGroups(): array

tests/MigrationTest.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Matteoc99\LaravelPreference\Tests;
4+
5+
class MigrationTest extends TestCase
6+
{
7+
8+
/** @test */
9+
public function migration_rollback_works()
10+
{
11+
for ($i = 0; $i < 10; $i++) {
12+
13+
$this->artisan('migrate:rollback', ['--database' => 'testbench'])->run();
14+
$this->artisan('migrate', ['--database' => 'testbench'])->run();
15+
}
16+
17+
$this->assertTrue($this->getSchema()->hasTable('custom_prefs'));
18+
$this->assertCount(4, $this->getSchema()->getTables());
19+
}
20+
}

tests/PreferenceBasicTest.php

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Validation\ValidationException;
66
use Matteoc99\LaravelPreference\Factory\PreferenceBuilder;
7+
use Matteoc99\LaravelPreference\Models\Preference;
78
use Matteoc99\LaravelPreference\Rules\InRule;
89
use Matteoc99\LaravelPreference\Tests\TestSubjects\Enums\General;
910
use Matteoc99\LaravelPreference\Tests\TestSubjects\Enums\OtherPreferences;
@@ -40,6 +41,20 @@ public function set_and_get_preference()
4041
$this->assertEquals('de', $preference);
4142
}
4243

44+
/** @test */
45+
public function set_and_get_with_instance()
46+
{
47+
/**@var Preference $preference * */
48+
$preference = Preference::query()->where('name', General::LANGUAGE->value)->first();
49+
$this->testUser->setPreference($preference, 'it');
50+
51+
$result = $this->testUser->getPreference(General::LANGUAGE);
52+
53+
$this->assertEquals('it', $result);
54+
$this->assertEquals($result, $this->testUser->getPreference($preference));
55+
}
56+
57+
4358
/** @test */
4459
public function remove_preference()
4560
{
@@ -88,7 +103,7 @@ public function init_and_delete()
88103
PreferenceBuilder::init(VideoPreferences::QUALITY)->updateOrCreate();
89104
PreferenceBuilder::init(VideoPreferences::QUALITY)->updateOrCreate();
90105

91-
$this->assertDatabaseCount('preferences', 3);
106+
$this->assertDatabaseCount((new Preference())->getTable(), 3);
92107

93108
$this->testUser->setPreference(VideoPreferences::QUALITY, "144p");
94109

tests/PreferenceBuilderBulkTest.php

+9-9
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ public function init_bulk_correctly_creates_multiple_preferences()
4545

4646
PreferenceBuilder::initBulk($preferences);
4747

48-
$this->assertDatabaseCount('preferences', 2);
49-
$this->assertDatabaseHas('preferences', ['name' => General::LANGUAGE]);
50-
$this->assertDatabaseHas('preferences', ['name' => VideoPreferences::LANGUAGE]);
48+
$this->assertDatabaseCount((new Preference())->getTable(), 2);
49+
$this->assertDatabaseHas((new Preference())->getTable(), ['name' => General::LANGUAGE]);
50+
$this->assertDatabaseHas((new Preference())->getTable(), ['name' => VideoPreferences::LANGUAGE]);
5151
}
5252

5353
/** @test */
@@ -66,8 +66,8 @@ public function delete_bulk_deletes_correct_preferences()
6666

6767
PreferenceBuilder::deleteBulk($deletePreferences);
6868

69-
$this->assertDatabaseCount('preferences', 1);
70-
$this->assertDatabaseHas('preferences', ['name' => VideoPreferences::LANGUAGE]);
69+
$this->assertDatabaseCount((new Preference())->getTable(), 1);
70+
$this->assertDatabaseHas((new Preference())->getTable(), ['name' => VideoPreferences::LANGUAGE]);
7171
}
7272

7373
/** @test */
@@ -104,8 +104,8 @@ public function init_bulk_creates_new_and_updates_existing_preferences()
104104

105105
PreferenceBuilder::initBulk($preferences);
106106

107-
$this->assertDatabaseCount('preferences', 2);
108-
$this->assertDatabaseHas('preferences', ['name' => General::LANGUAGE]);
107+
$this->assertDatabaseCount((new Preference())->getTable(), 2);
108+
$this->assertDatabaseHas((new Preference())->getTable(), ['name' => General::LANGUAGE]);
109109

110110
$found = Preference::query()->where('name', "=", General::LANGUAGE);
111111
$this->assertEquals(1, $found->count());
@@ -148,11 +148,11 @@ public function init_bulk_with_all_options()
148148
];
149149

150150
PreferenceBuilder::initBulk($preferences);
151-
$this->assertDatabaseCount('preferences', 2);
151+
$this->assertDatabaseCount((new Preference())->getTable(), 2);
152152
$this->assertEquals(true,$this->testUser->getPreference(General::LANGUAGE));
153153

154154
PreferenceBuilder::deleteBulk($preferences);
155-
$this->assertDatabaseCount('preferences', 0);
155+
$this->assertDatabaseCount((new Preference())->getTable(), 0);
156156

157157
}
158158

0 commit comments

Comments
 (0)