Laravel Eloquent 5.1 高效更新相关模型
Laravel Eloquent 5.1 update related model efficiently
我正在寻找一个干净的解决方案来查询和修改我的 Eloquent 模型的动态属性,存储在另一个 table.
我的主力模特是User
。一个 User
可能有多个 UserVariable
。通过 UserRepository
加载模型时,我可能会或可能不会预先加载变量。
我想实现的是UserVariable
可以在内存中修改,并且只有当User
被保存时自动保存。
这是我的解决方案(删除了不相关的部分),它有效,但既不优雅,也不可扩展:
/**
* @property boolean $isCommentingEnabled
*/
class User extends \Illuminate\Database\Eloquent\Model
{
public function variables()
{
return $this->hasMany('UserVariable', 'var_userid', 'user_id');
}
public function getIsCommentingEnabledAttribute()
{
foreach ($this->variables as $variable) {
if ($variable->name == UserVariable::IS_COMMENTING_ENABLED) {
return (boolean) $variable->value;
}
}
return false;
}
public function setIsCommentingEnabledAttribute($enabled)
{
foreach ($this->variables as $variable) {
if ($variable->name == UserVariable::IS_COMMENTING_ENABLED) {
$variable->value = $enabled ? 1 : 0;
return;
}
}
$this->variables()->add(new UserVariable([
'name' => UserVariable::IS_COMMENTING_ENABLED,
'value' => $enabled ? 1 : 0,
]));
}
}
/**
* @property-read int $id Unique ID of the record.
* @property string $name Must be one of the constants in this class.
* @property int $userId
* @property string $value
*/
class UserVariable extends EloquentModel {}
class UserRepository
{
public function findById($id)
{
return User::with('variables')->find($id);
}
public function saveUser(User $user)
{
return $user->push();
}
}
此解决方案显然无法扩展。如果用户有 5 个以上的变量,即使我提取了循环,代码也会很丰富。
我怀疑 Laravel 中一定有一个简短而干净的解决方案来按名称弹出 User
的 UserVariable
,或者如果没有则获取一个新的存在,修改它的值并把它放回模型中。当调用 User::push()
时,它会自动保存。完成。
我正在寻找类似
的东西
$user->variables()->where('name', UserVariable::IS_COMMENTING_ENABLED)->first()->value
= $enabled ? 1 : 0;
但是上面不能正常工作,因为它使用的是数据库,而不是模型。感谢任何帮助。
注意:我正在处理大型遗留代码库,因此目前无法更改数据库结构。
不幸的是,没有 built-in 方法可以做到这一点。幸运的是,实施起来还不错。
我们有我们的模型及其 ->variables
关系。
class User extends \Illuminate\Database\Eloquent\Model {
public function variables() {
return $this->hasMany('UserVariable', 'var_userid', 'user_id');
}
然后我们需要构建一个方法来告诉我们是否已经加载了所述关系,如果还没有加载它们。
protected function hasLoadedVariables() {
$relations = $this->getRelations();
return array_key_exists('variables', $relations);
}
protected function loadVariablesIfNotLoaded() {
if(!$this->hasLoadedVariables()) {
$this->load('variables');
}
}
这些方法允许我们为 UserVariable
构建通用 getter 和 setter。
getter 确保加载 variables
关系,然后 returns 具有匹配键的第一个值。
protected function getVariable($key) {
$this->loadVariablesIfNotLoaded();
foreach($this->variables as $variable) {
if($variable->key === $key) {
return $variable->value;
}
}
return null;
}
setter 有点复杂,因为我们想更新现有的 UserVariable
模型(如果存在),如果不存在则创建一个,并且在任何一种情况下都将更改保存在->variables
关系但不是数据库。 ($this->variables->push($variable)
保存到关系但不保存到数据库)。
protected function setVariable($key, $value) {
$this->loadVariablesIfNotLoaded();
foreach($this->variables as $k => $variable) {
if($variable->key === $key) {
$variable->value = $value;
return;
}
}
// We didn't find an existing UserVariable so we create one.
$variable = new UserVariable;
$variable->user_id = $this->id;
$variable->key = $key;
$variable->value = $value;
$this->variables->push($variable);
}
Laravel的->push()
方法默认不会将不存在的记录保存到数据库中,但我们可以重写它。
public function push(array $options = []) {
if($this->hasLoadedVariables()) {
foreach($this->variables as $variable) {
if(!$variable->exists) {
$this->variables()->save($variable);
} else if($variable->isDirty()) {
$variable->save();
}
}
}
parent::push();
}
最后,所有这些都准备就绪后,我们可以为单个属性添加特定的 getter 和 setter。
protected function setIsCommentingEnabledAttribute($enabled) {
$this->setVariable(UserVariable::IS_COMMENTING_ENABLED, $enabled);
}
protected function getIsCommentingEnabledAttribute($enabled) {
$this->getVariable(UserVariable::IS_COMMENTING_ENABLED);
}
}
要使用它,只需按照通常的方式编写代码即可。
$user = User::find(123);
$user->is_commenting_enabled; // Calls the getter, no DB calls
$user->is_commenting_enabled = 1; // Calls the setter, no DB calls
$user->push(); // Saves the user and any variables which have been added or changed.
我正在寻找一个干净的解决方案来查询和修改我的 Eloquent 模型的动态属性,存储在另一个 table.
我的主力模特是User
。一个 User
可能有多个 UserVariable
。通过 UserRepository
加载模型时,我可能会或可能不会预先加载变量。
我想实现的是UserVariable
可以在内存中修改,并且只有当User
被保存时自动保存。
这是我的解决方案(删除了不相关的部分),它有效,但既不优雅,也不可扩展:
/**
* @property boolean $isCommentingEnabled
*/
class User extends \Illuminate\Database\Eloquent\Model
{
public function variables()
{
return $this->hasMany('UserVariable', 'var_userid', 'user_id');
}
public function getIsCommentingEnabledAttribute()
{
foreach ($this->variables as $variable) {
if ($variable->name == UserVariable::IS_COMMENTING_ENABLED) {
return (boolean) $variable->value;
}
}
return false;
}
public function setIsCommentingEnabledAttribute($enabled)
{
foreach ($this->variables as $variable) {
if ($variable->name == UserVariable::IS_COMMENTING_ENABLED) {
$variable->value = $enabled ? 1 : 0;
return;
}
}
$this->variables()->add(new UserVariable([
'name' => UserVariable::IS_COMMENTING_ENABLED,
'value' => $enabled ? 1 : 0,
]));
}
}
/**
* @property-read int $id Unique ID of the record.
* @property string $name Must be one of the constants in this class.
* @property int $userId
* @property string $value
*/
class UserVariable extends EloquentModel {}
class UserRepository
{
public function findById($id)
{
return User::with('variables')->find($id);
}
public function saveUser(User $user)
{
return $user->push();
}
}
此解决方案显然无法扩展。如果用户有 5 个以上的变量,即使我提取了循环,代码也会很丰富。
我怀疑 Laravel 中一定有一个简短而干净的解决方案来按名称弹出 User
的 UserVariable
,或者如果没有则获取一个新的存在,修改它的值并把它放回模型中。当调用 User::push()
时,它会自动保存。完成。
我正在寻找类似
的东西$user->variables()->where('name', UserVariable::IS_COMMENTING_ENABLED)->first()->value
= $enabled ? 1 : 0;
但是上面不能正常工作,因为它使用的是数据库,而不是模型。感谢任何帮助。
注意:我正在处理大型遗留代码库,因此目前无法更改数据库结构。
不幸的是,没有 built-in 方法可以做到这一点。幸运的是,实施起来还不错。
我们有我们的模型及其 ->variables
关系。
class User extends \Illuminate\Database\Eloquent\Model {
public function variables() {
return $this->hasMany('UserVariable', 'var_userid', 'user_id');
}
然后我们需要构建一个方法来告诉我们是否已经加载了所述关系,如果还没有加载它们。
protected function hasLoadedVariables() {
$relations = $this->getRelations();
return array_key_exists('variables', $relations);
}
protected function loadVariablesIfNotLoaded() {
if(!$this->hasLoadedVariables()) {
$this->load('variables');
}
}
这些方法允许我们为 UserVariable
构建通用 getter 和 setter。
getter 确保加载 variables
关系,然后 returns 具有匹配键的第一个值。
protected function getVariable($key) {
$this->loadVariablesIfNotLoaded();
foreach($this->variables as $variable) {
if($variable->key === $key) {
return $variable->value;
}
}
return null;
}
setter 有点复杂,因为我们想更新现有的 UserVariable
模型(如果存在),如果不存在则创建一个,并且在任何一种情况下都将更改保存在->variables
关系但不是数据库。 ($this->variables->push($variable)
保存到关系但不保存到数据库)。
protected function setVariable($key, $value) {
$this->loadVariablesIfNotLoaded();
foreach($this->variables as $k => $variable) {
if($variable->key === $key) {
$variable->value = $value;
return;
}
}
// We didn't find an existing UserVariable so we create one.
$variable = new UserVariable;
$variable->user_id = $this->id;
$variable->key = $key;
$variable->value = $value;
$this->variables->push($variable);
}
Laravel的->push()
方法默认不会将不存在的记录保存到数据库中,但我们可以重写它。
public function push(array $options = []) {
if($this->hasLoadedVariables()) {
foreach($this->variables as $variable) {
if(!$variable->exists) {
$this->variables()->save($variable);
} else if($variable->isDirty()) {
$variable->save();
}
}
}
parent::push();
}
最后,所有这些都准备就绪后,我们可以为单个属性添加特定的 getter 和 setter。
protected function setIsCommentingEnabledAttribute($enabled) {
$this->setVariable(UserVariable::IS_COMMENTING_ENABLED, $enabled);
}
protected function getIsCommentingEnabledAttribute($enabled) {
$this->getVariable(UserVariable::IS_COMMENTING_ENABLED);
}
}
要使用它,只需按照通常的方式编写代码即可。
$user = User::find(123);
$user->is_commenting_enabled; // Calls the getter, no DB calls
$user->is_commenting_enabled = 1; // Calls the setter, no DB calls
$user->push(); // Saves the user and any variables which have been added or changed.