Given Eloquent Many To Many relationship:
Migration:
class Topics extends Migration
{
public function up()
{
Schema::create('topics', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
});
Schema::create('topic_user', function(Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->integer('topic_id')->unsigned();
$table->foreign('topic_id')->references('id')->on('topics');
});
}
}
Model:
class User extends Model
{
public function topics()
{
return $this->belongsToMany('App\Topic', 'topic_user');
}
}
I'm wondering how can I delete all topics by given user, currently my code looks like this:
Auth::user()->topics()->delete();
But I'm getting exception:
ERROR: missing FROM-clause entry for table "topic_user" LINE 1: delete
from "topics" where "topic_user"."user_id" = $1 ^ (SQL: delete from
"topics" where "topic_user"."user_id" = 6)
What I'm doing wrong?
That's pretty simple:
Auth::user()->topics()->detach();
Related
I have 3 table, table Courses, table Sections, and table Syllabuses. Where table courses relation to table Sections and table Sections relation to table Syllabuses. To make clear below my table look like:
#Table Courses:
public function up()
{
Schema::create('courses', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
$table->unsignedBigInteger('category_id')->default('1');
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade')->onUpdate('cascade');
$table->string('title');
$table->string('status')->default('publish');
$table->text('content')->nullable();
$table->timestamps();
});
}
Table Sections:
public function up()
{
Schema::create('sections', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('course_id');
$table->foreign('course_id')->references('id')->on('courses');
$table->string('name');
$table->timestamps();
});
}
and the last table Syllabuses:
public function up()
{
Schema::create('syllabuses', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('section_id');
$table->foreign('section_id')->references('id')->on('sections')->onDelete('cascade')->onUpdate('cascade');
$table->string('title')->nullable();
$table->text('content')->nullable();
$table->text('description')->nullable();
$table->timestamps();
});
}
and now I'm stuck to display data from table syllabuses base on Sections's ID, where the sections display base on Courses's ID, because I don't know how to get the ID from each row which related to Secations's ID to put in Syllabus::where('section_id',???)->get();. Anyone who can help me much much appreciate. Hope u understand what I mean.
Below the image you can see, there I have put some note to make u understand. The problem in the green box one.
enter image description here
Define relations in your models first.
I assume your models are: Course, Section and Syllabus
// Model Course
public function sections()
{
return $this->hasMany(Section::class);
}
// Model Section
public function course()
{
return $this->belongsTo(Course::class);
}
public function syllabuses()
{
return $this->hasMany(Syllabus::class);
}
// Model Syllabus
public function section()
{
return $this->belongsTo(Section::class);
}
Now in your controller you can get your designated course by
// Controller Course
public function show($id)
{
$course = Course::with('sections', 'sections.syllabuses')->where('id', $id)->first();
}
In this query you have a model from "Course" table, related models from "Sections" table and all the related models from "Syllabuses" table. If you are using laravel's blade then you can simply access them by:
// course
{!! $course->your_attribute !!}
// to access sections
#foreach($course->sections as $section)
#endforeach
// to access syllabuses
#foreach($course->sections as $section)
#foreach($section->syllabuses as $syllabus)
// Here you will have syllabuses for individual sections
#endforeach
#endforeach
https://laravel.com/docs/8.x/eloquent-relationships#one-to-many
You need to study laravel relationships in your case you have belongsTo relation.
In your Syllabus model add.
public function section(){
return $this->belongsTo(Section::class, 'section_id');
}
Then you can use this will get all Syllabuses with related to there sections.
Syllabus::with('section')->get();
I use Laravel 8. I have 3 table. Course table, UserCourse, and User table. I want to get user courses. I tried it with tinker: Course::find(1)->user_courses -it works fine and give back me user_course.
UserCourse::find(1)->user_course - the problem is here, this will return me "null"
How can I get the User Courses?
Course table
Schema::create('courses', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->timestamps();
});
UserCourse table
Schema::create('user_courses', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->foreignId('course_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
User table
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('email')->unique();
$table->string('username')->unique();
$table->string('password');
$table->timestamp('updated_at')->nullable();
$table->timestamp('created_at')->nullable();
});
Course.php
class Course extends Model
{
use HasFactory;
protected $fillable = [
'title',
];
public function user_courses()
{
return $this->hasMany(UserCourse::class);
}
}
UserCourse.php
class UserCourse extends Model
{
use HasFactory;
protected $fillable = [];
public function user_course()
{
return $this->belongsTo(Course::class);
}
}
Your database structure make it that the relation between course and user is a many to many relation with a pivot table in the middle.
Some correction you need to do for it to work seemingly with laravel conventions.
- The pivot table name should be course_user without a primary key
Schema::create('course_user', function (Blueprint $table) {
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->foreignId('course_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
- Remove the UserCourse.php model since it's a pivot
- Define the relation courses in User model as follow
User.php
public function courses()
{
return $this->belongsToMany(Course::class);
}
- Define the relation users in Course model as follow
Course.php
public function users()
{
return $this->belongsToMany(User::class);
}
Now to get any user courses, just run User::find(1)->courses
Same thing to get the users that belongs to the same couses Course::find(1)->users
get courses that the user has not taken:
$userId = 1;
$courses = Course::whereDoesntHave('users', function($userQB) use($userId) {
$userQB->where('id',$userId);
})->get();
Thank you in advance
I have 2 tables as below
1) users
2) reviews
The schema I have created is like below
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('first_name',100)->nullable();
$table->timestamps();
});
Schema::create('reviews', function (Blueprint $table) {
$table->id();
$table->bigInteger('user_id')->unsigned();
$table->string('name',100)->nullable();
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
When i am deleting the user, it is not deleting reviews belongs to the deleted user
I am deleting user like below
User::where('id',1)->delete();
is there any short and simple and perfect way to do them for all the eloquent models?
you can try this code in your parent model :
public static function boot()
{
parent::boot();
static::deleting(function ($model) {
$model->relations()->delete();
});
}
*update for softDeletes
public static function boot()
{
parent::boot();
static::deleting(function ($model) {
if($model->isForceDeleting()){
$model->relations()->delete();//or forceDelete if child also using softDelete
});
}
}
I want to rename the foreign key in Laravel.
This is how, I have created it:
Schema::create('holidays', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('account_id')->unsigned();
$table->date('holiday_date');
});
if (Schema::hasTable('accounts')) {
Schema::table(
'holidays',
function (Blueprint $table) {
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
}
);
}
And now, I want to change account_id to engagement_id. How to do that?
It should be something like this :
Note : Before Renaming Foreign, You Must Need To Delete Old Foreign And Assign New One
class RenameColumn extends Migration
{
public function up()
{
Schema::table('holidays', function(Blueprint $table) {
$table->dropForeign('holidays_account_id_foreign');
$table->renameColumn('account_id', 'engagement_id');
$table->foreign('engagement_id')->references('id')->on('accounts')->onDelete('cascade');
});
}
public function down()
{
Schema::table('holidays', function(Blueprint $table) {
$table->dropForeign('holidays_engagement_id_foreign');
$table->renameColumn('account_id', 'engagement_id');
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
});
}
}
What #rborum explained requires doctrine/dbal package to be installed. Else you could directly execute sql query to rename your key or do any other changes.
I was able to do this without dropping the column.
Very simply:
public $oldIndex = 'old_constraint_name_foreign';
public $newIndex = 'new_constraint_name_foreign';
public $oldColumn = 'old_column_name';
public $newColumn = 'new_column_name';
Schema::table('my_table', function (Blueprint $table) {
$table->renameIndex($this->oldIndex, $this->newIndex);
$table->renameColumn($this->oldColumn, $this->newColumn);
});
You need to make a new migration with:
php artisan make:migration rename_column
With this inside:
class RenameColumn extends Migration
{
public function up()
{
Schema::table('accounts', function(Blueprint $table) {
$table->renameColumn('account_id ', 'engagement_id');
});
}
public function down()
{
Schema::table('accounts', function(Blueprint $table) {
$table->renameColumn('account_id ', 'engagement_id');
});
}
}
Then execute your migration:
php artisan migrate
If you do not already have it, you will need Doctrine. You can get this via composer with
composer require doctrine/dbal
I have a complex relationship like a ManyToMany relationship between Category and Products and a Product can have many Inventory listings from different Shops(user). A Shop can have multiple listing of the same Product as a variant(color/size).
Everything is fine till now!
The issue begins when showing the listing to the visitors. I want to show all listings under a category but don't want to show multiple listings of the same product from the same shop. Instead, want to pick the lowest sale_price listing from the shop.
I have three models and relations are like:
class Category extends Model
{
public function products()
{
return $this->belongsToMany(Product::class);
}
}
class Product extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
public function inventories()
{
return $this->hasMany(Inventory::class);
}
}
class Inventory extends Model
{
public function product()
{
return $this->belongsTo(Product::class);
}
}
Tables:
//Categories
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
});
//Products
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
});
//Pivot table
Schema::create('category_product', function (Blueprint $table) {
$table->integer('category_id');
$table->integer('product_id');
});
//Inventories
Schema::create('inventories', function (Blueprint $table) {
$table->increments('id');
$table->integer('shop_id');
$table->integer('product_id');
$table->string('sku', 200);
$table->string('title');
$table->decimal('sale_price', 10, 2);
});
As Laravel doesn't provide any manyToManyThough() relationship. I have added a listings method in the Category model. This method returns all listings:
public function listings()
{
$product_ids = $this->products()->pluck('products.id')->all();
return Inventory::whereIn('product_id', $product_ids)->paginate(20);
}
Then I tried this:
public function listings()
{
$product_ids = $this->products()->pluck('products.id')->all();
return Inventory::whereIn('product_id', $product_ids)->groupBy('shop_id','product_id')->paginate(20);
}
These methods produce MySQL GroupBy Error. Yes, I can filter the result after taking all result but that'll affect the pagination. How to get the sorted results and also keep the pagination ability. Thanks and day by day I got more indebted to the community. :)
You can create a direct relationship by "skipping" the products table:
public function listings() {
return $this->belongsToMany(
Inventory::class,
'category_product',
null,
'product_id',
null,
'product_id'
);
}