Laravel JetStream get HasRole of user in resource method - laravel

I am using Laravel Jetstream teams feature and wants to get list of all team members with their role.
following method from JetStream can return role of user
public function teamRole($team)
{
if ($this->ownsTeam($team)) {
return new OwnerRole;
}
if (! $this->belongsToTeam($team)) {
return;
}
return Jetstream::findRole($team->users->where(
'id', $this->id
)->first()->membership->role);
}
When user hits route /teams/{team} I would like to response with all team members name along with their role in team so I have created a TeamResource like following.
class Team extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'user_id' => $this->user_id,
'owner_name' => $this->owner->name,
'owner_email' => $this->owner->email,
'name' => $this->name,
'personal_team' => $this->personal_team,
'users' => TeamMemberResource::collection($this->allUsers()),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
Following is my TeamMemberResource which is User model
class TeamMember extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'role' => //How do I get user's role in this team
'name' => $this->name,
'email' => $this->email,
'active' => $this->active,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
Relationship is User has many Team.
TeamUser table has the column role.
How do I access role of user in given team?
Thank you

The neatest way to do this is to define a separate model for a user within a specific team. Then you don't have to figure out which team you're dealing with. That's probably out of scope for this question, though.
Assuming you want to achieve this using the default models, you need to figure out how to tell the "team member" collection which team it's dealing with.
Start by defining a separate TeamMemberCollection resource. Override the default ResourceCollection constructor, and pass the team as a second argument.
class TeamMemberCollection extends ResourceCollection
{
public $team;
public function __construct($collection, $team)
{
$this->team = $team;
parent::__construct($collection);
}
}
Then update the TeamMember::toArray method to accept a team, and the TeamMemberCollection::toArray method to pass the team.
class TeamMember extends JsonResource
{
public function toArray($request, $team)
{
return [
// Other properties...
'role' => $this->teamRole($team),
];
}
}
class TeamMemberCollection extends ResourceCollection
{
public function toArray($request)
{
return $this->collection
->map
->toArray($request, $this->team)
->all();
}
}
Finally, don't forget to update the Team resource to pass the team to the TeamMemberCollection constructor.
class Team extends JsonResource
{
public function toArray($request)
{
return [
// Other properties...
'users' => new TeamMemberCollection($this->allUsers(), $this),
];
}
}

Related

Scope resource controller based on pivot table in Laravel

I have a User and an Organization model, bound together by a many-to-many relationship in a organization_user pivot table.
The User model contains:
public function organizations()
{
return $this->belongsToMany(Organization::class);
}
And likewise the Organization model contains:
public function users()
{
return $this->belongsToMany(User::class);
}
Organizations are a resource that a user can create, view, update, delete, and so forth. Of course, users should only be able to view, update and delete the organizations they're part of. I manage to scope the organizations to the current user in the OrganizationController index method, but I'm not sure how to do the same for the edit, update and delete methods. Such guards are not necessary for the create and store methods, I believe.
The controller looks like this:
class OrganizationController extends Controller
{
public function index(Request $request)
{
$organizations = $request->user()->organizations()->get();
return view('organizations.index', compact('organizations'));
}
public function create()
{
return view('organizations.create');
}
public function store(Request $request)
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
]);
$request->user()->organizations()->create([
'name' => $request->name,
]);
return redirect()->route('organizations.index');
}
public function edit(Request $request, Organization $organization)
{
// How to make make sure the user is part of the organization?
return view('organizations.edit', [
'organization' => $organization,
]);
}
public function update(Request $request, Organization $organization)
{
// How to make make sure the user is part of the organization?
$request->validate([
'name' => ['required', 'string', 'max:255'],
]);
$organization->update([
'name' => $request->name,
]);
return redirect()->route('organizations.index');
}
}

How can I store forign key a field employee_id without entering it?

I have two tables and the relationship between them is one to many
the model employee is :
class Employee extends Model implements HasMedia
{
use HasFactory;
protected $guarded = [];
protected $casts = [
];
public function familyDetails()
{
return $this->hasMany(FamilyDetails::class,'employee_id');
}
and the model FamilyDetails is:
class FamilyDetails extends Model
{
use HasFactory;
public function employee()
{
return $this->belongsTo(Employee::class,'employee_id');
}
I have an interface asking me to enter information
FamilyDetails table
But within this table there is an employee_id field that joins the two tables together
this is controller:
class FamilyDetailsController extends Controller
{
public function store(StoreFamilyDetailsRequest $request)
{
$familyDetails = FamilyDetails::create($request->validated())->with('employee');
return new FamilyDetailsResource($familyDetails);
}
}
and this is StoreFamilyDetailsRequest :
class StoreFamilyDetailsRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'Name_kanji' => ['required'],
'Relationship' => ['required'],
'Nama_katakana' => ['required'],
'Grade_In_school' => ['required'],
'Date_of_birth*' => ['required|array'],
'Date_of_birth.*day' => ['required'],
'Date_of_birth.*year' => ['required'],
'Date_of_birth.*month' => ['required'],
];
}
public function validated($key = null, $default = null)
{
return [
'Name_kanji' => $this->Name_kanji,
'Nama_katakana' => $this->Nama_katakana,
'Relationship' => $this->Relationship,
'Grade_In_school' => $this->Grade_In_school,
'Date_of_birth' => Carbon::create(
$this->Date_of_birth['year'],
$this->Date_of_birth['month'],
$this->Date_of_birth['day'])->format('Y-m-d'),
];
}
this is FamilyDetailsResource :
class FamilyDetailsResource extends JsonResource
{
public function toArray($request)
{
return [
'Name_kanji' => $this->Name_kanji,
'Relationship' => $this->Relationship,
'Nama_katakana' => $this->Nama_katakana,
'Grade_In_school' => $this->Grade_In_school,
'Date_of_birth' => [
'month' => $this->Date_of_birth->month,
'day' => $this->Date_of_birth->day,
'year' => $this->Date_of_birth->year,
]
];
}
}
When I run the code in postman the following error appears :
Briefly, how can I store the foreign key field when it is not
It asks me to enter it
in the interface???????
Can you explain more about your relationship table?
I think you can erase your code with in controller store if not used
class FamilyDetailsController extends Controller
{
public function store(StoreFamilyDetailsRequest $request)
{
$familyDetails = FamilyDetails::create($request->validated());
return new FamilyDetailsResource($familyDetails);
}
}

How to retrieve data with many to many relationship in Laravel resource

I am using Laravel 7.
I have three table with many to many relationship. The tables are users, task_user and tasks.
The models have the following relationships:
Task.php:
public function users()
{
return $this->belongsToMany('App\User')
->withPivot('user_id', 'task_id')
->withTimestamps();
}
TaskUser.php:
public function task()
{
return $this->belongsTo('App\Task');
}
public function user()
{
return $this->belongsTo('App\User');
}
User.php:
public function tasks()
{
return $this->belongsToMany('App\Task')
->withTimestamps();
}
This is my controller method:
public function get_delayed_tasks() {
$tasks = Task::select('id', 'name', 'description', 'deadline', 'closed_at', 'status_id', 'project_id')
->whereRaw('closed_at > deadline')
->get();
return TaskResource::collection($tasks);
}
This is my resource:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'deadline' => $this->deadline,
'closed_at' => $this->deadline,
'status' => $this->status->name,
'project' => $this->project->name,
'devs' => $this->relationLoaded('users')
? $this->users->pluck('users.name')->unique()->all()
: [], //problem
];
}
Unfortunately in the key dev in the resource I receive always [], even if I should receive an array of names.
How can I retrieve all the users that have worked with the task?
You have to load the relationship to use it within the resource
Controller
public function get_delayed_tasks() {
$tasks = Task::with(['users']) // <-- load relationship
->select('id', 'name', 'description', 'deadline', 'closed_at', 'status_id', 'project_id')
->whereRaw('closed_at > deadline')
->get();
return TaskResource::collection($tasks);
}
Resource
'devs' => $this->whenLoaded(
'users',
$this->users->pluck('name')->unique()->all(),
[]
)
Advanced modification for the Resource, if you decide to create a UserResource to get more data:
'devs' => UserResource::collection($this->whenLoaded('users'))

Laravel API Resource returned Undefined property: stdClass::$book",

I have a pivot table Book_Category which store the relationship between book table and category table.
In my Book model I have this
public function categories()
{
return $this->belongsToMany(Category::class);
}
In my Category Model` I have this
public function books()
{
return $this->belongsToMany(Book::class);
}
I don't think I need a model for Book_Category since its a pivot table.
But now I need to create an API Resource. I am trying to return a Book of a particular Category
So I do this this
public function singlepage(Request $request,$book)
$relatedCategory = BookCatResource::collection(DB::table('book_category')
->where('category_id', $request->category_id)->get());
I am using query builder because I don't have a model
In my resource, I have this
public function toArray($request)
{
return [
'book_id' => new BookResource($this->book),
'category_id' => $this->category_id
];
}
But it returned error
Undefined property: stdClass::$book",
In your scenario, you do not need to use the model for pivot table,
what you can do is that
Route::get('/', function () {
return CategoryResource::collection(Category::where('id', 1)->get());
});
CategoryResource.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class CategoryResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->title,
'books' => BookResource::collection($this->books),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
BookResource.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class BookResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}

How to avoid infinite loop when nesting api resources in Laravel?

I have two models: Company and Representative. Representative belongsTo Company, Company hasMany Representative.
Also I have two corresponding resources.
Company resource:
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'representatives' => RepresentativeResource::collection($this->representatives)
];
}
Representative resource:
public function toArray($request)
{
return [
'id' => $this->id,
'company' => $this->company ? new CompanyResource($this->company) : null
];
}
What I want to accomplish is when I get companies I want to get theirs representatives. When I get representative I want to get information about company.
What happens is infinite loop: their include each other infinitely.
So, how could it be fixed?
Did you try to use whenLoaded? It's documented here and I think it fits your needs.
With your code, you shoud have something like this:
class CompanyResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'representatives' => RepresentativeResource::collection(
$this->whenLoaded('representatives')
)
];
}
}
class RepresentativeResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'company' => new CompanyResource(
$this->whenLoaded('company')
)
];
}
}
In your controller then, you'll have to load the relationship with your model.
new RepresentativeResource(Representative::with('company')->first());

Resources