Laravel /雄辩模型属性可见性 [英] Laravel / Eloquent Model Attribute Visibility

查看:188
本文介绍了Laravel /雄辩模型属性可见性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以前,我使用的ORM已经将数据库列直接映射到类属性,这样可以让您具体的属性可见性,就像您通常会限制对某些属性的访问一样。密码。



使用Eloquent我似乎无法复制这一点,因为数据库列映射到不包含可见性的内部属性数组。



我的愿望是将访问用户密码的范围限制为只有对象,即私有的。



设置具有可见性的类属性不会t工作,因为这个属性超出了卓越模型属性的范围,因此该属性未映射到该列。



雄辩$隐藏和$ guarded属性不这些处理大量输出(toArray,toJSON)和批量分配而不是直接分配。



我尝试使用访问器/变量(getter / setter)



指定访问器的可见性不起作用,因为调用的访问器方法(例如getPasswordAttribute)从Eloquent\Model- > getAttribute方法,因此公共/受保护将始终工作,私有将永远失败,无论访问的属性在哪里。



然而,工作是停止强大的访问器完全返回属性对$ user-> password或$ user-> getAttribute('password')的任何请求失败,然后使用一个单独的方法定义可见性,以便直接从Eloquent属性数组返回属性,仅在允许的范围内,例如

  / ** 
*仅为私有范围返回密码字符串
* @return string
* /

private function getPassword()
{
return $ this-> attributes ['password'];
}

/ **
*不要使用访问器返回密码
* @param string $ password密码
* @return void
* @throws异常
* /

public function getPasswordAttribute($ password)
{
throw new Exception('Password access denied');
}

同样的方法也适用于需要setter方法可见性的任何人的mutator(setter) 。



这样做是否正确,还是有更好的Laravel-Approved处理方式? :)

解决方案

我不知道这样做的批准方式,但是您可以随时覆盖Eloquent的 __ get() magic方法来检查私人字段?



debug_backtrace() 检查有点恶作剧;我实际上不能像这样预期的那样工作,因为 getPassword()方法(或者基本上该类中的任何方法调用 $ this- > password )仍在使用 __ get 。这只是检查调用 __ get 的类是类本身,而不是另一个。



它不应该太低效,因为在执行回溯之前,非私有属性的in_array检查将失败。尽管如此,可能还有更好的方法!

  private $ private = array(
'password'
);

public function __get($ key)
{
//检查调用__get的类是这个类,并且该键不是'private'
if (in_array($ key,$ this-> private)&& debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,2)[1] ['class']!= get_class()){
throw new \Exception );
}

//其他任何东西都可以正常返回
return parent :: __ get($ key);
}

public function getPassword()
{
//在其他地方调用此方法可以运行
return $ this-> password;
}


Previously ORM's i've used have mapped database columns directly to class properties which allowed you to specific property visibility, just as you normally would to restrict access to certain properties e.g. passwords.

With Eloquent i can't seem to replicate this because database columns are mapped to the internal attributes array which contain no visibility.

My desire is to restrict the scope of access to a user password to only the object i.e. private.

Setting a class property with visibility doesn't work because this property is then outside the scope of the Eloquent model attributes and thus the property is not mapped to the column.

Eloquent $hidden and $guarded properties do not work as these deal with mass output (toArray, toJSON) and mass assignment rather than direct assignment.

I have attempted to use the accessors/mutators (getters/setters) in order to achieve this with mixed results.

Specifying the visibility on the accessor doesn't work because the accessor method called (e.g. getPasswordAttribute) is called from Eloquent\Model->getAttribute method and as such public/protected will always work and private will always fail regardless of where the attribute it accessed from.

What does work however is to stop the Eloquent accessor returning the attribute altogether so any request to $user->password or $user->getAttribute ('password') fails, and then having a separate method with visibility defined in order to return the attribute directly from the Eloquent attributes array only in the scope allowed e.g.

/**
 * Return password string only for private scope
 * @return string
 */

private function getPassword ()
{
    return $this->attributes['password'];
}

/**
 * Don't return password with accessor
 * @param string $password Password
 * @return void
 * @throws Exception
 */

public function getPasswordAttribute ($password)
{
    throw new Exception ('Password access denied');
}

This same approach also works for mutators (setters) for anyone wanting setter method visibility.

Does this seem correct or is there a better "Laravel-Approved" way of dealing with this? :)

解决方案

I'm not aware of an 'approved' way of doing this, as such, but you could always override Eloquent's __get() magic method to check for private fields?

The debug_backtrace() check is a bit hacky; I couldn't actually get this to work as expected without, as the getPassword() method (or basically any method in that class calling $this->password) was still using __get. This just checks that the class calling __get is the class itself, rather than another.

It shouldn't be too inefficient as the in_array check would fail for non-private properties before it does the backtrace anyway. There's probably a better way of doing it, though!

private $private = array(
    'password'
);

public function __get($key)
{
    // check that the class calling __get is this class, and the key isn't 'private'
    if (in_array($key, $this->private) && debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['class'] != get_class()) {
        throw new \Exception('Private');
    }

    // anything else can return as normal
    return parent::__get($key);
}

public function getPassword()
{
    // calling this method elsewhere should work
    return $this->password;
}

这篇关于Laravel /雄辩模型属性可见性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆