I can't retrieve data from the related table(model) in Laravel6 - laravel

I can't retrieve data from the related table.
There are 3 models(tables).
User
Chirp (has 'user_id' as foreign key)
Click (has 'chirp_id' as foreign key)
then I want to retrieve User & Click's data from Chirp model.
So I wrote:
Chirp.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Chirp extends Model
{
public $timestamps = false;
protected $guarded = [];
public function user()
{
return $this->belongsTo('App\User');
}
public function clicks()
{
return $this->hasMany('App\Click');
}
}
HomeController.php
class HomeController extends Controller
{
public function index()
{
$chirps = Chirp::with(['user','clicks'])
->orderBy('posted_at', 'desc')
->get();
return view('home', ['chirps' => $chirps]);
}
}
home.blade.php
#foreach($chirps as $chirp)
<div>
<div>by
<b>{{ $chirp->user->name }}</b>
on
<small>{{ $chirp->posted_at }}</small>
</div>
<div>
<p>{{ $chirp->text }}</p>
<p>{{ $chirp->click->ip_address }}</p>
</div>
</div>
#endforeach
at home.blade.php, {{ $chirp->click->ip_address }} can't be retrieved and get error "Facade\Ignition\Exceptions\ViewException Trying to get property 'ip_address' of non-object"
However, if I delete it, I can retrieve {{ $chirp->user->name }} properly.
Why can't I retrieve Click model from Chirp model, While I can retrieve User model from Chirp model?
Thank you.

You need to loop over your clicks as well:
#foreach($chirps as $chirp)
<div>
<div>by
<b>{{ $chirp->user->name }}</b>
on
<small>{{ $chirp->posted_at }}</small>
</div>
#foreach($chirp->clicks as $click)
<div>
<p>{{ $chirp->text }}</p>
<p>{{ $click->ip_address }}</p>
</div>
#endforeach
</div>
#endforeach

Chirp has many clicks (not click). You have to foreach $chirp->clicks in your blade.
#foreach ($chirp->clicks as $click)
<p>This is click id {{ $click->id }}</p>
#endforeach

You've hasMany relation with Chirp and clicks
And here you're getting many clicks instead of click
#foreach($chirp->clicks as $click)
<p>{{ $click->ip_address }}</p>
#endforeach

To debug this problem you can take the following steps:
Check if the chirps variable has any data within the controller.
dd($chirps);
If you know you have the data you can take the steps to make your blade better.
Becasue its a many to many relation you should loop trough the data.
#foreach($chirps as $chirp)
#foreach($chirp->clicks as $click)
<div>
<p>{{ $chirp->text }}</p>
<p>{{ $click->ip_address }}</p>
</div>
#endforeach
#endforeach

Related

property does not refresh in the internal components of Livewire

Take a look at the following examples:
showPost.blade.php:
<div>
<livewire:content-box :content="$post"/>
<button wire:click="nextPost" >Next Post >></button>
</div>
and
content-box.blade.php :
<div>
<h1>{{ $content->title }}</h1>
<p>{{ $content->content }}</p>
</div>
So far, it is completely clear what is going to happen ...: First, the information of the content to be viewed is received through showPost and passed to the contentBox, and everything is OK ..
Well now I want to get the information of the next content via the account through the button I put and calling the nextPost method:
class ShowPost extends Component
{
public Post $post;
public function render()
{
return view('livewire.show-post');
}
public function nextPost()
{
$id = $this->post->id;
$nextPost = Post::where('id', '>', $id)->first();
$this->post = $nextPost;
}
...
But nothing happens and the contentBox component has no reaction .... Has anyone had this problem ???!
I'm not sure livewire works well with nested components. could use the pagination instead. The livewire docs suggest you should not use them for little snippets or use blade components for that kind of nesting.
You can achieve what you're doing at the moment with some simple pagination.
<?php
namespace App\Http\Livewire;
use App\Models\User;
use Livewire\Component;
use Livewire\WithPagination;
class SomeContent extends Component
{
use WithPagination;
public function render()
{
// Using simplePaginate(1) instead of paginate(1).
// simplePaginate only shows "<- Previous" and "Next ->" links
// paginate shows those 2 buttons but also page numbers which you don't seem to want.
return view('livewire.some-content', [
'users' => User::simplePaginate(1),
]);
}
}
<div>
{{-- This might look wrong, but essentially it's looping through an array of length 1 because we're paginating --}}
#foreach ($users as $user)
<h1>{{ $user->name }}</h1>
<h2>{{ $user->email }}</h2>
#endforeach
{!! $users->links() !!}
</div>
EDIT
I can confirm blade components work.
Here, nextUser is the same implementation you gave.
public function nextUser()
{
$id = $this->user->id;
$nextUser = User::where('id', '>', $id)->first();
$this->user = $nextUser;
}
<div class="container">
<div class="content">
{{-- These two have the exact same template --}}
<livewire:child :user="$user" />{{-- Doesn't update when clicking Next --}}
<x-blade-child :user="$user" />{{-- Updates when clicking Next --}}
</div>
<div>
<button wire:click="nextUser">Next</button>
</div>
</div>
When clicking nextUser, the blade component updates but the livewire one doesn't.
Livewire doesn't like nested components. In your case, we can use basic blade component:
<div>
<x-content-box :content="$post"/>
<button wire:click="nextPost" >Next Post >></button>
</div>
And then:
Move content-box.blade.php to resources/views/components/
Remove component_name.php file in app/Http/Livewire
Most of the time, we can change 2 nested livewire components to livewire(parent) + basic blade component(child),

Showing data from database using Laravel Eloquent Model

So, I'm quite new to Laravel and what I am trying to achieve is to display some string from my data to a page. I'm using Eloquent Model and I can't figure out what I do wrong here. I've attached some of my code below. I hope I make it clear enough.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Product;
class ProductsController extends Controller
{
public function index()
{
$products = Product::all();
return view('products.index')->with('products', $products);
}
Here's where I want the data to be displayed.
#extends ('layouts.app')
#section ('content')
<div class="container-fluid">
<h1>Products</h1>
#if(count($products) > 1 )
#foreach ($products as $product)
<div class="well">
<h3>{{$product->prod_name}}</h3>
</div>
#endforeach
#else
<p>No product found</p>
#endif
</div>
#endsection
UPDATED: The problem is with my loop logic
Since I have only one item inside my database, my loop is supposed to be >= 1 instead of > 1
#if(count($products) >= 1 )
#foreach ($products as $product)
<div class="well">
<h3>{{$product->prod_name}}</h3>
</div>
#endforeach
#else
<p>No product found</p>
#endif
Let's fix up your code and use the correct approach.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Product;
class ProductsController extends Controller
{
public function index()
{
$products = Product::all();
return view('products.index', compact('products'));
}
Notice how I've passed an array via compact as the 2nd parameter of the view function. You can also use view('products.index', ['products' => $products]), I just prefer compact as it is cleaner.
#extends('layouts.app')
#section('content')
<div class="container-fluid">
<h1>Products</h1>
#if(!$products->isEmpty())
#foreach($products as $product)
<div class="well">
<h3>{{ $product->prod_name }}</h3>
</div>
#endforeach
#else
<p>No products found.</p>
#endif
</div>
#endsection
Notice how I've made use of isEmpty, which checks if a collection (obtained here from Eloquent) is empty or not.
Instead of with() maybe View::share can work.
$products = Product::all();
View::share('$products',$products);
return view('products.index');
And dont forget to import View class from Facades. Put this at the begining of page
use Illuminate\Support\Facades\View;

Undefined index: id Laravel 5.8

My Tables:
kategoris table
id | kode_kategori | kategori_name |
items table
id | kategori_id | item_name
In items table the kategori_id column has foreignkey.
My Controller:
public function edit($id)
{
// $item = Item::findOrFail($id);
$item = DB::table('items')
->join('kategoris', 'items.kategori_id', '=', 'kategoris.id')
->where('items.id', '=', $id)
->select('items.*', 'kategoris.*', 'items.id', 'items.kategori_id')
->get();
// dd($item);
return view('master-dev/item/edit', compact('item'));
}
My View:
<div class="card card-default">
{{ Form::model($item,['route'=>['item.update',$item['id']], 'files'=>true,'method'=>'PUT']) }}
<div class="card-header">
<h3 class="card-title"><b>Edit Data Item</b></h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>
</div>
</div>
<!-- /.card-header -->
<div class="card-body">
#if(!empty($errors->all()))
<div class="alert alert-danger">
{{ Html::ul($errors->all())}}
</div>
#endif
<div class="row">
<div class="col-md-6">
<div class="form-group">
{{ Form::label('kode_kategori', 'Kode Kategori') }}
<select name="kode_kategori" id="kode_kategori" class="form-control">
#foreach ($item as $i)
<option valu="{{ $i['kode_kategori'] }}">{{ $i['kode_kategori'] }}</option>
#endforeach
</select>
</div>
</div>
..........
..........
{{ Form::close() }}
I've tried any solutions in stackoverflow such as adding (ifempty...) and other solution but still the result Undefined index: id in my edit blade. When I was trying using dd and vardump the results was shown. I need to loop the foreach in my dropdown menu to show the list of data from my categories table. And I need to join my items table and my categories table to get the name of the categories.
you are calling same id from items and kategoris try this
public function edit($id)
{
// $item = Item::findOrFail($id);
$item = DB::table('items')
->join('kategoris', 'items.kategori_id', '=', 'kategoris.id')
->where('items.id', '=', $id)
->select('items.*', 'kategoris.id as kategory_id', 'kategoris.kode_kategori', 'kategoris.kategori_name')
->get();
// dd($item);
return view('master-dev/item/edit', compact('item'));
}
if this answer doesnot work show your database relation i will give you solution
$item = ....->get() will return a Collection to only have one item you need to use $item = ....->first() instead
But since you have #foreach ($item as $i) I believe, you still want to have a collection, but in that case, your issue is here
{{ Form::model($item,['route'=>['item.update',$item['id']], 'files'=>true,'method'=>'PUT']) }}
Since you have a collection, we don't know what $item['id'] it's referring to. Perhaps $item->first()['id'] ?
I solved the problem, there's a conflict fetching data from items and kategoris tables. There are differences calling a value with array and object, mostly if its data looped. So in the controller I must declared one by one, the selected value id from kategoris table, and I have to join both tables to get the name of the kategoris, and then I have to declare once more to get the list of the kategoris data. So there are three (3) variables to declare each one of them. For this long time I was looking for the short code in my Controller but I cannot find it.
Thank you for all of you guys helping me this problem. Cheers.

Laravel vue: I can't get the object related to the relationship betwenn models

I've created a simple comment system. Everything's working fine. Now I had to create the same approach with Vue.js. Everything works well with Vue.j too. The only problem is that I can't show the answers related to the comment using the relationship.
I show first the relationship code, then the PHP loop and finally the loop code with Vue.js
//USER MODEL
public function comments()
{
return $this->hasMany(Comment::class,'user_id');
}
//COMMENT MODEL
public function video()
{
return $this->belongsTo(Video::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function replies()
{
return $this->hasMany(CommentReply::class,'comment_id');
}
//CommentReply model
public function comment()
{
return $this->belongsTo(Comment::class);
}
This is the loop
#foreach( $video->comments as $comment )
<li id="li-comment-5">
<article class="comment even thread-odd thread-alt depth-1 clr" id="comment-5">
<header class="comment-meta"> <strong class="fn"> {{ $comment->user->name }}
</strong> <span class="comment-date">July 4, 2017 7:25 am </span></header>
<div class="comment-content entry clr">
<p>{{ $comment-body}}</p>
</div>
<h5>Reply</h5>
#foreach($comment->replies as $reply)
$reply->body
#enddoreach
</div>
</article>
</li>
#endforeach
Loop with Vue
<ol class="commentlist" v-if="comments.length > 0">
<li id="li-comment-4" v-for="comment in comments">
//...loop works fine
//Reply section
</li<ul class="children">
<li id="li-comment-6" v-for="reply in comment.replies">
//comment.replies does not work
</li>
</ul>
</li>
</ol>
As you can see in the code below comment.replies does not return the object I am waiting for.
How can you get the same result with vue?

Laravel - pagination sorting by created_at

So guys I add pagination to my project and I'm almost finishing it, witch by the way is my first project ever, and all I need to do right now is to set pagination by created_at.So I need to put posts from the same day on same page link. Right now it shows me posts from different days on one page. And after that I just need to show price sum of that day. If you know please help me, this would be my first project as a student, I'm still learning. Thank you !!
Here is my HomeController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use App\Post;
use DB;
use Auth;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
$posts = Post::where('user_id', Auth::id())->orderBy('created_at', 'DESC')
->paginate(3);
return view('home')->with('posts', $posts);
}
}
Here is my home.blade.php
#extends('layouts.theme')
#section('content')
<style>
body{
margin: 0;
background-color: #EBEBEB;
}
</style>
<div class="mainl">
<div class="row">
<div class="columna">
<h1>{{ Auth::user()->name }}</h1>
<hr>
</div>
<div class="columns">
<a href="{{ route('logout') }}" id="logout"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('LOGOUT') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
#csrf
</form>
</div>
</div>
</br></br></br>
#if(count($posts)> 0)
<table>
<thead>
<tr>
<th>BR.KESICE</th>
<th>IME I PREZIME</th>
<th>BR.TELEFONA</th>
<th>POSAO</th>
<th>CIJENA</th>
<th>PLACANJE</th>
<th>POPUST</th>
<th>DATUM PREUZ.</th>
<th>DATUM IZDAV.</th>
<th>SMJENA</th>
<th>RADNIK</th>
<th>STATUS</th>
<th>IZMIJENI</th>
</tr>
</thead>
<tbody>
#foreach($posts as $post)
<tr>
<td>{{$post->br_kesice}}</td>
<td>{{$post->ime}}</td>
<td>{{$post->br_telefona}}</td>
<td>{{$post->posao}}</td>
<td>{{$post->cijena}}</td>
<td>{{$post->placanje}}</td>
<td>{{$post->popust}}</td>
<td>{{$post->datum_preuz}}</td>
#if($post->status == 1)
<td>/</td>
#else
<td>{{$post->datum_izdav}}</td>
#endif
<td>{{$post->smjena}}</td>
<td>{{$post->radnik}}</td>
<td>
#if($post->status == 0)
<span class="label label-primary" id="statusdeaktivan">Deaktivan</span>
#elseif($post->status == 1)
<span class="label label-success" id="statusaktivan">Aktivan</span>
#elseif($post->status == 2)
<span class="label label-danger" id="statusdeaktivan">Rejected</span>
#else
<span class="label label-info" id="statusdeaktivan">Deaktivan</span>
#endif
</td>
#if($post->status == 3)
#else
<td><i class="far fa-edit"></i></td>
#endif
</tr>
#endforeach
</tbody>
<tfoot>
<tr>
<th>UKUPAN IZNOS: {{ Auth::user()->posts->sum('cijena')}}€</th>
<th>KARTICA: {{ Auth::user()->posts->where('placanje', 'Kartica')->sum('cijena')}}€</th>
<th>GOTOVINA: {{ Auth::user()->posts->where('placanje', 'Gotovina')->sum('cijena')}}€</th>
<th>VIRMAN: {{ Auth::user()->posts->where('placanje', 'Virman')->sum('cijena')}}€</th>
</tr>
</tfoot>
</table>
{{ $posts->links()}}
#else
<p>Trenutno nema unosa.</p>
#endif
</div>
#endsection
And I found something from past questions here in stack overflow and it's working but I have a problem with that, so
public function index()
{
$posts = Post::where('user_id', Auth::id())->where('created_at', '>=', \Carbon\Carbon::now()->subDays(10))->get();
return view('home')->with('posts', $posts);
}
When I add this ->where('created_at', '>=', \Carbon\Carbon::now()->subDays(10))->get(); it shows me all posts from past 10 days but after that 10 days nothing, could I use this but to sort it by all days, not to set maximum days?
I also add this code to my price sum and it is working but as I said just for past 10 days
<tfoot>
<tr>
<th>UKUPAN IZNOS: {{ Auth::user()->posts->where('created_at', '>=', \Carbon\Carbon::now()->subDays(10))->sum('cijena')}}€</th>
<th>KARTICA: {{ Auth::user()->posts->where('placanje', 'Kartica')->where('created_at', '>=', \Carbon\Carbon::now()->subDays(10))->sum('cijena')}}€</th>
<th>GOTOVINA: {{ Auth::user()->posts->where('placanje', 'Gotovina')->where('created_at', '>=', \Carbon\Carbon::now()->subDays(10))->sum('cijena')}}€</th>
<th>VIRMAN: {{ Auth::user()->posts->where('placanje', 'Virman')->where('created_at', '>=', \Carbon\Carbon::now()->subDays(10))->sum('cijena')}}€</th>
</tr>
</tfoot>
Thank you again and I would really appreciate it if you help me with this. It's my first project and I'm very happy about it.
What your current code is doing is taking all the posts, sort it by created_at and then show 3 at a time. It doesn't care about what day it is or how many $post are there for that particular day.
What I understand that, you want to do is to show it by date. In that case, your query should filter based on date.
What you need to do is pass the date to the controller and fetch only posts from that day. It is a bit tricky. You need to pass today's date to controller.
In HTTP GET method your URL should contain the date. For example, it can be something like http://example.com/index?date=20190716. Notice that "date=20190716" part. You can get this in controller. Then you can get the posts of that day by writing,
$date = new Carbon(request('date'));
$posts = Post::where('user_id', Auth::id())
->whereDate('created_at','=',$date)
->orderBy('created_at', 'DESC')
->paginate(3);
Now, what it will do is get only the posts from 16th July, 2019.
This is the main idea. How you pass the date is entirely on you. You can do that in several ways. You can use JS, HTTP GET method and HTTP POST method.
Try
public function index()
{
$posts = Post::where('user_id', Auth::id())->get();
return view('home')->with('posts', $posts);
}
Try this also, I hope helps you
public function index()
{
$dateFromUrl = \Carbon\Carbon::createFromFormat('d/m/Y', request()->date);
$posts = Post::where('user_id', Auth::id())->where('created_at',$dateFromUrl)->orderBy('created_at', 'DESC')
->get();
$sum = 0;
foreach($posts as $post){
$sum+=$post->price;
}
return view('home', compact("posts","sum"));
}

Resources