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.
Related
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.
I have Games table and which has the following schema
id | status | name
status column has 2 values (Active, Pending)
And GamePlayer table which has the following schema
id | game_id | player_id | request_status
request_status column has 3 values (Pending, Confirm, Rejected)
Now I have to select all game in which the player is involved but with the following constraints:
If the game is Pending state then it will be shown to all game_players
If the game is in Active state then it will be only shown to the game_player whose request_status is Confirm.
Game(Model)
public function GamePlayer()
{
return $this->hasMany('App\Models\GamePlayer', 'game_id', 'id');
}
public function getGames($playerId)
{
$gameList = Game::with(['GamePlayer','Category:id,name'])
->whereHas('GamePlayer', function ($q) use ($playerId) {
$q->where('player_id', $playerId);
})->get();
return $gameList;
}
Controller
$this->gameObj = new Game();
$gameList = $this->gameObj->getGames($player_id);
Please help me out how can I populate data from another table based on condition(parent table as well as the child).
You can use condition in your relationship to get only confirmed game players
public function activeGamePlayers()
{
return $this->hasMany('App\Models\GamePlayer', 'game_id', 'id')
->where('request_status', 'confirm');
}
You can as well use scopes (https://laravel.com/docs/7.x/eloquent#local-scopes) to select only active games
public function scopeActive($query)
{
return $query->where('status', 'active');
// You can then use $game->active()->...
}
So your getGame would look like:
public function getGames($playerId)
{
$player = GamePlayer::find($playerId);
if ($player->status == 'active') {
$gameList = Game::with(['GamePlayer', 'Category:id,name'])
->get();
} else {
$gameList = Game::with(['GamePlayer', 'Category:id,name'])
->active()->get();
}
return $gameList;
}
NOTE:
in your specific case, I would instead get started from the GamePlayer Model to get the games, instead of coming from the Game Model - you can use scopes and conditions in relationships as well to make your code more readable.
You can use Laravel method whereHas. You should read this part of Laravel the documentation.
Note that you should have relationships declared on every model.
I found this function in Internet and it works.
In my App
public function childs(){
return $this->hasMany('App\Account','p_id');
}
In my route:
Route::get('tests', function(){
return App\Account::with('childs')
->where('p_id',0)
->get();
});
So if you have in the dabase a raw with p_id = 0 and id = 1 it return a category and if you have a raw with p_id = 1 and id = 2 that mean that the child of the categorie with id = 1.
Another example::
If you have a raw with p_id = 6 and id = 16 that mean that the child of the category with id = 6
Please who can explain to mean why exactly it work like that ?
Laravel Relationship are not used to make relations between 1 model. You cannot make relation between Account and Account. An account does not has "hasMany" accounts.
You can have hasMany users for example.
public function childs(){
return $this->hasMany('App\User','p_id');
}
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.
as stated in the docs the current hasManyThrough can be used when u have something like country > users > posts
which result in something like Country::whereName('xx')->posts;
which is great but what if i have more than that like
country > cities > users > posts
or even
country > cities > towns > users > posts
how would you then implement something like that so you can write the same as above
Country::whereName('xx')->posts; or Town::whereName('xx')->posts;
I created a HasManyThrough relationship with unlimited levels: Repository on GitHub
After the installation, you can use it like this:
class Country extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function posts() {
return $this->hasManyDeep(Post::class, [City::class, Town::class, User::class]);
}
}
Here's what I've done. I did some modification to #ctfo's answer, so it will return as collection.
public function posts()
{
$posts = collect();
foreach ($this->towns->get() as $town) {
$post = $town->posts();
if ( $post->count() ) $posts = $posts->merge( $post );
}
return $posts;
}
I hope this can help anyone who came through.
sadly there is no one easy solution, so heres what i found
1- add the other table foreign id into the post table and stick to the hasMany & belongsTo, ex.
posts
id - integer
country_id - foreign
// etc...
title - string
2- go with the hasManyThrough on each table except user & post as there is no need unless you want to go deeper, ex.
countries
id - integer
name - string
cities
id - integer
country_id - foreign
name - string
towns
id - integer
city_id - foreign
name - string
users
id - integer
town_id - foreign
name - string
posts
id - integer
user_id - foreign
title - string
- so lets try with the 2nd option
1- set up your hasMany & belongsTo relations as usual
2- setup the hasManyThrough on the models.
3- to achieve the above example of Country::whereName('xx')->posts we add another method to the country model
// because Country::find($id)->towns, return an array
// so to get all the posts we have to loop over that
// and return a new array with all the country posts
public function posts()
{
$posts = [];
foreach ($this->towns as $town) {
$posts[] = $town->posts;
}
return $posts;
}
4- as the whole thing is working through the foreign_id so we search by the id instead of the name like Country::find($id)->posts()