简体   繁体   中英

In laravel how to pass extra data to mutators and accessors

What I'm trying to do is to append the comments of each article to the articles object, but the problem is that I need to request different number of comments each time.

and for some reason I need to use mutators for that, because some times I request 50 articles and I don't want to loop through the result and append the comments.

So is it possible to do something like the following and how to pass the extra argument.

This the Model:

    class Article extends Model
    {

        protected $appends = ['user', 'comments', 'media'];

        public function getCommentsAttribute($data, $maxNumberOfComments = 0)
        {
            // I need to set maxNumberOfComments
            return $this->comments()->paginate($maxNumberOfComments);

        }
    }

Here is the controller:

class PostsController extends Controller
{


    public function index()
    {
        //This will automatically append the comments to each article but I
        //have no control over the number of comments
        $posts = Post::user()->paginate(10);
        return $posts;
    }    

}

What I don't want to do is:

class PostsController extends Controller
{


    public function index()
    {

        $articles = Post::user()->all();

        $number = 5;
        User::find(1)->articles()->map(function(Article $article) {
            $article['comments'] = $article->getCommnets($number);
            return $article;
        });

        return Response::json($articles);
    }    

}

Is there a better way to do it? because I use this a lot and it does not seams right.

Judging from the Laravel source code, no – it's not possible to pass an extra argument to this magic accessor method.

The easiest solution is just to add another, extra method in your class that does accept any parameters you wish – and you can use that method instead of magic property.

Eg. simply rename your getCommentsAttribute() to getComments() and fire ->getComments() instead of ->comments in your view, and you are good to go.

It is been a while for this question, but maybe someone will need it too.

Here is my way

{
/**
 * @var string|null
 */
protected ?string $filter = null;

/**
 * @return UserSettings[]|null
 */
public function getSettingsAttribute(): ?array
{
    return services()->tenants()->settings($this)->getAll();
}

/**
 * @return FeatureProperty[]|null
 */
public function getFeaturePropertiesAttribute(): ?array
{
    return services()->tenants()->featureProperty($this)->getListByIds($this->filter);
}

/**
 * @param string|null $filter
 * @return Tenant
 */
public function filter(string $filter = null): Model
{
    $this->filter = $filter;
    return $this;
}

Accessor is using some service to get values. Service accepts parameters, in my case string, that will be compared with featureProperty->name

Magic happens when you return $this in filter method.

Regular way to call accessor would be:

$model->feature_properties 

Extended way:

$model->filter('name')->feature_properties

Since filter argument can be null, we can have accessor like this:

$filter = null
$model->filter($filter)->feature_properties

In case you would like to play with it a little more you can think about overriding models getAttribute or magic __call methods implementing filter in manner which will be similar to laravel scopes

I just set a public property on the model. At the accessing point, I update that property to my desired value. Then, in the attribute method, I read the desired arguments from that property. So, putting all of that together,

// Model.php

public $arg1= true;

public function getAmazingAttribute () {

   if ($this->arg1 === false)
      $this->relation()->where('col', 5);

   else $this->relation()->where('col', 15);
}

// ModelController.php
$instance->arg1 = false;

$instance->append('amazing');

I know its an old question, but there is another option, but maybe not the best:

$articles = Post::user()->all();

$number = 5;

$articles->map(function($a) use($number){ 
    $a->commentsLimit = $number;
    return $a;
});

And then in getCommentsAttribute():

return $this->comments()->paginate($this->commentsLimit);

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