Laravel / Eloquent Model Attribute Visibility

Previously, the ORM I used to map database columns directly to class properties, which allowed you to determine the visibility of a particular object, as usual, to restrict access to certain properties, for example. passwords.

With Eloquent, I cannot reproduce this because the columns of the database are mapped to an array of internal attributes that do not contain visibility.

My desire is to restrict the scope of access to the user password to only an object, that is, a private one.

Setting a class property with visibility does not work because this property goes beyond the attributes of the Eloquent model and therefore the property does not appear in the column.

Bright $ hidden and $ protected properties do not work, since they deal with mass output (toArray, toJSON) and mass assignment, rather than direct assignment.

I tried using accessors / mutators (getters / seters) to achieve this with mixed results.

Specifying visibility on an accessory does not work, because the access method called (for example, getPasswordAttribute) is called from the Eloquent \ Model-> getAttribute method, and since such public / protected will always work, and private will always fail, regardless of where the attribute is which he addressed.

However, that works to stop an Eloquent accessory that returns an attribute completely, so any request to $ user-> password or $ user-> getAttribute ('password') fails, and then has a separate method with the visibility defined in order to return an attribute directly from an Eloquent attribute array only in a valid area, 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'); } 

The same approach also works for mutators (setters) for those who want to see the visibility of the setter method.

Is this the right one, or is there a better "Laravel-Approved" way to handle this? :)

+6
source share
1 answer

I donโ€™t know about the โ€œapprovedโ€ way of doing this as such, but can you always override the Eloquent __get() magic method to check for private fields?

The debug_backtrace() check is a bit hacked; I could not get the work to work as expected, since the getPassword() method (or any method in this class that calls $this->password ) still used __get . This simply verifies that the class calling __get is the class itself and not another.

It should not be too inefficient, as the in_array check will fail for non-private properties before it performs backtracking. This is probably the best way to do this!

 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; } 
+2
source

Source: https://habr.com/ru/post/978785/


All Articles