0

I have two related Eloquent table models:

# app/Order.php

protected $fillable = [
  'id',  'status', 'client_email', 'partner_id',
];

public function partner()
{
    return $this->belongsTo('App\Partner');
}
# app/Partner.php

protected $fillable = ['id', 'email', 'name'];

public function order()
{
    return $this->hasOne('App\Order');
}

Then if I try add $partner to the array in my Order resource , I get a server error:

# app/Http/Resources/Order.php

public function toArray($request)
{
   // $partner = Order::find(1)->partner;

    return parent::toArray($request);

    return [
      'id' => $this->id,
      'status' => $this->status,
      'client_email' => $this->client_email,
      'partner_id' => $this->partner->id,
      'partner_name' => $this->partner->name,
     ];
}

created additional, but I don't know if I need it or not app/Http/Resources/Partner.php

<?php

namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;

class Partner extends JsonResource
{
    public function toArray($request)
    {
        return parent::toArray($request);

        return [
          'id' => $this->id,
          'name' => $this->name,
       ];
    }
}

How do I return 'partner_name' to OrderController for later use in Vue?

# OrderController.php

use App\Http\Resources\Order as OrderResource;

class OrderController extends Controller
{

    public function index()
    {
        $orders = Order::with('partner')->get();

        return OrderResource::collection($orders);
    }
}

Table partners columns:

id, email, name

Table orders columns:

id, status, client_email, partner_id

Is it correct to pass 'partner_name' to the Resources/Order array.php or does it need to be done in the controller?

Please show me how to do this correctly

Kenny Horna
  • 13,485
  • 4
  • 44
  • 71

2 Answers2

1

It seems that your relationships are a little bit off.

From your $fillable values in the Order model, I can see the partner_id, so -correct me if I'm wrong but- that is the foreign key.. making this model the child one.

Try updating your relations like so:

# Order.php

public function partner()
{
    return $this->belongsTo('App\Partner');
}   //            ^^^^^^^^^

And:

# Partner.php

public function order()
{
    return $this->hasOne('App\Order');
}   //            ^^^^^^^

So, now you could make your relationship work like so in your Order resource:

<?php

namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;

class Order extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id'           => $this->id,
            'status'       => $this->status,
            'client_email' => $this->client_email,
            'partner_id'   => $this->partner_id,
            'partner_name' => $this->partner->name,   // <---
        ];

    }
}

As a sidenote, given the fact that you want to use this Resource to return several models, when the resource will try to access the relationship value it will make an additional query.. the famous N+1 problem. To avoid it, just eager load the relationship in your controller:

use App\Http\Resources\Order as OrderResource;

public function index()
{
    $orders = Order::with('partner')->get();
    //               ^^^^^^^^^^^^^^^^^^^^^^^
    return OrderResource::collection($orders);
}
Kenny Horna
  • 13,485
  • 4
  • 44
  • 71
  • 1
    good catch on the relationship. `partner_id` is on the `Order` model, so naturally it `belongsTo`. (and apparently I'm not allowed to say "+1") – Erich Feb 12 '20 at 16:52
  • @Kenny all your edits don't return an error, but neither does `partner_name`. other data is displayed –  Feb 12 '20 at 18:01
  • @algebra could you update your post with your current code and also your tables structure? There's something missing there. This should work as expected. – Kenny Horna Feb 12 '20 at 21:39
  • @Kenny I update my post, as you requested. please take a look –  Feb 13 '20 at 11:54
  • @algebra I've fixed the format of your post. Now, as tt stands, I can see two return statements in your `OrderResource`. The first one is returning the `$order` just casted as array (so, the `partner_name` won't be returned). Remove the `return parent::toArray($request);` and check again if now is returning the expected attributes. – Kenny Horna Feb 13 '20 at 14:41
  • @algebra also, I've updated my answer including the full code of the `Order` resource. – Kenny Horna Feb 13 '20 at 14:45
  • @Kenny Thank you! –  Feb 13 '20 at 21:32
0

Access partner attributes using the relationship from your model in the resource:

return [
    'id' => $this->id,
    'status' => $this->status,
    'client_email' => $this->client_email,
    'partner_id' => $this->partner->id,       // <-- here
    'partner_name' => $this->partner->name,   // <-- here
];

EDIT:

In your controller, pass in exactly the data you want to use/transform. In your case, you're passing in a collection of User. You also need to pass in any relationships you are relying on.

return App\OrderResource::collection(Order::with('partner')->get());
Erich
  • 2,408
  • 18
  • 40
  • if I uncomment "$partner = Order::find(1)->partner; " - error. If I only change two lines to yours, nothing changes –  Feb 12 '20 at 16:42
  • I edited the response. Seems you're not passing in the related model when you call the `Resource`. – Erich Feb 12 '20 at 16:49