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
Related
So, my problem is that I need to build a tree with data from two tables.
I have the following tables:
Category:
| id | parent_id | name |
|----|-----------|----------------|
| 1 | null | Category 1 |
| 2 | 1 | Category 1.1 |
| 3 | 2 | Category 1.1.1 |
| 4 | null | Category 2 |
| 5 | 4 | Category 2.1 |
| 6 | null | Category 3 |
Layer:
| id | category_id | name |
|----|-------------|---------|
| 1 | 2 | Layer 1 |
| 2 | 2 | Layer 2 |
| 3 | 3 | Layer 3 |
| 4 | 4 | Layer 4 |
| 5 | 4 | Layer 5 |
| 6 | 5 | Layer 6 |
My Category model:
class Category extends Model
{
public function parent()
{
return $this->belongsTo('App\Category', 'parent_id');
}
public function childrens()
{
return $this->hasMany('App\Category', 'parent_id', 'id');
}
public function layers()
{
return $this->hasMany('App\Layer', 'category_id', 'id');
}
}
Layer model:
class Layer extends Model
{
public function category()
{
return $this->belongsTo('App\Category', 'category_id');
}
}
I'm using the following function to build the category tree:
public function index()
{
$categories = Category::all();
$layers = Layer::all();
return $this->buildTree($categories->toArray(), null);
}
function buildTree($categories, $parent_id)
{
$categoriesTree = [];
foreach ($categories as $category) {
$category['folder'] = true;
if ($category['parent_id'] == $parent_id) {
$childrens = $this->buildTree($categories, $category['id']);
if ($childrens) {
$category['childrens'] = $childrens;
}
$categoriesTree[] = $category;
}
}
return $categoriesTree;
}
The above function works well for categories and the response is:
Category 1
Category 1.1
Category 1.1.1
Category 2
Category 2.1
Category 3
But I want to add layers as child of respective category, like the following:
Category 1
Category 1.1
Category 1.1.1
Layer 3
Layer 1
Layer 2
Category 2
Category 2.1
Layer 6
Layer 4
Layer 5
Category 3
What is the best way to do this?
I suggest using a relationship in your Category model with the Layer model and eager load it. This way you achieve the same result but with less overhead on your buildTree function because Laravel is doing most of the work:
Category.php model
class Category extends Model
{
// ...
public function layers()
{
return $this->hasMany(Layer::class);
}
// ...
}
In your controller:
public function index()
{
$categories = Category::with('layers')->get();
// ...
}
This results in an array like this:
I have no idea how to solve this problem using Laravel Eloquent. So, I posted my question here.
I have tables like this:
+-------------+ +------------------------+
| POSTS | | COMMENTS |
|-------------| |------------------------|
| id | title | | id | text | post_id |
|-----+-------| |----+-------------------|
| 1 | A | | 1 | Lorem | 1 |
| 2 | B | | 2 | Ipsum | 1 |
+-------------+ | 3 | Dolor | 1 |
| 4 | Sit | 1 |
| 5 | Amet | 2 |
| 6 | Lorem 2 | 2 |
+------------------------+
I currently have 2 models, Post model
class Post extends Model
{
public function comment() {
$this->hasMany('App\Comment');
}
}
and Comment model
class Comment extends Model
{
public function comment() {
$this->belongsTo('App\Post');
}
}
The question is, What should I do on the controller so I can make each post has a comment count result? Or simply, just like the table below.
+-----------------------------------------+
| COMMENT COUNT |
|-----------------------------------------|
| posts.id | count(comments.post_id) AS n |
|----------+------------------------------|
| 1 | 4 |
| 2 | 2 |
+-----------------------------------------+
Thanks.
You forgot to return the relationships. So, the models should be defined as:
class Post extends Model
{
public function comments()
{
return $this->hasMany('App\Comment');
}
}
class Comment extends Model
{
public function post()
{
return $this->belongsTo('App\Post');
}
}
Now you can count the post comments as:
echo $post->comments()->count();
or even
echo $post->comments->count();
The difference between these 2 methods is that the latest one is getting and caching the post comments as well.
So I have the following match table which contains the numbers of the teams that participated in that match. I want to set up a relationship with the teams which looks something like this:
Teams Table
| id | number | name | etc |
| 1 | 1234 | Example | etc |
| 2 | 2345 | Example | etc |
etc...
Matches Table
| id | match | red1 | red2 | blue1 | blue2 |
| 1 | 1 | 1234 | 1710 | 673 | 2643 |
| 2 | 2 | 2345 | 1677 | 4366 | 246 |
etc...
I want to have something like $this->match->where("match", "=", "2")->first()->teams();.
I have tried using hasMany() but I can't seem to get to use the red1, red2, blue1, blue3 columns.
What I have tried:
class Matches extends Model
{
protected $table = "match_table";
protected $fillable = [
"match_id",
"time",
"bluescore",
"redscore",
"red1",
"red2",
"red3",
"blue1",
"blue2",
"blue3",
];
public function teams()
{
return $this->hasMany("App\Models\Teams", "number", ["red1", "red2", "blue1", "blue2"]);
}
}
What I ended up doing was just looping through each column I wanted and then just returning a new Collection with the results in it.
public function teams()
{
$result = [];
foreach($this::$teamColumns as $column) {
$result[] = $this->hasMany("App\Models\Teams", "number", $column)->first();
}
return new Collection($result);
}
I'm trying Eloquent now with high expectations.
I have a category tree.
Everything works fine. But now I want to return the whole tree as json. Therefore I'm doing:
$categories = Category::whereNull('parent_id')->get()->toJson();
And only get the adam and eve nodes.
[{"category_id":1,"name":"Boats","slug":"boats","parent_id":null},
{"category_id":2,"name":"Paddles","slug":"paddles","parent_id":null}]
Which is good basically. How to integrate the childs recursivly? No "native" eloquent way for that?
Tree like this:
select * from categories;
+-------------+----------------+----------------+-----------+
| category_id | name | slug | parent_id |
+-------------+----------------+----------------+-----------+
| 1 | Boats | boats | NULL |
| 2 | Paddles | paddles | NULL |
| 3 | Kayaks | kayaks | 1 |
| 4 | Canoes | canoes | 1 |
| 5 | Carbon Paddles | carbon-paddles | 2 |
| 6 | Vajda K1 | vajda-k1 | 4 |
| 7 | Dagger RPM | dagger-rpm | 3 |
| 8 | Kober Viper | vober-viper | 2 |
+-------------+----------------+----------------+-----------+
8 rows in set (0.03 sec)
and a model like that
class Category extends Eloquent {
protected $table = 'categories';
protected $primaryKey = 'category_id';
protected $fillable = array("name", "slug", "parent_id");
public $timestamps = FALSE;
// each category has many subcategories
public function childs() {
return $this->hasMany('Category');
}
// each category belogs to one parent category
public function parent() {
return $this->belongsTo('Category');
}
}
AS far as I know there is no native way to get a recursive result from eloquent directly.
For the first level you would use:
$categories = Category::whereNull('parent_id')->with('childs')->get()->toJson();
For the next level (and likewise further on):
$categories = Category::whereNull('parent_id')->with(['childs' => function ($query) {
$query->with('childs');
}])->get()->toJson();
Using Lazy Eager Loading you'll be able to build your own PHP giveMeMyCatTree() methode.
Does this help?
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.