5

I am trying to check in the constructor of a model if the currently authenticated user is allowed to access the given model, but I am finding that $this from the constructor's context is empty. Where are the attributes assigned to a model in Laravel and how should I go about calling a method once all of the attributes have been loaded?

public function __construct(array $attributes = [])
{
    parent::__construct($attributes);
    var_dump($this); // empty model
    $this->checkAccessible();

}

Cheers in advance

Brad Reed
  • 443
  • 7
  • 16
  • You can use this http://laravel.io/bin/7wJ6D . But the question is - why do you want to do that in a model? – Jarek Tkaczyk May 08 '15 at 21:42
  • @JarekTkaczyk Thanks, I ended up doing something similar. The reason I want to do this in a model is so that I can just do Model::find($id); in the controller and the base model class will worry about whether or not the currently authenticated user is allowed to access the resource. – Brad Reed May 10 '15 at 14:20

3 Answers3

3

As stated in the other answers & comments, there are better ways to achieve the aims of the question (at least in modern Laravel). I would refer in this case to the Authorization chapter of the documentation that goes through both gates and policies.

However, to answer the specific question of how to call a method once a models attributes have been loaded - you can listen for the Eloquent retrieved event. The simplest way to do this within a class is using a closure within the class booted() method.

protected static function booted()
{
    static::retrieved(function ($model) {
        $model->yourMethod() //called once all attributes are loaded
    });
}

You can also listen for these events in the normal way, using listeners. See the documentation for Eloquent events.

Rory
  • 2,175
  • 1
  • 27
  • 37
0

you can use controller filter to check whether user logged in or not and than you call any model function.

public function __construct(array $attributes = []){     
  $this->beforeFilter('auth', array('except' => 'login')); //login route

   if(Auth::user()){
        $user_id = Auth::user()->user_id;
        $model = new Model($attributes);
        //$model = User::find($user_id);
   }
 }

Binding Attributes to Model from constructor

Model.php

public function __construct(array $attributes = array())
{
    $this->setRawAttributes($attributes, true);
    parent::__construct($attributes);
}
kamlesh.bar
  • 1,774
  • 19
  • 38
  • The user will already be authenticated. The checkAccessible method checks the "created_by" attribute on the model against the Auth::user()->id. If they are not equal, it throws an exception. – Brad Reed May 08 '15 at 06:58
0

As it was mentioned by Rory, the retrieved event is responsible for that. Also, it could be formed in a much cleaner and OOP way with Event/Listener approach, especially if you need to write a lot of code or have few handlers.

As it described here, you can just create an event for the Model like

    protected $dispatchesEvents = [
        'retrieved' => UserLoaded::class,
    ];

You need to create this class, eloquent event accepts the model by default:

class UserLoaded
{
    protected User $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }
}

Then here is described how to declare listener for this event. It should be somewhere in the EventListenerProvider like this:

    protected $listen = [
        UserLoaded::class => [
            UserLoadedListener::class
        ],
    ];

The listener should just implement method handle() (check article) like:

    public function handle(UserLoaded $event)
    {
        // your code
    }

Another possibility is to register model Observer, as it´s described here

Akim Kelar
  • 635
  • 9
  • 16