I have 3 tables: Users, Projects, Items and Friends. I want to get all the items for a project and list each item with related friends. Am I missing something in my model? Ultimately I want to get all the friends which are related to the items.
// CONTROLLER
public function show($id)
{
$uid = Auth::user()->id;
$projects = Project::find($id)->with('item.friend')->get();
return View::make('projects.show', compact('projects'));
}
//VIEW
#foreach ($projects as $project)
#foreach ($project->friend as $friend)
<li>
<a href="#" class='itemLink' >{{$friend->email}}</a>
<a href="#" class='itemLink' >{{$projects->item->name}}</a>
</li>
#endforeach
#endforeach
// MODELS
class User extends Eloquent {
public function project()
{
return $this->hasMany('Project');
}
public function item()
{
return $this->hasMany('Item');
}
public function friend()
{
return $this->hasMany('Friend');
}
class Project extends Eloquent {
protected $guarded = array();
public static $rules = array();
public function item()
{
return $this->hasMany('Item');
}
public function friend()
{
return $this->hasMany('Friend');
}
class Item extends Eloquent {
protected $guarded = array();
public static $rules = array();
public function friend()
{
return $this->hasMany('Friend');
}
class Friend extends Eloquent {
protected $guarded = array();
public static $rules = array();
You are missing a loop. I recommend that when setting up a many to many relationship, make sure your method is plural. It makes a lot more sense when trying to read the code. You'd then send up with #foreach $project->items as $item or $item->friends as $friend.
#foreach ($projects as $project)
#foreach ($project->item as $item)
#foreach($item->friend as $friend)
<li>
<a href="#" class='itemLink' >{{$friend->email}}</a>
<a href="#" class='itemLink' >{{$item->name}}</a>
</li>
#endforeach
#endforeach
#endforeach
Your models seems OK at first look. I think since you are pulling item.friend relationship, this line
#foreach ($project->friend as $friend)
should be,
#foreach ($project->item->friend as $friend)
Related
I'm using a Livewire component, this is my code:
Search.php :
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Recipe;
use App\Models\Vegetable;
use App\Models\VegetablesRecipe;
class Search extends Component
{
public $query = '';
public $vegetables;
public function mount()
{
$this->resetQuery();
}
public function resetQuery()
{
$this->vegetables = [];
}
public function render()
{
if ($this->query != null) {
return view('livewire.search', [
'vegetables' => Vegetable::where('name', 'like', '%'.$this->query.'%')->get()->toArray()
]);
} else {
return view('livewire.search', [
'vegetables' => Vegetable::all()->toArray()
]);
}
}
}
search.blade.php :
<div class="searchcomponent">
<h1>Search</h1>
<input wire:model="query" type="text" placeholder="Rechercher...">
#if(!empty($query))
<ul>
#if(!empty($vegetables))
<div class="vegetables">
#foreach($vegetables as $vegetable)
<li><span class="material-icons">lunch_dining</span>{{ $vegetable['name'] }}</li>
#endforeach
</div>
#else
<li>No result</li>
#endif
</ul>
#endif
</div>
My vegetable Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Vegetable extends Model
{
use HasFactory;
public $timestamps = false;
protected $fillable = ['name'];
public function recipes(){
return $this->belongsToMany(Recipe::class, 'vegetables_recipes', 'vegetable_id', 'recipe_id');
}
public function getName($id) {
return $this->name;
}
}
My problem is, every time im typing something in my search bar, I just have a No result appearing on my screen even tho i seeded my data base with some vegetables already. Why doesn't it show me for example Carrot when i type it?
Or how can i fill my array vegetables with all the names of my vegetables datatable ?
Defining public $vegetables; will prevent you from passing it to the view.
Remove that. Also remove your mounting logic.
Thus you should have:
class Search extends Component
{
public $query = '';
public function render()
{
if ($this->query != null) {
return view('livewire.search', [
'vegetables' => Vegetable::where('name', 'like', '%'.$this->query.'%')->get()->toArray()
]);
} else {
return view('livewire.search', [
'vegetables' => Vegetable::all()->toArray()
]);
}
}
}
Also make sure you are calling #livewireScripts and #livewireStyles or their alternative syntaxes <livewire:styles /> <livewire:scripts /> from your main view which uses <livewire:search />.
Edit:
Alternatively, you could also use a public properly and write to it using $this->vegetables like so:
class Search extends Component
{
public $query = '';
public $vegetables;
public function render()
{
$this->vegetables = Vegetable::where('name', 'like', '%' . $this->query . '%')->get()->toArray();
return view('livewire.search');
}
}
Also, you can remove the #if(!empty($query)) and the #if(!empty($vegetables)) in place of a #forelse utilising the #empty statement rather than a #foreach. E.g.
#forelse($vegetables as $vegetable)
<li><span class="material-icons">lunch_dining</span>{{ $vegetable['name'] }}</li>
#empty
<li>No result</li>
#endforelse
That way, you will still get a list of your vegetables when the search box is empty, and if it's not empty but there's no matching results, you'll get your "No result" message.
This is because on the mount you are resetting the vegetable array to an empty array.
Refer to this fiddle for more details:
https://laravelplayground.com/#/snippets/f51e212a-dab3-4325-b6b0-4c6af4c0ab72
Hello im trying to do a quiz app with laravel and im struggeling with retrieving my questions with category..
i have a unsightly solution with this but it's not dynamically..
public function startQuiz(Request $request){
$questions = Question::all();
foreach ($questions as $key => $question) {
dd($question->where('categories_id', 'LIKE', 2)->get()); // i want to change the 2 to the real category id
}
}
i thought i could to that with the relationship like $question->category->id but wont work.
thats my model:
class Question extends Model
{
protected $fillable = ['question_text', 'categories_id', 'correct_answer', 'options'];
protected $casts = ['options' => 'array'];
public function category(){
return $this->belongsTo(Category::class, 'categories_id');
}
}
class Category extends Model
{
protected $fillable = ['name', 'slug'];
public function question()
{
return $this->hasMany(Question::class, 'questions_id');
}
i cant somehow pass the id and check it i dont know why.. thats my form where i pass the category:
#section('content-categories')
<div class="card">
<div class="card-header">Choose Category to Start</div>
<div class="card-body">
#foreach($categories as $category)
<form class="form-group" action="{{route('user.quiz', $category->slug)}}" method="post">
#csrf
<input type="submit" name="categoryTest" class="form-control" value="{{$category->name}}">
</form>
#endforeach
</div>
</div>
#endsection
Edit:
i think i know why i couldnt retrieve data with my relationship..i had an error with my relationship in Category Class, i have not a field for questions_id, i replaced it to:
public function question()
{
return $this->hasMany(Question::class);
}
and now i could get the questions with:
public function startQuiz(Request $request){
$questions = Question::all();
$questionsCategory = [];
if($request){
foreach ($questions as $question) {
if ($request->categoryTest == $question->category->name) {
$questionsCategory = $question->where('categories_id', '=', $question->category->id)
->get();
var_dump($questionsCategory);
}
}
}
}
For your form listing probably you already have $categories = Categories::all().
Next to get all questions of this category after the submit you should first get the category and then questions for it.
Let say you have category id in your form:
$categoryQuestions = Category::find($request->get('id'))->questions;
I see you are using category slug for your url, can also use it to find the category:
public function startQuiz(Request $request, string $slug){
$questions = Category::whereSlug($slug)->first()->questions;
...
}
Bonus:
In your service provider you can bind {category} directly to your model like this:
Route::bind('category', function($value) {
return Category::whereSlug('slug', $value)->first();
});
And then your category will be available in controller methods:
public function startQuiz(Request $request, Category $category){
$questions = $category->questions;
}
Try replacing 'LIKE' with '='. And remove dd(...)Like this:
foreach ($questions as $key => $question) {
dd($question->where('categories_id', 'LIKE', 2)->get());
}
to:
foreach ($questions as $key => $question) {
$question->where('categories_id', '=', 2)->get();
}
So i have this eloquent query
$categories = categories::all();
foreach($categories as $c):
$c->items = item_categories::where('cat_id',$c->cat_id)->with('item')->with('item.item_images')->get();
endforeach;
and in my blade, I can display this part
with('item')
like doing
#foreach($categories as $c)
#foreach($c->items as $i)
{{ $i->item->item_name }}
#endforeach
#endforeach
How about retrieving data from this part?
with('item.item_images')
I tried
#foreach($categories as $c)
#foreach($c->items as $i)
{{ $i->item->item->item_images->image_name }}
#endforeach
#endforeach
but it gives me error
Trying to get property of non-object
Any ideas, help please?
here's the 'categories' model
class categories extends Model
{
protected $table = 'categories';
protected $primaryKey = 'cat_id';
public function item_category(){
return $this->belongsTo('App\item_categories','cat_id','cat_id');
}
}
and the 'item_categories' model
class item_categories extends Model{
protected $table = "item_categories";
public function item(){
return $this->belongsTo('App\items','item_id','item_id');
}
public function category(){
return $this->hasOne('App\categories','cat_id','cat_id');
}
}
and the 'items' model
class items extends Model
{
protected $table = 'items';
protected $primaryKey = 'item_id';
public function item_images(){
return $this->hasMany('App\item_images','item_id','item_id');
}
public function item_categories(){
return $this->hasMany('App\item_categories','item_id','item_id');
}
}
You're going too deep. It looks like item_categories has an item, which has an item_image, so you just need to access it like this:
{{ $i->item->item_images->image_name }}
Since each item has many item_images, you need to iterate through it.
#foreach($i->item->item_images as $image)
{{$image->image_name}}
#endforeach
My guess is that your code is okay but item doesn't have item_image. Try checking if checking if $i->item->item->item_images is empty before trying to use the value
So I have a basic forum set up and I have the relationships between models completed. However I am stuck trying to get the last user who posted in the sub category. This is how its laid out.
mysql tables
forum_category (this is used for the main category and also the sub category)
forum_post (this is used for the posts)
Here is my ForumCategory.php
namespace App\Models\Forum;
use Illuminate\Database\Eloquent\Model;
class ForumCategory extends Model {
protected $table = 'forum_category';
public static function category()
{
return ForumCategory::with('ForumSubCategory')->whereNull('parent_id')->get();
}
public function User()
{
return $this->belongsTo('App\User');
}
public function ForumSubCategory()
{
return $this->hasMany('App\Models\Forum\ForumSubCategory' , 'parent_id');
}
public function ForumPost()
{
return $this->hasMany('App\Models\Forum\ForumPost' , 'parent_id');
}
}
And here is my ForumSubCategory.php the sub category model even though they are using the same table...
namespace App\Models\Forum;
use App\User;
use Illuminate\Database\Eloquent\Model;
class ForumSubCategory extends Model
{
protected $table = 'forum_category';
public function ForumCategory()
{
return $this->belongsTo('App\Models\Forum\ForumCategory');
}
public function User()
{
return $this->belongsTo('App\User');
}
public function ForumPost()
{
return $this->hasMany('App\Models\Forum\ForumPost' , 'parent_id');
}
}
And here Is my ForumPost.php model
namespace App\Models\Forum;
use Illuminate\Database\Eloquent\Model;
class ForumPost extends Model
{
protected $table = 'forum_post';
public function User()
{
return $this->belongsTo('App\User');
}
public function ForumSubCategory()
{
return $this->belongsTo('App\Models\Forum\ForumSubCategory');
}
}
The controller is pretty basic, the index is
public function index() {
return view('forum.index', ['category' => ForumCategory::category()]);
}
Now at the moment I am currently getting my last user who posted with this
public static function LastPost($value)
{
$lastPost = ForumPost::whereParentId($value)->orderBy('created_at', 'DESC')->pluck('user_id')->first();
return User::whereId($lastPost)->pluck('username')->first();
}
Which I DO NOT want to do. I want to know the correct way of doing this :(
Here is my view
<ul>
#foreach ($category as $cat)
<li>
{{$cat->category_name}} - this is main category
{{$cat->category_description}} - this is main category description
#if ($cat->ForumSubCategory)
<ul>
#foreach ($cat->ForumSubCategory as $sub)
<li>
<a href="/forum/{{$cat->slug}}/{{$sub->slug}}"> - this is the category slug with the sub category slug
{{$sub->category_name}} - this is the sub category name
</a>
{{$sub->category_description}} - this is the sub category description
{{$sub->ForumPost->count()}} - this is how many posts are in the sub category
{{$sub->LastPost($sub->id)}} - this is how i am currently getting the last user who posted
</li>
#endforeach
</ul>
#endif
</li>
#endforeach
</ul>
Thanks for taking the time to look at this!
The fastest solution:
You can filter/order relationships, hence the function below.
latest() is an eloquent shortcut for orderBy('created_at','DESC')
ForumSubCategory Model:
class ForumSubCategory extends Model
{
...
public function latestPost()
{
return $this->hasOne('App\Models\Forum\ForumPost' , 'parent_id')->latest()->with('user');
}
}
In your view:
From:
{{$sub->LastPost($sub->id)}} - this is how i am currently getting the last user who posted
To:
#if($sub->latestPost)
#if($sub->latestPost->user)
{{$sub->latestPost->user->username or 'Username not set'}}
#else
{{'User Not Found'}}
#endif
#else
{{'No Last Post'}}
#endif
The most stable solution should be a service class around forum sub categories to take care of edge cases such as users being deleted, posts banned and so forth.
You could make use of dynamic properties. Check out Relationship Methods Vs Dynamic Properties
// Controller
public function lastPost()
{
$lastPost = ForumPost::whereParentId($value)->orderBy('created_at', 'DESC')->first();
$username = $lastPost->user->username;
return view('post.view', compact('username'));
}
I'm trying to print all books' name in 'books' table and its category associated. But it doesn't show any content nor error messages.
Model::Book.php
class Book extends Eloquent{
protected $table ='books';
public function bookCat()
{
return $this->belongsTo('BookCategory');
}
}
Model::BookCategory.php
class BookCategory extends Eloquent{
protected $table ='book_categories';
}
Controller::route.php
Route::get('/', function()
{
$books = Book::all();
return View::make('books')
->with('books', $books);
});
View::books.blade.php
#foreach ($books as $book)
<li>{{ $book->book_name }}</li>
- <small>{{ $book->bookCat }}</small>
#endforeach
Table::books
(int)id, (string)book_name, (int)category_id
Table::book_categories
(int)id, (string)category
Add the relationship to BookCategory.
class BookCategory extends Eloquent{
protected $table ='book_categories';
public function books() {
return $this->hasMany('Book');
}
}
Your local key doesn't match the model names, either, so you would need to specify that in the relation:
class Book extends Eloquent{
protected $table ='books';
public function bookCat()
{
return $this->belongsTo('BookCategory', 'category_id');
}
}
You may also want to eager-load the categories in your controller, as your query is for the books:
$books = Book::with('bookCat')->get();