Laravel - How to delete record based on condition - laravel

In my Laravel-5.8, I have these three (3) models:
Parameter
class Parameter extends Model
{
protected $table = 'parameters';
protected $primaryKey = 'id';
protected $fillable = [
'max_score',
'min_score',
'identity_id',
];
public function identity()
{
return $this->belongsTo('App\Models\Identity','identity_id');
}
}
Identity
class Identity extends Model
{
protected $table = 'identity';
protected $fillable = [
'id',
'name',
];
public function goals()
{
return $this->hasMany('App\Models\Goal');
}
public function parameter()
{
return $this->hasOne(Parameter::class, 'identity_id');
}
}
Goal
class Goal extends Model
{
protected $table = 'goals';
protected $fillable = [
'id',
'identity_id',
'title',
];
public function identity()
{
return $this->belongsTo('App\Models\Identity','identity_id');
}
}
From the model, Identity has a foreign key (identity_id) in Parameter, also Identity has foreign key (identity_id) in Goal.
I have this controller in Identity:
public function destroy($id)
{
try
{
$identity = Identity::findOrFail($id);
$identity->delete();
Session::flash('success', 'Record deleted successfully.');
return redirect()->back();
}
catch (Exception $exception) {
Session::flash('error', 'Record delete failed!.');
return redirect()->back();
}
}
I want the user to delete Identity Record based on these conditions:
As the user tries to delete Identity, the application should check Parameter table and also delete the record where identity_id foreign key exist.
Secondly, if record with identity_id exists in Goal table, the application should prevent the delete.
How do I adjust public function destroy($id) to achieve this?

you can add a function like "deleteAll()" in your 'Identify' Model and delete parameter using relation like this:
class Identity extends Model
{
protected $table = 'identity';
protected $fillable = [
'id',
'name',
];
public function goals()
{
return $this->hasMany('App\Models\Goal');
}
public function parameter()
{
return $this->hasOne(Parameter::class, 'identity_id');
}
public function deleteAll(){
if(!$this->goals){
$this->parameter->delete();
return parent::delete();
}
return;
}
}

First in your migrations in the identity you need to do like
$table->foreign('identity_id')->references('id')->on('parameters')->onDelete('cascade');
So when you delete the Identity the related Parameter will be deleted automatically on database level.
To prevent delete (your mentioned 2 case), you need to check like this
$identity = Identity::with('goals')->findOrFail($id);
if($identity->goals){
// you can throw some error here
}

Related

laravel update() is not working on some models

I am trying to update the database record but Laravel update() function is not working. I have fillable array in the model. but still, it is not working.
The Property Model:
class Property extends Model
{
use HasFactory;
protected $table = 'properties';
protected $primaryKey = 'proID';
public $timestamps = false;
protected $fillable = [ 'proID', 'ProStatus', 'ProPurpose', 'ProType', 'SubType', 'basePrice', 'unitPrice', 'Width', 'Length', 'LandArea','PropertyNumber', 'water', 'electricity', 'gas', 'severage', 'fk_Street', 'createdBy', 'delete'];
public function streets(){
return $this->belongsTo(Street::class,'fk_Street');
}
public function hasInstallments(){
return $this->hasMany(Installments::class,'proID');
}
The PropertyController:
public function destroy($id)
{
$property = Property::find($id);
$property->delete = true;
if($property->save()){
return response()->json(['success'=>true]);
}
}
the $property->update() always returns true but record does not update in database.
The method update() is for mass update wich require an array of attributes and bypass mutators.
public function destroy($id)
{
$property = Property::find($id);
$property->update(['delete' => 1]);
}
You might want to use save() instead
public function destroy($id)
{
$property = Property::find($id);
$property->delete = 1;
$property->save();
}
Both will update the record, you'll need to implement your method's return logic on top of this code but as for updating the record, I think you get the idea.
Your property table primary key is "proID"
public function destroy($id)
{
$property = Property::where('proID', $id)->first();
if($property->update(['delete' => 1])) {
return response()->json(['success' => true]);
}
}

Laravel access to two level parent table in a relationship

i have use laravel and i have this models and relationship between tables
Customers table
class Customers extends Model
{
public $primaryKey = 'id';
protected $fillable = [
'contr_nom',
'contr_cog',
'benef_nom',
'benef_cog',
'email',
'polizza',
'targa',
'iban',
'int_iban',
'cliente',
];
public function claims()
{
return $this->hasMany(Claims::class);
}
public function refunds()
{
return $this->hasManyThrough(Refunds::class, Claims::class);
}
}
claims table
class Claims extends Model
{
public $primaryKey = 'id';
protected $fillable = [
'dossier',
'date_cla',
];
public function refunds()
{
return $this->hasMany(Refunds::class);
}
public function customers()
{
return $this->belongsTo(Customers::class,'customers_id');
}
}
refunds table
class Refunds extends Model
{
public $primaryKey = 'id';
protected $fillable = [
'date_ref',
'status_ref',
'disactive',
'num_pre',
'date_liq',
];
public function services()
{
return $this->belongsToMany(Services::class)
->withPivot(['services_id','services_amount','services_status']);
}
public function claims()
{
return $this->belongsTo(Claims::class,'claims_id');
}
}
in controller i did this function
public function addDateLiq2(Request $request){
$date_liq = request("date_liq");
$refunds = Refunds::whereNotNull('num_pre')->get();
foreach ($refunds as $refund) {
$status_ref= $refund->status_ref;
if ($status_ref == 5){
//send mail
//I need to retrieve mail field from customers table
}
$refund->date_liq = $date_liq;
$refund->save();
if(!$refund->save()){
App::abort(500, 'Error');
}
}
return Response::json(array('success' => 'Date salvate massivamente correttamente!'), 200);
}
that add a date in all records where num_pre is not null.
OK i wanted also send a mail but mail field is in Customer parent table....how can i access it?
Thx
Ok i seem i found a way with this in function addDateLiq2
$data = Claims::with(array('customers'=>function($query){
$query->select('id','email');
}))
->whereHas('refunds', function($query) use($claims_id) {
$query->where('claims_id', $claims_id);
})
->first();

Laravel - How to prevent delete when there is dependent field

In my Laravel-5.8 project, I have these models
HrGradeLevel
class HrGradeLevel extends Model
{
protected $table = 'hr_grade_levels';
protected $fillable = [
'grade_level_code',
'grade_level_name',
'description',
];
public function designation(){
return $this->hasMany('App\Models\Hr\HrDesignation');
}
public function employee(){
return $this->hasMany('App\Models\Hr\HrEmployee');
}
}
HrDesignation
class HrDesignation extends Model
{
protected $table = 'hr_designations';
protected $fillable = [
'designation_name',
'grade_level_id',
];
protected $casts = [];
public function gradelevel()
{
return $this->belongsTo('App\Models\Hr\HrGradeLevel','grade_level_id');
}
}
HrEmployee
class HrEmployee extends Model
{
protected $table = 'hr_employees';
protected $fillable = [
'first_name',
'last_name',
'grade_level_id',
];
protected $casts = [];
public function gradelevel()
{
return $this->belongsTo('App\Models\Hr\HrGradeLevel','grade_level_id');
}
}
HrDesignation and HrEmployee has foreign key grade_level_id that is derived from HrGradeLevel
HrGradeLevelController
public function destroy(Request $request, $id)
{
$grade = HrGradeLevel::find($id);
$grade->delete();
Session::flash('success', 'Grade Level deleted successfully.');
return redirect()->route('hr.grade_level.index');
}
From the Controller above, the user can delete HrGradeLevel row.
Using Laravel, before the user is allowed to delete I want the application to check HrDesignation and HrEmployee, if any of them have data in grade_level_id, I want the application to display a message and it shouldn't allow delete.
How do I achieve this?
Thank you.
You have 2 options:
Use foreign key constraints on your migrations and MySQL will prevent deleting a record if foreign key is used on other tables/records by default:
public function destroy(Request $request, $id)
{
$grade = HrGradeLevel::find($id);
try {
$grade->delete();
}
catch (\Illuminate\Database\QueryException $e) {
if ($e->getCode() == 23000)
{
//SQLSTATE[23000]: Integrity constraint violation
abort('Resource cannot be deleted due to existence of related resources.');
}
}
Session::flash('success', 'Grade Level deleted successfully.');
return redirect()->route('hr.grade_level.index');
}
Check existence of your relationships before deleting:
public function destroy(Request $request, $id)
{
$grade = HrGradeLevel::find($id);
if ($grade->designation()->exists()
|| $grade->employee()->exists())
{
abort('Resource cannot be deleted due to existence of related resources.');
}
$grade->delete();
Session::flash('success', 'Grade Level deleted successfully.');
return redirect()->route('hr.grade_level.index');
}

Cannot Extend Laravel Model

I have 2 models. The User model, and the relationship works correctly, I use tinker, and I can see the application that is associated with the user.
User::find(4)->application
However, the application will not return the user - in tinker I get null, whats worse, if I try to access rep in tinker, I get Bad Method Exception Call
Application::find(8)->user
is null
Note: I have an id column in users which I "find" users. and there is "ucid" column in users that I have defined as the primaryKey in Application.
Application Model:
class Application extends Model
{
protected $data = [
'data' => 'array'
];
protected $primaryKey = 'ucid';
protected $fillable = [
'ucid', 'data'
];
public function user()
{
return $this->belongsTo(User::class,'ucid');
}
public function rep()
{
return 'Test';
}
}
User Model
class User extends Authenticatable
{
public function application()
{
return $this->hasOne(Application::class,'ucid');
}
}
What am I missing?
Can you try this? Let me know if it works..
Application Model
class Application extends Model
{
protected $data = [
'data' => 'array'
];
protected $primaryKey = 'ucid';
protected $fillable = [
'ucid', 'data'
];
public function user()
{
return $this->hasOne(User::class, 'ucid');
}
public function rep()
{
return 'Test';
}
}
User Model
class User extends Authenticatable
{
public function application()
{
return $this->belongsTo(Application::class, 'ucid', 'ucid');
}
}
As you see I switched hasOne and belongsTo in your models.
Also.. third argument on hasOne of Application Model is not required since value from $primaryKey will be used since its defined, however you have to specify the third argument in belongsTo of User model

How to use "select" method to reduce data transfer when using Eager Loading

I have a API and its taking long time to get all the info and its because I'm only hidding some data but I want to omit not to hidde. I found select() method to chose wich data send and reduce the time to query all information I really need.
Im trying to use select just after the relation just like this, just to retrieve only name from OPR_User table:
public function creatorUser() {
return $this->belongsTo('Knotion\OPR_User', 'idCreatorUser', 'idUser')->select('name');
}
but is not working
This is my Model code
<?php
namespace Knotion;
use Illuminate\Database\Eloquent\Model;
class CTL_Resource extends Model {
protected $table = "CTL_Resource";
protected $primaryKey = "idResource";
public $incrementing = false;
public $timestamps = false;
public static $snakeAttributes = false;
protected $hidden = [
'coachVisibility', 'thumbnail',
'studentVisibility', 'isHTML','studentIndex', 'coachIndex',
'isURL', 'source', 'path', 'status', 'updateTime', 'isfolder',
'parentResource', 'idModifierUser', 'idResourceType', 'idCreatorUser', 'idCreationCountry'
];
protected $fillable = ['idResourceType','productionKey', 'idCreatorUser', 'idModifierUser', 'idCreationCountry', 'title', 'description', 'URL', 'fileName', 'extension', 'minimumAge', 'maximumAge', 'productionKey'];
public function creatorUser() {
return $this->belongsTo('Knotion\OPR_User', 'idCreatorUser', 'idUser');
}
public function creationCountry() {
return $this->belongsTo('Knotion\CTL_Country', 'idCreationCountry', 'idCountry');
}
public function resourceType() {
return $this->belongsTo('Knotion\CTL_ResourceType', 'idResourceType', 'idResourceType');
}
public function quickTags() {
return $this->belongsToMany('Knotion\CTL_QuickTag', 'CTL_Resource_has_QuickTags', 'idResource','idQuickTag');
}
public function tags() {
return $this->belongsToMany('Knotion\CTL_Tag','CTL_Resource_has_Tags', 'idResource', 'idTag');
}
public function relatedTo() {
return $this->belongsToMany('Knotion\CTL_RelatedTo', 'CTL_Resource_has_RelatedTo', 'idResource', 'idRelatedTo');
}
}
this is my relation model code (just in case needed):
<?php
namespace Knotion;
use Illuminate\Database\Eloquent\Model;
class OPR_User extends Model {
protected $table = "OPR_User";
protected $primaryKey = "idUser";
public $incrementing = false;
public $timestamps = false;
public static $snakeAttributes = false;
protected $hidden = ['firstName', 'secondName', 'firstSurName', 'secondSurName', 'password', 'picture', 'status', 'createTime', 'updateTime', 'idUserType', 'email'];
public function resources() {
return $this->hasMany('Knotion\CTL_Resource', 'idResource');
}
public function userType() {
return $this->belongsTo('Knotion\CTL_UserType', 'idUserType', 'idUserType');
}
}
and this is my Controller code:
public function index(Request $request) {
$resources = CTL_Resource::all();
$resources->resourceType->select('name');
return $resources->load('creatorUser', 'creationCountry', 'resourceType', 'tags', 'quickTags', 'relatedTo');
}
When you add the ->select after the ->belongsTo it's no longer an actual relationship type, it's a query builder. You need to add the select afterwards before you call the ->load.
To fix the problem I had to include the id also in the relation, something like this:
public function resources() {
return $this->hasMany('Knotion\CTL_Resource', 'idResource')->select('idResource', 'name');
}

Resources