laravel adding custom another query into releatinship - laravel

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

Related

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

How can I solve "Relation 'a' is not instance of HasOne or BelongsTo." in the laravel?

My laravel eloquent like this :
$query = ItemDetail::selectRaw('a.item_number, sum(abs(a.quantity)) as "total_quantity"')
->from('item_detail as a')
->join('items as b', 'b.id', '=', 'a.item_number');
if(isset($param['vendor'])) {
$query = $query->where('b.vendor_id', '=', $param['vendor']);
}
$query = $query->groupBy('a.item_number')
->paginate($paged);
return $query;
If the query executed, there exist error like this :
Relation 'a' is not instance of HasOne or BelongsTo.
How can I solve this problem?
Update
My item model like this :
class Item extends Model
{
...
protected $fillable = [
'name',
'vendor_id'
];
public function item_details()
{
return $this->hasMany(ItemDetail::class, 'id', 'item_number');
}
}
My item detail model like this :
class ItemDetail extends Model
{
....
protected $fillable = [
'item_number',
'name',
'posting_date'
];
public function item()
{
return $this->belongsTo(Item::class, 'id', 'item_number');
}
}
According to your few details, please confirm if this is what you want:
Item Model:
class Item extends Model
{
...
protected $fillable = [
'name',
'vendor_id'
];
public function item_details()
{
return $this->hasMany(ItemDetail::class, 'item_number', 'id');
}
}
ItemDetail Model:
class ItemDetail extends Model
{
....
protected $fillable = [
'item_number',
'name',
'posting_date'
];
public function item()
{
return $this->belongsTo(Item::class, 'item_number', 'id');
}
}
Controller Method:
$itemDetails = ItemDetail::whereHas('item', function($q) use ($param) {
if (isset($param['vendor']){
$q->where('vendor_id', '=', $param['vendor']);
}
})
->selectRaw('item.id', 'item_detail.item_number', 'sum(abs(a.quantity)) as total_quantity')
->groupBy('item_number')->paginate($paged);
View file:
#foreach($itemDetails as $itemDetail)
#dump($itemDetail->item_number)
#dump($itemDetail->total_quantity)
#endforeach
It makes more sense to access the main model you want and include in it, the relationships you need to include.
Here's a potential different solution:
$query = Item::with(['item_details' => function ($query) {
$query->groupBy('item_number')->selectRaw("item_number, sum(abs(a.quantity)) as 'total_quantity'");
}]);
if (isset($param['vendor'])) {
$query->where('vendor_id', $param['vendor']);
}
$itemsPage = $query->paginate($paged);
return $pages;
You can access the paged data if you do:
foreach ($itemsPage as $item) {
// $item is an instance of Item
// $item->item_details->total_quantity should have the sum of the item details
}
I can only guess because of too few information: your model is missing something like this:
public function a()
{
return $this->belongsTo(RelatedModel::class);
}

How can I use parent relation attribute in sub query in laravel eloquent

$order_detail = Order::where([['user_id', $user->id], ['updated_at', '>', $updated_at]])
->with([
'currency' => function ($query) {
$query->select('currency_code', 'currency_symbol', 'ex_rate_with_base');
},
'orderList' => function ($query) {
$query->select('id', 'order_id', 'product_code', 'qty',
DB::raw('(unit_price*orders.ex_rate_with_base) as unit_price_new'), 'status');
},
])->get();
Please help,
How can I use the attribute ex_rate_with_base from order table in sub query.
I do not want to use DB query. Please solve it with eloquent.
I would have done it like this 👇
Database Structure:
ModelCurrency.php
class ModelCurrency extends Model
{
public $timestamps = true;
protected $table = 'currency';
protected $guarded = [];
}
ModelOrderList.php
class ModelOrderList extends Model{
public $timestamps = true;
protected $table = 'order_list';
protected $guarded = [];
}
ModelOrderDetail.php
class ModelOrderDetail extends Model{
public $timestamps = true;
protected $table = 'order_detail';
protected $guarded = [];
public function scopeOfUser($query, $user_id){
return $query->where('user_id', $user_id);
}
public function scopeUpdatedAfter($query, $updated_at){
return $query->where('updated_at', '>', $updated_at);
}
public function currency(){
return $this->hasOne(ModelCurrency::class, 'id', 'currency_id');
}
public function order_lists(){
return $this->hasMany(ModelOrderList::class, 'order_id', 'id');
}
}
Function in controller:
//imports
use App\ModelOrderDetail;
use Illuminate\Support\Carbon;
public function prices() {
$user_id = 1;
$updated_at = Carbon::yesterday();
$data = ModelOrderDetail::with('currency', 'order_lists')->ofUser($user_id)->updatedAfter($updated_at)->get();
foreach ($data as $d){
$base_rate = $d->currency->base_rate;
foreach($d->order_lists as $o) $o->new_unit_price = $base_rate * $o->unit_price;
}
return response()->json($data);
};
Edit - Output : https://pastebin.com/i53PytSk

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

Subrelationships not using previous conditions

I'm using Laravel 4. I have the following models:
class User extends Eloquent {
protected $table = 'users';
public function questions()
{
return $this->hasMany('UserQuestion', 'user_id', 'user_id');
}
}
class UserQuestion extends Eloquent {
protected $table = 'user_questions';
public function user()
{
return $this->belongsTo('User', 'user_id', 'user_id');
}
public function subquestions()
{
return $this->hasMany('UserSubquestion', 'question_id', 'id');
}
}
class UserSubquestion extends Eloquent {
protected $table = 'user_subquestions';
public function question()
{
return $this->belongsTo('UserQuestion', 'question_id');
}
public function answers()
{
return $this->hasMany('UserAnswer', 'subquestion_id', 'id');
}
}
class UserAnswer extends Eloquent {
protected $table = 'user_answers';
public function subquestion()
{
return $this->belongsTo('UserSubquestion', 'subquestion_id');
}
}
I have the following query:
$results = User::with(['questions' => function($query) {
$query->where('status', '1');
$query->where('category', 'medicine');
}])
->with('questions.subquestions', 'questions.subquestions.answers')
->get();
However, the where conditions I'm applying to the questions relationship aren't being applied to the joined tables (subquestions and answers).
How can I make the conditions apply to them as well?
Note: The values of status and category in the conditions are dynamic (i.e. won't always be 1 or medicine).
Try doing your call like this instead:
$results = User::with(['questions' => function($query) {
$query->where('status', '1');
$query->where('category', 'medicine');
},
'questions.subquestions',
'questions.subquestions.answers'
])->get();
Note, this time the method with is only called once.

Resources