belongsTo not going to the right table - laravel

I have a controller with a function:
public function show(Activity $linkActivity, $id)
{
$activity = $this->activityRepository->getById($id);
$project = $linkActivity::find($activity->project_id)->project;
$employee = $linkActivity::find($activity->employee_id)->employee;
//\Debugbar::info($manager);
return view('activity/show', compact('activity'))->with('project',$project)->with('employee',$employee);
}
and here is my model Activity.php:
public function employee()
{
return $this->belongsTo('App\Employee');
}
The problem is that it is not looking at the right table and it is calling the activity table instead of the employee table. In the debugbar, I see the request to the db done which is:
select * from `activity` where `activity`.`id` = '2' limit 1
And id is well the 2 from the employee I m asking it but it looks in the wrong table.
Why is that?

You are searching for a row in Activity with Employee ID? I'm not sure what exactly you want, but if you want an employee why not simply do this
$employee = $activity->employee;

I think that the error is in find($activity->project_id).
In fact in the find, I need to put the id of the record holding the foreign key and not the id of the foreign key itself.

Related

Get only one column from relation

I have found this: Get Specific Columns Using “With()” Function in Laravel Eloquent
but nothing from there did not help.
I have users table, columns: id , name , supplier_id. Table suppliers with columns: id, name.
When I call relation from Model or use eager constraints, relation is empty. When I comment(remove) constraint select(['id']) - results are present, but with all users fields.
$query = Supplier::with(['test_staff_id_only' => function ($query) {
//$query->where('id',8); // works only for testing https://laravel.com/docs/6.x/eloquent-relationships#constraining-eager-loads
// option 1
$query->select(['id']); // not working , no results in // "test_staff_id_only": []
// option 2
//$query->raw('select id from users'); // results with all fields from users table
}])->first();
return $query;
In Supplier model:
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id')
//option 3 - if enabled, no results in this relation
->select(['id']);// also tried: ->selectRaw('users.id as uid from users') and ->select('users.id')
}
How can I select only id from users?
in you relation remove select(['id'])
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id');
}
now in your code:
$query = Supplier::with(['test_staff_id_only:id,supplier_id'])->first();
There's a pretty simple answer actually. Define your relationship as:
public function users(){
return $this->hasMany(User::class, 'supplier_id', 'id');
}
Now, if you call Supplier::with('users')->get(), you'll get a list of all suppliers with their users, which is close, but a bit bloated. To limit the columns returned in the relationship, use the : modifier:
$suppliersWithUserIds = Supplier::with('users:id')->get();
Now, you will have a list of Supplier models, and each $supplier->users value will only contain the ID.

Eloquent hasMany with foreign key on joint table

Assume this:
class List extends Model
{
public function items(){
return $this->hasMany(Items::class, 'c.class_id', 'class_id')
->rightjoin('items_classes as c', 'c.items_id', '=', 'items.id');
}
}
The problem is that Eloquent prepends items to foreign key field and the final query is:
SELECT * FROM items
RIGHT JOIN items_classes as c ON c.items_id = items.id
// here it is
WHERE items.c.class_id = 10
Even using DB::raw('c.class_id') didn't solve the problem.
If you notice the signature of hasMany relation method :
return $this->hasMany(Model::class, 'foreign_key', 'local_key');
Which means when Laravel will make the query, it will consider second argument foreign_key as a column of table defined in Model::class.
To simplify in your case :
return $this->hasMany(Items::class, 'c.class_id', 'class_id')->...
Leaving the rightjoin aside for a moment, Laravel is considering c.class_id as a foreign key of Item::class table which is indeed items table.
So the resultant query is :
SELECT * FROM items WHERE items.c.class_id = 10
Then when you add the right join, laravel just adds into the main query and makes it :
SELECT * FROM items
RIGHT JOIN items_classes as c ON c.items_id = items.id
WHERE items.c.class_id = 10
Laravel will not refer items_classes in the relation because you are relating List Model to Item::class and not ItemClass::class.
I am not sure about the data you need but see if you can use with like below :
class List extends Model
{
public function items(){
return $this->hasMany(Items::class, 'c.class_id', 'class_id');
}
}
List::with(['items', function($q){
return $q->->rightjoin('items_classes as c', 'c.items_id', '=', 'items.id');
}])->get();
Hope this gives you an idea how you can update your relationships to get desired query. If you add your table structure and data you want, I can update the answer with relationships for you.

Laravel eloquent use id from one table to search junction table?

So I have 3 tables
-Business
- id
-Address
- id
-business_address
- business_id
- address_id
And now at the moment when I go into a view business page I pass business->id from business table as $id:
public function displayBusiness($id) {
$business = Business::find($id);
$address = Address::find($id);
Which works absolutely fine at this moment but what if address has a different id?
so:
-Business
- id = 1
-Address
- id = 2
-business_address
- business_id = 1
- address_id = 2
So how can I modify that so that when id in business table = 1 it goes into business_address and find matching address id and bring back records that match it
What you should have is a relationship. So in your Business model you'd add the following.
public function addresses() {
return $this->belongsToMany(Address::class, 'business_address', 'address_id', 'business_id');
}
Then in your Address model you'd have the following.
public function addresses() {
return $this->belongsToMany(Business::class, 'business_address', 'business_id', 'address_id');
}
With this, you can now do the following.
public function displayBusiness($id) {
$business = Business::with('addresses')->find($id);
}
Then you access addresses by doing $business->addresses.
This is all based on what you currently have, so I'm assuming that one Address can belong to several Business. If this should not be the case, you'll need to refactor your relationship and database, as the pivot table isn't needed.

laravel one-to-many get data without inner join

I am trying to get a feel around the laravel ORM and I have the following models.
I have a:
user table with- id, firstname, lastname
city table with - id, name
usercity table with - user_id, city_id
The usercity table tracks the cities the user has visited.
I added the following in city model:
public function usercity()
{
return $this->hasMany('App\UserCity');
}
And another function in user model
public function usercity()
{
return $this->hasMany('App\UserCity');
}
I also added a model for UserCity and added following function there.
public function city()
{
return $this->belongsTo('App\City');
}
public function user()
{
return $this->belongsTo('App\User');
}
Now, the goal is to retrieve all the cities a user has visited. I used the following function.
$usercities = User::where('id','=',1)->first()->usercity()->get();
This works in the sense that it retrieves the user_id and city_id.
What would i need to do to get all the fields in the city table also?
Current response:
[[{"user_id":"1","city_id":"1"},{"user_id":"1","city_id":"2"},{"user_id":"1","city_id":"3"},{"user_id":"1","city_id":"4"}]]
I might be able to use inner join but I wanted to see if there was another way to retrieve the data which safely populates the data for me.
What you really have is a many-to-many relationship between users and cities, with the usercity table being the pivot table. Laravel uses the BelongsToMany relationship to implement this. You'll need to make a few changes to get this to work.
In your city model:
public function users() {
return $this->belongsToMany('App\User', 'usercity');
}
In your user model:
public function cities() {
return $this->belongsToMany('App\City', 'usercity');
}
You can get rid of the UserCity model. There is usually no reason to need a model for the pivot table.
The usercity table may need to be updated to add an id field as the primary key. I've not tried it without one, however, so it may work as you have it. Also, if you wanted, you could rename the table to city_user to conform to Laravel conventions, and then you wouldn't need to specify the table name in the relationship definitions.
Once your relationships are setup correctly, you can access a user's cities via the cities relationship on the user, and you can access a city's users via the users relationship on the city. For example:
// all of the cities visited by user 1
$user = User::find(1);
$usercities = $user->cities;
// all of the users that have visited city 1
$city = City::find(1);
$cityusers = $city->users;
You can find more information about the relationships in the documentation here.

Laravel 4 Eloquent 'hasMany': how to set the default lookup value rather than primay key

I want to retrieve all the comments under the post_id(post1) in page:
//localhost/posts/post1/
table comments
id:int[primary], comment:varchar, post_id:varchar, comment_id:varchar
1 this is a comment post_1 comment_1
table posts
id:int[primary], post_title:varchar, post_id:varchar
1 this is post title post_1
model comment.php
public function post()
{
return $This->belongsTo('Post');
}
model post.php
public function comments()
{
return $this->hasMany('Comment');
}
controller postsController.php
public function show($id)
{
$comments = Post::where('post_id','=',$id)->first()
->comments()->where('post_id','=',$id)->get();
}
When I visit //localhost/posts/post1/ , no related comment is displayed. The SQL runs as below:
select * from `posts` where `post_id` = 'post1' limit 1
select * from `comments` where `comments`.`post_id` = '1' and `post_id` = 'post1'
How can I remove `post_id = '1'` to retrieve the corresponding comments?
In your posts table the id column should be named id instead of post_id as this is what laravel expects. It is possible to set the primary key in your eloquent model to something other than id but it would be better to use id and follow the standard. Please refer to the docs here http://four.laravel.com/docs/eloquent. Once you are naming your id column as id you can get the individual post by Post::find($id)

Resources