I getting results from a query built using Eloquent (Laravel's ORM)
$query = Lawyer::whereHas('user', function($q) use ($request) {
$q->where('is_active', true);
});
$result = $query->get()
I would like to pass the results I get throught a trasformer class LawyerTransformer extends TransformerAbstract{} to add some data to the results.
When I try this :
$this->collection($query->get(), new LawyerTransformer())
I have the following issue : Method [collection] does not exist.
How can I transform all the results using a transformer ?
You could use the transform method on the collection instance to achieve something like that here is an example that will increment all values in an array by 1;
$collection = collect([1, 2, 3]);
$collection->transform(function ($item, $key) {
return (new IncrementTransformer)->transform($item);
});
And the transfomer class
class IncrementTransformer
{
public function transform($item)
{
return $item += 1;
}
}
You could probably write this a little cleaner but you get the basic idea.
Related
I am trying to build a Laravel Nova Filter for my Model "Question", based on data from two different tables. I have figured out the exact SQL query I would need to use, but cannot figure out how to use it in the apply() method of the Nova filter.
Table "questions" columns:
id, ...
Table "themes" columns:
id, question_id, theme_id
The SQL Query I am trying to use:
SELECT questions.*
From questions
Inner JOIN themes on questions.id=themes.question_id
WHERE themes.theme_id = 3 (value taken from the Nova Filter options)
My Filter in Laravel Nova QuestionsThemeFilter.php:
class QuestionsThemeFilter extends BooleanFilter
{
public $name = 'filter by theme';
public function apply(Request $request, $query, $value) {
// This is what I'm missing...
}
public function options(Request $request) {
$themes = Themes::all();
$themesArray = array();
foreach($themes as $item) {
$themesArray[$item['title']] = strval($item['id']);
}
return $themesArray;
}
}
So, how exactly should I do this?
Other question: Since I am a beginner in Laravel, how exactly should I start debugging this? Using dd() doesn't work (the filter just breaks) and I don't know how I can debug this. Is there a way to dump some values from the apply method (for example the $value)?
Thanks in advance for any help, highly appreciated :-D
Check the comments in the code
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
class QuestionsThemeFilter extends BooleanFilter
{
public function apply(Request $request, $query, $value) {
// Since you are using BooleanFilter $value will be an associate array with true/false value
$selectedThemes = Arr::where($value, function ($v, $k) {
return $v === true;
});
$selectedThemeIds = array_keys($selectedThemes)
// For debugging print some logs and check
Log::info($value)
Log::info($selectedThemeIds);
return $query->join('themes', 'questions.id', '=', 'themes.question_id')
->whereIn('themes.theme_id', $selectedThemeIds);
// If you are using normal filter then below code will be enough
/*
return $query->join('themes', 'questions.id', '=', 'themes.question_id')
->where('themes.theme_id', $value);
*/
}
public function options(Request $request) {
// You can use Laravel collection method pluck
return Themes::pluck('id', 'title')->all();
}
}
References:
Pluck
Boolean Filter
Arr::where
After eager loading attributes and their items I tried to sort the attributes without of luck.
public function __invoke(Category $category)
{
$category->load(['attributes']);
$category->attributes->load(['items' => function ($query) use ($category) {
$query->whereHas('productVariations.product.categories', function ($query) use ($category) {
$query->where('categories.id', $category->id);
});
}]);
foreach ($category->attributes as $attribute) {
$attribute->items = $attribute->items->sortByDesc('name');
}
dump($category->attributes->first()->items->pluck('name')); // Items are sorted
dd($category->attributes->toArray()); // Items are not sorted
}
Can you please tell me why is that and how can I sort them with collections (not Eloquent and MySql)?
Your problem is that you are not replacing the items in the collection itself. So I believe a map will do a better job here than a traditional foreach. So try this instead and let me know:
$attributes = $category->attributes->map(function($attribute) {
$attribute->items = $attribute->items->sortByDesc('name');
return $attribute;
});
dd($attributes);
I have array of collections. In collections I have relation. How I can use whereIn in these relations?
$arrayCollections = $category->products;
$arrayCollections = $arrayCollections->character->whereIn('id', [1,2,3,4]); //I need use whereIn in character relation. I get error: Property [character] does not exist on this collection instance.
foreach($arrayCollections as $product) {
.... //but in foreach I can use $product->character
}
Relation in product model::
public function character()
{
return $this->hasMany('App\Models\ProductCharacter');
}
Try this:
$characters = $category->products()->character()->whereIn('id', [1,2,3,4])->get();
foreach($characters as $character) {
// $character
}
You seem to need an indirect relationship. The best way to get this is by using hasManyThrough
In your Category model
public function characters() {
return $this->hasManyThrough(Character::class, Product::class); // Has many characters through products
}
Then you can directly do:
$characters = $category->characters()->whereIn('id', [ 1, 2, 3, 4 ])->get();
what about this ? I added first() :
$characters = $category->products()->first()->character()->whereIn('id', [1,2,3,4])->get();
foreach($characters as $character) {
// $character
}
You can try this
$arrayCollections = $category->products()->with('character')->whereIn('id' , [1,2,3,4])->get();
foreach($arrayCollections as $product) {}
You should use the whereHas() methode and with() method.
$arrayCollections = $category->products()
->whereHas('character', function($character){
$character->whereIn('id' , [1,2,3,4]);
})
->with('character')->get();
This will get you a collection of "products" that have "characters" attach to it that have ID in [1,2,3,4].
I was hoping I could do this on one line:
$users = [];
$rawUsers = User::select('id','first_name','last_name')->where('company_id',Auth::user()->company_id)->get();
foreach($rawUsers as $u) {
$users[$u['id']] = $u['first_name'].' '.$u['last_name'];
}
I see the Collection class has a ->map function which would let me do the concatenation, but I don't know how to get the results indexed by id. Is there a way to do what I want?
You can do this using lists method on the query:
User::select(DB::raw('concat(first_name," ",last_name) as full_name'), 'id')->lists('full_name', 'id');
// returns array(id => full_name, ...)
Or use accessor on the model and lists on the collection:
// User model
public function getFullNameAttribute()
{
return $this->attributes['first_name'].' '.$this->attributes['last_name'];
}
// then on the collection call lists:
$usersRaw = User::where(...)->get()->lists('fullName','id');
I have a complex Model with multiple defined relations. In this example I would want to count the Like model and create a property named likes so it can be returned from a REST service.
Is it possible to eager load a model count into a dynamic property?
$beat = Post::with(
array(
'user',
'likes' => function($q){
$q->count();
}
))
->where('id', $id)
->first();
Assuming you are having Post->hasMany->Like relationship and you have declared likes relationship as:
class Post{
public function likes(){
return $this->hasMany('Like');
}
}
create a new function say likeCountRelation as:
public function likeCountRelation()
{
$a = $this->likes();
return $a->selectRaw($a->getForeignKey() . ', count(*) as count')->groupBy($a->getForeignKey());
}
now you can override __get() function as:
public function __get($attribute)
{
if (array_key_exists($attribute, $this->attributes)) {
return $this->attributes[$attribute];
}
switch ($attribute) {
case 'likesCount':
return $this->attributes[$attribute] = $this->likesCountRelation->first() ? $this->likesCountRelation->first()->count : 0;
break;
default:
return parent::__get($attribute);
}
}
or you can use getattribute function as :
public function getLikesCountAttribute(){
return $this->likesCountRelation->first() ? $this->likesCountRelation->first()->count : 0;
}
and simply access likesCount as $post->likesCount you can even eager load it like:
$posts=Post::with('likesCountRelation')->get();
foreach($post as $post){
$post->likesCount;
}
NOTE: Same logic can be used for morph many relationships.
You should use the SQL Group By statement in order to make it works. You can rewrite your query like the following one.
$beat = Post::with(
array(
'user',
'likes' => function($q) {
// The post_id foreign key is needed,
// so Eloquent could rearrange the relationship between them
$q->select( array(DB::raw("count(*) as like_count"), "post_id") )
->groupBy("post_id")
}
))
->where('id', $id)
->first();
The result of likes is a Collection object with one element. I'm assuming the relationship between model Post and Like is Post hasMany Like. So you can access the count like this.
$beat->likes->first()->like_count;
I'm not tested code above but it should works.