Laravel 5 - Find Fields on "MorphOne" Relationship - php

I'm quite new to Laravel and I'm now facing this issue while trying to create a query:
I have the following Morphable classes:
\App\User
class User {
public function userable()
{
return $this->morphTo();
}
}
\App\Distributor
class Distributor {
public function user()
{
return $this->morphOne('App\User', 'userable');
}
}
user table has the fields: name, email, status, userable_type and userable_id.
distributor table has the fields: store_code and location_id.
By using Eloquent, i need to start the query from Distributor model and select only the following fields: 'name, email, store_code'.
I'm trying the following, but laravel says user.name doesn't exists :(
$queryBuilder = \App\Distributor::has('user');
$queryBuilder->select(['user.name']);
$queryBuilder->get();
QueryException in Connection.php line 651:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user.name' in 'field list' (SQL: select user.name from distributor where (select count(*) from user where user.userable_id = distributor.id and user.userable_type = App\Distributor and user.deleted_at is null) >= 1)
I was able to achieve my goal forcing the join relationship, but this seems wrong, I think Eloquent is able to find the relation by itself as the Morph relationship is specified in the Model.
Just for record, this works good:
$queryBuilder = \App\Distributor::has('user');
$queryBuilder->join('user', function($join) {
$join->on('userable_id', '=', 'distributor.id')
->where('userable_type', '=', \App\Distributor::class);
});
$queryBuilder->select(['user.name']);
$queryBuilder->get();
Also, since its a one-to-one like relationship, sometimes I'll need to order the results using one of the users columns
But I need another way to do it without forcing the join, something clean as the first example.

read about with() function in the docs
$queryBuilder->select('id','store_code');
$queryBuilder = \App\Distributor::with(['user'=>function($query){
$query->select('id','name','email')
}]);
$queryBuilder->has('user');
$queryBuilder->get();

Related

Laravel get all data through pivot Table

Hello I've got problem with getting the name of Group which Recipent is member.
I use 3 tables for that subject : recipent, group and group_recipent.
In group_recipent table I've got only columns like recipent_id and group_id. All is correct to Laravel naming convention.
It's my Recipent model:
public function groups()
{
return $this->belongsToMany(Group::class)->withPivot('group_recipent', 'recipent_id', 'group_id');
}
And my Group model:
public function recipents()
{
return $this->belongsToMany(Recipent::class)->withPivot('group_recipent', 'recipent_id', 'group_id');
}
Accessing data:
$user = Recipent::find(4);
$data="";
foreach ($user->groups as $group)
{
$data .= $group->name ." ";
}
dd($data);
After trying to access the name of a group through pivot table I get an error:
Illuminate\Database\QueryException
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'group_recipent.group_recipent' in 'field list' (SQL: select groups.*, group_recipent.recipent_id as pivot_recipent_id, group_recipent.group_id as pivot_group_id, group_recipent.group_recipent as pivot_group_recipent from groups inner join group_recipent on groups.id = group_recipent.group_id where group_recipent.recipent_id = 4)
I wanted to acces the name all names of group which recipent is member of but I get error like above. Have you any idea how to solve that? :/
Try to delete from your models 'group_recipent'. I assume you're wonder that the 1st field is pivot table name. It should look like this:
return $this->belongsToMany(Recipent::class)->withPivot('recipent_id', 'group_id');
If someone got other idea, just add comment below.

Laravel use a pivot field to filter polymorphic many to many relationship

I'm attaching user permissions to several different models using a polymorphic many-to-many relationship - the pivot table is called permissables:
Permissables
- id
- user_id
- permissable_type
- permissable_id
- role
- created_at
- updated_at
This is working well - I can return a list of permitted users for my Project model using:
public function users()
{
return $this->morphToMany(User::class, 'permissable')->withPivot('role')->withTimestamps();
}
If I want to filter this to just owners - ie where the pivot field role is equal to owner - I can do the following in Tinker:
Project::first()->users->where('pivot.role', '=', 'owner')
But if I try this in my model:
public function owners()
{
return $this->users()->where('pivot.role', '=', 'owner');
}
when I call Project->owners in Tinker, I get an error:
>>> Project::first()->owners
[!] Aliasing 'Project' to 'App\Project' for this Tinker session.
Illuminate/Database/QueryException with message 'SQLSTATE[HY000]: General error: 1 no such column: pivot.role (SQL: select "users".*, "permissables"."permissable_id" as "pivot_permissable_id", "permissables"."user_id" as "pivot_user_id", "permissables"."permissable_type" as "pivot_permissable_type", "permissables"."role" as "pivot_role", "permissables"."created_at" as "pivot_created_at", "permissables"."updated_at" as "pivot_updated_at" from "users" inner join "permissables" on "users"."id" = "permissables"."user_id" where "permissables"."permissable_id" = 1 and "permissables"."permissable_type" = App/Project and "pivot"."role" = owner)'
For the first question:
return $this->users->where('pivot.role', '=', 'owner');
This line works because $this->users return the users' collection with pivot(The key name is pivot). And you are using where-method to filter users collection.
For the second question:
$this->users() change the laravel code to raw sql like:
select users.*, permissables.permissable_id as pivot_permissable_id, permissables.user_id as pivot_user_id, permissables.permissable_type as pivot_permissable_type, permissables.role as pivot_role, permissables.created_at as pivot_created_at, permissables.updated_at as pivot_updated_at
from users
inner join permissables on users.id = permissables.user_id
where permissables.permissable_id = 1 and permissables.permissable_type = "App/Project"
So the Intermediate Table name is permissables, not pivot. Mysql cannot found the intermediate's column when applying where('pivot.role', 'owner') to users().
Laravel provide wherePivot method, which will add intermediate table name for you.
public function owners()
{
return $this->users()->wherePivot('role', 'owner'); // change to where pemissables.role = 'owner'
}

How replace join query with whereHas?

I am using Laravel 5.6 and i have a standard query
Order::where('dict_statuses_id', 1)
->leftJoin('dict_statuses', 'dict_statuses_id', '=', 'dict_statuses.id')
->get();
So i have list of orders with details where status = 1 (new) after join table i see status as New or Complete. Is any way to change this query using whereHas ?
i tried use
Order::whereHas('status', function($q){
$q->where('dict_statuses_id', 1);
})->get();
But no results, in model Order i have
public function status()
{
return $this->hasMany('App\DictStatuses');
}
[Updated]
i have an error:
Column not found: 1054 Unknown column 'dict_statuses.orders_id'
in 'where clause' (SQL: select * from `orders` where exists
(select * from `dict_statuses` where `orders`.`id` = `dict_statuses`.`orders_id` and `dict_statuses_id` = 1)
and `orders`.`deleted_at` is null)
In my table i have table Orders where is field: dict_statuses_id
and table dict_statuses with fields: id, public_name
Why error is about dict_statuses.orders_id
Try Order::has('status')->get();
You can pass in variables to a relationship so you could potentially do.
public function status($id) {
return $this->hasMany(DictStatuses::class)->where('dict_statuses_id', $id);
}
Try defining the local key & foreign key.
$this->hasMany(DictStatuses::class, 'foreign_key', 'local_key');
I think your dict_statuses doesn't have a column called order_id.
Please include that column in your migration
then call
Order::whereHas('status', function($q){
$q->where('dict_statuses_id', 1);
})->get();
in your controller
or change the relation in Order model as
public function status(){
return $this->belongsTo('App\DictStatuses'):
}

Eager Loading is not working laravel 5.3

I have three related models.
1.User model
public function users_wishlst(){
return $this->hasMany('App\Users_wishlst');
}
2.Product Model
public function users_wishlst(){
return $this->belongsTo('App\Users_wishlst');
}
3.Users_wishlst model
public function user(){
return $this->belongsTo('App\User');
}
public function product(){
return $this->hasMany('App\Product');
}
in users_wishlsts table i have the followibg columns
id
user_id
product_id
I want to get the product info of an users wishlist. I have tried this
public function showWishList(){
$id= Auth::id();
$WishList = wishlist::with('product')->where(['user_id'=>$id])->get();
return json_encode($WishList);
}
But this gives me the following error
SQLSTATE[42S22]: Column not found: 1054 Unknown column
'products.users_wishlst_id' in 'where clause' (SQL: select * from
products where products.users_wishlst_id in (1, 2, 3))
what is the problem
Without knowing all about your database structure this seems like a problem with your foreign keys. Eloquent tries to automatically guess the key. Based on the error it seems like your products table doesn't contain a users_wishlst_id column (maybe you named it different?). Try looking at you Database and give Laravel the correct foreign_key.
https://laravel.com/docs/5.3/eloquent-relationships#one-to-many

Laravel 5.3 Eloquent & Relationship

I have a record model and status model. Which each record has status can be "approved", "disapproved" or "in process" which is stored in the status model that connected trough status_id in the record model.
This is my model & their relationship.
Records(id, user_id, status_id, note, date, timestamp)
function status()
{
return $this->hasOne('App\Status');
}
Statuses(id, name)
function record()
{
return $this->belongsToMany('App\Record');
}
I would like to callback like this on my view $records->status->name. But it gives error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Statuses.record_id' in 'where clause' (SQL: select * from `statuses` where `statuses`.`record_id` = 3 and `statuses`.`record_id` is not null limit 1)
I try to to play the relationship & the callback but it not work. Is it possible to do that? Or better i just save the status directly on the record table without using the status record. Thank you.
You have the relationships reversed. Can you try the following instead:
class Record extends Model
{
public function status()
{
return $this->belongsTo('App\Status');
}
}
class Status extends Model
{
public function records()
{
return $this->hasMany('App\Record');
}
}
I think you are going for a 'One To Many', rather than a 'Many To Many' relationship.
Try the following instead:
Records(id, user_id, status_id, note, date, timestamp)
function status()
{
return $this->belongsTo('App\Status');
}
Statuses(id, name)
function record()
{
return $this->hasMany('App\Record');
}
Define hasOne Relationship on Records
Records(id, user_id, status_id, note, date, timestamp)
function status(){
return $this->hasOne('App\Status','id','status_id');
}
and hasMany Relationship on Status
Statuses(id, name)
function record(){
return $this->hasMany('App\Record','status_id','id');
}
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Statuses.record_id' in 'where clause' (SQL: select * from `statuses` where `statuses`.`record_id` = 3 and `statuses`.`record_id` is not null limit 1)
According to the Error! It says that you don't have records_id in your status table. So add it.
For this to work on You should have a unsigned integer named as record_id in your Status Migration.
$table->unsignedInteger('record_id')->references('id')->on('records'); //This will work as the foreign key to find the respective Status.
After editing the migration file you'll have to rollback migrations.
In terminal at your project directory,
php artisan migrate:rollback
If you could add the migrations as well, It will be easier to point out.
model:Record
Records(id,user_id,status_id,note)
function status(){
return $this->belongsTo('App\Status','id);
}
model:Status
Status(id,name)
function record(){
return $this->hasmany('App\Record','id','status_id');
}
Try this relation it will work

Categories