Create a nested lists of categories in Laravel 5 - php

Am fairly new to Laravel and am trying to create a tree-like categories structure for my app. This is the code have I used to far but still unable to achieve what I want.
My controller:
public function index()
{
$categories = Category::with('children')->get();
return view('backend.categories.index')->with('categories', $categories);
}
My category model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $guarded = ['id'];
public function parent()
{
return $this->belongsTo('App\Category', 'parent_id');
}
public function children()
{
return $this->hasMany('App\Category', 'parent_id');
}
}
My view:
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Slug</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach ($categories as $category)
{{--#foreach ($category->children as $children)--}}
<tr>
<td>{{ $category->name }}</td>
<td>{{ $category->description }}</td>
<td>{{ $category->slug }}</td>
<td><a class="edit" href="{!! action('Admin\CategoriesController#edit', $category->id) !!}" title="Edit"><i class="fa fa-pencil-square-o"></a></i> <a class="delete" href="{!! action('Admin\CategoriesController#destroy', $category->id) !!}" title="Are you sure you want to delete?"><i class="fa fa-trash-o"></i></a></td>
#foreach ($category->children as $children)
<tr>
<td>{{ $children->name }}</td>
<td>{{ $children->description }}</td>
<td>{{ $children->slug }}</td>
<td></td>
</tr>
#endforeach
</tr>
</tbody>
{{--#endforeach--}}
#endforeach
</table>
Am trying to produce a structure like below:
Fashion Accessories
Bags
Cloths
Mobile Phones
Tablets
Smartphones
EDIT
There is my database structure:
+-------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| slug | varchar(255) | NO | | NULL | |
| parent_id | int(11) | YES | | NULL | |
| description | text | NO | | NULL | |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+-------------+------------------+------+-----+---------------------+----------------+

You are currently loading all categories (including the child ones) and then looping through them. You only want to load the root categories (categories without parent). To do this, change your controller method to only load categories where the parent_id is null.
$categories = Category::whereNull('parent_id')->with('children')->get();

Probably in model you need to change inorder to refer to children model:
public function children()
{
return $this->hasMany('App\Children', 'parent_id');
}
Model for category:
class Category extends Model
{
protected $guarded = ['id'];
protected $fillable = array('name','description','slug','created_at','updated_at');
public function children()
{
return $this->hasMany('App\Children', 'parent_id');
}
}
Model for childrens:
class Children extends Model {
protected $table = 'children';
protected $fillable = array('name','description','parent_id','created_at','updated_at');
}
In controller get categories with children like this:
$categories = Category::with(['children'])->get();
and correct the tags -- <i class="fa fa-pencil-square-o"></i></a>
then in the view:
#foreach ($categories as $category)
<ul>
<li>{{ $category->name }}</li>
<li>{{ $category->description }}</li>
<li>{{ $category->slug }}</li>
<li><a class="edit" href="{!! action('Admin\CategoriesController#edit', $category->id) !!}" title="Edit"><i class="fa fa-pencil-square-o"></i></a> <a class="delete" href="{!! action('Admin\CategoriesController#destroy', $category->id) !!}" title="Are you sure you want to delete?"><i class="fa fa-trash-o"></i></a></li>
#foreach ($category->children as $children)
<ul>
<li>{{ $children->name }}</li>
<li>{{ $children->description }}</li>
<li>{{ $children->slug }}</li>
<li></li>
</ul>
#endforeach
</ul>
#endforeach

Related

How to return images sequentially inside a "for loop"?

My view displays collections from four different tables. $redtable is my longest collection.
#for ($i = 0; $counter < $redtable->count(); $i++)
<div>
{{ $red->slice($i, 1)->first()?->content }}
{{ $green->slice($i, 1)->first()?->content }}
{{ $blue->slice($i, 1)->first()?->content }}
{{ $gray->slice($i, 1)->first()?->content }}
<div>
#endfor
My image table:
+----+------------------------------------+-------------------------+--------------+
| id | image | imageable_type | imageable_id |
+----+------------------------------------+-------------------------+--------------+
| 1 | /path/redtable/image.png | App\Models\Red | 1 |
| 2 | /path/greentable/image.png | App\Models\Green | 1 |
| 3 | /path/blue/image1.png | App\Models\Blue | 1 |
| 4 | /path/blue/image2.png | App\Models\Blue | 1 |
| 5 | /path/blue/image3.png | App\Models\Blue | 1 |
| 6 | /path/blue/image4.png | App\Models\Blue | 1 |
| 7 | /path/blue/image5.png | App\Models\Blue | 1 |
| 8 | /path/gray/image.png | App\Models\Gray | 2 |
+----+------------------------------------+-------------------------+--------------+
My Controller:
class ColorsController extends Controller
{
public function index()
{
$red = \App\Models\Red::with('polymorphicRelationship')->limit(3)->orderby('id', 'desc')->get();
$green = \App\Models\Green::with('polymorphicRelationship')->limit(3)->orderby('id', 'desc')->get();
$blue = \App\Models\Blue::with('polymorphicRelationship')->limit(3)->orderby('id', 'desc')->get();
$gray = \App\Models\Gray::with('polymorphicRelationship')->limit(3)->orderby('id', 'desc')->get();
return view('home.colors', [
'red' => $red,
'green' => $green,
'blue' => $blue,
'gray' => $gray
]);
}
How to display the images of the "Model Blue" table in the view.
I did a test using $picture->first()?->polymorphicRelationship()->first()->image, but it only displays the image of the first line of the table.
#for ($i = 0; $counter < $red->count(); $i++)
<div class="general">
{{ $red->slice($i, 1)->first()?->content }}
{{ $green->slice($i, 1)->first()?->content }}
{{ $blue->slice($i, 1)->first()?->content }}
<div class="slide">
<!-- First slide image -->
{{ $blue->polymorphicRelationship->image1 }}
<!-- Second slide image -->
{{ $blue->polymorphicRelationship->image1 }}
<!-- Third slide image -->
{{ $blue->polymorphicRelationship->image1 }}
<!-- Fourth slide image -->
{{ $blue->polymorphicRelationship->image1 }}
<!-- Fifth slide image -->
{{ $blue->polymorphicRelationship->image1 }}
</div>
{{ $graytable->slice($i, 1)->first()?->content }}
</div>
#endfor
Assumming the relationship is defined as a polymorphic one to many, you can just add another loop.
Also you can replace slice($i, 1)->first() with get($i).
#for ($i = 0; $counter < $red->count(); $i++)
<div class="general">
{{ $red->get($i)?->content }}
{{ $green->get($i)?->content }}
{{ $blue->get($i)?->content }}
<div class="slide">
#foreach ($blue->polymorphicRelationship as $image)
{{ $image->image }}
#endforeach
</div>
{{ $graytable->get($i)?->content }}
</div>
#endfor

Symfony4: routing references another page

After updating from Symfony 3.4 to 4.4 and verifying the operation, I found that app_hq_article_trendtag in input.html.twig refers to another page. The reference destination was B of ArticleController.
As of Symfony 3.4, it worked fine.
Did you make a mistake in the settings? If there is something else to check other than the command
please tell me.
I also changed some code and checked the operation.
Change #Template("#AppBundle/Hq/Article/index.html.twig") of ArticleController to another page-> Another page is displayed.
Change #Template("#AppBundle/Hq/Article/trendTag.html.twig") of ArticleController to another page-> No change
Change app_hq_article_trendtag of input.html.twig to another page-> Another page is displayed.
ArticleController
* #Route("/hq")
*/
class ArticleController extends BaseArticleController
{
protected $indexRoute = "app_hq_article_index";
protected function getInputTemplate($articleType)
{
return sprintf("#AppBundle/Hq/%s/input.html.twig", ucfirst($articleType));
}
/**
* #Method("GET")
* #Route("/article/")
*
* #Template("#AppBundle/Hq/Article/index.html.twig")
*/
public function indexAction(Request $request)
{
return parent::indexAction($request);
}
/**
* #Method("GET")
* #Route("/article/trendtag")
*
* #Template("#AppBundle/Hq/Article/trendTag.html.twig")
*/
public function trendTagAction(Request $request)
{
return parent::trendTagAction($request);
}
Brandevent/input.html.twig
{{ form_start(form) }}
<div class="formGroup trendTags" data-prototype="{{ macros.trendTagForm(form.trendTags.vars.prototype)|e }}" data-index="{{ ec_tag_contents|length }}">
<label>Tag</label>
<button type="button" class="add btn">Add</button>
<ul class="trend-tag-list2" {% if not ec_tag_contents|default %} style="display:none"{% endif %} id="trendTagsWrap">
{% for tag in ec_tag_contents|default %}
<li>
<div class="tagForm">
<div class="input-trendtag-display-name"> {{ tag.name }}</div>
<div class="input-trendtag-display-term">({{ tag.str_tag_display }} {{ tag.str_term }})</div>
<br>
{% for category in tag.categories|split(',') %}
<div class="tag-form__category-sticker" name="{{ category }}">{{ category }}</div>
{% endfor %}
<button class="removeTrendTag"><i class="icon-remove"></i></button>
</div>
<div id="brandevent_trendTags_{{ loop.index0 }}">
<input type="hidden" id="brandevent_trendTags_{{ loop.index0 }}_trendTagId" name="brandevent[trendTags][{{ loop.index0 }}][trendTagId]" required="required" value="{{ tag.tag_id }}">
</div>
</li>
{% endfor %}
{% do form.trendTags.setRendered(true) %}
</ul>
</div>
{{ form_end(form) }}
//Problem part
{% set q = app.request.query.get("q")|default({}) %}
{% set trendTagUrl = path("app_hq_article_trendtag", {"q[sex]": q.sex|default(0), "q[brand_id]": q.brand_id|default(), "q[del_flg]": 0}) %}
<div id="trendTagDialog" title="Tag Select" data-url="{{ trendTagUrl }}">
</div>
Command
$ php bin/console debug:router app_hq_article_trendtag
+--------------+--------------------------------------------------------------------+
| Property | Value |
+--------------+--------------------------------------------------------------------+
| Route Name | app_hq_article_trendtag |
| Path | /admin/hq/article/trendtag |
| Path Regex | #^/admin/hq/article/trendtag$#sD |
| Host | ANY |
| Host Regex | |
| Scheme | http |
| Method | ANY |
| Requirements | NO CUSTOM |
| Class | Symfony\Component\Routing\Route |
| Defaults | _controller: AppBundle:Hq\Article:trendTag |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
| Callable | AppBundle\Controller\Hq\ArticleController::trendTagAction |
+--------------+--------------------------------------------------------------------+
If you change the order of the functions will work fine
when you try to get Route /hq/article/trendtag,it will get the first /hq/article that find it,so you can change it like the code below
the file is being read from the top, when it finds the route "/article/" before /article/trendtag even if you want to get /article/trendtag, he only considers the /article/ first part that found it.
* #Route("/hq")
*/
class ArticleController extends BaseArticleController
{
protected $indexRoute = "app_hq_article_index";
protected function getInputTemplate($articleType)
{
return sprintf("#AppBundle/Hq/%s/input.html.twig", ucfirst($articleType));
}
/**
* #Method("GET")
* #Route("/article/trendtag")
*
* #Template("#AppBundle/Hq/Article/trendTag.html.twig")
*/
public function trendTagAction(Request $request)
{
return parent::trendTagAction($request);
}
/**
* #Method("GET")
* #Route("/article/")
*
* #Template("#AppBundle/Hq/Article/index.html.twig")
*/
public function indexAction(Request $request)
{
return parent::indexAction($request);
}

Laravel Model Count By Relationship

I have an eCommerce site with a Product model and a ProductCategory model. I currently show products on the page from the Product model but would like to be able to get a list of all the categories with products in the current model and how many products are in each category. I can get the overall count but can't figure out how to get the list of categories being shown and how many results per category have been returned.
Product Model
Product_ID
Product_Name
Product_Description
Category_ID (Many-To-1: ProductCategory.Category_ID
ProductCategory Model
Category_ID
Category_Name
Currently, I access the results in the blade using...
#foreach($products->chunk(3) as $row)
<div class="item-row">
#foreach($row as $product)
<div class="item item-thumbnail" style="height: 250px;">
<a href="product_detail.html" class="item-image">
#if(empty($product->Images{0}->original_image))
<img style="width: 100px; height: 100px;"
src="https://example.com/100x100/d3d3d3/fff.gif&text=No+Image"
alt="" />
#else
<img style="width: 100px; height: 100px;"
src="https://cdn.example.com.au/products/{{$product->id}}/{{$product->Images{0}->original_image}}"
alt="" />
#endif
</a>
<div class="item-info">
<h4 class="item-title">
<a href="/store/{{$category->alias}}/{{$product->alias}}">
{{$product->product_name}}
</a>
</h4>
<p class="item-desc"> </p>
#if(empty($product->special_price))
<div class="item-price">
${{$product->normal_price}}
</div>
#else
<div class="item-price">
${{$product->special_price}}
</div>
<div class="item-discount-price">
${{$product->normal_price}}
</div>
#endif
</div>
</div>
#endforeach
</div>
#endforeach
And would like to be able to generate a list of all the categories with products displayed as...
#foreach($products->categories as $category)
<li>
{{$category->category_name}} ({{$category->count}})
</li>
#endforeach
All from within the same model.
Additional
If it helps clarify I don't want the model to change drastically in that I still want to be able to access the products in the model from the blade template as is currently done but would like to also be able to pull a list of categories such as the below example...
| Product_ID | Product_Name | Category_ID |
| ---------- | ------------ | ----------- |
| 1 | Product 1 | 1 |
| 2 | Product 2 | 1 |
| 3 | Product 3 | 2 |
| Category ID | Category Name |
| ----------- | ------------- |
| 1 | Category 1 |
| 2 | Category 2 |
And wind up with the following table on my page to show the product categories being shown in the results...
| Category Name | # Products |
| ------------- | ---------- |
| Category 1 | 2 |
| Category 2 | 1 |
It would be super helpful if you provided the code where you query the products and categories.
But here's essentially what you need to do. You need to make use of ->withCount(..):
$products = Product::with([
'categories' => function ($query) {
// Adds count of category-related products
$query->withCount('products as count');
},
])->get();
And then this would work in your view:
#foreach($products as $product)
#foreach($product->categories as $category)
<li>{{$category->category_name}} ({{$category->count}})</li>
#endforeach
#endforeach

Laravel5 Eloquent: How to get a few articles from special condition?

First, I'm sorry my poor english.
I want to got highest views with 5 articles.
I tried it, but I'm having problem with Eloquent query.
laravel source
<?php
$up = "SELECT id FROM articles WHERE id IN (SELECT id from (SELECT id FROM articles ORDER BY view_count DESC LIMIT 0,5) x)";
$builder = new \App\Article;
$query = $builder->selectRaw("articles.*, $up");
?>
#forelse($query->latest() as $article)
<img src="{{ $article->thumbnail }}" alt="{{ $article->title }}" title="{{ $article->title }}">
#empty
<p class="text-center text-danger">
empty...
</p>
#endforelse
DB query result
MariaDB [test]> SELECT id FROM articles WHERE id IN (SELECT id from (SELECT id FROM articles ORDER BY view_count DESC LIMIT 0,5) x);
+------+
| id |
+------+
| 4018 |
| 4045 |
| 3800 |
| 4011 |
| 4005 |
+------+
5 rows in set (0.00 sec)
I've seen the other posts on this topic, but i didn't get the solution.
Thanks for your help.
First you have to your services sttuf in the controller to clean up the views and to respect the MVC pattern.
So in the controller you can use Eloquent to do that :
$articles = App\Article::orderBy('view_count', 'desc')
->take(5)
->get();
return view('SomeView')->withArticles($articles);
And in SomeView.blade.php :
#forelse($articles as $article)
<img src="{{ $article->thumbnail }}" alt="{{ $article->title }}" title="{{ $article->title }}">
#empty
<p class="text-center text-danger">
empty...
</p>
#endforelse
5 articles ordered by views you just need to write in your controller:
$articles = Article::orderBy('views', DESC)->take(5)->get();
return view('article', ['articles' => $articles
]);
in your article.blade.php:
#forelse($articles() as $article)
<img src="{{ $article->thumbnail }}" alt="{{ $article->title }}" title="{{ $article->title }}">
#forelse
<p class="text-center text-danger">
empty...
</p>
#endforelese

How to retrive data from database to a treeview using laravel

My requirement is to construct the treeview using database values.
Here are my database tables:
| Categories | |sub_categories |
| id(pk) | | id(pk) |
| cate_name | | sub_cat_name |
| route_name | | route_name |
|Categories_id(fk)|
I'm getting categories and sub categories as well which are related to categories table.
Here is my Controller code:
$treeView = DB::table('categories')
->join('sub_categories', 'sub_categories.categories_id', '=', 'categories.id')
->get();
Here is the HTML structure in the *.blade.php :
#foreach($treeView as $tv)
<li class="treeview">
<a href="#"><i class="fa fa-link"></i> <span>{{ $tv->category_name }}</span> <i
class="fa fa-angle-left pull-right"></i></a>
<ul class="treeview-menu">
<li class="">{{$tv->sub_category_name}}</li>
<li>Update Article</li>
</ul>
</li>
#endforeach
But it doesn't work fine. It gives same main category again and again..
Can anyone suggest a proper way to retrieve data?
I suggest you use Eloquent, as it will make the code simpler and will make your life easier in the future.
Create model classes for your tables:
class Category extends Illuminate\Database\Eloquent\Model {
protected $table = 'Categories';
public function subcategories() {
return $this->hasMany(Subcategory::class, 'Categories_id');
}
}
class Subcategory extends Illuminate\Database\Eloquent\Model {
protected $table = 'sub_categories';
public function category() {
return $this->belongsTo(Category::class, 'Categories_id');
}
}
In your controller fetch data like that:
$treeView = Category::with(['subcategories'])->get();
And then in the view:
#foreach($treeView as $category)
<li class="treeview">
<i class="fa fa-link"></i> <span>{{ $category->cate_name }}</span> <i class="fa fa-angle-left pull-right"></i>
<ul class="treeview-menu">
#foreach($category->subcategories as $subcategory)
<li class="">{{$subcategory->sub_category_name}}</li>
#endforeach
</ul>
</li>
#endforeach
I can see that your categories and subcategories have the same stucture. You might consider storing them in the same table, just add a parent_id field to the table and set it to NULL for parent categories and to parent id for subcategories.

Categories