简体   繁体   中英

Laravel another way of appending to model

I'm building an api Laravel. In my message model I've append the following:

/**
 * @var array
 */
protected $appends = ['subscribed'];


/**
 * @return mixed
 */
public function getSubscribedAttribute()
{
    return $this->isSubscribedBy();
}

IsSubscribedBy(); lives in a trait that looks like this:

/**
 * @return mixed
 */
public function isSubscribedBy()
{
    return $this->subscriptions()
        ->where('user_id', Auth::user()->id)
        ->exists();
}

This is working but doing it like this has the n + 1 problem and I can't load the messages in algolia with php artisan scout:import "App\\Messages\\Message" that obviously throws an error (because no one is signed in but it's looking for someone: Auth::user()->id):

[ErrorException]
Trying to get property of non-object

So are there better ways? I already tried fractal but then I still have the n + 1 problem.

---EDIT---

I'm returning like this:

/**
 * @return mixed
 */
public function index()
{
    return Message::orderBy('created_at', 'DESC')
        ->paginate(10);
}

So for each message it will exec this query:

$this->subscriptions()
        ->where('user_id', Auth::user()->id)
        ->exists();

If a user isn't logged in at all then obviously they can't be subscribed. So you could do something like this:

public function isSubscribedBy()
{
    if(!Auth::check()) {
        return false;
    }
    return $this->subscriptions()
        ->where('user_id', Auth::user()->id)
        ->exists();
}

Or if you need something other than false like null just return that instead.

Ok figured out how to eager load it, first you need to constrain your eager loading to the current user:

return Message::orderBy('created_at', 'DESC')->with(['subscriptions'=> function ($query) {
    $query->where('user_id', '=', Auth::user()->id);
}])->paginate(10);

Then it eager loads only the current users subscriptions for the messages. Now in your attribute getter you need to access the collection that has been eager loaded not eloquent getter. You do this simply by removing the () on subscriptions() and using collection methods instead of eloquent methods (which most of the time look exactly the same). So your function can look like this:

public function isSubscribedBy()
{
    return ($this->subscriptions->count() > 0);
}

Hopefully that works for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM