Laravel load pivot data in resource - php

I want to show pivot data into json format
I have 2 relationship many to many mode: SubmitForm and Fisherman.
// submitform model
public function fisherman()
{
return $this->belongsToMany(Fisherman::class, 'submitform_fisherman','submitform_id', 'fisherman_id');
}
// fisherman model
public function submitForm()
{
return $this->belongsToMany(SubmitForm::class,'submitform_fisherman','fisherman_id', 'submitform_id');
}
this is my submitformcontroller to show the data
use App\Http\Resources\SubmitformResource;
use App\SubmitForm;
class SubmitFormController extends Controller
{
public function index()
{
return SubmitformResource::collection(SubmitForm::with('fisherman')->get());
}
....
}
this is my SubmitformResource
class SubmitformResource extends JsonResource
{
public function toArray($request){
return [
"id" => $this->id,
"product_form" => $this->product_form,
"fisherman" => $this->whenPivotLoaded('submitform_fisherman', function(){
return new FishermanResource($this->pivot->fisherman);
})
}
}
when I tried i dont get fisherman data.
Can someone help me?

Related

Eloquent Relationships Laravel connecting multiple tables together

i am attempting to rewrite all my joins into Elequent model relationships.
Here is what i have so far:
class SectionAndUser
{
public function sections()
{
return $this->belongsTo('App\Models\Section');
}
public function users()
{
return $this->belongsTo('App\Models\User');
}
...
class User
{
public function sectionAndUser()
{
return $this->hasMany('App\Models\SectionAndUser');
}
...
class Section
{
public function sectionAndUsers()
{
return $this->hasMany('App\Models\SectionAndUser');
}
...
With the select:
$sections = User::find($userId)->sectionAndUser()->get();
I get the result:
{
"id": 1,
"section_id": 1,
"user_id": 133
}
How do i now attach the 3 model section that carries all the data about section_id 1?
This is the join that i am hoping to achieve:
$id=Auth::id();
$results = DB::table('sections')
->join('section_and_users', function ($join) use ($id) {
$join->on('sections.id', '=', 'section_and_users.section_id')
->where('section_and_users.user_id','=', $id);
})
->get();
The expected result:
{
"id": 1,
"section_id": 1,
"section_name": 'sectionName'
"user_id": 133
}
I think the solution is to create only models Section and User, and add the relationship as BelongsToMany.
class User
{
public function sections()
{
return $this->BelongsToMany('App\Models\Section');
}
...
And
<?
class Section
{
public function users()
{
return $this->BelongsToMany('App\Models\User');
}
...
And of course, you need to create the pivot table. You can consult BelongsToMany documentation.
If you use this way, you can simple get the result with this query:
$section = Section::find(1); // This will return all your Section data
$section_related_users = $section->users; // This will return a collection of Users
You could do it this way
$id=Auth::id();
$results = SectionAndUser::where('user_id', $id)->with('users', 'sections')->get();
then you could map it to get your desired output
$sections = collect($results)->map(function ($section){
return [
'id' => $section->id,
'section_id' => $section->id,
'section_name' => $section->sections->name,
'user_id' => $section->user_id
];
});
You can create a many-to-many realtionship without the SectionAndUser-model.
With the belongsToMany-method, you can pass the name of the pivot table as a second argument. You can view Illuminate\Database\Eloquent\Concerns\HasRelationships#belongsToMany if you want to know what other arguments you can pass.
Section:
class Section extends Model
{
...
public function users()
{
return $this->belongsToMany(User::class, 'section_and_users');
}
...
}
User:
class User extends Model
{
...
public function sections()
{
return $this->belongsToMany(Section::class, 'section_and_users');
}
...
}
Then use it as this:
$user->sections->where(...
// Post Model
public function user()
{
return $this->belongsTo('App\User');
}
public function categories()
{
return $this->belongsToMany('App\Category')->withTimestamps();
}
public function tags()
{
return $this->belongsToMany('App\Tag')->withTimestamps();
}
// Role Model
public function users()
{
return $this->hasMany('App\User');
}
// User Model
public function role()
{
return $this->belongsTo('App\Role');
}
public function posts()
{
return $this->hasMany('App\Post');
}
//Tag Model
public function posts()
{
return $this->belongsToMany('App\Post')->withTimestamps();
}
// Catgory Model
public function posts()
{
return $this->belongsToMany('App\Post')->withTimestamps();
}
// controller
public function index()
{
$posts = Post::latest()->get();
return view('admin.post.index',compact('posts'));
}
// posts tabel to user result get
foreach($posts as $post){
$post->user->name
}

Create nested API

I'm trying to make an api that have lists and inside each list there is anther list inside of it called cards and the cards list is the cards of this list.
I tried to show it in index function and didn't work it was like this:
public function index()
{
// $list = List -> cards();
$list = List::cards();
return response( $list );
}
Card Model:
public function list()
{
return $this->belongsTo( List::class() );
}
Card Model:
public function cards()
{
return $this->hasMany( Card::class() );
}
What i want to output is json data like this:
"lists":[
'name':listname
'cards':[
'card one': card name,
]
]
If you use Laravel framework use Resource for response, in Resource of laravel you can load cards. For example in ListController :
public function index()
{
return ListResource::collection(List::all()->paginate());
}
And in ListResource :
public function toArray($request)
{
'cards' => CardResource::collection('cards');
}
belongsTo or hasMany accepts model name as a first argument. In your case you need to pass your model class name in your relations methods.
public function list()
{
return $this->belongsTo(List::class);
}
and
public function cards()
{
return $this->hasMany(Card::class);
}
So if you want to receive models including relations you can use with method.
return response(List::query()->with('cards'));
You can use resources.
Http\Resources\List:
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class List extends JsonResource
{
public function toArray($request)
{
$cards = [];
foreach ($this->cards as $card) {
$cards[] = $card->name;
}
return [
'name' => $this->name,
'cards' => $cards,
];
}
}
Http\Controllers\ListController:
namespacce App\Http\Controllers;
use App\Http\Resources\List as ListResource;
use App\Components\List;
class ListController extends Controller
{
$lists = List::query()->get();
return ListResource::collection($lists)->response();
}

custom serialization data on laravel

this is my first post. I have a problem with my Laravel application.
I need to modify the serialization of the data for my endpoint to get the data of a specific bike.
The endpoint return this:
{"bike":{"id":32,
"unlock_code":2342,
"rack": {"id":3,
"available_stands":10,
"latitude":"46.754",
"longitude":"8.5732",
"available_bikes":10
},
"bike_state":{"description":"Available"}
}
}
but i want to have this:
{"bike":{"id":32,
"unlock_code":2342,
"rack":{"id":3,
"available_stands":10,
"latitude":"46.754",
"longitude":"8.5732",
"available_bikes":10
},
"bike_state":{"Available"}
}
}
the field name ('description') must be hidden. It's the first time i use laravel and i don't know if it's possible to do this.
This is the model
class BikeState extends Model
{
protected $hidden = ['id'];
public function bikes()
{
return $this->hasMany('App\Bike');
}
}
this is the repository with the method to retrieve the data:
class BikeRepository
{
public function findBikeById($id)
{
return Bike::with('rack','bikeState')->findOrFail($id);
}
}
and this is the controller
class BikeController extends Controller
{
private $bikeRepository;
public function __construct(BikeRepository $bikeRepository)
{
$this->bikeRepository = $bikeRepository;
}
public function getBike($id)
{
return response() ->json(['bike' => $this -> bikeRepository ->
findBikeByid($id)], 200);
}
}
Thank you
Create an accessor on your Bike model like this:
public function getBikeStateAttribute($value)
{
return json_encode($this->attributes['description']);
}
Then add accessor to Bike model's array like this:
protected $appends = ['bike_state'];

Conditional responses in Laravel Eloquent API resources

Laravel 5.7. I have a model Audio, with the fields id and title. An Audio can have many AudioVersions, where AudioVersion has id, audio_id (referring to Audio) and url.
Now, I have two parent models, Foo and Bar, which can have many Audio models.
Audio:
class Audio extends Model
{
public function versions()
{
return $this->hasMany('App\AudioVersion', 'audio_id');
}
}
AudioVersion:
class AudioVersion extends Model
{
public function audio()
{
return $this->belongsTo('App\AudioContent');
}
}
Foo:
class Foo extends Model
{
public function audioContents()
{
return $this->morphToMany('App\Audio', 'audio_contentable', 'audio_contentable');
}
}
I have an Eloquent API resource, FooResource, which returns its Audio objects:
FooResource:
class FooResource extends JsonResource
{
public function toArray($request)
{
return [
'audio' => AudioResource::collection($this->audioContents),
];
}
}
AudioResource:
class AudioResource extends JsonResource
{
public function toArray($request)
{
return [
'urls' => $this->versions,
];
}
}
My problem is that in the audio key of my FooResource I only want to return Audios which have AudioVersions related to them. I.e. if I have an Audio with no AudioVersions, I do not want that Audio included in the Foo's audio key. I can't find a way to do this deep conditional logic in Eloquent / Resources.
In the FooResource class, you could filter() the collection before passing it to the collection method.
class FooResource extends JsonResource
{
public function toArray($request)
{
$audioContents = $this->audioContents()->filter(function($audio, $key) {
return $audio->versions->count();
}
return [
'audio' => AudioResource::collection($audioContents),
];
}
}
You need to do something like this. This is the example, you only need to add join inside with so that only those audios will be fetched which have audio versions.
$audioContents = AudioContents::with([
'audio' => function ($query) use ($SpecificID) {
return $query->join("audio_versions")
->on("audio_versions.audio_id", "=", "audios.id");
}
])->get();
Try this and let me know if you are facing any issue.
In the end I added a scope to Audio:
public function scopeHasVersions($query)
{
return $query->whereHas('versions');
}
Then in FooResource:
return [
'audio' => AudioResource::collection($this->audioContents()->hasVersions()->get()),
];

Laravel Polymorphic Relations returns NULL

I've read many posts about this issue but none of them works for me. I have a 'ISA' relationship in my database. A person can be either a Patient or a Nurse:
class Person extends Model
{
protected $table = 'persons';
public function commentable()
{
return $this->morphTo();
}
}
class Patient extends Model
{
public function persons()
{
return $this->morphMany('App\Person', 'commentable');
}
}
class Nurse extends Model
{
public function persons()
{
return $this->morphMany('App\Person', 'commentable');
}
}
This is my tables and the data inside them:
And this is my Route:
Route::get('person', function () {
$person = Person::find(1)->commentable();
return json_decode(json_encode($person), true);
});
I get an empty array!
You have to access the relationship as a property:
$person = Person::find(1)->commentable;

Categories