Laravel / Eloquent模型属性可见性

时间:2014-11-27 11:53:11

标签: php laravel eloquent visibility accessor

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

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

我希望将对用户密码的访问范围限制为仅对象即私有。

设置具有可见性的类属性不起作用,因为此属性超出了Eloquent模型属性的范围,因此该属性未映射到列。

Eloquent $ hidden和$ guarded属性不起作用,因为它们处理大量输出(toArray,toJSON)和质量赋值而不是直接赋值。

我试图使用accessors / mutators(getters / setters)来实现这一目标,结果不一。

指定访问者的可见性不起作用,因为调用的访问器方法(例如getPasswordAttribute)是从Eloquent \ Model-> getAttribute方法调用的,因此public / protected将始终有效,并且private将始终失败,无论在何处它从中访问的属性。

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

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

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

这看起来是否正确或是否有更好的“Laravel-Approved”处理方式? :)

1 个答案:

答案 0 :(得分:3)

我不知道这样做的“批准”方式,但你总是可以覆盖Eloquent的__get()魔术方法来检查私有字段吗?

debug_backtrace()检查有点hacky;我实际上无法按预期工作,因为getPassword()方法(或该类调用$this->password中的任何方法)仍在使用__get。这只是检查调用__get的类是类本身,而不是另一个。

它不应该太低效,因为in_array检查在非私有属性无论如何都要进行回溯之前都会失败。不过,可能有更好的方法!

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