I have the following models:
namespace App;
use Illuminate\Database\Eloquent\Model;
class forum_category extends Model
{
//
protected $table = 'forum_category';
public function posts()
{
$this->hasMany('App\forum_post');
}
}
And
namespace App;
use Illuminate\Database\Eloquent\Model;
class forum_post extends Model
{
//
protected $table = 'forum_post';
public function category()
{
$this->belongsTo('App\forum_category');
}
}
in my controller i attempt to get all categories with their posts:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use App\forum_category as forum_category;
class ForumController extends Controller
{
public function __construct()
{
}
public function index ()
{
$categories = forum_category::all();
return view('forum', ['categories' => $categories]);
}
public function createPost()
{
}
public function createReply()
{
}
}
However it seems to only be returning my categories.
Can someone tell me what ive done wrong?
The query should look like this:
$categories = forum_category::with('posts')->get();
https://laravel.com/docs/5.5/eloquent-relationships#eager-loading
If you have category_id in the forum_post table, this will load categories with related posts.
Then just iterate over the collection to get posts:
#foreach ($categories as $category)
#foreach ($category->posts as $post)
{{ $post->title }}
#endforeach
#endforeach
Also, the relationship should be:
public function category()
{
return $this->belongsTo('App\forum_category');
}
Related
For my Laravel assignment I am working on a store, and using models to create the pages of shown products. However, the view pages gives me the error of class not found. I am a bit stumped on that to be honest.
Here is the controller I use:
namespace App\Http\Controllers\Shop;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Category;
use App\Models\Product;
class ShopController extends Controller{
public function displayProduct($cat, $pro) {
$data['category'] = Product::getProduct($cat, $pro);
return view('shop.prosuct', $data);
}
public function displayCategory($slug) {
$data['category'] = Category::getCategory($slug);
return view('shop.category', $data);
}
public function displayShop() {
$data['categories'] = Category::getCategories();
return view('shop.shop', $data);
}
}
Said Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
public function category() {
return $this->belongsTo('App/Model/Category');
}
public static function getProduct($cat, $pro){
$product = self::where('slug', $pro)->firstorFail();
$product_cat = $product->category->slug;
//retun ($product_cat === $cat) ? $product_cat: false;
abort_if($product_cat !== $cat, 404);
return $product;
}
//use HasFactory;
}
the Category model (just in case):
<?php
namespace App\Models;
//use App\Http\Modles;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function products() {
return $this->hasMany('App\Model\Product');
}
public static function getCategory($slug){
return self::where('slug', $slug)->firstOrFail(['id', 'slug']);
}
public static function getCategories() {
return self::orderBy('slug')->get();
}
//use HasFactory;
}
and finally, the view page:
#extends('template')
#section('content')
<h1 class="mb-5"> {{$category->name}} </h1>
<div class="row">
#foreach ($category->products as $product)
<div class="col-md-4 mb-5">
<div class="pro-container">
<h3>{{$product->name}}</h3>
<img src="{{asset('images/products/' . $product->image)}}">
<h4> ₪ {{$product->price}} </h4>
<a class="btn btn-primary" herf=""> ADD TO CART </a>
<a class="btn btn-primary" herf="{{url()->current() . '/' . $product->slug}}"> READ MORE </a>
</div>
</div>
#endforeach
</div>
#endsection
The idea is to save the space and create the page of each category to show its products; I have 3 categories in total it needs to be done for.
Thank you in advance for your help! (also, I'm using Laravel 7)
In both of your relationships you are referencing the Model directory instead of the Models one:
# Category.php
public function products() {
return $this->hasMany('App\Model\Product');
} ^^^^^^
# Product.php
public function category() {
return $this->belongsTo('App\Model\Category');
} ^^^^^^^^
Fix them and it should work now.
To avoid this kind of issues, given that you're dealing with strings, why not make use of this other (better) syntax? It's also IDE-friendly and supports refactoring:
# Category.php
public function products() {
return $this->hasMany(Product::class);
} ^^^^^^^^^^^^^^
# Product.php
public function category() {
return $this->belongsTo(Category::class);
} ^^^^^^^^^^^^^^^
I have a relationship in my app. A candidate can have several "candidate_trainings" and each "candidate_training" is associated with a training. I wanted to avoid making "candidate_trainings" the piviot since it's hard to delete the right values when detaching, etc. So, how can I, on my hasMany relationship get the CandidateTraining model with the data from the Training model.
Here are my relationships:
<?php
namespace App;
use App\Traits\SanitizeIds;
use App\Salary;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class Candidate extends Model
{
public function saveTraining($data) {
$this->candidateTrainings()->delete();
foreach(json_decode($data['training']) as $training) {
if(Training::find($training->training)->first()) {
$candidateTraining = new CandidateTraining;
$candidateTraining->description = $training->value;
$candidateTraining->training_id = $training->training;
$this->candidateTrainings()->save($candidateTraining);
}
}
}
public function candidateTrainings() {
return $this->hasMany('\App\CandidateTraining');
}
public function trainings() {
return $this->belongsToMany('\App\Training');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Training extends Model
{
protected $fillable = ['name_french', 'name_english'];
public function candidates() {
return $this->belongsToMany('\App\Candidate');
}
public function candidateTrainings() {
return $this->hasMany('\App\CandidateTraining');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class CandidateTraining extends Pivot
{
public function candidate() {
return $this->belongsTo('\App\Candidate');
}
public function training() {
return $this->belongsTo('\App\Training');
}
}
Thank you!
For you to be able to update the data directly on the CandidateTraining model, you need to add the $fillable fields to it.
protected $fillable = ['training_id', 'description'];
Your code should work! But if you don't mind, I did a little refactoring. You can accomplish this in another way:
<?php
namespace App;
use App\Traits\SanitizeIds;
use App\Salary;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class Candidate extends Model
{
public function saveTraining($data)
{
// remove all relationships
$this->trainings()->detach();
// add new ones
foreach(json_decode($data['training']) as $training)
{
if(Training::find($training->training)->first())
{
$this->trainings()->attach($training->training, [
'description' => $training->value,
]);
}
}
}
public function candidateTrainings()
{
return $this->hasMany(App\CandidateTraining::class);
}
public function trainings()
{
return $this->belongsToMany(App\Training::class)
->withTimestamps()
->using(App\CandidateTraining::class)
->withPivot([
'id',
'training_id',
'description',
]);
}
}
That $training->training stuff is not readable, change it to something like $training->id if you are able to.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Training extends Model
{
protected $fillable = ['name_french', 'name_english'];
public function candidates()
{
return $this->belongsToMany(App\Candidate::class)
->withTimestamps()
->using(App\CandidateTraining::class)
->withPivot([
'id',
'training_id',
'description',
]);;
}
public function candidateTrainings()
{
return $this->hasMany(App\CandidateTraining::class);
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class CandidateTraining extends Pivot
{
protected $fillable = ['training_id', 'description'];
public function candidate()
{
return $this->belongsTo(App\Candidate::class);
}
public function training()
{
return $this->belongsTo(App\Training::class);
}
}
If you want to access the pivot object from a controller:
$candidates = Candidate::with(['trainings'])->get();
foreach ($candidates as $candidate)
{
dd($candidate->pivot);
}
Im working on my Laravel project, and have a problem with many-to-many relationship : cannot use "sync" function to store the data in Intermediary Table.
Im following the tutorial in this series : Part 37 - Adding Tag UI/UX
Problem seems to be with this code line : $post->tags()->sync($request->tags, false);
It throws back the error :
BadMethodCallException Call to undefined method App\Post::tags()
I have tried to use attach function instead of sync, does not work.
I dont know which part of code could lead to this issue.
Pls tell me if u guys notice anythings. Tysm !
Post.php (Model)
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table = "posts";
public function category(){
return $this->belongsTo('App\Category');
}
public function user(){
return $this->belongsTo('App\User');
}
public function tag(){
return $this->belongsToMany('App\Tag', 'post_tag');
}
}
Tag.php (Model)
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
protected $table = "tags";
public function post(){
return $this->belongsToMany('App\Post', 'post_tag');
}
}
create_post_tag_table.php (migrations - Intermediary Table)
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePostTagTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('post_tag', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('post_id')->unsigned()->nullable();
$table->foreign('post_id')->references('id')->on('posts');
$table->bigInteger('tag_id')->unsigned()->nullable();
$table->foreign('tag_id')->references('id')->on('tags');
});
}
}
posts.create.blade.php (views - select multiple tags)
<select class="form-control select2-multi" name="tags[]" multiple="multiple" style="width:100%;">
#foreach($tags as $tag)
<option value='{{ $tag->id }}'>{{ $tag->name }}</option>
#endforeach
</select>
PostsController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\Post;
use App\Tag;
use App\User;
class PostsController extends Controller
{
public function create()
{
$tags = Tag::all();
return view('posts.create')->with('tags', $tags);
}
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required',
'category_id' => 'required',
]);
$post = new Post;
$post->title = $request->input('title');
$post->description = $request->input('description');
$post->content = $request->input('content');
$post->category_id = $request->input('category_id');
$post->user_id = auth()->user()->id;
$post->status = $request->input('status');
$post->save();
$post->tags()->sync($request->tags, false);
return redirect('/posts')->with('success', 'Post created.');
}
}
You have defined the relationship as tag in your Post model but you are calling tags. You should change it to tags since it is a belongsToMany relationship.
public function tags()
{
return $this->belongsToMany('App\Tag', 'post_tag');
}
I just finishing my blog, using laravel, and I want to add a comment feature on it, but i got few errors like this, can anyone help me, please??,
sorry for my English, English is not my native language,
Thank you :)
(1/1) ErrorException
Undefined offset: 1
Here is my AdminBlog.php Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class AdminBlog extends Model
{
protected $table = 'admin';
protected $fillable = ['title','text','images','slug'];
public function comment(){
return $this->hasMany('App\Comment');
}
}
Comment.php Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $table = 'comment';
protected $fillable = ['name','email','text','post_id'];
public function post(){
return $this->belongsTo('App\AdminBlog');
}
}
BlogController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\AdminBlog;
use App\Comment;
class BlogController extends Controller
{
//Index
public function index(){
$post = AdminBlog::all();
return view('blog/index', compact('post'));
}
//Show
public function show($id){
$post = AdminBlog::findOrFail($id);
$comment = Comment::all();
//dd($comment);
return view('blog/show', ['post' => $post,
'comment' => $comment]);
}
}
show.blade.php
<div class="col-md-12 post-comment-show">
#foreach($post->comment() as $list)
<p>{{ $list->text }}</p>
#foreach
</div>
You should use:
<div class="col-md-12 post-comment-show">
#foreach($post->comment as $list)
<p>{{ $list->text }}</p>
#foreach
</div>
Note that, you have used comment(). Also, you should use a plural name for a hasMany relationship, so comment should be comments.
Also, in your show method, you should use something like the following:
public function show($id)
{
$post = AdminBlog::with('comment')->findOrFail($id);
return view('blog/show', ['post' => $post]);
}
Try the following
$post->comment()->get()
or
$post->comment
when calling a relationship with ()it returns a instance of the query builder and allows you to filter the object. If you remove the call it without () it returns you a collection which is array accessible
Another suggestion if you have many comments you should name your relationship plural.
in this case:
public function comments(){
return $this->hasMany('App\Comment');
}
// Use it like this
$post->comments
You need to change your show function:
public function show($id){
$post = AdminBlog::findOrFail($id);
$comment = Comment::all();
//dd($comment);
return view('blog/show', ['post' => $post,
'comment' => $comment]);
}
TO
public function show($id){
$post = AdminBlog::with('comment')->where('admin.id',$id)->get();
return view('blog/show', compact('post'));
}
Hope this work for you!
This is my first laravel Application, and my first database based application so please be patient with me !!
I will try to be specific!!
Categories Table:
Id
Name
Timestamps
Posts table:
Id
title
body
slug
Category_id
timestamps
Lets say i have 4 catergories.
Laptops, computers,phones,tablets
I want when i go to /computers to be able to get all the posts that are specific to that category.
Posts Model
Category Model
Category Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
use App\Category;
class CatController extends Controller
{
public function getCategory($Category_id)
{
$posts = Post::where('Category_id',$Category_id);
return view('blog.index',['posts' => $posts]);
}
Route:
Route::get('computer/{Category_id}','CatController#getCategory');
I am really confused at the moment !!
Thanks everyone in advance!!
Define your Model
class Category extends Model
{
/**
* Get the posts.
*/
public function posts()
{
return $this->hasMany('App\Post', 'Category_id');
}
}
class Post extends Model
{
/**
* Get the category.
*/
public function category()
{
return $this->belongsTo('App\Category', 'Category_id');
}
}
Define your Controller
class CatController extends Controller
{
public function getCategory($Category_id)
{
$category = Category::find($Category_id);
if($category !== null){
$posts = $category->posts;
return view('blog.index',['posts' => $posts]);
}
}
I hope this will help you.
Route:
Route::get('categories/{category_id}/computers','CatController#show');
Controller:
public function show($category_id)
{
$category = Category::findOrFail($category_id);
if($category){
$posts = Post::where('Category_id',$category_id)->get();
return view('category.index', compact('posts'));
}
return view('errors.404');
}
Simply add this to your controller
public function category($id){
$data['posts'] = Post::where('status', 1)->where('category_id', $id)->orderBy('id', 'DESC')->get();
return view('frontEnd.home', $data);
}