Same Foreing Key Twice That Refers to One Model - laravel

I need to make an advice platform for products. User can make advices under product section. So product has many advices. Also advices belongsTo product. But on product_advices table i have product_id and product_advice_id these both refers to id on products table.
So here is the problem. I can take advices from product_advices table which refers to product_id. But how can i take the other one as product.
product->advices to show advice and user message
each advices as advice and advice->product->name to show adviced product name
I couldn't make a relationship with eloquent between them.
//Product Model
public function advices()
{
return $this->hasMany('App\ProductAdvice', 'product_id');
}
//ProductAdvice Model
protected $table = 'product_advices';
public function product() {
return $this->belongsTo('App\Product', 'product_id');
}
//Product Advice Table
Schema::create('product_advices', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->text('body')->nullable();
$table->integer('product_id')->unsigned();
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->integer('product_advice_id')->unsigned();
$table->foreign('product_advice_id')->references('id')->on('products')->onDelete('cascade');
$table->timestamps();
});
For example :
Iphone has many advices by users.
Iphone->advices brings the advices from product_advices that Iphone belongs to product_id column.
When User recommends Samsung Galaxy S10 to Iphone. Samsung refers to product_advice_id column on product_advices table. But how to show Samsung Galaxy S10 as a product.
$advice->product->name returns Iphone instead of Samsung Galaxy S10.

EDIT 2
After your answer, I understood what you want.
Just update your ProductAdvice model to have another relationship, like:
class ProductAdvice extends Model
{
public function product()
{
return $this->belonsTo('App\Product', 'product_id');
}
public function related()
{
return $this->belonsTo('App\Product', 'product_advice_id');
}
}
Then you can do:
$product = Apple
$product->advices->message = 'blablabla'
$product->advices->related = 'ProductX'
If you need to to the inverse order, $advice->product->related add the same relationship on your Product model.
EDIT 1
Sorry, you edited the post after my answer...
Could you explain the 'product_advice_id' necessity? You already have the product_id.
Unless you want a pivot table, like: Product -> ProductAdvice -> Advice, which is not needed in your case, since you can just put the advice information in the Advice table and link it to the product (belongsTo), removing the necessity of the ProductAdvice pivot.
I think your structure should be like this:
Product model with all the product data
ProductAdvice model with product_id and the advice information (message, rating, etc)
Then, your Product hasMany Advices and your Advice belongsTo Product:
class Product extends Model
{
public function advices()
{
return $this->hasMany('App\ProductAdvice', 'product_id');
}
}
class ProductAdvice extends Model
{
public function product()
{
return $this->belonsTo('App\Product', 'product_id');
}
}
Finally, you can query the advices of a specific Product to get the advice information:
$product->advices->message
$product->advices->rating
Or query the product name if you have an advice:
$advice->product->name

So, If understand well, you want and advice from product A to return the name of product B.
You can make this by creating multiple method related to the same model.
Your models will look similar at this:
class Product extends Model
{
public function advices()
{
return $this->hasMany('App\ProductAdvice', 'product_id');
}
public function relations()
{
return $this->hasMany('App\ProductAdvice', 'related_id');
}
}
class ProductAdvice extends Model
{
public function product()
{
return $this->belonsTo('App\Product', 'product_id');
}
public function relation()
{
return $this->belonsTo('App\Product', 'related_id');
}
}
Then you will have to create another column in your talbe name :related_id (it could be something else, just made it match in your model. You can also change relations() and relation() method to whatever name you want.)
After this it's how you store your data. You have to make your code associate the good product model into your product_id and into related_id. This way. You can have $advice->product->name === 'iPhone' && $advice->relation->name === 'Samsung S10'

Found a solution like this for now.
//ProductAdvice Model
protected $table = 'product_advices';
public function user()
{
return $this->belongsTo('App\User');
}
public function product() {
return $this->belongsTo('App\Product', 'product_id');
}
public function advicedProduct()
{
return Product::where('id', $this->product_advice_id)->first();
}
//Product Model
public function advices()
{
return $this->hasMany('App\ProductAdvice', 'product_id');
}
How i show it on view
#foreach($product->advices as $advice)
<li>{{ $advice->body }} - {{ $advice->advicedProduct()->name }}</li>
#endforeach

Related

Laravel apply where clause to belongsToMany query using with() method

I have a products table with brand_id, and a category_products table with, product_id and category_id.
My Products model :
class Product extends Model
{
public function categories() {
return $this->belongsToMany(Category::class)->withTimestamps();
}
}
My Brands Model :
class Brand extends Model
{
public function products() {
return $this->hasMany(Product::class)->with(['categories']);
}
}
My question is, How can I fetch the products from a Brand instance that belongs to certain category?
$brand = App\Brand::find(1);
/*
I want to be able to do something in the likes of :
*/
$brand->products_which_are_under_this_category
Remove with(['categories']) method from inside products() and write a query like that.
$brand->products()->with(['categories' => function ($query) {
$query->where('category_id', CATEGORY_ID);
}])->get();
hope this can help.

Laravel - Return related models of parameter in controller

I have the following route:
Route::get('/api/products/{product}', 'ProductController#get');
My Product model looks like this:
class Product extends Model
{
public function ingredients()
{
return $this->belongsToMany(Ingredient::class)->withPivot('value');
}
}
In my controller, the method is:
public function get(Product $product)
{
return $product;
}
This only returns the attributes of the Product object as a JSON. I would also like to return the related ingredients and pivot table values (as it would with the with method), and possibly other related models.
return $product->with('ingredients') creates a collection of all Products, so that doesn't really work, I have to filter it again by the product ID. I can obviously construct the JSON myself, but that becomes tedious if I want multiple related models included. Is there an easy way to accomplish this?
You have three options:
Using $with in model
class Product extends Model
{
protected $with = ['ingredients'];
public function ingredients()
{
return $this->belongsToMany(Ingredient::class)->withPivot('value');
}
}
Load the relation and return product:
public function get(Product $product)
{
$product->ingredients;
return $product;
}
Use the load method on the product:
public function get(Product $product)
{
return $product->load('ingredients');
}

Laravel Polymorphic Many to Many relationship

I am very new to polymorphic relationships and am struggling on my first task. My real life scenario is complicated, so for the purpose of this question, I have simplified it a little.
I have a range of products. Each of these products can be 'tagged' to one or more "Categories", "Brand" and "Consumer". For example:
I figured with this setup, I would need a table for my polymorphic relationships as below:
I have created a new Taggable class which contains the following
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Taggable extends Model
{
public function taggable()
{
return $this->morphTo();
}
}
...and added a method to my Product class:
public function taggedCategories()
{
return $this->morphMany(Taggable::class, 'taggable');
}
Finally, in my ProductController, I am trying to retrieve all products with their relationships as such:
$products = Product::with('taggedCategories')
Whilst this isn't producing an error, there are no categories returned in my results. Looking at the SQL output in LaravelDebugBar, I see the following SQL.
select * from `taggables` where `taggables`.`taggable_id` in (1) and `taggables`.`taggable_type` = 'App\Models\Product'
This clearly is not right, but I cannot for love nor money figure out where I have gone wrong. I feel I am close, but not quite there.
Can anyone explain what is wrong? Also, would I need to do something different for getting the "Brand" as this is a one-to-many relationship, not many-to-many?
Thanks
Your model structure is going to be like:
class Categories extends Model
{
public function products()
{
return $this->morphToMany('App\Tag', 'productable');
}
}
class Brand extends Model
{
public function products()
{
return $this->morphToMany('App\Tag', 'productable');
}
}
// and Consumers, ....
User Model:
class Product extends Model
{
public function categories()
{
return $this->morphedByMany('App\Categories', 'productable');
}
public function brands()
{
return $this->morphedByMany('App\Brunds', 'productable');
}
}
Database schema:
categories
id - integer
...
brands
id - integer
...
consumer
id - integer
...
productable
product_id - integer
productable_id - integer
productable_type - string
Now, you can retrieve the relations:
$categories = App\Categories::find(1);
// retrieve product of a type
foreach ($categories->products as $product) {
//
}
$product = App\Product::find(1);
// retrieve categories of a product
foreach ($product->categories as $categories) {
//
}
Actually, your type product (categories, brands, consumers) are productable.

Laravel Eloquent Relationship Through Tables

I have the following database tables:
users
id
name
seasons
id
name
teams
id
name
standings
id
season_d
team_id
user_id
fixtures
id
season_id
home_team_id
away_team_id
My question is, how would I get which user a team belongs to for a certain fixture? For example I may want to do the following:
$fixture = Fixture::find(1);
echo $fixture->homeTeam->user->name;
My models look like this:
Fixture Model
class Fixture extends Eloquent{
public function season(){
return $this->belongsTo('Season');
}
public function homeTeam(){
return $this->belongsTo('Team', 'home_team_id');
}
public function awayTeam(){
return $this->belongsTo('Team', 'away_team_id');
}
}
Team Model
class Team extends Eloquent{
public function standings(){
return $this->hasMany('Standing');
}
public function seasons(){
return $this->belongsToMany('Season', 'Standings');
}
public function users(){
return $this->belongsToMany('User', 'Standings');
}
}
Season Model
class Season extends Eloquent{
public function standings(){
return $this->hasMany('Standing');
}
public function teams(){
return $this->belongsToMany('Team', 'Standings');
}
public function users(){
return $this->belongsToMany('User', 'Standings');
}
public function fixtures(){
return $this->hasMany('Fixture');
}
}
I think I need to add a user function to the Team model instead of the current users function that's there, but I can't figure out the correct way to do the relationship. A team will only have one user for any given season. Any help would be appreciated, thanks!
UPDATE
I have added the following relationships to the Fixture model, which allows me to get the user and team through the standings table:
public function homeTeamStanding(){
return $this->belongsTo('App\Modules\Leagues\Models\Standing', 'home_team_id', 'team_id')->where('season_id', $this->season_id);
}
public function awayTeamStanding(){
return $this->belongsTo('App\Modules\Leagues\Models\Standing', 'away_team_id', 'team_id')->where('season_id', $this->season_id);
}
The problem with this is that I can't use it with eager loading, so there's quite a lot of queries running, as when I try to eager load them $this->season_id is null. Surely there's a better way?
I replaced the above with joins instead so that I can eager load which results in a lot less queries!
public function homeTeamStanding(){
return $this->belongsTo('App\Modules\Leagues\Models\Standing', 'home_team_id', 'team_id')
->join('fixtures', 'fixtures.season_id', '=', 'standings.season_id');
}
public function awayTeamStanding(){
return $this->belongsTo('App\Modules\Leagues\Models\Standing', 'away_team_id', 'team_id')
->join('fixtures', 'fixtures.season_id', '=', 'standings.season_id');
}

Laravel 4 eloquent

Is there any way I can do this with eloquent?
$orders = Customer::with('orders','orders.shop')->where('orders.shop.location','=','Japan')->get()
Customers, orders and shop are tables where 1 customer has many orders and each order has one shop only.
Location is a column in the shop table
I keep getting an error stating orders.shop.location is a column not found.
Anyone can help? Thanks in advance.
You need to defined relationship in your model classes.
Customer model:
public function orders()
{
return $this->hasMany('Order');
}
Order model:
public function customer()
{
return $this->belongsTo('Customer');
}
Then if you want orders of a special customer you just have to do :
$orders = Customer::find($id)->orders;
Or find the user attatched to an order:
$user = Order::find($id)->user;
You can also use the same kind of relation between your Shop and Order model and do something like this:
$orders = Order::with(array('shop' => function($query)
{
$query->where('location', '=', 'japan');
}))->get();
Which should give you all orders for a shop located in japan.
More informations about this type of request:
http://laravel.com/docs/eloquent#eager-loading
in CostumerModel you need set a relationship (One To Many):
public function order()
{
return $this->hasMany('OrderModel', 'foreign_key_in_orderTable');
}
in OrderModel too:
public function costumer()
{
return $this->belongsTo('CostumerModel', 'foreign_key_in_orderTable');
}
then in OrderModel one more relationship with Shop (One To One):
public function shop()
{
return $this->hasOne('ShopModel', 'foreign_key');
}
Now in ShopModel (One To One):
public function order()
{
return $this->belongsTo('OrderModel', 'local_key');
}
query:
$orders = Customer::with('costumer', 'shop')->where('location','=','Japan')->get();

Resources