Hi,
If user can have many settings and setting is related to many users, you need this pivot table. In all other case it's not a good way.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
Hi, i am looking for elegant way to model my database tables.Easy way is creating 3 model for me but i really dont like to use that way.
Tables: user,settings,user_settings
user Table*
settings Table
user_settings Table ( pivot table )*
Hi,
If user can have many settings and setting is related to many users, you need this pivot table. In all other case it's not a good way.
in my case user can have many settings and it must be flexible to add new setting fields.
So looks like you just need a one to many relation :
user Table
id
name
email
password
settings Table
id
name
user_id
description
Unless a particular setting is related to many users. In this case you need the pivot.
The most important question is:
Do you want to check if a user sets a valid setting or can anything be set?
If anything can be set: Just make the tables users and user_settings like you suggested.
If you need to validate if the setting is allowed to be set AND the collection of all valid settings is held in the database, you need the pivot table.
However, you could also keep this in PHP code. Maybe you have an array of all allowed settings. This depends heavily on how often you change allowed settings. In this case, you could do the validation in the model and just use users and user_settings.
This all comes down to the complexity you need. Do you need to be able to search for settings at any point? This will give you a hint as to whether you need a separate table for storing user settings or if you can do something else.
As mentioned above, you could keep the list of valid settings within your code using an enumeration object. That way you can prevent users from arbitrarily storing settings.
For an application I was working on recently, we stored the settings as a JSON-encoded object in a settings field in the User table. On login, the user settings would be pulled out, merged with the site defaults, and stored in cache indefinitely. If the user changed a setting, we would blow away the stored cache and store the new values.
If you don't want or need the complexity of storing everything in the database, you don't have to.
Hi @xuma, here you can find some tips that Philip Brown gives you about that feature:
Storing User Settings in a Relational Database
Creating the Foundation of a User Settings System
Hope it helps you.
Thank you all of you guys here is my final setup;
Schema::create('settings', function(Blueprint $table){
$table->increments('id');
$table->string('name');
$table->string('description');
$table->timestamps();
});
User table;
Schema::create('users', function(Blueprint $table){
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password', 60);
$table->boolean('admin')->default(false);
$table->rememberToken();
$table->timestamps();
});
User settings table;
Schema::create('setting_user', function(Blueprint $table){
$table->increments('id');
$table->integer('setting_id')->unsigned()->index();
$table->foreign('setting_id')->references('id')->on('settings')->onDelete('cascade');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->string('value');
});
User model;
class User extends Model{
public function settings()
{
return $this->belongsToMany('App\Setting')->withPivot('value');
}
}
Setting model (not really needed)
class Setting extends Model {
public function users()
{
return $this->belongsToMany('App\User')->withPivot('value');
}
}
I know this is an older thread, but this inspired my solution and I decided to refresh it in case others land here. I'm currently on Laravel 10.
Schema::create('settings', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('cast')->default('string');
$table->string('description');
$table->timestamps();
});
Schema::create('setting_user', function(Blueprint $table){
$table->id();
$table->unsignedBigInteger('setting_id');
$table->foreign('setting_id')->references('id')->on('settings')->onDelete('cascade');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->string('value');
});
public function settings(): BelongsToMany
{
return $this->belongsToMany(Setting::class)->withPivot('value');
}
public function getSetting($settingName)
{
$setting = $this->settings->where('name', $settingName)->first();
if ($setting && $setting->cast) {
$castType = $setting->cast;
$value = $setting->pivot->value;
return match ($castType) {
'bool', 'boolean' => (bool) $value,
'integer', 'int' => (int) $value,
'array' => explode(',', $value),
// 'object' => json_encode($value),
'string' => (string) $value,
// Add more cases as needed for other cast types
default => $value,
};
}
return null;
}
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class)->withPivot('value');
}
$sampleSetting = new Setting();
$sampleSetting->name = 'subscribe_to_newsletter';
$sampleSetting->description = 'Get our newsletter.';
$sampleSetting->cast = 'boolean';
$sampleSetting->save();
$user = auth()->user();
$setting = Setting::where('name', 'subscribe_to_newsletter')->firstOrFail();
// $user->settings()->attach($setting, ['value' => true]);
// $user->settings()->detach($setting);
$user->settings()->sync([$setting->id => ['value' => true]]);
dd($user->getSetting('subscribe_to_newsletter'));
Hope it helps someone else!
Please or to participate in this conversation.