There is a database structure like this:
users
id
name
user_options
id
user_id
option_name
option_value
There can be a lot of options, so I didn’t make a separate field for each of them.
I would like to make it easier to access an option by its name.
Currently implemented like this:
In the User model:
public function options() : HasMany
{
return $this->hasMany(UserOptions::class);
}
For the test, I write the code directly in web.php in routes:
$user = User::with('options')->first();
$theme = $user
->options
->firstWhere('option_name', '=', 'theme')
->option_value;
There are many options and I would not like to make such a voluminous appeal to each of them.
Please help me to simplify access to options
CodePudding user response:
If you absoltely must access like an object you could add an attribute accessor on your user model like so:
protected function options(): Attribute
{
return Attribute::make(
get: function($_){
if($this->userOptions !== null){ // have the user options not already been set?
$this->setUserOptions() // set them if not
}
return $this->userOptions // return them
}
)
}
private function setUserOptions(): void
{
$this->userOptions = new stdClass()
foreach(UserOptions::where('user_id', $this->id)->get() as $option){
$optionName = $option['option_name']
$optionValue = $option['option_value']
$this->userOptions->$optionName = $optionValue
}
}
Call like
$user->options->theme
But be way of nonexistant options
A much less complex way would be adding a helper function on your user Model though like so:
/**
* @return Collection<UserOption>
*/
public function options(): HasMany
{
return $this->hasMany(UserOption::class, 'user_id', 'id');
}
/**
* @param string $optionName
* @return mixed
*/
public function getOption(string $optionName): mixed
{
/** @var UserOption $option */
foreach($this->options as $option){
if($option->option_name === $optionName){
return $option['option_value'];
}
}
return null;
}
And simply call like $user->getOption('color'); // eg: "red" | null