Laravel - search by title? - php

How to search by title in the ServiceType only? There is also a title field in the Package which should be avoided
For example, in the Model:
class Package extends Eloquent {
protected $table = 'package';
function serviceType()
{
return $this->belongsTo('ServiceType');
}
public static function getPackagesByServiceType($service)
{
return Package::with('serviceType')->where('title', '=', $service);
}
}
Note:
There is a service_type_id field in the Package and id, title fields in the serviceType
in the controller:
$packages = Package::getPackagesByServiceType('something')->get();
No result appeared for some reason? It should search for something in the serviceType
It seem it wouldn't work to combine with() and where(). When I remove the where() and it work.

You can't use where() like that to filter by a related model. You should use whereHas() instead:
public static function getPackagesByServiceType($service)
{
return Package::with('serviceType')->whereHas('serviceType', function($q) use ($service){
$q->where('title', '=', $service);
});
}
Note if you don't need serviceType in the packages afterwards you don't have to eager load it, ergo you can remove the with('serviceType')
Also if you call get() in the controller you should use a query scope. It offers the same functionality but it's not a static function and it's the Laravel way
public function scopeByServiceType($query, $service){
return $query->with('serviceType')->whereHas('serviceType', function($q) use ($service){
$q->where('title', '=', $service);
});
}
And you use it like this:
$packages = Package::byServiceType('something')->get();

class Package extends Eloquent {
protected $table = 'package';
function serviceType()
{
return $this->belongsTo('ServiceType');
}
public static function getPackagesByServiceType($service)
{
return Package::with('serviceType')->where('title', '=', $service)->get();
}
}
You forgot the ->get();

The ->get() should be in the Model
public static function getPackagesByServiceType($service)
{
return Package::with('serviceType')->where('title', '=', $service)->get(); // here
}
and in the controller it should be like this:
$packages = Package::getPackagesByServiceType('something');
Hope that helps... I had similar issues in my Model - Controller structure....

Related

laravel: unable to use model methods in controller to get attribute

I've been trying to do this for a while now. Most of the time, I solve it by using accessors. I'm currently trying to get if the column exists and I created a function in my model which is suppose to return boolean.
Model code:
class Inventory extends Model
{
protected $attributes = ['inventory'];
protected $appends = ['colorThumb'];
public function hasAttribute($attr){
return array_key_exists($attr, $this->attributes);
}
}
Controller code:
public function allInvOperation(Request $request){
$inv = Inventory::where('is_deleted', 0)->with(['product', 'size','color'])->orderByDesc('id')->get();
if(!is_null($request->searchText)){
dd($inv->hasAttribute('inventory'));
$inv = Inventory::where('is_deleted', 0)->with(['product', 'size','color'])->orderByDesc('id');
if($request->inv_filter == 'inventory'){
$inv = $inv->where('inventory', 'like', "%".$request->searchText."%")->get();
}
if($request->inv_filter == 'code'){
$inv = $inv->whereHas('product', function ($q) use ($request){
$q->where('code', "%".$request->searchText."%");
})->get();
}
}
ERROR
Method Illuminate\Database\Eloquent\Collection::hasAttribute does not exist.
The code you are doing hasAttribute on is a Collection of objects, you need to use first on that query to get a single result on which you can later do hasAttribute

Laravel Eloquent deep nested query

I'm still learning Laravel and I can't find the solution for this problem.
I need to get invoices(with expenses) that are related to specific Partner Type.
I tried this:
$p = Project::with(['invoices.partner.partnerType' => function($query){
$query->where('partnerTypeName', 'Lieferant');
}, 'expenses'
])->where('id', $id)
->first();
I want to select invoices for Lieferant, but I get all invoices for one project.
Project Model:
public function invoices()
{
return $this->hasMany('App\Invoice');
}
Invoice Model
public function expenses()
{
return $this->hasMany('App\Expense');
}
public function partner()
{
return $this->belongsTo('App\Partner');
}
Partner Model
public function partnerType()
{
return $this->belongsTo('App\PartnerType');
}
Edit: PartnerType Model
public function partners()
{
return $this->hasMany('App\Partner');
}
Edit 2: Database
Partner(partnerID, name, partnerTypeId)
PartnerType(partnerTypeId, partnerTypeName)
Project(projectID, name)
Invoice(invoiceID, name, projectID, partnerID)
Expenses(expenseID, invoiceID)
If your models look like that.
Should be like :
$p = Project::with(['invoices' => function($query){
$query->where('partnerTypeName', 'Lieferant')
->with(['expenses','partner' => function($q){
$q->with('partnerType');
}]);
}])->where('id', $id)
->first();
return dd($p);
The solution to your problem is to update your query like this:
$p = Project::with(['invoices' => function($query){
$query->with('expenses')->whereHas('partner.partnerType', function($q){
$q->where('partnerTypeName', 'Lieferant');
});
}])
->where('id', $id)
->first();
But a cleaner solution would be using a scope for your problem.
In your Invoice model.
// Invoice.php
public function scopeByPartnerType($query, $partnerType)
{
$query->whereHas('partner.partnerType', function($q) use ($partnerType) {
$q->where('partnerTypeName', $partnerType);
});
}
And then in your Project model, add another relation that will just get Invoices with a particular partner type.
// Project.php
public function lieferantInvoices()
{
return $this->hasMany('App\Invoices')->byPartnerType('Lieferant');
}
Now you can do just this:
$project->find($id)->load('lieferantInvoices');

Laravel Custom Eloquent Method

I have been building queries and repeating code, is there a way to build this into the eloquent model?
I have a model Transaction where I am selecting specific currencies. How can I add this into the model? Is there a way of changing this:
Transaction::select('*')->where('currency', '=', 'GBP')
So that I can do this:
Transaction::select('*')->currency('GBP')
Then in the model it adds onto the query somehow. I've tried to create Transaction::currency but it didn't work. This is just an example and I plan on adding a few selectors to keep the code clean.
class Transaction extends Model
{
protected $table = 'transactions';
public function currency($query, $currency) {
return $query->where('currency', '=', $currency);
}
}
Laravel has such thing called Query Scopes. It allows you to do exactly what you want. You just need to prefix your currency() method with scope keyword like this:
class Transaction extends Model
{
protected $table = 'transactions';
public function scopeCurrency($query, $currency) {
return $query->where('currency', '=', $currency);
}
}
Then you can do this Transaction::select('*')->currency('GBP')
Read more about scopes here
you are almost done,you have to write currency method as query scope.
public function scopeCurrency($query, $currency) {
return $query->where('currency', '=', $currency);
}
after doing that you can use scope like this
Transaction::select('*')->currency('GBP')
For more details go here https://laravel.com/docs/5.2/eloquent#local-scopes
You can do this by using scope.
Add these code to Transaction.php file
public function scopeCustom($query, $column, $exp, $value)
{
return $query->where('votes', $exp, $value); // ('currency', '=', 'GBP')
}
Now use this scope as like
Transaction::select('*')->custom('currency', '=', 'GBP');
Transaction::select('*')->custom('amount', '>', 1000);

Eloquent Query Scope on Relationships

I have two models, App\Song (belongsTo App\Host) and App\Host (hasMany App\Song).
I have the following query in my Controller:
$songs = Song::whereHas('host', function($query) {
$query->where('skip_threshold', '>', \DB::raw('songs.attempts'))
->where('active', 1);
})
->whereNull('downloaded')
->get();
For reusability I would like to turn into a query scope(s).
I'm quite new to Eloquent so I'm not sure this is the correct way to do this being that its two Models as its not returning any results (where there should be).
Song.php
public function scopeEligable($query)
{
$query->where('skip_threshold', '>', \DB::raw('songs.attempts'));
}
public function scopeActiveHost($query)
{
$query->where('active', 1);
}
public function scopeInDownloadQueue($query)
{
$query->whereNull('downloaded');
}
You should put scopes into Models they belong to. Looking at your initial query scopes scopeEligable and scopeActiveHost belongs to Host model, so you should move them into Host model and then you'll be able to use your query using scopes like this:
$songs = Song::whereHas('host', function($query) {
$query->eligable()->activeHost();
})->inDownloadedQueue()->get();
and as already pointed in comment you should add return to each scope so they could be used as they intended.
EDIT
If you would like to make using it shorter, you could create new relationship in Song model:
public function activeHost()
{
return $this->belongsTo(Host:class)->eligable()->activeHost();
}
so now, you could write:
$songs = Song::whereHas('activeHost')->inDownloadedQueue()->get();
I think you're mistaken about 2 models. I think this should work
Song.php
public function scopeEligable($query, $active) {
return $query->whereHas('host', function($q) {
$q->where('skip_threshold', '>', \DB::raw('songs.attempts'))->where('active', $active);
})
}
public function scopeInDownloadQueue($query)
{
$query->whereNull('downloaded');
}
Usage
$songs = Song::eligable(true)->inDownloadQueue()->get();

laravel whereHas in relationships "where not working"

i need help for Laravel 4.2
the models are:
//1. model kelengkapan
class Kelengkapan extends Eloquent{
public function detilKelengkapan(){
return $this->hasMany('DetilKelengkapan', 'id_kelengkapan');
}
}
// 2. model DetilKelengkapan
class DetilKelengkapan extends Eloquent{
public function tDetilKelengkapanPaket(){
return $this->hasMany('TDetilKelengkapanPaket', 'id_detil_kelengkapan');
}
public function kelengkapan(){
return $this->belongsTo('Kelengkapan', 'id_kelengkapan');
}
}
// 3. model TDetilKelengkapanPaket
class TDetilKelengkapanPaket extends Eloquent{
public function detilKelengkapan(){
return $this->belongsTo('DetilKelengkapan', 'id_detil_kelengkapan');
}
}
the controller is:
$kelengkapan = Kelengkapan::with('detilKelengkapan.tDetilKelengkapanPaket')
->whereHas('detilKelengkapan.tDetilKelengkapanPaket', function($q) use ($id){
$q->where('id_paket', $paket);
})->get();
but the result has not filtering by "id_paket" but showed all data. thanks. (newbie)
Your Code:
$kelengkapan = Kelengkapan::with('detilKelengkapan.tDetilKelengkapanPaket')
->whereHas('detilKelengkapan.tDetilKelengkapanPaket', function($q) use ($id){
$q->where('id_paket', $paket);
})->get();
The correct Code:
$kelengkapan = Kelengkapan::with('detilKelengkapan.tDetilKelengkapanPaket')
->whereHas('detilKelengkapan.tDetilKelengkapanPaket', function($q) use ($id){
//the function should return the $q variable.
return $q->where('id_paket', $id);
})->get();
Explanation:
whereHas function has 2 compulsory arguments. A relationship function name, and a closure. The closure must return a query object so that filters can be chained.
Source: http://laravel.com/docs/4.2/eloquent#querying-relations
In there whereHas function you pass $id variable in the closure but you are using $packet inside.
$kelengkapan = Kelengkapan::with('detilKelengkapan.tDetilKelengkapanPaket')
->whereHas('detilKelengkapan.tDetilKelengkapanPaket', function($q) use ($id){
$q->where('id_paket', $id);
//---------------------^
})->get();
Try it and let me know the result.

Categories