Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

xuma's avatar
Level 9

Creating user settings eloquent models

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*

  • id
  • name
  • email
  • password

settings Table

  • id
  • name
  • description

user_settings Table ( pivot table )*

  • user_id
  • setting_id
  • setting_value
0 likes
8 replies
bestmomo's avatar

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.

xuma's avatar
Level 9

in my case user can have many settings and it must be flexible to add new setting fields.

bestmomo's avatar

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.

cm's avatar

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.

michaeldyrynda's avatar

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.

1 like
xuma's avatar
Level 9

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');
    }
}
rockBalancer's avatar

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.

Migration:

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');
});

User Model

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;
}

Setting Model

public function users(): BelongsToMany
{
	return $this->belongsToMany(User::class)->withPivot('value');
}

Insert Sample Setting

$sampleSetting = new Setting();
$sampleSetting->name = 'subscribe_to_newsletter';
$sampleSetting->description = 'Get our newsletter.';
$sampleSetting->cast = 'boolean';
$sampleSetting->save();

Usage

$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!

1 like

Please or to participate in this conversation.