Currently I've got 3 models, Listing, Offer & Payment which have the following relationships:
Listing
class Listing extends Model {
public function offers() {
return $this->hasMany(\App\Models\Offer::class)->orderBy('created_at', 'desc');
}
}
Offer
class Offer extends Model {
public function payment() {
return $this->hasOne(\App\Models\Payment::class, 'item_id', 'id')->where('item_type', \App\Models\Offer::class)->where('status', '1');
}
public function listing() {
return $this->belongsTo(\App\Models\Listing::class)->withTrashed();
}
}
Payment
class Payment extends Model {
public function offer() {
return $this->belongsTo(\App\Models\Offer::class, 'item_id', 'id')->withTrashed();
}
}
How can I go from them Listing model & return a relationship with the payments table directly?
Listing can have unlimited amounts of Offer but Offer can only have 1 max Payment
To find any corresponding payment information, I'm having to query the Offer based on the listing_id within the model, and then access the Offer->payment, when I'd much prefer to be able to just do something like this:
$transaction_id = $id;
$listing = Listing::whereHas('payment', function($q) use ($id) {
$q->where('transaction_id', $id);
$q->where('user_id', Auth::user()->id);
})->first();
Use HasManyThrough:
public function payments() {
return $this->hasManyThrough(Payment::class, Offer::class, null, 'item_id')
->where('payments.item_type', Offer::class)
->where('payments.status', '1')
->orderBy('offers.created_at', 'desc');
}
Related
I am trying to get all of the users notifications, and depending on if the user is a buyer or seller (can be both). I have made two functions in my notifications table to filter each other out.
My goal is to ultimately run:
$notifications = Auth::user()->notifications()->getBuyerNotifications();
or
$notifications = Auth::user()->notifications()->getSellerNotifications();
I am running into an issue: Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany
User Model:
public function notifications() {
return $this->hasMany('App\Notification', 'user_id', 'id');
}
Notifications Model:
public function user() {
return $this->belongsTo('App\User', 'id', 'user_id');
}
public static function getBuyerNotifications() {
return self::whereNotNull('buyer_id')
->whereNull('deleted_at')
->get();
}
public static function getSellerNotifications() {
return $this->whereNotNull('seller_id')
->whereNull('deleted_at')
->get();
}
The command I want to run to get all of the users notifications if they're a buyer: $notifications = Auth::user()->notifications()->getBuyerNotifications();
Firstly, you don't need to use whereNull('deleted_at'), you can import the softDeletes Trait in your model:
use Illuminate\Database\Eloquent\SoftDeletes;
...
class Notification extends Model {
use SoftDeletes;
...
}
Laravel will automatically use whereNull('deleted_at') on Eloquent-Builder.
Secondly, you cannot use static method on Illuminate\Database\Eloquent\Relations\HasMany.
Use scope method instead:
public function scopeBuyerNotifications($query) {
return $query->whereNotNull('buyer_id');
}
public function scopeSellerNotifications($query) {
return $query->whereNotNull('seller_id');
}
So you can find the notification like this:
$notifications = Auth::user()->notifications()->sellerNotifications()->get();
$notifications = Auth::user()->notifications()->buyerNotifications()->get();
Auth::user() uses session data.
Try this:
optional(User::find(Auth::id())->notifications)->getBuyerNotifications;
or
$userId = 1; // Example id you can just pass the user Id.
User::find($userId)->notifications->getBuyerNotifications;
You can add two other methods in user model as follows
public function getBuyerNotifications() {
return $this->hasMany('App\Notification', 'buyer_id', 'id');
}
public function getSellerNotifications() {
return $this->hasMany('App\Notification', 'seller_id', 'id');
}
And you can call it directly from the user instance
$user->getBuyerNotifications();
$user->getSellerNotifications();
I'm developing a simple survey system, and I'm having problem with getting the right data.
I'm trying to retrieve all categories with questions and answers, that are assigned to a specific survey.
ERD:
The following code nearly works, however it does not filter the questions that are assigned to a specific survey.
$categories = Category::whereHas('questions.surveys', function ($query) use ($id) {
$query->where('surveys.id', $id);
})->with('questions', 'questions.answers', 'questions.surveys')
->get();
Question Model:
class Question extends Model
{
public function answers()
{
return $this->belongsToMany('App\Models\Surveys\Answer', 'question_answers');
}
public function category()
{
return $this->belongsTo('App\Models\Surveys\Category');
}
public function surveys()
{
return $this->belongsToMany('App\Models\Surveys\Survey', 'survey_questions');
}
}
Category Model:
class Category extends Model
{
public function questions()
{
return $this->hasMany('App\Models\Surveys\Question');
}
}
Survey Model
class Survey extends Model
{
public function questions()
{
return $this->belongsToMany('App\Models\Surveys\Question', 'survey_questions');
}
}
For this you need to constrain your eager loads as well:
$categories = Category::with([
'questions' => function ($query) use ($id) {
$query->with('answers', 'surveys')
->whereHas('surveys', function ($query) use ($id) {
$query->where('id', $id);
});
},
])->whereHas('questions.surveys', function ($query) use ($id) {
$query->where('id', $id);
})->get();
This way you're saying only get you the categories that are related to a specific survey and only get the question that relate to that category and the specific survey.
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();
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']);
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