call relation in accessor function - php

I want to call relation into accessors function with less query
ticket has many messages
ticket model has accessors function
I want into accessors function if ticket->messages()->exist() == TRUE returns messages body, or ** if ticket->messages()->exist() == TRUE** returns tickets body
this line code ($ticket->last_body) in view make one Query for each row and i want to decrease my query
Ticket model:
class Ticket extends Model
{
public function messages()
{
return $this->hasMany(TicketMessage::class, 'ticket_id');
}
public function getLastBodyAttribute()
{
if($this->messages()->exists()){
return $this->messages()->orderByDesc('created_at')->first()->body;
} else {
return $this->body;
}
}
}
Ticket massage belongsto tickets
TicketMessage model :
class TicketMessage extends Model
{
public function ticket()
{
return $this->belongsTo(Ticket::class,'ticket_id');
}
}
I get tickets with own relationships and passed to view
TicketController:
class TicketController extends Controller
{
public function index(Request $request)
{
$tickets = Ticket::with('messages')
->where('status', 'open')
->get();
return view('ticket::supporter.supporter', compact('tickets'));
}
}
this line code $ticket->last_body make one Query for each row and i want to decrease my query
**supporter.blade** :
#foreach($tickets as $ticket)
<a href="{{url(Route('show_client_ticket', ['id' => $ticket->id]))}}">
{{$ticket->subject}}
</a>
<p style="color: #959A9D;">
{{$ticket->last_body}} //this line returns too much Query
</p>
<hr>
#endforeach

Try to change this.
public function ticket()
{
return $this->belongsTo(Ticket::class,'ticket_id');
}
to this.
public function ticket()
{
return $this->belongsTo(Ticket::class,'id');
}
because the default primary key of the model is "id".
or if you want to change the primary key. try this:
class Ticket extends Model
{
protected $primaryKey = 'ticket_id';
...

Related

Cannot access Intermediate table in HasManyThrough relationship

My DB schema looks like this.
Now, in artisan tinker mode, When I try to query Details table from user Model, it shows me the records of the details table but I cannot access the the Cases Model for some reason, it always returns NULL in tinker.
This is my User Model
public function details()
{
return $this->hasManyThrough('App\Models\Detail', 'App\Models\Cases', 'user_id', 'case_id', 'id', 'id');
}
What am I doing wrong?
If for convenience you want to access Details directly from the User model then you can define relations as - (may seem like a little duplication but worth if it results in ease)
class User extends Model
{
public function cases()
{
return $this->hasMany(Case::class);
}
public function details()
{
return $this->hasManyThrough(Detail::class, Case::class);
}
}
class Case extends Model
{
public function details()
{
return $this->hasMany(Detail::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
class Detail extends Model
{
public function case()
{
return $this->belongsTo(Case::class);
}
}
Now both cases and details can be directly accessed via User record
$user->cases;
$user->details;
The idea of hasManyThrough is to skip the intermediate table. If you need to look at the cases and the details maybe you should define other relations for it.
// User model
public function cases()
{
return $this->hasMany(Cases::class, 'user_id');
}
// Cases model
public function details()
{
return $this->hasMany(Detail::class, 'user_id');
}
$users = User::with('cases.details')->get();
foreach ($users as $user) {
// an user
foreach ($user->cases as case) {
// a case
foreach ($case->details as $detail) {
// the details of a case
}
}
}

Laravel 5.6: Relationship with multiple tables and conditions

Consider I'm a hotel owner, and I have to know the bookings related to my hotel.
I need all bookings that which associated with my hotel.
Is there any eloquent functions to join? How?
How to get bookings of a hotel with owner(userid) with using eloquent relationship functions?
Hotel.php
class Hotel extends Model
{
public function userId(){
return $this->belongsTo(User::class,'user_id');
}
public function rooms(){
return $this->hasMany(Room::class,'hotel_id','id');
}
}
Room.php
class Room extends Model
{
public function hotelId(){
return $this->belongsTo(Hotel::class,'hotel_id');
}
public function bookings(){
return $this->hasMany(Booking::class,'room_id','id');
}
}
User.php
class User extends Model
{
public function hotels(){
return $this->hasMany(Hotel::class,'user_id','id');
}
}
Below code add in your respective controller.
$user = \App\User::find(Auth::id());
$hotels = $user->hotels;
foreach ($hotels as $hotel) {
$rooms = $hotel->rooms;
foreach ($rooms as $room) {
print_r($room->bookings);
}
}
Define the relationship with user in model
class Booking extends Model{
/**
* Get the user that owns the booking.
*/
public function owner()
{
return $this->belongsTo(App\User::class,'user_id,'id');
}
}
Then in your controller
$bookings = Booking::with('owner')->all(); // or get() or whatever to get
the booking list
foreach($bookings as $booking){
echo $booking->user->name; // you have access to owner fields
}
Finally i found this.
Booking model
public function room( )
{ return $this->belongsTo('App\room');
}
public function hotel( )
{
return $this->room()->with(['hotel'=> function($query){
$query->with('user');
}]);
}
BookingController
public function owner(Booking $booking ) {
return $booking->with('hotel')->get()
Next thing is Filter with owner

Laravel models to implement one to many and many to many in single query

i have this table structure, project has one to many relation with rewards , rewards and shipping has many to many relation with pivot table reward_ship.
projects rewards shipping reward_ship
--------- -------- -------- ------------
id id id id
title amount location reward_id
amount project_id name ship_id
i am trying to extract one particular project details with all other associate tables data(rewards and shipping data using reward_ship table) in one query.
These is how i am trying
Projects Model
class Rewards extends Model {
public function projs(){
return $this->hasMany('App\Rewards');
}
public function rewds(){
return $this->belongsToMany('App\Shipping')
->withPivot('reward_ship', 'ship_id', 'reward_id');
}
public function shiplc(){
return $this->belongsToMany('App\Rewards')
->withPivot('reward_ship', 'ship_id', 'reward_id');
}
}
class Rewards extends Model {
public function proj() {
return $this->belongsTo('App\Projects');
}
}
Controller api class
Route::get('projects/{id}', function($id) {
$p = Projects::find($id);
$getd = Rewards::with('proj')
->where('rewards.project_id', '=', $p->id)
->get();
});
it doesn't work.
i search and tried many related model base query in larvel.
i know my implementation are wrong. Please suggest me to work out.
You can use Laravel 5.5 new feature API Resources.
It helps you to format the output of objects such as models or collections, to display attributes and also relationships.
So, you could do something like this in your ItemResource:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class Project extends Resource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request
* #return array
*/
public function toArray($request)
{
return [
'project_id' => $this->project_id,
'title' => $this->title,
'amount' => $this->amount,
// To access relationship attributes:
'rewards' => $this->rewards->load('shippings'),
];
}
}
Then in your controller, you just need to create a new Resource instance and pass the item object that you want to return:
use App\Http\Resources\Project as ProjectResource;
// some code
/**
* Show a single formatted resource.
*
* #param Project $project
* #return ProjectResource
*/
public function show($project)
{
return new ProjectResource($project);
}
// the rest of your code
The output should be the expected.
You have to fix the relationships that you have :
Projects Model :
public function rewards(){
return $this->hasMany('App\Rewards');
}
Rewards Model :
public function projects() {
return $this->belongsTo('App\Projects');
}
public function shippings(){
return $this->belongsToMany('App\Shipping','reward_ship', 'reward_id', 'ship_id');
}
Shipping model:
public function rewards(){
return $this->belongsToMany('App\Rewards','reward_ship', 'ship_id', 'reward_id');
}
After that you can call the relationships in the controller to eager load the wanted elements like this :
$project = Projects::with('rewards.shippings')
->where('id', $project_id)
->get();
And in the view you can loop over the rewards then get the shippings like this :
#foreach ($project->rewards as $reward)
<p>This is a reword {{ $reward->amount }}</p>
#foreach ($reward->shippings as $shipping)
<p>This is a shipping {{ $shipping->name }}</p>
#endforeach
#endforeach
class Project extends Model
{
public function rewds()
{
return $this->hasMany('App\Rewards');
}
public function shiplc()
{
return $this->hasManyThrough('App\Shipping', 'App\Rewards');
}
}
class Rewards extends Model
{
public function shiplc()
{
return $this->belongsToMany('App\Shipping');
}
public function projs()
{
return $this->belongsTo('App\Project');
}
}
class Shipping extends Model
{
public function shiplc()
{
return $this->belongsToMany('App\Shipping');
}
}
Route::get('projects/{id}', function($id) {
$p = Projects::with(['rewds', 'shiplc'])->find($id);
});
Project.php
class Project extends Model {
public function rewards() {
return this->hasMany(Reward::class, 'project_id', 'id');
}
}
Reward.php
class Reward extends Shipping {
public function shipping(){
return $this->belongsToMany(Shipping::class, 'reward_ship', 'reward_id', 'ship_id');
}
public function project(){
return $this->belongsTo(Project::class);
}
}
You can retrieve it like this:
$projectDetails = Project::where('id', $projectId)
->with(['rewards', 'rewards.shipping'])->get();

Laravel 5.1 belongs to many not working

I have following tables.
Users
id
name
Events
id
name
Cards
id
name
Transfers
id
event_id
card_id
I added the belongs to relationship in the Card.php as well as in Event.php
class Card extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function events()
{
return $this->belongsToMany(Event::class,'transfers');
}
}
class Event extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
public function user()
{
return $this->belongsTo(User::class);
}
public function cards()
{
return $this->belongsToMany(Card::class,'transfers');
}
}
I was trying to use the following statements in my controller both of them returned error
> echo count($user->events->cards->where([['id', '=',
> '57']])->find());die; //$cards is not defined.
> echo count($user->events->cards()->where([['id', '=',
> '57']])->find());die; // method cards() is not defined.I tried this after reading a tutorial
Any help on resolving this issue is appreciated.
Thanks in advance.
You can make your life a lot easier by using the hadManyThrough relationship:
class User extends Model {
public function cards() {
return $this->hasManyThrough(Card::class, Event::class);
}
}
Then in principle you can do something like :
$user->cards()->where(['id', '=', '57']);

Laravel 5.1 - Join through multiple tables

I have the following tables:
Customer
id
Order
id
customer_id
Order_notes
order_id
note_id
Notes
id
If I want to get all order notes for a customer so I can do the following, how can I do it? Is there way to define a relationship in my model that goes through multiple pivot tables to join a customer to order notes?
#if($customer->order_notes->count() > 0)
#foreach($customer->order_notes as $note)
// output note
#endforeach
#endif
Create these relationships on your models.
class Customer extends Model
{
public function orders()
{
return $this->hasMany(Order::class);
}
public function order_notes()
{
// have not tried this yet
// but I believe this is what you wanted
return $this->hasManyThrough(Note::class, Order::class, 'customer_id', 'id');
}
}
class Order extends Model
{
public function notes()
{
return $this->belongsToMany(Note::class, 'order_notes', 'order_id', 'note_id');
}
}
class Note extends Model
{
}
You can get the relationships using this query:
$customer = Customer::with('orders.notes')->find(1);
What about 'belongsToMany' ?
E.g. something like
$customer->belongsToMany('OrderNote', 'orders', 'customer_id', 'id');
Of course, it'll not work directly, if you want to get order object also (but maybe you can use withPivot)
In the end I just did the following:
class Customer extends Model
{
public function order_notes()
{
return $this->hasManyThrough('App\Order_note', 'App\Order');
}
}
class Order_note extends Model
{
public function order()
{
return $this->belongsTo('App\Order');
}
public function note()
{
return $this->belongsTo('App\Note')->orderBy('notes.id','desc');
}
}
Then access the notes like so:
#foreach($customer->order_notes as $note)
echo $note->note->text;
#endforeach

Categories