Can you DD just after line 3 and show us the result.
Property [products] does not exist on this collection instance.
Hello all.
Having a bit of an odd issue I am not sure on how to get taken care of. I have a method that should pull all products for the query, and then sorts them by amazin score descending. After sorting just return the categories with the best products.
But when I try it out I get "Property [products] does not exist on this collection instance." and I am not sure why.
This is what I have worked up
public function scopeBestCategories($query)
{
$rightNow = $query->get();
$best = $rightNow->products->orderByDesc(function($item) {
return $item->reviews->amazin_score;
});
return self::whereIn($best->pluck('node_id'));
}
Any assistance with this would be greatly appreciated.
Still learning the ropes...so forgive my ignorance. But I have this in "class Node extends Model" so I am not quite sure how to show that dd... :|
When I try pass it to the pagecontroller to display it on the home blade is when I see
"Exception Property [products] does not exist on this collection instance."
if this helps, this is how I get the Get Products
public function scopeGetProducts($query)
{
$children_ids = $this->children()->pluck('id');
$children_ids->push($this->id);
return Product::whereIn('node_id', $children_ids);
}
Basically what I am trying to do it display 3 categories that have the highest ranking products.
@tomwebb Can you explain further? Maybe show us your Controller and how you want to display that in your view?
Best thing that comes to my mind in this state and as sleepy as I am is that maybe you could try changing orderByDesc for sortByDesc since you already have an array.
PS: for bnazarov suggestion just:
public function scopeBestCategories($query)
{
$rightNow = $query->get();
$best = $rightNow->products->orderByDesc(function($item) {
return $item->reviews->amazin_score;
});
dd($best);
return self::whereIn($best->pluck('node_id'));
}
This should show in the browser an array of what you are returning. Edit: forgot a semicolon.
The short answer is there will never be any 'Products' property in the collection, because the collection is just empty. (Pretty sure);
Provide us the complete Model(s) code. The whole file(s).
You have a Product model, and a Category model? Where the Product belongs to a category?
What are children?
ps. you can DD these 3:
- dd($best);
- dd(self::whereIn($best->pluck('node_id')));
- dd($children_ids);
- dd(Product::whereIn('node_id', $children_ids));
one at time. dd() calls exit.
Finally some issues:
-
referencing $this in a query scope returns a Illuminate\Database\Eloquent\Builder. So you should not use '$this' use the $query builder.
-
your ::whereIn use is incorrect. And I don't know why you don't get an exception. you need to pass the column name as the first param. as in: ::whereIn('id', [1,2]);
-
any use of $this->somerelationship (e.g. $this->children) will always return an empty collection. it returns kinda like an empty model. use $children = $query->with('children')->get()->pluck('children'). This gives you a collection of children.
lastly, I think DB::raw is better here, as you are doing aggregation.
https://laracasts.com/discuss/channels/eloquent/eloquent-order-by-related-table
My page controller. I am still learning and trying to get the hang of laravel. So sorry if I seem a little lost in some aspects.
namespace App\Http\Controllers;
use Illuminate\Http\Request; use App\Product; use App\Node;
class PageController extends Controller { public function home(Request $request) { $products = Product::byFilters($request)->byImpressions()->take(20)->get();
$tenBest = array(
Node::bestCategories()->byImpressions()->get()
);
// $tenBest = array(
// Product::whereNodeId(2)->with('reviews')->get(),
// Product::whereNodeId(10)->with('reviews')->get(),
// Product::whereNodeId(27)->with('reviews')->get(),
// );
return view('home', [
'products' => $products,
'tenBest' => $tenBest
]);
}
public function search(Request $request)
{
$query = $request->input('q');
$products = Product::searchFor([
'title'
], $query)->paginate(20);
return view('search', [
'query' => $query,
'products' => $products
]);
}
public function about()
{
return view('about.about');
}
}
Node.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Node extends Model { use \App\Traits\SlugTrait;
protected $table = 'nodes';
protected $fillable = [
'name','node','parent','slug', 'impressions'
];
/**
* Delete the node if you are able to
*/
public function deleteIfPossible()
{
// Check to see if Node already contains anything important
if($this->canBeDeleted())
return false;
$this->delete();
return true;
}
/**
* Eloquent relationship one to many
*/
public function products()
{
return $this->hasMany('App\Product');
}
/**
* Return a URL to view a single node
*/
public function getNodeLink()
{
return action('Backend\NodesController@single', $this->slug);
}
public function getFrontendLink()
{
return action('NodeController@single', $this->slug);
}
/**
* Scope to return only parent nodes
*/
public function scopeParentsOnly($query)
{
return $query->whereParent(null);
}
public function hasProducts()
{
return $this->products->count() > 0;
}
/**
* Returns the child nodes for the current model
*/
public function scopeChildren($query)
{
return $query->where('parent', '=', $this->id);
}
/**
* Determine if the Node has children Nodes
*/
public function hasChildren()
{
return $this->children()->get()->count() > 0;
}
/**
* Returns the products for the given node, as well as its children
*/
public function scopeGetProducts($query)
{
$children_ids = $this->children()->pluck('id');
$children_ids->push($this->id);
return Product::whereIn('node_id', $children_ids);
}
public function scopeBestCategories($query)
{
$rightNow = $query->get();
$best = $rightNow->products->orderByDesc(function($item) {
return $item->reviews->amazin_score;
});
return self::whereIn($best->pluck('node_id'));
}
public function canBeDeleted()
{
$child_count = $this->children()->count();
$product_count = $this->products->count();
return $child_count === 0 && $product_count === 0;
}
public function scopeByImpressions($query)
{
return $query->orderBy('impressions', 'desc');
}
}
ProductController
namespace App\Http\Controllers;
use Illuminate\Http\Request; use App\Product; use App\Node;
class ProductController extends Controller { public function single($category, $slug) {
$product = Product::whereSlug($slug)->firstOrFail();
$product->impressions++;
$product->update();
return view('product.single')->withProduct($product);
}
public function index(Request $request)
{
$fields = $request->only(['sort_by','sort_order']);
$products = Product::byFilters($fields)->byImpressions()->paginate(20);
$paginateProds = Product::paginate(20);
return view('product.index', [
'products' => $products,
'nodes' => Node::parentsOnly()->get(),
'paginateProds' => $paginateProds,
]);
}
}
NodeController
namespace App\Http\Controllers;
use Illuminate\Http\Request; use App\Node;
class NodeController extends Controller {
public function index()
{
return view('node.index', [
'nodes' => Node::parentsOnly()->paginate(10)
]);
}
public function single($slug)
{
$node = Node::whereSlug($slug)->firstOrFail();
$node->impressions++;
$node->update();
return view('node.single', [
'node' => $node,
'products' => $node->getProducts()->byImpressions()
]);
}
}
what I am currently working on. http://bed-bath-and-kitchen.com/
Basically I am trying to display the top 10 products for the top categories. Nodes are categories
Also this is the home.blade
@extends('layout.app')
@section('jumbotron')
Bed Bath & Kitchen
Delivering the best choices for all things bed, bath, and kitchen. Helping you purchase exactly what you want using our special ranking method.
@section('content')
Find the top bed, bath, and kitchen products on the internet. Easily find the product that fits your needs. Using our ranking system you can make sure you are getting exactly what you are looking for.
@include('forms.search')
@foreach($tenBest as $title => $row)
@include('components.product-preview', ['products'=>$row, 'node' => $row->first()->node])
@endforeach
@include('product.partials.product-grid')
<div class="text-center">
<a href="{{ action('ProductController@index')}}" class="btn btn-default btn-lg">View More</a>
</div>
Please or to participate in this conversation.