Eloquent Query: All News with same categories. Pivot table - laravel

I need to get all the news that has the same (one or more) categories as a specific new in an Eloquent query. And I dont know with pivot table.
I have 3 tables:
News
id | title | content
NewsxCategory (Pivot Table)
news_id | category_id
NewsCategory
id | name
Eloquent Models
// NewsCategory model
class NewsCategory extends Model
{
}
// News Model
class News extends Model
{
public function categories()
{
return $this->belongsToMany(NewsCategory::class, 'news_x_category', 'news_id', 'category_id');
}
}
I tried this.
In helper:
/**
* only related news
*
*
* #return \Illuminate\Database\Eloquent\Builder
*/
public static function relatedNews(News $new)
{
$categories = $new->categories(); //obtain all categories of $new
return News::whereHas('categories', function ($query) use ($categories) {
$query->whereIn('new_id', $categories);
});
}
And in view:
<div class="related-articles">
<h5>{{ __('RELATED ARTICLES') }}</h5>
<ul class="articles">
#foreach ( App\Helpers\News::relatedNews($newsItem) as $new)
<li>
<h6>{{ $new->title }}</h6>
<p>{{ $new->publication_date }}</p>
</li>
#endforeach
</ul>
</div>
But helper always return null.
Also I tried in helper:
return News::with('categories')->where('category_id',$categories )->get();
But this option return all news.
I need all news related, I mean news with similar categories. Pivot tables give me a headache.
Thanks in advance!

In whereIn clause, you need to pass array of ids. But you are not passing correct.
So here is the correct one.
/**
* only related news
*
*
* #return \Illuminate\Database\Eloquent\Builder
*/
public static function relatedNews(News $new)
{
$categoryIds = $new->categories->pluck('category_id')->toArray(); //obtain all categories of $new
return News::whereHas('categories', function ($query) use ($categoryIds) {
$query->whereIn('category_id', $categoryIds);
});
}
I think after change above function changes. you will get related news.
Updated
If you want to print related news then use this:
#foreach ( App\Helpers\News::relatedNews($newsItem)->get() as $new)
{{ $new->title }}
#endforeach

Related

how can i handle the relations beetween products attributes and values?

i'm working on a Laravel/Livewire project
there are some products and services in this platform that user can order them.
the price of these products and services are changeable by their attributes . like size,color,quality and....
and i made a Many To Many relation between products and attributes.
but a can't handle it in my view where user should select that attributes before ordering
and my for each loop return wrong data . and i get this error :
Trying to get property 'pivot' of non-object .
my migration :
public function up()
{
Schema::create('attr_product', function (Blueprint $table) {
$table->foreignId('attr_id')->constrained();
$table->foreignId('product_id')->constrained();
$table->string('value')->nullable();
$table->string('price')->nullable();
$table->timestamps();
});
}
product model :
public function attr(){
return $this->belongsToMany(Attr::class)->withPivot(['value','price'])->withTimestamps();
}
attr model:
public function product(){
return $this->belongsToMany(Product::class)->withPivot(['value','price'])->withTimestamps();
}
my controller :
class SingleProduct extends Component
{
public $product;
public function mount($id){
$this->product=Product::with('attr')->findOrFail($id);
}
public function render()
{
return view('livewire.front.product.single-product')->extends('layouts.Default')->section('content');
}
}
my loop in blade :
#foreach($product->attr as $attr)
<div class="col-lg-4 col-sm-6 mt-3">
<h6 class="mb-2 text-black">{{$attr->title}}</h6>
<select class="custom-select shadow-none">
#foreach($attr as $av)
<option value="{{$av->pivot->price}}">{{$av->pivot->value}}</option>
#endforeach
</select>
</div>
#endforeach
before #foreach add
#php
dd($product)
#endphp
You can troubleshoot your $product Model and relations
The right syntax for withPivot should be parameters separated by comma, try this:
product model
public function attr(){
return $this->belongsToMany(Attr::class)
->withPivot('value','price')
->withTimestamps();
}
attr model:
public function product(){
return $this->belongsToMany(Product::class)
->withPivot('value','price')
->withTimestamps();
}

relation between tables Laravel

I have 3 tables one for courses and second table for classes and the other table for categories which categories can have multiple classes. so I want to show list of courses with classe_name and category name.
I make pivot table between classes and categories which also contain course name, but I can't show catgory name from table categories and I don't know if this is the correct way
//method to show courses
public function index()
{
$categories=Course_category::all();
return view('teacher.courses')->with('categories',$categories);
}
blade
#foreach ($categories->classe as $item)
{{$item->category_name}}
#endforeach
categorie model
protected $table = 'categories';
protected $fillable =['id','category_name','categorie_image'];
/**
* The roles that belong to the Course_category
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function classe(){
return $this -> belongsToMany('App\Classe','classe_categorie','categorie_id','classe_id');
}
classe model
protected $table = 'classes';
protected $fillable=['id','classe_name','classe_image'];
public function course_categorie() {
return $this -> belongsToMany('App\Course_category','classe_categorie','classe_id','categorie_id');
}
You should loop through classes, not categories:
#foreach ($categories->classe as $item)
{{$item->category_name}}
#endforeach
It should be
#foreach ($categories as $item)
{{$item->classe->classe_name}}
{{$item->category_name}}
#endforeach
As you want to show classes, why don't you collect all Classes in the controller and start from there? Unless you want to group by categories, which is easily done with eloquent.
thank you for your help i found the solution
$categories=Course_category::with('classe')->get();
and i use loop inside loop for the collection
#foreach ($categories as $item)
{{-- {{$item->course_category->category_name}} --}}
#foreach ($item->classe as $cat)
{{$cat->course_name}}
{{$cat->classe_name}}
#endforeach
#endforeach

Why can't I use method on relation in laravel?

I wanna using method on relation in laravel but show error[Method Illuminate\Database\Eloquent\Collection::getMessage does not exist.].
Error was changed to Call to a member function getMessage() on null when I rewrite {{$item->board2->getMessage()}} to {{$item->aaaaaaaa->getMessage()}} so I think relation was succeed.
I have no Idea what's wrong.
please give me advice.
Board2.php(model)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Board2 extends Model
{
protected $table = 'boards2';
protected $fillable = [
'person2_id',
'message'
];
public function person2()
{
return $this->belongsTo('App\Person2');
}
public function getMessage()
{
return $this->message;
}
}
Person2(model)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Person2 extends Model
{
protected $table = 'people2';
protected $fillable = [
'name'
];
public function board2()
{
return $this->hasMany('App\Board2', 'person2_id');
}
}
View
<ul>
#foreach($items_p2 as $item)
<li>
{{$item->name}}
</li>
<li>
{{$item->board2->getMessage()}}
</li>
#endforeach
</ul>
controller
・
・
・
public function show2()
{
$items_p2 = Person2::all();
$data = [
'items_p2' => $items_p2
];
return view('Review.show2', $data);
}
migration files
class CreatePeople2Table extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('people2', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBoards2Table extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('boards2', function (Blueprint $table) {
$table->increments('id');
$table->integer('person2_id');
$table->text('message');
$table->timestamps();
});
}
first:
in order to get the relation data you should load it first ...
$items_p2 = Person2::with('board2')-> all();
second: in your blade file
{{$item->board2->getMessage()}}
$item->board2 return a collection not a single board, so you should put it in foreach as well
#foreach($items_p2 as $item)
<li>
{{$item->name}}
</li>
<li>
#foreach($item->board2 as $board)
<li>
{{$item->board2->getMessage()}}
<li>
#endforeach
</li>
#endforeach
</ul>
Inside Board2.php(model) file, you have defined the method getMessage(), the method is loaded on the instance of the model and not the array of models (in Laravel's case, multiple models are loaded in a collection).
Inside Person2(model) file, you have defined the relation board2() which is linked to Board2 model via HasMany Relation. The catch is that HasMany relation, as the name suggests will load collection from the db and not a single instance of the model.
Try changing HasMany to HasOne inside Person2 model, your error should be resolved.
Accoring to the code you have written, each board2 record is connected to a single instance of person2, but on the other side, each person2 record is connected to a collection/array of board2 (not connected to single board2). This is the point keep in mind. Now let's proceed to next step.
Let's take a look in your view file. The code you wrote in view is
<ul>
#foreach($items_p2 as $item)
<li>
{{$item->name}}
</li>
<li>
{{$item->board2->getMessage()}}
</li>
#endforeach
</ul>
Here in $item->board2 , the board2 is not a single instance/record/model, rather it is a collection/array of multiple board2 instances/records/models. And each of that record/model will have the method "getmessage()" as you expected. So, the thing you have to do is, iterate through the records/models by making foreach to $item->board2, this way you will have the access to each single board2 record/model, then call the getMessage() method from that record/model. Let's modify the view code like this.
<ul>
#foreach($items_p2 as $item)
<li>
{{$item->name}}
</li>
<li>
#foreach( $item->board2 as $board )
{{$board->getMessage()}}
//this echo is just to break the line
echo '<br>';
#endforeach
</li>
#endforeach
</ul>
Hope it will work now. :)
You have to change this location. You write this in Person2 model
public function getMessage(){
return $this->message;
}

Laravel 5.3 How to use multiple controllers in one view

I'm working with a view that at first displays all products, and on the sidebar, users can see a list of categories. My aim is when users press on any categories, it will display products of that category only. However, since there are 2 controllers is interacting with this view and send the same data, one is not running(CategoriesController). It does not show any error, just when I click on the link of each of the categories, it does not reload the page.
Here is my ProductsController:
class ProductsController extends Controller
{
// display all products and categories
public function index() {
$products = Product::all();
$categories = Category::all();
return view('frontend.product', compact('products','categories'));
}
And my CategoriesController:
class CategoriesController extends Controller
{
public function showProducts($category_id) {
$products = Category::find($category_id)->products;
return view('frontend.product', compact('products'));
}
Here is my view:
// Products part
#foreach($products as $product)
{{ $product->name }}
#endforeach
//Categories part
#foreach($categories as $category)
{{ $category->name }}
#endforeach
And route:
Route::get('/products', [ 'as' => 'products', 'uses' => 'frontend\ProductsController#index']);
Route::get('/categories/{category_id}', ['as' => 'categories', 'uses' => 'backend\CategoriesController#showProducts']);
Just include all of the categories in your showProducts function, and omit the current category:
public function showProducts($category_id)
{
$categories = Category::whereNotIn('id', $category_id)->get();
$products = Category::find($category_id)->products;
return view('frontend.product', compact('products', 'categories'));
}
Now there will be no discrepancies between the variables that are being used.
If I have not misunderstood, I thought you can use #inject in blade. For example:
namespace App\Presenters;
use App\User;
class UserPresenter
{
/**
* 是否顯示email
* #param User $user
* #return string
*/
public function showEmail(User $user)
{
if ($user->show_email == 'Y')
return '<h2>' . $user->email . '</h2>';
else
return '';
}
}
and
<div>
#inject('userPresenter', 'MyBlog\Presenters\UserPresenter')
#foreach($users as $user)
<div>
{!! $userPresenter->showEmail($user) !!}
</div>
</div>

Laravel Category Model Relationships

I have the following table structure in my database.
Table Name: tiles
Columns: id, tile_name, tile_thumb, tile_snippet
Table Name: tags
Columns: id, tag_title
Table Name: tile_tags
Columns: id, tile_id, tag_id
Models:
Tile, Tag, TileTag
In my main model class for entries I am specifying the following relationship to a model called TileTag which is a pivot table.
<?php namespace Tiles;
use Illuminate\Database\Eloquent\Model;
class Tile extends Model {
protected $table = 'tiles';
public function tags() {
return $this->belongsTo('Tiles\TileTag');
}
}
During my foreach loop it returns the tile_name and any other columns from my table, except the ones joined by the relatipnship.
#foreach($tiles as $tile)
<a href="tile/{{$tile->tile_name}}">
<li class="col-md-4 mix" data-category="{{ $tile->tags->tag_title }}">
{!! HTML::image($tile->tile_thumb, null, array('class' => 'img-responsive')) !!}
</li>
</a>
#endforeach
How can I get my categories/tags linked to my primary entries when they are sorted during each loop?
I try returning the data during the loop by {{ $tile->tags->tag_title }} but it returns an empty string.
Controller Method:
class TileController extends Controller {
/**
* Display a listing of tiles from the database.
*
* #return Response
*/
public function index() {
// Get tile data from the model
$tiles = \Tiles\Tile::all();
return view('pages.index', compact('tiles'));
}
Returned Array:
I think that you don't have to create a model for Tile_Tag. Laravel can handle ManyToMany relationships out of the box (I suppose that this is the type of the relationship because you use pivot table). Your models should be
class Tile extends Model {
protected $table = 'tiles';
public function tags() {
return $this->belongsToMany('Tiles\Tag');
}
}
and
class Tag extends Model {
protected $table = 'tags';
public function tiles() {
return $this->belongsToMany('Tiles\Tile');
}
}
Laravel will know that you have a pivot table named "tag_tile" with columns "tag_id" and "tile_id". Check the relevant documentation here
Then you can iterate through tags collection for each tile like this
#foreach ($tiles as $tile)
{!!$tile->tile_name!!}
#foreach ($tile->tag as $tag)
{!!$tag->tag_title!!}
#endforeach
#endforeach
Hope it helps.

Resources