Home > other >  Laravel - How to use eloquent ORM to populate a foreign key column when getting all results from a t
Laravel - How to use eloquent ORM to populate a foreign key column when getting all results from a t

Time:10-01

I have setup my model as following:

class Items extends Model {
    use HasFactory;
    protected $table = 'item';
    protected $primaryKey = 'id';
    protected $connection = 'mysql';
    public $timestamps = false;
    protected $fillable = ['user_id', 'title', 'desc', 'start_datetime', 'due_datetime', 'priority', 'status'];
    public function getManager() {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function getAssignees() {
        return $this->belongsToMany(User::class);
    }
}

I am getting all items using the controller method below, what I want to do is to populate the user_id field in each of the items using getManager() method I declared in my Item model. I know how to do this when getting only one item, but how to populate every record when getting all of them?

public function getall() {
        try {
            $items = Item::get();
            return response()->json(['items' => $items], 200);
        } catch (Throwable $err) {
            return response()->json($err, 400);
        }
    }

I have tried this but no luck:

 public function getall() {
        try {
            $items = Item::get();
            $items = array_map(function ($el) {
                return $el->manager = $el->getManager()->get();
            }, $items);

            return response()->json(['items' => $items], 200);
        } catch (Throwable $err) {
            return response()->json($err, 400);
        }
    }

CodePudding user response:

    public function getall() {
            try {
                $items = Item::get()
                          ->transform(function($el){
                                $el->manager = $el->getManager()->get();
                            );
                return response()->json(['items' => $items], 200);
            } catch (Throwable $err) {
                return response()->json($err, 400);
            }
        }

Try the transform method on your results and it would work. https://laravel.com/docs/8.x/collections#method-transform

the transform function would basically just iterate over the results and do whatever it is told to like a for loop but for collections.

Also, to make your query efficient avoid the use of loading the relation in the transform function and and use with function of laravel to make it efficient

CodePudding user response:

There are a few things here that I have some concerns about. Your code may work, but you are also doing more than you need to and not using Laravel how it was meant to be used.

Model Name

Your model name is Items, but it should be singular, Item. This helps Laravel automate things so you have less work to do.

https://laravel.com/docs/8.x/eloquent#eloquent-model-conventions

class Item extends Model {

Database Settings

You've set the $table, $primaryKey, and $connection attributes, but these should be automatic. You can probably remove them.

protected $table = 'items'; // assuming your model name is Item, this would automatically be 'items'
protected $primaryKey = 'id'; // default is already 'id'
protected $connection = 'mysql'; // default is your main db, probably already 'mysql', unless if you have multiple db connections

Timestamps

I'm not sure why you'd want to turn timestamps off. You definitely can but I always find it helpful to know when something was created or last updated. Since Laravel handles the timestamps for you, I'd suggest leaving it on, but it's up to you.

https://laravel.com/docs/8.x/eloquent#timestamps

public $timestamps = false;

Manager Relationship

Your manager relationship is getManager but should just be manager. It will still work, but isn't how Laravel was meant to work. I would suggest changing it to manager(), and not specifying the column name. This would make the column name automatically manager_id, so you'd have to update that. Or you can keep the column name 'user_id'.

https://laravel.com/docs/8.x/eloquent-relationships#one-to-many-inverse

 public function manager() {
        return $this->belongsTo(User::class);
 }

Assignees Relationship

Same as with the Manager relationship, you should change getAssignees() to assignees(). I'm assuming you already have a database migration set up for your 'item_user' table that Laravel will look for. If not, check the Laravel docs on how to set it up.

https://laravel.com/docs/8.x/eloquent-relationships#many-to-many

public function assignees() {
    return $this->belongsToMany(User::class);
}

Retrieving Items

Finally, with the above changes, getting all Items should be easy. To load the relationships, use the $with method. This is called Eager Loading. Check the docs for more info.

https://laravel.com/docs/8.x/eloquent-relationships#eager-loading

$items = Item::with('manager','assignees')->get();

Returning Response Codes

You were returning your responses incorrectly. You do not need to set the response code 200, as this is the default. If you are going to set it to something else, put the code in the response() method, instead of the json() method.

https://laravel.com/docs/8.x/responses

return response()->json(['items' => $items]);


return response($err,400);

Now putting it all together, your Item model should look something like this:

class Item extends Model {
    use HasFactory;

    protected $fillable = ['manager_id', 'title', 'desc', 'start_datetime', 'due_datetime', 'priority', 'status'];

    public function manager() {
        return $this->belongsTo(User::class);
    }

    public function assignees() {
        return $this->belongsToMany(User::class);
    }
}
  • Related