Laravel 5.2 and belongsToMany combined query? - laravel-5

Could you please help me with combined query (I am beginner in laravel)
I have 3 tables
users : id and name
words : id and name
user_word : user_id ,word_id and level
Each user have his own Words
With relation model
Class User:
public function words()
{
return $this->belongsToMany('App\Word' , 'user_word','user_id','word_id')
->withPivot('level');
}
class Word
public function users()
{
return $this->belongsToMany('App\User' , 'user_word','word_id','user_id')
->withPivot('level');
}
In the WordController.php i need to mack query of other users words but if the current Auth::user have the same words I want it to be excluded.
$words = $user->words()
->paginate(10,["mword","tword","image","id"],"p");
this code gave me all the words for the Auth::user.
Thank you.

Related

Laravel : BelongstoMany relationship implementation

i have following tables
1.Shops (shop_id , company_id , name, latitude, logntitude, phone)
2.packages(package_id, company_id, cost, value, expire_date)
3.shop_packages (package_id, shop_id)
and i am trying to access this shops associated with package as below
Package Model
public function shop():BelongsToMany{
return $this->belongsToMany(Shop::class,'shop_packages','package_id','package_id');
}
Shop Model
public function package(){
return $this->belongsToMany(Package::class,'shop_packages','shop_id','shop_id');
}
now when i try below it returns me shop with empty result while there is data available ,
Package::with('shop')->where('package_id',$request['package_id'])->first();
i am using laravel 8.x for this project . Can someone please help me to sort the issue
Shop Table
Package Table
shop_packages
You entered the wrong foreign key in the relation. The belongsToMany relation should be declared like this
Package Model
public function shops():BelongsToMany{
return $this->belongsToMany(Shop::class,'shop_packages','package_id','shop_id');
//you can also just ignore the foreign keys since they follow naming standards
//return $this->belongsToMany(Shop::class,'shop_packages');
}
Shop Model
public function packages(){
return $this->belongsToMany(Package::class,'shop_packages','shop_id','package_id');
//same here
//return $this->belongsToMany(Package::class,'shop_packages');
}
You should also use plural to better express the many to many relation
Package::with('shops')->where('package_id',$request['package_id'])->first();

Get data from eloquent relationship with pivot in laravel

I have 3 DB table.
shows
show_genres
show_show_genre
In my show model, i have:
public function genres()
{
return $this->belongsToMany('App\ShowGenre');
}
So when i do:
$show=Show::find(1);
$show->genres give me collection with all genres that have show_id in shows_genres db.
I have also ShowGenre model where is all genres i have and i use.
Becouse i want to use sync for my genres, that names need to be in database.
But how can i find all shows that have genre id.
I couldn't find any way to get that list. Please help, thanks.
Edit:
You should do this other way around:
Have a model for Genre
your relationship method in Genre model should be
public function shows()
{
return $this->belongsToMany('App\Show', 'shows_genres');
}
belongsToMany accepts two parameters, model and pivot table name if not a standard name.
Your solution:
//Get genre 'strict'
//where could be followed by column name example:whereSlug, whereName
$strictGenre = Genre::whereName('strict')->first();
if($strictGenre)
{
//get shows of this genre
$strictShows = $strictGenre->shows;
}
Read manytomany relationships:
https://laravel.com/docs/6.x/eloquent-relationships#many-to-many
You may use
$show->genres()
->wherePivot('column', value)
->get();
By default Pivot table name must be singular : show_genre (without
plural s)
See docs
Assuming you have this relationship in your genres model
public function shows()
{
return $this->belongsToMany('App\Show', 'shows_genres', 'genre_id', 'show_id');
}
Then you can directly get all shows by genres id like this
$shows = Genre::find($id)->shows;

Laravel whereHas ManyToMany relation but then order by a value in the third table

I have 3 tables
entry (
id,
title,
other_stuff)
entry_award (
id,
award_id,
entry_id)
award (
id,
name,
type)
I am trying to create a laravel query which lets me get all the entries that have awards, and order them by award.type ASC
$Entries = Entry::with('award')
->whereHas('award', function ($query) {
$query->orderBy('award.award_id','ASC');
})->paginate(20);
But this doesn't work.
This is the sql version of it
SELECT DISTINCT entry.*
FROM entry, award, entry_award
WHERE entry.id = entry_award.entry_id
AND award.id = entry_award.award_id
ORDER BY award.type ASC;
Now I tried to just use the raw sql for it, but the problem seems to be that laravel does not then recognize the result as Entry models/objects. And i need to get other Entry relations later on in the html via blade.
So how can I either make a query-builder query that gets me all entries that have awards and orders them by award.type value
or use the raw sql but have Laravel see it as an array of Entry
objects instead of just an array of JSON values.
class Entry extends Model {
public function entry_award(){
return $this->belongsToMany('App\Award', 'entry_award');
}
}
class Award extends Model {
public function entries() {
return $this->belongsToMany('App\Entry', 'entry_award');
}
}

Laravel returns a Collection with duplicates of the first model

I'm developing a Laravel 5.7 (API) application with a PostgreSQL database behind it. The relevant Models are: User (customers and employees), Car, and Request.
An employee User creates a Request for a Car, that belongs to a customer User.
The relationships are:
Car (as customer) : User = n:m
Car : Request = 1:n
User : Request (as employee) = 1:n
(The data design is suboptimal, to put it mildly, but anyway, it's the given reality for now.)
Now to the actual issue. I want to display all Requests of a customer User:
Request::query()
->join('user_car', 'user_car.car_id', '=', 'request.car_id')
->join('user', 'user.id', '=', 'user_car.user_id')
->where('user.id', '=', $customer->id)
->select()
->get();
The customer with the given $customer->id has n Requests. And the length of the result Collection of the call above is correct. But all these n entries are duplicates of the first one. Means: I'm getting a list with n instances of Request#1.
Why does the first call return a list of references to the same Model object? Is it a (known) bug?
ADDITIONAL INFORMATION
Relationships:
class User extends \Illuminate\Foundation\Auth\User
{
// ...
public function cars()
{
return $this->belongsToMany('App\Car', 'user_car')->withTimestamps();
}
public function requests()
{
return $this->hasMany(Request::class, 'user_id');
}
}
class Car extends Model
{
// ...
public function users()
{
return $this->belongsToMany('App\User', 'user_car')->withTimestamps();
}
public function requests()
{
return $this->hasMany(Request::class);
}
}
class Request extends Model
{
// ...
public function car()
{
return $this->belongsTo(Car::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
The query is correct.
I logged the database requests, got the generated statement
SELECT *
FROM "request"
INNER JOIN "user_car" ON "user_car"."car_id" = "request"."car_id"
INNER JOIN "user" ON "user"."id" = "user_car"."user_id"
WHERE "user"."id" = 1;
..., and executed it manually. The result table contains as expected n different entries.
NOT just references
The result Collection's entries instances references to the different objects:
$test1 = $resultCollection->first();
$test2 = $resultCollection->last();
$test3 = spl_object_hash($test1);
$test4 = spl_object_hash($test2);
Xdebug output:
$test3 = "0000000077505ccd000000007964e0a8" <-- ccd0
$test4 = "0000000077505c33000000007964e0a8" <-- c330
Workaround
I found a workaround. This call
Request::whereIn('car_id', $customer->cars()->pluck('id')->toArray())->get();
... retrieves the correct/expected set of model.
First, note that your object hashes are not actually identical, and you're likely dealing with two separate instances.
What you're likely experiencing is an issue with ambiguous column names. When you JOIN together multiple tables, any matching/duplicate column names will contain the value of the last matching column. Your SQL GUI/client usually separates these. Unfortunately Laravel doesn't have a prefixing mechanism, and just uses an associative array.
Assuming all of your tables have a primary key column of id, every Request object in your result set will likely have the same ID - the User's ID you pass in the WHERE condition.
You can fix this in your existing query by explicitly selecting the columns you need to prevent ambiguity. Use ->select(['request.*']) to limit the returned info to the Request object data.

Correct relationship in Laravel

I have four tables in database: groups, specialties, lessons, group_lesson. It's structures:
groups
id
specialty_id
name
specialties
id
name
lessons
id
specialty_id
group_lesson (UNIQUE INDEX lesson_id, group_id)
lesson_id
group_id
date
My models look like that for now:
class Group extends Eloquent {
public function specialty() {
return $this->belongsTo('Specialty');
}
}
class Lesson extends Eloquent {
public function specialty() {
return $this->belongsTo('Specialty');
}
}
class Specialty extends Eloquent {
public function lessons() {
return $this->hasMany('Lesson');
}
public function groups() {
return $this->hasMany('Group');
}
}
I need get additional fields in Group model look like that
Group - Eloquent model
name - string
lessons - collection of Lesson models of Group Specialty
date - date from group_lesson table
I've tried different relationships and combinations, but it's doesn't work. Please help me to write correct relationships.
You can use eager-loading to access relational data through relationships, and can even chain relationships further. As a rule of thumb, if you can draw a path to from 1 model to another through a relationship, you can eagerload all the relevant and relational data for that with chained eager-loads.
Laravel Eager Loading
As an example
$speciality_group = Speciality::with('group','lessons')->find($id);
Even though you are only getting a single instance of the speciality model, the related data is hasMany, meaning multiple records. You need to loop through these records using a foreach loop to access the relevant data for them, or alternitavely add additional closures in your initial query to load only a single related model.
foreach($speciality_group->group as $group)
{
echo $group->name;
}
You will need to do this for both instances where you want to display related information.

Resources