Laravel: Eloquent Relationship error - laravel

I have a many to many relationship between products and a product_categories tables. Now I want to create a translation table for categories.
But how do I relate them in eloquent? i am learning database relationships so forgive my ignorance.
Here is my tables:
//languages
Schema::create('locales', function(Blueprint $table)
{
$table->increments('id');
$table->string('code', 2);
$table->string('name');
});
//products
Schema::create('products', function(Blueprint $table)
{
$table->increments('id');
$table->string('thumbnail');
$table->timestamps();
});
//categories
Schema::create('product_categories', function(Blueprint $table)
{
$table->increments('id');
$table->string('category');
});
//relationship table
Schema::create('product_productcategory', function(Blueprint $table)
{
$table->integer('product_id')->unsigned()->index(); // the id of the bear
$table->foreign('product_id')->references('id')->on('products');
$table->integer('product_category_id')->unsigned()->index(); // the id of the picnic that this bear is at
$table->foreign('product_category_id')->references('id')->on('product_categories');
});
//category translations
Schema::create('category_translations', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('product_categories')->onDelete('cascade');
$table->integer('locale_id')->unsigned();
$table->foreign('locale_id')->references('id')->on('locales')->onDelete('cascade');
$table->unique(['category_id', 'locale_id']);
});
Product Model:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'product_productcategory')->translation(1);
}
}
Product categories:
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'product_productcategory');
}
}
Category Translations
class Category_Translation extends Model
{
protected $table = 'category_translations';
public function product_category() {
return $this->belongsTo('App\product_category');
}
}
But when i run:
$product = App\Product::find(1)->first();
echo $product->product_category;
I get error:
Call to undefined method Illuminate\Database\Query\Builder::translation()

You should not call translation in the Product model category relation (because you still interacting with the query builder), instead you should access the translation as a property on the category object:
echo $product->product_category->first()->getTranslatedIn(1)->name;
So you could refactor your code like this:
Product Model:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'product_productcategory');
}
}
Product categories:
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'product_productcategory');
}
public function translations() {
return $this->hasMany('App\Category_Translation', 'category_translations');
}
// relation filtered by language (cannot be accessed as a property unless you define the parameter as optional)
public function translatedIn($language) {
return $this->hasOne('App\Category_Translation', 'category_id')->where('locale_id', $language);
}
// access translated object
public function getTranslatedIn($language) {
return $this->translatedIn($language)->getResults();
}
}

Related

Laravel eloquent relations not working completely

I've a payment gateway, I want to access the product items after returning, so I created several tables Payments, Orders, OrderItems and configured the relationships between them.
Each Payment is for one Order and each Order contains several OrderItem and each OrderItem contains one product. Now I want to access each Product through an object of the Payment Model, which returns the following error.
Illuminate\Database\QueryException SQLSTATE[42S22]: Column not found:
1054 Unknown column 'orders.order_item_id' in 'field list' (SQL:
select products.*, orders.order_item_id as laravel_through_key
from products inner join orders on orders.id =
products.order_id where orders.order_item_id = 68 limit 1)
$product_order_item = $payment->order->order_items->map(function ($order_item) {
dd($order_item->product);
});
Payment Model:
protected $table = "payments";
protected $guarded = [];
public function order() {
return $this->belongsTo(Order::class);
}
Order Model:
protected $table = "orders";
protected $guarded = [];
public function payment() {
return $this->hasOne(Payment::class);
}
public function order_items() {
return $this->hasMany(OrderItem::class);
}
OrderItem Model:
protected $table = "order_items";
protected $guarded = [];
public function order() {
return $this->belongsTo(Order::class);
}
public function product() {
return $this->hasOneThrough(Product::class, Order::class);
}
Product Model:
protected $table = "products";
protected $guarded = [];
public function order_items() {
return $this->belongsToMany(OrderItem::class);
}
That is migrations:
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE');
$table->unsignedInteger('amount');
$table->unsignedInteger('res_code');
$table->enum('status', ['paid', 'unpaid']);
$table->timestamps();
});
=====================================================
Schema::create('order_items', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('order_id');
$table->foreign('order_id')->references('id')->on('orders')->onDelete('CASCADE');
$table->unsignedBigInteger('product_id');
$table->foreign('product_id')->references('id')->on('products')->onDelete('CASCADE');
$table->unsignedInteger('price');
$table->timestamps();
});
===========================================================
Schema::create('payments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('order_id');
$table->foreign('order_id')->references('id')->on('orders')->onDelete('CASCADE');
$table->enum('status', ['paid', 'unpaid']);
$table->unsignedInteger('ref_id');
$table->unsignedInteger('res_id');
$table->enum('gateway', ['idpay', 'zarinpal']);
$table->timestamps();
});
what is the problem?
Thanks in advance...
You should use belongsTo for the product relationship of OrderItem Model
OrderItem Model:
public function product() {
return $this->belongsTo(Product::class);
}
https://laravel.com/docs/8.x/eloquent-relationships#one-to-many-inverse
And hasMany for the order_items relationship of Product Model
Product Model:
public function order_items() {
return $this->hasMany(OrderItem::class);
}
https://laravel.com/docs/8.x/eloquent-relationships#one-to-many

Need to save foreign key manually on belongsTo relationship with withDefault()?

it seems that I need to save the original model on the newly generated model in order to save the relation correctly.
I hope the below test case illustrates my problem:
// migrations
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->bigInteger('user_id')->nullable();
$table->timestamps();
});
//models
class User extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
class Post extends Model
{
public function user()
{
return $this->belongsTo(User::class)
->withDefault(['name' => 'Guest User']);
}
}
//test
public function test_foreign_key()
{
$post = factory(Post::class)->create();
$user = $post->user; // created from ->withDefault()
$user->save();
$this->assertNotNull($post->user);
$this->assertNotNull($post->user_id);
}
With additional association of the original model the test passes:
public function test_foreign_key_associates()
{
$post = factory(Post::class)->create();
$post->user->save();
$this->assertNotNull($post->user);
$post->user()->associate($post);
$this->assertNotNull($post->user_id);
}
edit: what I'm doing right now is the following for the withDefault relationship:
class Post extends Model
{
public function user()
{
return $this->belongsTo(User::class)
->withDefault(function (User $user, Post $post) {
$user->name = "Guest User";
$user->save();
$post->user_id = $user->id;
});
}
}

Eloquent - How to match data between tables of a single ID

Having multiple tables with data that relates to each other, i'm trying to display that data in a view using Laravel.
I must be confused with how Laravel runs its queries and I need help to sort how to do, what in PHP&SQL would be a left join.
My Asset Model:
public function category(){
return $this->hasOne(Category::class);
}
My Category Model:
public function asset()
{
return $this->belongsTo(Asset::class);
}
My Country Model:
public function country()
{
return $this->belongsTo(Asset::class);
}
And my AssetsController:
public function asset($id)
{
$asset = Asset::find($id);
return view('admin.assets.asset')->with('assets', $asset);
}
And the Router:
Route::get('/admin/assets/asset/{id}', [
'uses' => 'AssetsController#asset',
'as' => 'assets.asset'
//Show the Asset
]);
And the View:
<p><strong>Price:</strong>{{$assets->price}} €</p>
<p><strong>Description:</strong>{{$assets->description}}</p>
<p><strong>Country:</strong>{{$assets->country}}</p>
<p><strong>Category:</strong>{{$assets->name}}</p>
So in the 'asset.blade.php' I get the id from a previous index.blade.php that has a list of all the assets. I want to get via the ID, an asset page that displays the category name and the country name, instead of the ID that belongs to the Asset table.
So it should echo something like $assets->country->country_name and $assets->category->name
dd($asset);
EDIT: Additional information about migrations
categories_table migration
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('url');
$table->timestamps();
});
}
assets_table migration:
public function up()
{
Schema::create('assets', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->double('price',15,2);
$table->mediumText('description');
$table->integer('country');
$table->integer('category');
$table->integer('subcategory');
$table->integer('subsubcategory');
$table->integer('broker');
$table->string('featured');
$table->string('slug');
$table->timestamps();
});
}
Got it working.
class Category
{
public function asset()
{
return $this->hasMany(Asset::class);
}
}
class Asset
{
public function category()
{
return $this->belongsTo(Category::class);
}
}
use App\Asset;
use App\Category;
use App\Country;
use App\Subcategory;
use Illuminate\Http\Request;
class AssetController extends Controller
{
public function asset($id)
{
$asset = Asset::find($id);
return view('admin.assets.asset')
->with('asset', $asset)
->with('category', Category::all())
->with('subcategory', Subcategory::all())
->with('country', Country::all());
}
}
The other models have the same relationship towards the Asset model and vice-versa.
The View:
<p><strong>Category:</strong>{{$asset->category->name}}</p>
<p><strong>Sub-Category:</strong>{{$asset->subcategory->name}}</p>
It now shows the name matching the id of the corresponding tables.

How to access the values of a foreign key of another table using laravel

I created a custom pivot model which is SectionSubject that have an id, section_id and subject_id. I want now to access the other values related to the section_id. Here is my Sectionsubject model and section_subject table:
SectionSubject.php
class SectionSubject extends Model
{
protected $table = 'section_subject';
public function students()
{
return $this->belongsToMany(Student::class, 'section_subject_student','section_subject_id'
)->withTimestamps();
}
public function assignStudents(Student $student)
{
return $this->students()->save($student);
}
}
create_section_subject.php
Schema::create('section_subject', function (Blueprint $table) {
$table->increments('id');
$table->integer('section_id')->unsigned();
$table->integer('subject_id')->unsigned();
$table->string('schedule')->unique();
$table->string('room_no');
$table->foreign('section_id')
->references('id')
->on('sections')
->onDelete('cascade');
$table->foreign('subject_id')
->references('id')
->on('subjects')
->onDelete('cascade');
});
Now I want to fetch those values and place it on my ReservationController. I tried to use one to many relationship but it seems not working.
class ReservationController extends Controller
{
public function index()
{
$sectionSubject = SectionSubject::find(1);
//code here
return view('reservation.form', compact('sectionSubject');
}
}
you can fetch relationship by doing this
$sectionSubject = SectionSubject::with('students')->find(1);
//print your variable
echo "<pre>";
print_r($sectionSubject->toArray());
echo "</pre>";
you will find the related table data

Laravel BelongsToMany Error - Base table or view not found

I hope this thread find everyone healthy.
What is wrong with the following code? I am getting an error on my many to many relationship. For the past 4 hours i am stuck with this problem. I would be very thankful if you find the bug or source of problem.
Here is my code and tables:
Schema::create('products', function(Blueprint $table)
{
$table->increments('id');
$table->integer('category');
$table->string('thumbnail');
$table->string('images');
$table->string('logo');
$table->string('main_photo');
$table->timestamps();
});
//categories table
Schema::create('product_categories', function(Blueprint $table)
{
$table->increments('id');
$table->string('category');
});
//relationship table
Schema::create('product_productcategory', function(Blueprint $table)
{
$table->increments('id');
$table->integer('product_id'); // the id of the bear
$table->integer('productcategories_id'); // the id of the picnic that this bear is at
});
products model:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'App\product_productcategory', 'product_id', 'productcategories_id');
}
}
And pivot model
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'App\product_productcategory', 'productcategories_id', 'product_id');
}
}
Thanks in advance!
Updates: The problem is solved thanks to #mimo.
But now i want to translate the categories in different languages so i created a table like this:
Schema::create('category_translations', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('product_categories')->onDelete('cascade');
$table->integer('locale_id')->unsigned();
$table->foreign('locale_id')->references('id')->on('locales')->onDelete('cascade');
$table->unique(['category_id', 'locale_id']);
});
And my product categories with new relationship to the translations
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
//return $this->belongsToMany('App\Product', 'App\product_productcategory', 'productcategories_id', 'product_id');
return $this->belongsToMany('App\Product', 'product_productcategory');
}
public function translation($lang) {
return $this->hasMany('App\Category_Translation')->where('locale_id', '=', $lang);
}
}
And in category translation:
class Category_Translation extends Model
{
protected $table = 'category_translations';
public function product_category() {
return $this->belongsTo('App\product_category');
}
}
And finally my Product:
class Product extends Model
{
protected $table = 'products';
public function translation($lang) {
return $this->hasMany('App\Product_Translation')->where('locale_id', '=', $lang);
}
public function product_category() {
//return $this->belongsToMany('App\product_category', 'App\product_productcategory', 'product_id', 'productcategories_id');
//return $this->belongsToMany('App\product_category', 'product_productcategory');
return $this->belongsToMany('App\product_category', 'product_productcategory')->translation(1);
}
}
Now when i run:
$product = App\Product::find(1)->first();
echo $product->product_category;
I get error:
Call to undefined method Illuminate\Database\Query\Builder::translation()
Your migration file is wrong:
//relationship table
Schema::create('product_productcategory', function(Blueprint $table)
{
$table->integer('product_id')->unsigned()->index(); // the id of the bear
$table->foreign('product_id')->references('id')->on('products');
$table->integer('productcategories_id')->unsigned()->index(); // the id of the picnic that this bear is at
$table->foreign('productcategories_id')->references('id')->on('product_categories');
});
This code will made the relationship on the database level.
When you have 12 min free time you can check out this tutorial about many to many relationships in laravel:
https://laracasts.com/series/laravel-5-fundamentals/episodes/21
Update:
you need to update your relationships too:
class Product extends Model
{
protected $table = 'products';
public function product_category() {
return $this->belongsToMany('App\product_category', 'product_productcategory');
}
}
and:
class product_category extends Model
{
protected $table = 'product_categories';
public function product() {
return $this->belongsToMany('App\Product', 'product_productcategory');
}
}

Resources