I have a categories table
CREATE TABLE categories (
name
clean_name
image
description
lft
rgt
)
I need to be able to query all products within a category, organized by sub-categories. In other words:
Products
-Electronics
--Portable
>>> Product 1
>>> Product 2
--TV
>>> Product 1
>>> Product 2
>>> Product 3
So I'd love to be able to loop over Electronics and display the products within their distinctive categories...
So far, all I've been able to do is use a raw query to return the categories, but all on one level, and no products.
Ideally, I'd love to use Eloquent to manage all of this...
Your questions not very clear about exactly what you have set up so far, but essentially you would want:
a categories table with an id and name
a products table with an id, a category_id and a name.
You then need a corresponding model for each:
//category model
Category extends Eloquent
{
public function products()
{
return $this->hasMany('Product');
}
}
//product model
Product extends Eloquent
{
public function category()
{
return $this->BelongsTo('Category');
}
}
You would then grab your categories with your products and perhaps use a nest loop like so:
$categories Category::with('Products')->get();
foreach($categories as $category)
{
echo '<h2>'.$category->name.'</h2>'
foreach($category->products as $product)
{
echo $product->name
}
}
Hope this helps, if not, you'll need to post some more details about what you have so far
Related
I'm using Laravel 5 and I need to know the number of books by category, these data I will use on google charts.
I have the code below that I use to find out the number of users by sex. However, the data is in the same table.
$data = DB::table('books')
->select(
DB::raw('category_id as category'),
DB::raw('count(*) as number'))
->groupBy('category')
->get();
$array[] = ['Category', 'Number'];
foreach($data as $key => $value)
{
$array[++$key] = [$value->category->name, $value->number];
}
$test = json_encode($array);
Using the same logic as above, how can I get the number of books by category?
I have the Books table:
ID | Name | ID_CATEGORY
1 Laravel 20
2 Java 20
Category table :
ID | Name
20 Programming
Could you help me in this situation?
You should just group by your ID_CATEGORY column instead of sex.
If you want to construct such array as before, you probably want the name of category. That would be easy if you used Eloquent. You would have $value->category->Name_Category available. If you want those preloaded instead of a query for every value, just add ->with('category') to the query and you'll have it.
If you are not using Eloquent, you should just load the category table separately, key it, and use $categories[$value->ID_CATEGORY]->Name_Category.
Other comments
DB::raw('sex as sex') is equivalent to sex.
++$key seems redundant, you could just push to the end by assigning to $array[].
Array with a header row is not very JSON. Typically you'd have key:value pairs all of the time.
You can construct the array using collection methods.
If you don't have good reasons for the opposite, you should stick to Laravel naming conventions.
I would probably not create an array myself, but do your example as something like this:
$stats = User::select('sex', DB::raw('count(*) as number'))
->groupBy('sex')
->get();
$stats->setVisible(['sex', 'number']);
return $stats;
I'm trying to add a multi-level categories in my website. where a category can have multiple child and also have multiple parent. It's look like many to many relationship in Laravel and I have to use a pivot table.
So that i create a table called categories and also a pivot table categories_reltionship like below. Now my question is how i will make this many to many relationship with this single table in Laravel.
categories table
==================
id title
=== ======
1 title_1
2 title_2
3 title_3
4 title_4
5 title_5
categories_relationship table
==================
parent_id child_id
========== ======
1 2
1 3
4 2
4 3
5 2
5 3
You can have methods like below on Category model :
//This will get you the list of categories
public function categories()
{
return ($this->hasManyThrough('App\Models\Category', 'App\Models\CategoryRelation', 'child_id', 'id', 'id', 'parent_id'));
}
//This will get you the list of children
public function childs()
{
return ($this->hasManyThrough('App\Models\Category', 'App\Models\CategoryRelation', 'parent_id', 'id', 'id', 'child_id'));
}
on CategoryRelation model :
class CategoryRelation extends Model
{
protected $table = 'categories_relationship';
}
I hope this will help you to solve your problem
Note : I suggest you to have 3 tables for many to many relationships,
in many to many relationship you should to have three tables. I hope that help you below example.
in our scenario as mentioned we have three tables with user , role and pivot names that each user can many roles and each role independent to many users.
user table have my_user_id(optional name) and other need column.
role table to have my_role_id (optional name) and other.
pivot table includes my_user_id , my_role_id.
in User model your codes should like below:
class User extends Model
{
public function roles()
{
return $this->belongsToMany('App\Role', 'pivot', 'my_user_id', 'my_role_id');
}
}
in Role model your codes should like below:
class Role extends Model
{
public function users()
{
return $this->belongsToMany('App\User', 'pivot', 'my_role_id', 'my_user_id');
}
}
You can also refer to laravel official documentation:
many to many relationships
The is the table structure,which basically has three tables,namely expenses,categories and sunbcategories
table expenses
(id,category_id,sub_category_id,date,description,amount)
table categories
(id,category_name)
table subcategories
(id,sub_category_name,category_id)
This is the SQL query that is needed
select expense.date, expense.description, expense.amount,
category.category_name, subcategory.sub_category_name
from expenses as expense,categories as category,subcategories as subcategory
where expense.category_id=category.id and
category.id=subcategory.category_id);
This is the function in Expense model with which I pass the category_id
The same query mentioned above is written in laravel, but I am not able to
fetch the data.
function fetchExpenseData($categoryId)
{
$expense = Expense::select("expenses.*","categories.category_name as
Categoryname","subcategories.Sub_category_name")
->join("categories","categories.id","=","expenses.category_id");
->join("subcategories",function($join)
{
$join>on("subcategories.category_id","=","expenses.category_id")
->on("suncategories.id","=","expenses.sub_category_id")
})->get();
return $expenses;
}
$expenses that are returned will be printed in blade.php.
Can I know what is the mistake
thanks in advance
Hye there ,
You need to add eloquent model for retrieving data fromenter code here three tables
Like
I have School Table , Student Table , Teacher Table
School is relating with both Student and Teacher then we will add relationship
In School Model
`
public function getStudent(){
return $this->hasMany('student_id' , App\Student);
}
public function getTeachers(){
return $this->hasMany('teacher_id' , App\Teacher);
}
In Student table
public function getSchool(){
return $this->hasOne('school_id' , App\School);
}
`
now call data from student
`
$students = Student::with('getSchool.getTeachers')->get()
This Demonstration for what I have get from your Question
I have one-to-one relationship between Post and Category. Let me try to illustrate columns. Post columns:
| id | pr_name | pr_description | ..... | `category_id`
And here is Category columns
| id | name
So what am I trying to do is the following. Category is already defined by me and will have only names of Categories. I should retrieve the name of category in my Blade.php file using it's id like this: $post->category->name. But I get error: Trying to get property of non-object. Here are my models: Model of Post
class Post extends Model
{
public function category()
{
return $this->hasOne('App\Like','id','category_id'); // 'id' is foreign key,
// 'category_id' is local key
}
}
Model of Category:
class Category extends Model
{
public function post()
{
return $this->belongTo('App\Post');
}
}
Changed Like to category. And relationship, where Category hasOne('App\Post') and Post model belongsTo('App\Category')
This query gives a pagination of all 'albums' with a picture and description for each. Now I am trying to get always the latest picture of each album.
I have tried to add a second orderBy('pics.created_at') , but that did not work. I think I need some kind of subquery but don't know how.
$query = AlbumPic::select(DB::raw('COUNT(pics.id) as picscount,
pics.url,
pics.user_id,
pics.created_at,
albums.id as album_id,
albums.title,
albums.text,
users.username'))
->join('albums','albums.id','=','album_pic.album_id')
->join('pics','pics.id','=','album_pic.pic_id')
->join('users','users.id','=','pics.user_id');
if(!is_null($user_id))
$query->where('album_pic.user_id',$user_id);
$albums = $query->groupBy('albums.id')
->orderBy('albums.created_at','desc')
->paginate(20);
edit
I made a mistake. I don't have created_at and updated_at in the album_pic table .
So my 'Album' - model/relations are now like this:
public function pics()
{
return $this->belongsToMany('Pic');
}
public function latestPic()
{
return $this->belongsToMany('Pic')->latest('pics.created_at');
}
And the query now looks like this:
$q = Album::with('pics')->with('latestPic.users');
if(!is_null($user_id))
$q->where('albums.user_id',$user_id);
$albums = $q->orderBy('albums.created_at','desc')
->paginate(20);
This works. Only thing I would like to improve is the way, the pictures per album are counted. Now I get all with with('pics') and then do a count($album->pics) in the view. If there is a way to not load everything, but only count the pictures, it would be nice.
You need to get the MAX(created_at) inside a subquery; see MySQL select MAX(datetime) not returning max value for example.
Really, though, if you're doing this in Laravel, it would be better to set these all up as relations and leverage the power of Eloquent. Then, you can define a relationship for pictures that uses ->latest() to return the most recent. See laravel eloquent query group by last id for an example (which uses one table, but the principle is the same for multiple tables).
Here's how you could set this up using Eloquent relations:
User model (User.php)
class User extends Eloquent {
public function albums()
{
return $this->hasMany('Album');
}
}
Album model (Album.php)
class Album extends Eloquent {
public function pics()
{
return $this->belongsToMany('Pic');
}
public function latestPic()
{
return $this->belongsToMany('Pic')->latest('album_pic.created_at');
}
}
Because you have a many-to-many relationship between albums and pics, in the latestPic() relation, you must specify the album_pic.created_at field for latest()—since we are actually interested in the order of entries in the pivot table, rather than in the pics table.
Finally, link this all together. For example, for a user with id of 1:
$albums = User::find(1)->albums()->with('pics')->with('latestPic')->paginate(20);
foreach($albums as $album) {
echo('<br>Album:');
var_dump($album->title);
echo('All pics:');
foreach($album->pics as $pic) {
var_dump($pic->url);
}
echo('Latest pic:');
$latestPic = $album->latestPic->first();
if ($latestPic) {
var_dump($latestPic->url);
}
}
Note that we are eager loading the pics and latestPic to reduce the number on calls to the database. Also note that accessing the $latestPic->url is wrapped in an if statement, otherwise albums that do not have any photos will throw an error since $album->latestPic would return null.
As #cedie correctly noted, Laravel doesn't handle pagination all that efficiently when using a groupBy statement, but that shouldn't be a problem in this case. The underlying queries do not use groupBy, so you should be save to use ->paginate(20).
Try using this in your select query:
max(pics.created_at) as created_at
instead of this:
pics.created_at
So your code should look like this:
AlbumPic::select(DB::raw('COUNT(pics.id) as picscount,
pics.url,
pics.user_id,
max(pics.created_at) as created_at,
albums.id as album_id,
albums.title,
albums.text,
users.username'))
Perhaps ypu can figure out how to adapt this for your purposes...
SELECT ap.*
, p.*
FROM album_pic ap
JOIN pics p
ON p.id = ap.pic_id
JOIN
( SELECT ap.*
, MAX(p.created_at) max_created_at
FROM album_pics ap
JOIN p.*
ON p.id = ap.pic_id
) x
ON x.album_id = ap.album_id
AND x.max_created_at = p.created_at;