on cascade delete on many to many relationship in laravel - laravel

I had used many to many relationship.i have three table named:product,tag,productstag. in here I want whenever I am going to delete a product it will also delete the relationship it had on productstag table.
public function up()
{
Schema::create('productstags', function (Blueprint $table) {
$table->integer('product_id');
$table->integer('tag_id');
$table->primary(['product_id','tag_id']);
$table->timestamps();
});
}
as you can see I have used product_id and tag_id as the primary key.
so I can't use this
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->foreign('tag_id')->references('id')->on('products')->onDelete('cascade');
so what's the alternative?
on my product model
public function tags()
{
return $this->belongsToMany('App\Tag','productstags','product_id','tag_id')->withTimestamps();
}
on my tag model:
public function products()
{
return $this->belongsToMany('App\Product','Productstags','tag_id','product_id');
}
on my produduct destroy function:
public function destroy(Request $request,$id)
{
$product=Product::findOrFail($id);
if($request->file('image')==''){
$input=$request->except('photo_id');
}
else{
$input=$request->all();
unlink(public_path()."/images/".$product->image->name);
}
$product->delete($input);
Session::flash('deleted_user','the user has been deleted');
return redirect(route('product.index'));
}

It's not as pretty as cascade but you could override the delete method and do this:
public function delete(){
$this->name_of_the_relationship()->delete();
return parent::delete();
}

Related

Laravel - How to prevent row getting deleted when there is dependent field

I am a laravel beginner. In my laravel CRUD project, I have these migration table
GroupTable
class Group extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('group', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('group_code');
$table->string('group_desc');
$table->timestamps();
});
}
CategoryTable
class Category extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('category', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('category_code');
$table->string('category_desc');
$table->timestamps();
});
}
ItemTable
class Item extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('item', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('item_code');
$table->string('item_desc');
$table->string('item_picture');
$table->string('item_cost');
$table->string('item_price');
$table->string('group_desc');
$table->string('category_desc');
$table->timestamps();
});
}
The group_desc and category_desc from ItemTable are foreign key from GroupTable and CategoryTable.
GroupController
public function destroy($id)
{
Group::find($id)->delete();
return response()->json(['success'=>'Group deleted successfully.']);
}
CategoryController
public function destroy($id)
{
Category::find($id)->delete();
return response()->json(['success'=>'Category deleted successfully.']);
}
This is the ajax delete function in my view of group
//Delete
$('body').on('click', '.deleteRecord', function () {
var id = $(this).data("id");
if(confirm("Are you sure want to delete? "))
{
$.ajax({
type: "DELETE",
url: "{{ url('group/delete') }}" + '/' + id,
success: function (data) {
table.draw();
},
error: function (data) {
console.log('Error:', data);
}
});
}
});
Before user want to delete the row on GroupTable or CategoryTable, how to display a message shows that the row are not allow to delete if ItemTable have data from GroupTable or CategoryTable?
If you are using the foreign key and if it is not a 'cascade' delete, then laravel won't allow you to delete the row when If the same Id used somewhere. for example,
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); //inside item table. (CASCADE delete).
$table->foreign('category_id')->references('id')->on('categories');// non-cascade
assume, If you are using cascade delete, and you are trying to delete the category which is used in the item table, this will delete the category and related item lists in item table.
If you are using non-cascade method, It won't allow you to delete the category when it is used in item table.
If you follow Laravel's convention, things will be a lot easier to do. Might be longer at first but it gets better
(I am assuming you are using Laravel 8)
1: Table names are usually in plural forms, so your tables should be groups, categories and items
2: Next is to properly define foreign keys for groups and categories tables in items table like this
Schema::create('item', function (Blueprint $table) {
//...
$table->foreignId('group_id')->constrained();
$table->foreignId('category_id')->constrained();
//...
});
3: Define the respective relations in the 3 models
Group Model
namespace App\Models;
class Group extends Model
{
//...
public function items(){
return $this->hasMany(Item::class);
}
//...
}
Category model
namespace App\Models;
class Category extends Model
{
//...
public function items(){
return $this->hasMany(Item::class);
}
//...
}
Item Model
namespace App\Models;
class Item extends Model
{
//...
public function category(){
return $this->belongsTo(Category::class);
}
public function group(){
return $this->belongsTo(Group::class);
}
//...
}
All the above, while kind of long, will make your work easier later.
From here you can implement the following
GroupController
public function destroy($id)
{
$group = Group::withCount('items')
->find($id);
if($group->items_count < 1){
$group->delete()
return response()->json(['success'=>'Group deleted successfully.']);
}
return response()->json(['fail'=> 'Group has items, cannot be deleted.' ]);
}
CategoryController
public function destroy($id)
{
$category = Category::withCount('items')
->find($id);
if($category->items_count < 1){
$category->delete()
return response()->json(['success'=>'Category deleted successfully.']);
}
return response()->json(['fail'=> 'Category has items, cannot be deleted.' ]);
}

Can't create one to many relationship on same model

I want to create sponsors users on my website. I use the same model as relationship.
User.php (model):
public function sponsor(): HasMany
{
return $this->hasMany(self::class, 'sponsored_id', 'sponsor_id');
}
public function sponsored(): BelongsTo
{
return $this->BelongsTo(self::class, 'sponsor_id', 'sponsored_id');
}
Sponsor rows :
Schema::table('users', function (Blueprint $table) {
$table->foreignId('sponsor_id')->nullable();
$table->foreignId('sponsored_id')->nullable();
});
My UserSeeder:
$sponsor = User::factory()->create(['name' => 'sponsor']);
$sponsor->sponsor()->save(
User::factory()->make()
);
As per your comment you are trying to retrieve one record from sponser so it should be
$sponsor->sponsor()->first()

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 make a reflexive relationship in Laravel migration and model

I would like to have a table that has a one to many with itself. Eg: I have like a people table that can have many other people.This is how my code looks like:
public function up()
{
Schema::create('people', function (Blueprint $table) {
$table->string('id')->primary();//Here my PK is a string
$table->string('name');
$table->string('title')->nullable();
$table->string('parent_id');//Here is the foreign key of another person
$table->timestamps();
});
}
And in my Person.php model I have this:
public function people()
{
return $this->belongsTo('App\Person')->withDefault();
}
public function person()
{
return $this->hasMany('App\Person');
}
Take a look to this image:
In Person.php model:
public function parent()
{
return $this->belongsTo('App\Person', 'parent_id');
}
public function child()
{
return $this->hasMany('App\Person', 'parent_id');
}
Add parent_id in your migration and define relationship in you model
public function people()
{
return $this->belongsTo('App\Person')->withDefault();
}
public function person()
{
return $this->hasMany(self::class, 'parent_id');
}

Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation

Trying to get a list of users associated with an event. Here are my eloquent models:
User.php:
public function fbevents()
{
$this->belongsToMany('Fbevent', 'fbevent_user');
}
Fbevent.php:
public function users()
{
$this->belongsToMany('User', 'fbevent_user);
}
I get this error when I try to find the list:
$event = Fbevent::find(10);
var_dump($event->users->lists('userId'));
I've set up a pivot table in the db with the following migration:
$table->increments('id');
$table->integer('fbevent_id')->unsigned()->index();
$table->foreign('fbevent_id')->references('id')->on('fbevents')->onDelete('cascade');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
And added an entry in the fbevent_user table with fbevent_id = 10 and user_id = 1.
You need to return a result from your relations
public function fbevents()
{
return $this->belongsToMany('Fbevent', 'fbevent_user');
}
public function users()
{
return $this->belongsToMany('User', 'fbevent_user');
}

Resources