Laravel access to two level parent table in a relationship - laravel

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();

Related

Laravel - How to delete record based on condition

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
}

Search in Laravel relation using json column

I have problem with search in json column.
I have 3 relations:
products
feature products
feature_values
My tables:
products: https://ibb.co/1dgjT6m
feature products: https://ibb.co/K9f74Wn
feature_values: https://ibb.co/rc3zG5W
My migrations:
Product:
class Product extends Model implements Presentable
{
....
public function featureProducts()
{
return $this->hasMany(FeatureProduct::class, 'product_id');
//return $this->belongsToMany(Feature::class, 'feature_product', 'id');
}
}
FeatureProduct
class FeatureProduct extends Model
{
protected $table = "feature_product";
protected $with = [
'values'
];
public function values()
{
return $this->belongsTo(FeatureValue::class, 'feature_values_ids', 'id');
}
}
FeatureValues:
class FeatureValue extends Model
{
use SoftDeletes,
Translatable;
protected $fillable = [
'feature_id',
'value'
];
protected $dates = [
'created_at',
'updated_at',
'deleted_at'
];
protected $translatable = [
'value'
];
public function feature(): BelongsTo
{
return $this->belongsTo(Feature::class);
}
public function getAdminUrlAttribute(): AbstractAdminUrlPresenter
{
return new FeatureValueUrlPresenter($this);
}
}
I need to show products with features and assigned features_values
I heve problem with search in json column: feature_product. feature_values_ids
When I have INT in this column, then this is working fine:
public function values()
{
return $this->belongsTo(FeatureValue::class, 'feature_values_ids', 'id');
}
When I have:
["1", "2","3"]
I haven't any results :(
Haw can I repair it?

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');
}

laravel adding custom another query into releatinship

in laravel i have this query which that work fine,
$months = Month::with(['lessons' => function ($query) {
$query->with(['files']);
}])->get();
in this query i have $query->with(['files']) which that is:
public function files()
{
return $this->hasMany(LessonFiles::class);
}
i want to add this query for all of $query->with(['files']) rows which that have lesson_file_key:
LessonsView::whereLessonFileKey($lessonFile->lesson_file_key)->count()
it means i want to get count of each row of $query->with(['files']) in this query by adding above code, for example:
$months = Month::with(['lessons' => function ($query) {
$req = $query->with(['files']);
// for example using foreach on $req
// LessonsView::whereLessonFileKey($req->lesson_file_key)->count()
}])->get();
my models:
class Month extends Model
{
protected $guarded = ['id'];
protected $hidden = ['id'];
public function lessons()
{
return $this->hasMany(Lesson::class);
}
public function files()
{
return $this->hasMany(MonthFiles::class);
}
}
class Lesson extends Model
{
protected $guarded = ['id'];
protected $hidden = ['id', 'month_id', 'filename', 'file_url'];
public function month()
{
return $this->belongsTo(Month::class);
}
public function files()
{
return $this->hasMany(LessonFiles::class);
}
}
class LessonFiles extends Model
{
protected $guarded = ['id'];
protected $hidden = ['id', 'lesson_id', 'filename', 'file_url'];
public function lesson()
{
return $this->belongsTo(Lesson::class);
}
public function visits(){
return $this->hasMany(LessonsView::class);
}
}
class LessonsView extends Model
{
protected $guarded = ['id'];
protected $hidden = ['id','user_id','lesson_files_id','lesson_file_key','ip_address'];
public function visitedLesson(){
return $this->belongsTo(LessonFiles::class);
}
}
For something like this you could add a views relationship to you LessonFiles model, something like:
public function views()
{
return $this->hasMany(LessonsView::class, 'lesson_file_key', 'lesson_file_key');
}
Then in your query you can use withCount():
$months = Month::with([
'lessons.files' => function ($query) {
$query->withCount('views');
},
])->get();
Use withCount and whereColumn like this:
$months = Month::with(['lessons' => function ($query) {
$query->with(['files' => function($q) {
$q->withCount(['visits' => function($vq) {
$vq->whereColumn('lesson_views.lesson_file_key', 'lesson_files.lesson_file_key')
}]);
}]);
}])->get();

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