I have the next stucture: table menus(id, title, type, parent_id, page_id) and
pages(id, alias title,content)
Model Menu
class Menu extends Model
{
public function parent()
{
return $this->belongsTo('App\Menu', 'parent_id');
}
public function children()
{
return $this->hasMany('App\Menu', 'parent_id');
}
public function page()
{
return $this->belongsTo('App\Page', 'page_id');
}
}
I want get the next result:
-Item 1 (show name menu table)
-Item 2
-Subitem 1 and alias (show name **menu** table and show alias **page** table)
-Subitem 2 and alias
-Item 3
- Suitem 1 and alias
Eloquent query
$items = Menu::with(['children' => function($query){
$query->with('page');
}])->where(['parent_id' => null])->get();
view
#foreach($items as $item)
#if($item->children()->count() > 0)
#foreach($item->children as $child)
<li>{{$child->title}}</li>
#endforeach
#else
<li><a href="/page/{{$item->page->alias}}">{{$item->title}}
#endforeach
How get alias page nested in foreach ?
You can use:
{{ $child->page->alias }}
to display child menu page alias assuming you have page for each child.
Otherwise you can use:
{{ optional($child->page)->alias }}
if you are running Laravel 5.5 or:
{{ $child->page ? $child->page->alias : '' }}
if you are running Laravel < 5.5
Also you could improve eager loading and code a bit:
$items = Menu::with('children.page', 'page')->whereNull('parent_id')->get();
Related
I am working with Laravel data querying and I need a query that is going to group all the children of a parent when I take the categories.
the categories table has a name and a parent_id, the routes of the categories have the parent_id set as null, the query should return every category grouped by parent id and the parent should be the first node of every group.
If you only want to display the categories as parent child somewhere, you do not need to collect them like that, you can make a relationship within the model like
class Category {
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
public function parent()
{
return $this->hasMany(self::class, 'id', 'parent_id');
}
}
may be it will be one-to-many relationship instead of many-to-many depending on your requirement.
Now you can just get all the parents like
Category::whereNull('parent_id')->get();
or using a scope
Category::parent()->get(); and define the scope in the model
and loop through the parent category like
#foreach ( $categories as $category )
{{ $category->name }}
#foreach ( $category->children as $subCategory )
{{ $subCategory->name }}
#endforeach
#endofreach
and to retrieve parent with children you can use
Category::whereNull('parent_id')->with('children')->get();
or
Category::parent()->with('children')->get();
I have not tested the code, but roughly it will be like this.
contoller
$locations = OurLocation::groupBy('country_id')->with('children')->get();
model
public function children()
{
return $this->hasMany(OurLocation::class, 'country_id','country_id');
}
blade
#foreach($locations as $index=>$location)
#foreach($location->children as $children)
{{ $children->company_name }} <br>
#endforeach
#endforeach
When you get the returned collection from the query, you are able to use the ->groupBy() method where you can specify the field which the results should be grouped by.
Assuming your categories model is Category:
$categories = Category::all()->groupBy('parent_id')->toArray();
i'm trying to get all the Level_id and Term_id on my intermediate table using many to many relationship but i couldn't make it work and i want to pass it to my view using ordered list html.
i always end up with this..Trying to get property of non-object
Controller:
public function get_term_level()
{
$terms=Term::find(1);
foreach ($terms->level as $tm) {
$tm->pivot->Level_id;
}
return view('term_level.index',compact('terms'));
}
Term Model same as with my LevelModel
public function level(){
return $this->belongsToMany(Level::class, 'term_levels')->withPivot('Term_id', 'Level_id');
}
View
#foreach ($terms->pivot as $tm )
<ul>
<li>{{ $tm->Term_id }}</li>
{{ $tm->Level_id }}
</ul>#endforeach
Try this (inside your controller):
foreach ($terms->level()->get() as $tm) {
$tm->pivot->Level_id;
}
I'm using laravel 5.6.
I have 3 tables : players, games and game_player table.
Retrieving the game count of every player is easy with this in the index action of the PlayersController:
//Get game count of every player
$players = Player::withCount('games')->get();
Is there a way to retrieve the game count for the games when the player has won the game? (in the index action of the playerscontroller) I'm not sure how to do this. Can someone help?
games table migration
$table->integer('winner')->unsigned()->index();
$table->foreign('winner')->references('id')->on('players')->onDelete('cascade');
game_player table migration
table->integer('game_id')->unsigned()->nullable();
$table->foreign('game_id')->references('id')->on('games')->onDelete('cascade');
$table->integer('player_id')->unsigned()->nullable();
$table->foreign('player_id')->references('id')->on('players')->onDelete('cascade');
game model relation
public function players(){
return $this->belongsToMany('App\Player')->withTimestamps();
}
//this is for the winner of the game
public function player()
{
return $this->hasOne('App\Player');
}
player model relation
public function games(){
return $this->belongsToMany('App\Game')->withTimestamps();
}
//the game the player has won
public function game()
{
return $this->belongsTo('App\Game');
}
playerscontroller
public function index()
{
$players = Player::all();
//Get game count of every player
$players = Player::withCount('games')->get();
/*Load the view and pass the groups*/
return \View::make('players.index')->with('players', $players);
}
The result I want is to get played games (is working) and won games.
player > index blade
#foreach($players as $player)
<p>{{ $player->id }}</p>
<p>{{ $player->firstname }} {{ $player->lastname }}</p>
<ul>
<li>Played games: {{ $player->games_count }}</li>
<li>Won games: </li>
</ul>
#endforeach
update
I don't think we can see it as a duplicate of this question (Laravel using where clause on a withCount method) because I'm using a many to many relationship also.
If I use this code which isn't the correct one, because the 1 needs to be dynamic $id:
$players = Player::withCount('games')
->having('winner', '=', 1)
->get();
I get the error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'winner' in 'having clause' (SQL: select players., (select count() from games inner join game_player on games.id = game_player.game_id where players.id = game_player.player_id) as games_count from players having winner = 1)
update 2
When I use this code:
controller
$players = Player::all();
//Get game count of every player
$players = Player::withCount('games')->get();
$wongames = Player::withCount(['games' => function($query) { $query->where('winner', '=', 5); }])->get();
//$players = Player::withCount('games')->where('winner', '=', 1);
/*Load the view and pass the groups*/
return \View::make('players.index')->with('players', $players)->with('wongames', $wongames);
blade index
#foreach($players as $player)
<p>{{ $player->id }}</p>
<p>{{ $player->firstname }} {{ $player->lastname }}</p>
<ul>
<li>Played games: {{ $player->games_count }}</li>
#foreach($wongames as $wongame)
<li>Won games: {{ $wongame->games_count }}</li>
#endforeach
</ul>
#endforeach
I get this (not what I exactly want, but getting there I think):
Since you define a foreign key on the games table, you have a one-to-many relationship between the Player and Game already. Try adding the following relation to your Player model:
// Player.php
public function won()
{
// must specify the foreign key because it is not the usual `_id` convention.
return $this->hasMany(Game::class, 'winner');
}
Then access it on each player like:
#foreach($players as $player)
{{ $player->won->count() }}
#endforeach
Rather than querying in the view file, you should ideally do the following in your controller:
public function index()
{
/*Load the view and pass the groups*/
return \View::make('players.index')->with('players', Player::with('won')->get());
}
I have parent and child categories on the page. What I'm trying to do is when there is no products and no sub-categories assigned in some parent category to not be shown on the page.
So I have this in Category model
public function item()
{
return $this->hasMany('Item','category_id');
}
public function children()
{
return $this->hasMany('App\Category', 'parent_id');
}
public function getCategories()
{
$categoires = Category::where('parent_id',0)->get();
$categoires = $this->addRelation($categoires);
return $categoires;
}
public function selectChild( $id )
{
$categoires = Category::where('parent_id',$id)->where('published', 1)->get();
$categoires = $this->addRelation($categoires);
return $categoires;
}
This in the controller
public function index()
{
$Category = new Category;
$allCategories = $Category->getCategories();
return view('frontend.home', compact('allCategories', 'unviewedMessagesCount'));
}
And this on the blade view
#foreach($allCategories as $category)
{!!$category->title!!} ({!! $category->itemCount!!})
<p class="card-text">
#foreach($category->subCategory as $subcategory)
{!!$subcategory->title!!} {!! $subcategory->itemCount !!}
#endforeach
</p>
View Category
#endforeach
This is sample of the records in category table there are column
id | title | parent
1 Main cat 0
2 Sub-Cat 1
3 Sub-Cat 2 1
4 Main cat 2 0
So each parent is 0 and each child(sub category) has the parent ID
item table has also reference to category table -> column category_id
I can't figured it out how to make the condition if no items and no childs to not show it on page.
In Controller
$allCategories = Category::where('parent_id', 0)->has('children.item')
->with(['children'=> function($query){
$query->withCount('item');
}])
->get()
->each(function($parentCategory){
// if you wants calculate sum child category item count and assign to parent category item_count.
$parentCategory->item_count = $parentCategory->children->sum(function ($child) { return isset($child->item_count)?$child->item_count:0;});
});
return view('frontend.home', compact('allCategories'));
In this query only one query will be executed and it return all of your needs.
And In Blade View file
#foreach($allCategories as $category)
{!!$category->title!!} ({!! $category->item_count!!})
<p class="card-text">
#foreach($category->children as $subcategory)
{!!$subcategory->title!!} {!! $subcategory->item_count !!}
#endforeach
</p>
View Category
#endforeach
I was wondering what the cleanest way was to count the number of posts that are connected to a category in my blog.
Here is how the table relationship is set up.
What I have is a hasMany relationship from the Category to the Post models like this:
In Categories Model
public function blog_posts()
{
return $this->hasMany('App\Http\Models\Blog_Post', 'category_id');
}
And in the Blog_Post Model
public function blog_categories()
{
return $this->belongsTo('App\Http\Models\BlogCategories', 'category_id');
}
In effect all I want to do is be able to return to my view the total number of posts that each category has as shown below. Where x is the number of posts within each category.
cat1 (x)
cat2 (x)
cat3 (x)
It's not hard to count I know however as I only want a count I do not want to also retrieve the records as they are not required and I also do not want to create more queries than is necessary.
I have not completed the view as yet but probably a start would be to pass through the categories in a loop to display each and add the count at the same time?
#foreach ($categories as $category)
{!! $category->name !!} - {!! Count of posts here !!}
#endforeach
Hopefully that is clear(ish)!
Eager load the relation in your controller:
public function index()
{
$categories = Category::with('blog_posts')->get();
return view('categories.index', compact('categories'));
}
You can then use the count() method on the blog_posts relation when looping over categories in your view:
#foreach ($categories as $category)
<li>{{ $category->name }} ({{ $category->blog_posts->count() }})</li>
#endforeach
EDIT: Since Laravel 5.3, you can use withCount() to load counts of relations, i.e.
$categories = Category::withCount('blog_posts')->get();
This will make the count available via a property:
foreach ($categories as $category) {
$blog_posts_count = $category->blog_posts_count;
}
The nicest way to do it with eager loading support I know is to create a separate relation with the post count. Check this out:
public function blog_posts_count() {
return $this->hasOne('App\Http\Models\Blog_Post', 'category_id')
->selectRaw('category_id, count(*) as aggregate')
->groupBy('category_id');
}
public function getBlogPostsCountAttribute() {
if(!array_key_exists('blog_posts_count', $this->relations))
$this->load('blog_posts_count');
$related = $this->getRelation('blog_posts_count');
return $related ? (int) $related->aggregate : 0;
}
Usage is simple:
{{ $category->blog_posts_count }}