Laravel, Detach() method to delete parent records - php

Hi guys I'm working with many to many relationship and I want to know if is there any way to delete the records of the main table.
These are my tables
Schema::create('inventario_inicial', function (Blueprint $table) {
$table->increments('id');
$table->integer('producto_nombre_id')->unsigned();
$table->foreign('producto_nombre_id')->references('id')->on('producto_nombre');
$table->integer('existencias');
$table->double('promedio');
$table->timestamps();
});
Schema::create('empresa_inventario_inicial', function (Blueprint $table) {
$table->integer('empresa_id')->unsigned();
$table->foreign('empresa_id')->references('id')->on('empresas');
$table->integer('inventario_inicial_id')->unsigned();
$table->foreign('inventario_inicial_id')->references('id')->on('inventario_inicial');
});
I can get the data via pivot with this code
$empresa = Empresa::find($request->empresa_id);
$empresa->inventario_inicial();
To detach the data of that $empresa i use $empresa->inventario_inicial()->detach();
It deletes the records of the pivot table witch is correct, but also I want to delete not only what's in empresa_inventario_inicial but also inventario_inicial that were related. Something like cascade deleting but from pivot table.

You can use $table->foreign('inventario_inicial_id')->references('id')->on('inventario_inicial')->onDelete('cascade') in your migration.
If you don't want to cascade, consider using model events to automatically detach any empresa_inventario_official pivot records when deleting an inventario_official, and then use the $empresa->inventario_inicial()->delete() method in place of your detach() above.
In App\InventarioOfficial:
protected $dispatchesEvents = ['deleting' => InventarioDeleting::class];
Then you can define the event and a listener for the event:
In App\Events\InventarioDeleting
class InventarioDeleting
{
use SerializesModels;
public $inventario_official;
public function __construct(InventarioOfficial $inventario_official)
{
$this->inventario_official = $inventario_official;
}
}
In App\Providers\EventServiceProvider
public function boot()
{
parent::boot();
Event::listen(\App\Events\InventarioDeleting::class, function ($io) {
DB::('empresa_inventario_inicial')->where('inventario_inicial_id',$io->id)->delete();
//or $io->empresas()->detach();
});
}

Related

Laravel Eloquent where statement returns no attributes

So from my previous post, I was advised to start using Eloquent models, which I did.
My end goal, is to print out specific gifts, that belongs to that specific box.
Migrations:
gift_items:
public function up()
{
Schema::create('gift_items', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->float('unit_price');
$table->integer('units_owned');
});
}
gift_campaigns:
public function up()
{
Schema::create('gift_campaigns', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->foreignId('user_foreignK')->constrained('users');
$table->integer('gift_item_count')->nullable();
$table->string('status');
$table->date('dispatch_date');
$table->date('delivery_date');
});
}
Pivot table:
public function up()
{
Schema::create('campaigns_gifts', function (Blueprint $table) {
$table->foreignId('gift_id')->constrained('gift_items');
$table->foreignId('campaign_id')->constrained('gift_campaigns');
});
}
Controller:
function box($id){
$data = Campaign::with('gifts')->where('id', $id)->get();
return view('DBqueries.boxView', ['data'=>$data]);
}
Error that I receive using this way:
Seems like the updated version is trying to call the gift_campaigns table id, instead of the pivots table campaign_id.
Once again, I need that Request $id would match the pivots table campaign_id, and print out all of the gifts that this specific id holds
First of all as I sense the campaigns_gifts is a pivot table for campaigns and gifts having a Many-to-Many relation. You are doing it completely against the conventions of Laravel.
You generally do not use a Model for pivot table.
You generally do not fetch data from the pivot table directly. Instead use the relation on one of the related Models.
Note: Laravel does allow a Model for a Pivot, and you can query the pivot table directly, just check the documentation.
The correct way:
Pivot
Make a pivot table (that you already have) with column gift_id and campaign_id. i.e., the convention for naming keys as [table_name_singular]_[primary_key_on_table]
Model
One each model, define relationship for the other data as:
Gift.php Model:
public function campaign() {
return $this->belongsToMany(Campaign::class, 'campaign_gift');
}
Campaign.php Model:
public function gifts() {
return $this->belongsToMany(Gift::class,'campaign_gift');
}
since gift have a hasMany relation, the gifts table must contain a foreign key to campaigns table named campaign_id (same as the one on pivot).
Controller
Now in your controller:
function box($id){
$data = Campaign::where('id',$id)->with('gifts')->get();
return view('DBqueries.boxView', ['data'=>$data]);
}
You don't need to tell Laravel which columns, tables etc are you referring to, as long as you follow the conventions, Laravel will magically do things that otherwise would have been much more painful.

One to Many Relationship Laravel cannot display the related data

I have two models called DataKelurahan and RegistrasiPasien and have a one-to-many relationship, but I can't access the relationship.
I have made a form for adding patient and save it to the registrasi_pasiens table and it works well. but when I try to display the relation data, it doesn't work properly.
In the registrasi_pasiens table, I have 1 record with kelurahan_id = 3. Then, I try to access it via php artisan tinker with these command:
$kelurahan = App\Domain\DataKelurahan\Models\DataKelurahan::find(3) works fine and data is exist.
$pasien = App\Domain\RegistrasiPasien\Models\RegistrasiPasien::find(2007000001) works fine and the data is exist with kelurahan_id = 3
$kelurahan->pasiens the result is null. Shouldn't it show the pasien data that has kelurahan_id = 3?
$kelurahan->pasiens->nama and the result is like this PHP Notice: Trying to get property 'nama' of non-object in D:/PROFESSIONAL/PROJECT/WEB DEVSeval()'d code on line 1 => null
I don't have any idea what's wrong with my codes. Much appreciate for your help guys.
Below are the models that I have made:
DataKelurahan.php
<?php
namespace App\Domain\DataKelurahan\Models;
use Illuminate\Database\Eloquent\Model;
use App\Domain\RegistrasiPasien\Models\RegistrasiPasien;
class DataKelurahan extends Model
{
protected $fillable = ['nama_kelurahan', 'nama_kecamatan','nama_kota'];
public function pasiens(){
return $this->hasMany('RegistrasiPasien');
}
}
RegistrasiPasien.php
<?php
namespace App\Domain\RegistrasiPasien\Models;
use Illuminate\Database\Eloquent\Model;
use App\Domain\DataKelurahan\Models\DataKelurahan;
class RegistrasiPasien extends Model
{
protected $fillable = [
'nama',
'alamat',
'telepon',
'rt',
'rw',
'tgl_lahir',
'jenis_kelamin'
];
public function kelurahan(){
return $this->belongsTo('DataKelurahan');
}
}
And below are my database tables:
data_kelurahans
Schema::create('data_kelurahans', function (Blueprint $table) {
$table->increments('id');
$table->string('nama_kelurahan');
$table->string('nama_kecamatan');
$table->string('nama_kota');
$table->timestamps();
});
registrasi_pasiens
Schema::create('registrasi_pasiens', function (Blueprint $table) {
$table->increments('id');
$table->integer('kelurahan_id')->unsigned();
$table->string('nama');
$table->string('alamat');
$table->char('telepon', 15);
$table->integer('rt');
$table->integer('rw');
$table->date('tgl_lahir');
$table->string('jenis_kelamin');
$table->timestamps();
});
Schema::table('registrasi_pasiens', function (Blueprint $table){
$table->foreign('kelurahan_id')->references('id')->on('data_kelurahans')->onDelete('cascade');
});
From Docs:
Eloquent will automatically determine the proper foreign key column on
the model. By convention, Eloquent will take the "snake case"
name of the owning model and suffix it with _id.
So, Eloquent probably got your foreign key name wrong so you must override the foreign key by passing additional arguments to the hasMany/belongsTo method:
public function pasiens(){
return $this->hasMany('RegistrasiPasien','kelurahan_id');
}
public function kelurahan(){
return $this->belongsTo('DataKelurahan','kelurahan_id');
}

Seeding Relationship one to many in Laravel

I need to seed a relationship in Laravel, where each user has many devices
The User model
public function devices()
{
return $this->hasMany(Device::class);
}
The Device model
public function users()
{
return $this->belongsTo(User::class);
}
}
The device_user table
Schema::create('device_user', function (Blueprint $table) {
$table->increments('id');
$table->integer('device_id')->unsigned()->index();
$table->foreign('device_id')->references('id')->on('devices')->onDelete('cascade');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
});
The seeder
factory(App\Device::class, 20)->create()->each(function(App\Device $device) {
$device->users()->attach([
rand(1,5),
rand(6,15),
rand(16,20),
]);
});
But, when I run the migration with seeder, I get this message
Call to undefined method Illuminate\Database\Query\Builder::attach()
Please, help
attach for many to many relationships, you don't need device_user table for one to many relationship, in one to many you should create a column with name user_id in device table and just it. after that you can insert data in device table with user_id. and get user relationship with
Device::user()->get();

Laravel relationship with single column

I have a table called "fields":
Schema::create('fields', function (Blueprint $table) {
$table->increments('id');
$table->string("label");
$table->string("name")->unique();
$table->text("options")->nullable();
$table->timestamps();
});
I want to have another table which simply stores the ids of some of the fields. I will call this default_fields.
I basically want a relationship or logic that allows me to grab these default_fields like I would with any other relation:
Schema::create('default_fields', function (Blueprint $table) {
$table->increments('id');
$table->integer("field_id");
});
How can I create a relationship that grabs all the fields whose id's are present in this table? I also want to be able to sync().
Would I just make a model for DefaultField and then do something like Field::whereIn('id', DefaultField::get()->pluck('id'))?
And then code my own sync() logic? Is there a super easy way to do this that I'm missing? I'd also like to be able to sort this like I would any other relation.
You can have a model Field that has this relationship:
public function defaultFields()
{
return $this->hasMany('App\DefaultField');
}
In you controller, you can fetch the Field with his related DefaultFields like:
$fields = Field::with('defaultFields')->get();
You can have a similar method field in your DefaultField model:
public function field()
{
return $this->belongsTo('App\Field');
}
In you controller, you can fetch the DefaultField with his parent Field:
$defaultFields = DefaultField::with('field')->get();
In your case, more productive will be 'is_default' boolean property in the fields table.

Laravel delete by BelongsToMany relationship

I have a Task class. And each record of this table can have one or many childs and can be one or many parents of another task.
Table tasks
id | name
Table tasks_links
parent_id | child_id
Task model
<?php
namespace App;
class Task extends Model
{
public function childs()
{
return $this->belongsToMany(Task::class, 'tasks_links', 'parent_id','child_id');
}
public function parents()
{
return $this->belongsToMany(Task::class, 'tasks_links' , 'child_id' , 'parent_id');
}
}
And in my controller and views
I can use the relationship like
Task::find($id)->parents(); //Return an array
When I delete a task, I would also to delete the links with other related tasks
So the following is working :
\DB::table('tasks_links')->where('parent_id' , $task->id)->delete();
\DB::table('tasks_links')->where('child_id' , $task->id)->delete();
But I the following is not working
foreach ($task->parents() as $parent) {
$parent->delete();
}
Is there any way to delete the links by using the parents and childs functions instead of searching directly in the database ?
$task =Task::find($id);
$task->childs()->detach();
$task->parents()->detach();
$task->delete();
The fastest way of doing this.. if every time you delete a task you will want to delete all relations you should just include this in your task migrations
$table->foreign('the_foreign_key')->references('related_table_primary_key')->on('table_name_related')->onDelete('cascade');
Every time you delete a task on relationships will be deleted.
What I usually do on these situations is, when designing the database, I write a migration and set what columns I want to be affected by cascade.
Example
php artisan make:migration cascade_implementation
and on the Up() I set whatever I wish to be affected, on Down() I set the inverse, in case of a rollback needed. In your case, something like (or the other way around, depending on your needs):
public function up()
{
Schema::table('tasks', function (Blueprint $table) {
$table->foreign('parent_id')
->references('id')->on('tasks_links')
->onDelete('cascade');
$table->foreign('child_id')
->references('id')->on('tasks_links')
->onDelete('cascade');
});
}
Read more at https://laravel.com/docs/5.5/migrations

Categories