Laravel adding custom attribute to where clause - laravel

I have a mutator that calculate the product existing quantity by:
summing the product credit and minus it from the sold credit.
public function getReportTotalQuantityAttribute() {
// GET IMPORT INVOICE SUM
$import_invoices_sum = $this -> credits -> sum('quantity');
// GET EXPORT INVOICE SUM
$export_invoices_sum = $this -> sold -> sum('quantity');
// CALCULATE THE SUM
return $import_invoices_sum - $export_invoices_sum;
}
This mutator works fine and return the actually product quantity as report_total_quantity attribute whenever I call the model.
What I am trying to do:
I am trying to get the product where('report_total_quantity', '>', 0).
What I have tried:
$condition_queries = Product::withCreditsAndWarehouses() -> where('report_total_quantity', '>', 0);
But I am getting error say Unknown column 'report_total_quantity'. And this is logical since I don't have this column but I append it using $append and mutator.
What I searched and found:
I have found something called filters but I don't think it is good solution since I am using paginate(10) and like that I will return 10 values and filter them.
Also I have many other conditions and filter is not working good for me.

If you want to use WHERE with attribute create by mutator You must first create Collection then use Where statement.
$condition_queries = Product::withCreditsAndWarehouses()->get()->where('report_total_quantity', '>', 0);
But after ->get() you can not use paginate. Instead you must use Collection paginate method forPage. Check this

Related

Laravel relation with custom join condition

I received quite strange database to work with and I'm trying to create relation on model Invoice like below:
public function order()
{
return $this->hasOneThrough(Order::class, Shipment::class,
'id',
'id',
DB::raw('-order_id'),
Shipment::COL_ORDER_ID
);
}
but it gives me the error array_key_exists(): Argument #1 ($key) must be a valid array offset type.
Of course the problem is in the DB::raw part... As you may have guessed I'm trying to create join condition like -Invoice.order_id = Shipment.id or ABS(Invoice.order_id) = Shpment.id will be fine too because only order_id on the Invoice needs to be converted into positive number.
Any ideas to get it to work with minimal additional code as possible? Any help will be appreciated :)

Search in belongsToMany-relation for item by pivot value

I got these models:
Order
Invoice
An Order can have many Invoices and an Invoice can belong to many Orders.
Example:
Orders:
Order #1
Order #2
Order #3
Invoices:
Invoice #1 -> belongs To Order #1 and Order #2 (so this Invoice contains both Orders)
Invoice #2 -> belongsTo Order #2 and Order #3
Each belongsTo-relation saves a date as pivot, which defines the last date this order has been invoiced.
Now I'd like to create a isInvoiceable() getter for my Order-Model, which returns, whether the order has been invoiced within the last month or not. If the latest date is older than one month, return true, as this Order should create a new invoice.
So now I need your help: I need to check all invoices, whether there's an Order (belongsToMany) with the order_id of the current Order, and a date-pivot that's older than now - one month. I need to check the order_id because the Invoice could possibly contain information about other Orders, too.
And this is the missing link for me: How can I check the belongsToMany-relation in Invoice for date and order_id?
Asuming you have defined your relation as 'invoices', you may do something like this:
class Order extends Model {
...
public function isInvoiceable(){
$lastInvoiceDate = (date('Y-m-d', $this->invoices()->latest()->created_at));
$today = new Carbon(date('Y-m-d', strtotime(Input::get('startdate'))));
$diff_months = $lastInvoiceDate->diff($today)->months;
return $diff_months < 1;
}
There is a wherePivot method, which should do what you want.
From the docs:
Filtering Relationships Via Intermediate Table Columns:
You can also filter the results returned by belongsToMany using the
wherePivot, wherePivotIn, and wherePivotNotIn methods when defining
the relationship:
return $this->belongsToMany('App\Role')->wherePivot('approved', 1);
return $this->belongsToMany('App\Role')->wherePivotIn('priority', [1, 2]);
return $this->belongsToMany('App\Role')->wherePivotNotIn('priority', [1, 2]);
I have not tested it, but you should be able to do something like this:
public function isInvoiceable()
{
// replace 'invoices()' with your relationship
if ($this->invoices()->wherePivot('date', '>=', Carbon::now()->subMonth())->count() > 0) {
return false;
}
return true;
}
you have two choices:
1- like Remul said in his answer: using wherePivot();
2- using newPivotQuery()
witch give you more space to work with ...
when you use this method, the query will be on pivot table directly ...
class Order extends Model {
public function isInvoiceable()
{
return $this->invoices()-> newPivotQuery()->firstWhere('date', '>=', Carbon::now()->subMonth())!=null;
}
the advantage of using newPivotQuery() that you can insert,update, make overall queries ...

changing a query result value according to wherehas condition in laravel

I am using laravel
I want to change the value of a column according to a specific condition.
if a condition is satisfied in wherehas then change the value of specific column to 1 let's say.How could i do it.
if i can call a function in the model inside the wherehas function to change the value how could I do it ??
i can iterate the result set using a 2 for loops and change it, however I want to decrease the complexity by changing the value while retrieving the data
Course::with('stages','stages.levels')->whereHas('stages.levels', function($query)use ($levelsarray){
$query->wherenotIn('id', $levelsarray);
here I want to change a column value in table levels
})->first();
Here is a general way,
Assuming you have Three models, Course, Stage, Level
When you are retrieving data from Level model, add an accessor,
For more info click here.
Eg:
On Level.php model,
public function getColumnNameAttribute($value) // replace ColumnName with column name
{
//write application logic here.
return $value;
}

Using Laravel 5, how do I get all() and order by belongsToMany relationship by the pivot table

I have Deals and Faq's. I have functional relationships working and I can reference $deal->faqs() and it returns the right faqs.
The problem I am trying to solve comes up as I administer the faqs related to a deal. In my Deal admin view (new / edit) I am getting all the Faq's.
$faqs = \App\Faq::all();
This works great, and I am even able to check if an faq is related to a deal through my checkbox: in the view:
{!! Form::checkbox('faqlist[]', $faq->id, $deal->faqs->contains($faq->id) ? true : false) !!}
So now we have a list of all the faqs and the correct ones are checked.
I have setup an order column on the pivot table (deal_faq). That table consists of:
deal_id
faq_id
timestamps
order
In my form, I have a drag and drop ordering solution (js) built and working. By working I mean, I can drag/drop and a hidden field value is updated to reflect the correct order.
When creating a deal, this is no problem. Get all the faq's, check a few to associate, drag to order, then save.
When editing a deal, I need to load based on the order column in the deal_faq table. This is my issue.
I have tried a few things but always get an error. An example of what I have tried is:
$faqs = \App\Faq::orderBy('deal_faq.order', 'asc')->get();
This returns an error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'deal_faq.order' in 'order clause' (SQL: select * from `faq` order by `deal_faq`.`order` asc)
I think the issue is that I am trying to get all, but order by a field that only exists for the related faqs since the order field is on the deal_faq. Just not sure how to solve.
In essence you need to join the pivot table and then apply the order
$faqs = \App\Faq::join('deal_faq', 'faqs.id', '=', 'deal_faq.faq_id')
->orderBy('deal_faq.order', 'asc')
->get();
You may need to adjust table and column names to match your schema.
Now you can extract this logic into a scope of the Faq model
class Faq extends Model
{
...
public function scopeOrdered($query)
{
return $query->join('deal_faq', 'faqs.id', '=', 'deal_faq.faq_id')
->orderBy('deal_faq.order', 'asc');
}
}
and then use it like this
$faqs = \App\Faq::ordered()->get();
UPDATE:
This works to get the FAQ's in order but it only get the ones that
have been associated. There will be FAQ's that are not associated and
thus not ordered.
In this case you just need to use an outer join - LEFT JOIN. The scope definition would then look like this
public function scopeOrdered($query)
{
return $query->join('deal_faq', 'faqs.id', '=', 'deal_faq.faq_id', 'left')
->orderBy('deal_faq.order', 'asc');
}
or a bit more expressively
public function scopeOrdered($query)
{
return $query->leftJoin('deal_faq', 'faqs.id', '=', 'deal_faq.faq_id')
->orderBy('deal_faq.order', 'asc');
}
Please consider adding a secondary order (i.e. by id, or any other field(s) in faqs table that make sense). This way you'd have a deterministically ordered resultsets each time regardless of whether you have an explicit order defined in a pivot table or not.

how to get the size of product to the cart page

I have size of product (XS, XL, ...).
I want add column in cart table Size, where show sizes of products.
I added SKU in this table $_item->getSku(); This works.
But $_item->getSize(); not works. Please, help me.
try adding ->addFieldToSelect('*'), it'll add every attribute associated with your products in the returning data, you can replace the * with the attribute code of the attribute your trying to display
problem is, it'll return integers that are used in either eav_attribute_option or eav_attribute_option_value (not sure why there's 2 different tables, one has values and one has sort order, it's not like Magento even links a value to 2 options), however if you use the following code
$attributeInfo = Mage::getResourceModel('eav/entity_attribute_collection')->setCodeFilter('ATTRIBUTE_CODE')->getFirstItem();
$sizeValues = array();
// populates sizevalue array with data
foreach ($attributeOptions as $key => $value)
{
$sizeValues[$value['value']] = $value['label'];
}
you get an array of values with their index's being that of that it returned in your collection

Resources