I need to show feeds with total comments, and total likes on that feed with the detail of users who have commented.
Feeds Table
| id | movie_id | user_id | description |
|----|----------|----------|-------------|
| 1 | 1 | 1 | Lorem Ipsum |
Comments Table
| id | feed_id | user_id | comment |
|----|-------- |----------|-----------|
| 1 | 1 | 2 | comment 1 |
| 2 | 1 | 3 | comment 2 |
Likes Table
| id | feed_id | user_id |
|----|-------- |----------|
| 1 | 1 | 2 |
| 2 | 1 | 3 |
Users Table
| id | username| email |
|----|-------- |--------|
| 1 | a | a#a.com|
| 2 | b | b#b.com|
| 3 | c | c#c.com|
Relations
Feed.php
public function user () {
return $this->belongsTo('App\User');
}
public function likes () {
return $this->hasMany('App\Like');
}
public function comments () {
return $this->hasMany('App\Comment');
}
User.php
public function feeds () {
return $this->belongsToMany('App\Feed');
}
public function like () {
return $this->belongsTo('App\Like');
}
public function comment () {
return $this->belongsTo('App\Comment');
}
Like.php
public function user () {
return $this->belongsTo('App\User');
}
public function feed () {
return $this->belongsTo('App\Feed');
}
Comment.php
public function user () {
return $this->belongsTo('App\User');
}
public function feed () {
return $this->belongsTo('App\Feed');
}
Now I need to fetch all feeds (I have done with this), with comments count, likes count, and users details who have commented.
Ho can I get that in single query using Eloquent.
Try this
$commentsCount = \App\Models\Comment::select('feed_id',\DB::raw('count(id) as comments_count'))->groupBy('feed_id')->toSql();
$likesCount = \App\Models\Like::select('feed_id',\DB::raw('count(id) as likes_count'))->groupBy('feed_id')->toSql();
$records = \DB::table('feeds as f')
->leftJoin('comments as c','f.id','=','c.feed_id')
->leftJoin('users as u','c.user_id','=','u.id')
->leftJoin(\DB::raw('('.$commentsCount.') as k'),'f.id','=','k.feed_id')
->leftJoin(\DB::raw('('.$likesCount.') as l'),'f.id','=','l.feed_id')
->select('f.id as fid','f.description','u.id as uid','u.name','u.email','k.comments_count','l.likes_count')
->orderBy('fid')
->get();
$transform = function(array $records){
$records = collect($records)->groupBy('fid');
return $records->transform(function($items){
$feed['id'] = $items->first()->fid;
$feed['description'] = $items->first()->description;
$feed['count'] = [
'likes' => is_null($items->first()->likes_count) ? 0 : $items->first()->likes_count,
'comments' => is_null($items->first()->comments_count) ? 0 : $items->first()->comments_count,
];
$feed['users'] = $items->transform(function($user){
return is_null($user->uid) ? [] : ['id'=>$user->uid,'name'=>$user->name,'email'=>$user->email];
});
return $feed;
});
};
return array_values($transform($records)->toArray());
you can swap the closure function with other function. like
$this->transform($records);
You can simply access all those properties through the functions defined.
Example:
$feed = Feed::find($id);
foreach($feed->likes() as $like){
echo $like->user()->get('username');
}
And so forth. Up to a point when you call ->get(), you are accessing an object, which can traverse all of these.
Related
I wrote a recursive function in order to echo a nested list. In fact it's a helper function in laravel that get a collection of nested items and supposed to go through it and print all items' name.
But when I using it in view, just the first level of items is printed.
It seems to doesn't execute itself at items_list($item->children());.
function items_list($items)
{
foreach($items as $item) {
if(!$item->hasChild())
{
echo "
<li>
".$item->id.".".$item->name."
</li>
";
return null;
}
else
{
echo "<li>".
$item->id.".".$item->name
."<ul>";
items_list($item->children());
echo "</ul></li>";
}
}
}
here is the collection of items:
| id | parent_id | name |
+----+-----------+---------------------+
| 1 | NULL | Dr. Shany Braun Jr. |
| 2 | NULL | Lily Jerde |
| 3 | NULL | Dr. Herbert Kunze |
| 4 | 1 | Ms. Shanie Skiles |
| 5 | 1 | Dr. Anissa Kunze |
| 6 | 2 | Maybelle Sawayn |
| 7 | 3 | Cassie Trantow Jr. |
| 8 | 5 | Gussie Smith |
| 9 | 5 | Carol Mueller |
| 10 | 7 | Shany Bayer |
+----+-----------+---------------------+
edit:
The input of function is in fact a collection of an eloquent model that has retrieved from database I have printed above.
And here is the model:
class Person extends Model
{
protected $table = 'people';
function parent()
{
return $this->belongsTo(self::class, 'parent_id');
}
function children()
{
return $this->hasMany(self::class,'parent_id');
}
static function first_level()
{
return self::all()->where('parent_id', NULL);
}
function hasChild()
{
return ($this->children() ? TRUE : FALSE);
}
}
I have tested each function of this class and they work ‌properly.
and here is controller:
class HomeController extends Controller
{
public function show(){
$people = Person::first_level();
items_list($people);
}
}
and this is the output:
1.Dr. Shany Braun Jr.
2.Lily Jerde
3.Dr. Herbert Kunze
I have two tables, school_users and users. I need to create a query, using Eloquent, that gets all users where user_id equal school_id.
so the result must be more than one user, so that also I need to group the result by school_id
thank you in davance
Relations:
User Model:
public function school()
{
return $this->hasMany(SchoolUser::class);
}
SchoolUser Model:
public function user()
{
return $this->hasMany(User::class);
}
School_users table:
+----+---------+------------+-------------+
| id | user_id | school_id | created_at |
+----+---------+------------+-------------+
| 1 | 79 | 79 | <SOME TIME> |
| 2 | 85 | 79 | <SOME TIME> |
| 3 | 86 | 85 | <SOME TIME> |
| 4 | 87 | 85 | <SOME TIME> |
+----+---------+------------+-------------+
users table:
+----+
| id |
+----+-
| 79 |
| 85 |
| 86 |
| 87 |
+----+-
User Model:
public function getUsers()
{
return $this
->leftJoin('school_users', $this->table . '.id', '=', 'school_users.school_id')
->select(
$this->table . '.*',
'school_users.school_id as school_id'
)
->whereIn('users.id', '=', 'school_users.school_id')
->orderBy('id', 'desc')
->get();
}
Use whereColumn to filter user_id equal to school_id,
and use join instead of leftjoin:
public function getUsers()
{
return $this
->join('school_users', function($join) {
$join->on('school_users.user_id', '=', $this->table.'.id')
->whereColumn('school_users.user_id', 'school_users.school_id');
})
->select
(
$this->table.'.*',
'school_users.school_id as school_id'
)
->orderBy($this->table.'.id','desc')
->get();
}
I got 4 tables:
// Table countries
+----+------+
| Id | Name |
+----+------+
| 1 | USA |
| 2 | GB |
+----+------+
// Table platforms
+----+---------+
| Id | Name |
+----+---------+
| 1 | Windows |
| 2 | Linux |
+----+---------+
// Table users
+----+-------+------------+-------------+
| Id | Name | country_id | platform_id |
+----+-------+------------+-------------+
| 1 | Admin | 1 | 1 |
| 2 | Test | 2 | 1 |
+----+-------+------------+-------------+
// Table posts
+----+-----------+------------+-------------+---------+
| Id | Title | country_id | platform_id | user_id |
+----+-----------+------------+-------------+---------+
| 1 | TestPost1 | 2 | 1 | 1 |
| 2 | TestPost2 | 2 | 2 | null |
+----+-----------+------------+-------------+---------+
The database should be able to implement the following relations:
User (N) <-> (N) Platform
User (N) <-> (N) Country
User (0..1) <-> (N) Post
Post (N) <-> (N) Country
Post (N) <-> (1) Platform
So now I tried to implement these relations following Laravel Eloquent ORM documentation:
// Country.php
public function posts()
{
return $this->belongsToMany('App\Post');
}
public function users()
{
return $this->belongsToMany('App\User');
}
// Platform.php
public function users()
{
return $this->belongsToMany('App\User');
}
public function posts()
{
return $this->belongsToMany('App\Post');
}
// User.php
public function posts()
{
return $this->hasMany('App\Post');
}
public function countries()
{
return $this->hasMany('App\Country');
}
public function platforms()
{
return $this->hasMany('App\Platform');
}
// Post.php
public function countries()
{
return $this->hasMany('App\Country');
}
public function platforms()
{
return $this->hasMany('App\Comment');
}
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
But now I am confused, as I thought the way to implement N to N relations in mysql is to add a third table to db, for example like that:
// Table CountryUserRelations to implement User (N) <-> (N) Country
+----+------------+---------+
| Id | country_id | user_id |
+----+------------+---------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 1 | 2 |
| 4 | 2 | 2 |
+----+------------+---------+
But how does Eloquent ORM handle the rules inside my model? Will it keep the N to N relations without having to add a relations table? Or am I missing something or misunderstanding the Eloquent ORM Relations concept?
I just joined stackoverflow so I do not have enough credit to comment so I will leave an asnwer here.
First of all please correct your relationship definition.
in User Model:( you have mistake here)
public function countries(){
return $this->belongsToMany(Country::class);
}
and in your Country Model:
public function users(){
return $this->belongsToMany(User::class);
}
second you need to create country_user table using:
php artisan make:migration create_country_user_table
after it you need to complete your table:
Schema::create('country_user', function (Blueprint $table){
$table->increments('id');
$table->unsignedInteger('country_id');
$table->unsignedInteger('user_id');
$table->foreign('country_id')->references('id')->on('countries');
$table->foreign('user_id')->references('id')->on('users');
}
I have these tables:
Entries table
---------------------------------
| id | blog_id | title |
---------------------------------
| 1 | 1 | 1st Entry |
---------------------------------
Blogs Table
-----------------
| id | name |
-----------------
| 1 | 1stBlog |
-----------------
Field Groups Table
-------------------------
| id | blog_id | name |
-------------------------
| 1 | 1 | Group1 |
-------------------------
Fields Table
---------------------------------
| id | field_group_id | name |
---------------------------------
| 1 | 1 | field_1 |
---------------------------------
Values Table
------------------------------------------
| id | field_id | entry_id | value |
------------------------------------------
| 1 | 1 | 1 | Hello World |
------------------------------------------
Now on my Models I've set up these relationships:
class Entry extends Model
{
public function blog()
{
return $this->belongsTo(Blog::class);
}
}
class Blog extends Model
{
public function entries()
{
return $this->hasMany(Entry::class);
}
public field_group()
{
return $this->hasOne(FieldGroup::class);
}
}
class FieldGroup extends Model
{
public function fields()
{
return $this->hasMany(Entry::class);
}
public function blog()
{
return $this->belongsTo(Blog::class);
}
}
class Field extends Model
{
public function group()
{
return $this->belongsTo(FieldGroup::class, 'field_group_id');
}
public function values()
{
// this method should get the values from the Values table per entry id
return $this->hasManyThrough(Value::class, Entry::class, 'id', 'entry_id');
}
}
class Value extends Model
{
public function field()
{
return $this->belongsTo(Field::class, 'field_id');
}
}
Using this query I can
$entry = Entry::with('blog.field_group.fields')->find(1)
I can get the entry, along with its blog, field groups and fields. I want to get the values associated with the entry too,
$entry = Entry::with('blog.field_group.fields.values')->find(1)
I am having trouble on which relationship to use. Any help is much appreciated. I just started using laravel.
Try it...
Replace ID by field_id:
return $this->hasManyThrough(Value::class, Entry::class, 'id', 'entry_id');
Like this:
return $this->hasManyThrough(Value::class, Entry::class, 'field_id', 'entry_id');
Because you are using the standard laravel column names you can simplify even more:
return $this->hasManyThrough(Value::class, Entry::class);
See in: https://laravel.com/docs/5.1/eloquent-relationships#has-many-through
I think you should use 'foreign_key' with 'hasMany' and 'hasOne'.
return $this->hasMany('Comment', 'foreign_key');
class Blog extends Model
{
public function entries()
{
return $this->hasMany(Entry::class, 'blog_id');
}
public field_group()
{
return $this->hasOne(FieldGroup::class, 'blog_id');
}
}
refer
http://laravel.com/docs/4.2/eloquent#one-to-many
I have two tables, posts and likes. I need to create a query, using Eloquent, that gets all posts that have been liked by a specific user_id.
In other words, it should be something like this:
SELECT * FROM posts p LEFT JOIN likes l ON p.id = l.post_id WHERE l.user_id = 2 ORDER BY l.created_at DESC
posts table:
+----+---------+------------+-------------+
| id | user_id | message | created_at |
+----+---------+------------+-------------+
| 1 | 2 | Hello! | <SOME TIME> |
| 2 | 3 | World! | <SOME TIME> |
| 3 | 2 | Something. | <SOME TIME> |
| 4 | 2 | Another. | <SOME TIME> |
+----+---------+------------+-------------+
likes table:
+----+---------+---------+-------------+
| id | post_id | user_id | created_at |
+----+---------+---------+-------------+
| 1 | 1 | 2 | <SOME TIME> |
| 2 | 2 | 2 | <SOME TIME> |
| 3 | 1 | 3 | <SOME TIME> |
| 4 | 3 | 2 | <SOME TIME> |
+----+---------+---------+-------------+
Here is my Postclass:
<?php
class Post extends Eloquent {
protected $table = 'posts';
public function likes()
{
return $this->hasMany('Like');
}
}
And the Like class:
<?php
class Like extends Eloquent {
protected $table = 'likes';
public function post()
{
return $this->belongsTo('Post');
}
}
How can I do this?
This should work:
$userId = //however you get the userid here.
$posts = Post::whereHas('likes', function ($q) use ($userId) {
$q->where('user_id', $user_id);
})->get();
You can use Laravel's DB class to perform joins on two or more tables, following is how your query will be executed in laravel:
$users = DB::table('posts')
->leftJoin('likes', 'posts.id', '=', 'likes.post_id')
->select('posts.*', 'likes.*')
->where('likes.user_id', '=', '2')
->orderBy('likes.created_at', 'desc')
->get();
Don't forget to use DB class on the top of your controller;
If you want to do it with eloquent, you should do the follwing:
$result = Post::whereHas('likes', function ($q) use($user_id)
{
$q->where('user_id', $user_id);
})
->orderBy('likes.created_at')
->get();