Laravel ORM relationship returns error when value not present in DB - laravel

I have an issue with querying relationships.
I am querying relations between Projects, Companies and Products. However, whenever a Project ID is not present in the database an fatal exception is trown:
Call to a member function companies() on a non-object
public function index($i) {
return $this->returnTop($i, Array(
'projectid' => 5,
'products' => Array(1, 2, 3)
)
);
}
public function returnTop($count = 6, $args = Array()) {
$companies = Project::find($args['projectid'])->companies()->whereHas('products', function($q) use($args) {
$q->whereIn('products.id', $args['products']);
})->with('products')->limit($count)->get();
return Response::json($companies);
}
Now, I know that project id 5 is not present in the DB, and this is likely to be the cause of this error, but I want to return a message instead of the application throwing a fatal error....
Any ideas?

Just check if find() returns null. Something like this:
$project = Project::find($args['projectid']);
if(is_null($project)){
return Response::json(['message' => 'Project not found']);
}
$companies = $project->companies()->whereHas('products', function($q) use($args) {
$q->whereIn('products.id', $args['products']);
})->with('products')->limit($count)->get();
return Response::json($companies);
An alternative would be findOrFail which throws a ModelNotFoundException. You could handle the exception globally or catch it inside the controller:
try {
$companies = Project::findOrFail($args['projectid'])->companies()->whereHas('products', function($q) use($args) {
$q->whereIn('products.id', $args['products']);
})->with('products')->limit($count)->get();
return Response::json($companies);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e){
return Response::json(['message' => 'Project not found']);
}

You first have to test whether the returned object is actually not null. Blindly assuming a database query succeeds is waiting for sh*t to hit the fan.
public function returnTop($count = 6, $args = Array()) {
$project = Project::find($args['projectid']);
if($project) {
$companies = $project->companies()->whereHas('products', function($q) use($args) {
$q->whereIn('products.id', $args['products']);
})->with('products')->limit($count)->get();
return Response::json($companies);
}
else {
return; // .. your error or whatever
}
}
Also the "call to a member function on a non-object" is quite specific, it tells you that a method (member function) could not be called due to the fact that you are trying to call it on a non-object.

Related

Laravel model function best prickets

im new in Laravel , I have an issue as below
I make in category model query to check is category is exist or not
as below
public function scopeIsExist($query ,$id)
{
return $query->where(['deleted' => 1, 'id' => $id])->orderBy('id', 'DESC')->first();
}
and my controller is
public function edit($id)
{
$dataView['category'] = Category::IsExist($id);
if(!$dataView['category'])
{
return view('layouts.error');
}else{
$dataView['title'] = 'name';
$dataView['allCategories'] = Category::Allcategories()->get();
return view('dashboard.category.edit')->with($dataView);
}
}
my problem is when I use method isEXIST if id not found it not redirect to error page but ween i remove ISEXIST AND replace it as below
$dataView['category'] = Category::where(['deleted' => 1, 'id' => $id])->orderBy('id', 'DESC')->first();
it work well .
can any one help me
That's because local scope should return an instance of \Illuminate\Database\Eloquent\Builder. You should remove the first() in the scope and put it in the controller.
Redefine your scope like so:
public function scopeIsExist($query ,$id)
{
return $query->where(['deleted' => 1, 'id' => $id])->orderBy('id', 'DESC');
}
In your controller edit method:
$dataView['category'] = Category::IsExist($id)->first();
You can have a look to the doc for local scopes https://laravel.com/docs/8.x/eloquent#local-scopes

Method Illuminate\Database\Eloquent\Collection::attach does not exist error in laravel 8

I was trying to add categories to products. I want to do it with a couple table between items and categories. I made a function in my controller to send it to the database. However, when I want to send it, I get the following error, and I don't know I can fix it. Method Illuminate\Database\Eloquent\Collection::attach does not exist.
Controller:
public function store(ItemsValidatorRequest $request)
{
if ($files = $request->image) {
$destinationPath = 'images';
$profileImage = date('YmdHis') . "." . $files->getClientOriginalExtension();
$files->move($destinationPath, $profileImage);
}
else {
return redirect()->back()->with('warning', 'Mislukt');
}
$user = Auth::user()->id;
Item::create([
'user_id' => $user,
'item_title' => $request->titel,
'item_img' => $profileImage,
'item_description' => $request->beschrijving,
'item_price' => $request->prijs,
'item_slug' => $this->slugify($request->titel)
]);
$items = Item::latest()->get();
// line where it goes wrong
$items->each->categories()->attach($request->categories);
return redirect()
->route('admin.items.index')
->with('success', 'Het item is toegevoegd aan je verlanglijst');
}
My model :
public function categories()
{
return $this->belongsToMany('App\Models\Category');
}
Laravels higher order function calls, take a single method call, not multiple. Therefor if you create an helper method on the Item class, it will solve your problem.
class Item {
public function attachCategories($categories) {
$this->categories()->attach($categories);
}
}
Which will make it possible to assign categories like so.
$items->each->attachCategories($request->categories);

How to avoid error when using Eloquent's toArray when getting null result

l am getting start at a new laravel project with 5.7, but one problem, when l use first() to fetch data, and if data is not exist, it will return null, and then execute toArray() will throw a PHP error. So l use follow code to reslove it.
$user_model = \App\Model\User::where('id', $id);
if ($select) {
$user_model->select(explode(',', $select));
}
$user_data = $user_model->first();
$user_data = $user_data ?? $user_data->toArray();
So is there any better way?
Any one of the following will work, each providing their own way of dealing with a null result:
1. optional helper:
The optional function accepts any argument and allows you to access
properties or call methods on that object. If the given object is null,
properties and methods will return null instead of causing an error.
$user_data = optional($user_model->first())->toArray();
2. firstOr():
Execute the query and get the first result or call a callback.
$data = User::where('id', $id)->when(!is_null($select), function ($query) use ($select) {
return $query->select(explode(',', $select));
})->firstOr(function () {
return ['message' => 'No results'];
});
3. rescue helper:
The rescue function executes the given Closure and catches any exceptions that occur during its execution. All exceptions that are caught will be sent to your exception handler's report method; however, the request will continue processing.
$data = rescue(function () use ($select) {
\App\Model\User::where('id', $id);
if ($select) {
$user_model->select(explode(',', $select));
}
return $user_model->first()->toArray();
});
4. try catch:
try {
$user_model = \App\Model\User::where('id', $id);
if ($select) {
$user_model->select(explode(',', $select));
}
$user_data = $user_model->first();
$user_data = $user_data ?? $user_data->toArray();
} catch(\Exception $e) {
// handle the exception...
}
Laravel provides a firstOrFail method which throws an 404 Exception by default.
$user_data = $user_model->firstOrFail(); // If not found an exception is thrown and will be handled by default ExceptionHandler which displays a 404 error page.
// if found, cast the User to array
$user_data = $user_data->toArray();

Laravel upgrade issue with whereHas

I recently changed versions of Laravel and I am now getting this error:
LogicException
Has method invalid on "belongsTo" relations.
Can anyone explain why I am now getting this error?
If I comment out the below three lines, no error.
Version: "laravel/framework": "4.1.7"
The piece of code in question is this:
$orderCount->whereHas('order', function($query) {
$query->whereRaw("status IN ('pending', 'prepaid')");
});
The entire controller logic here:
public function show($id) {
// the fields we want back
$fields = array('id', 'title', 'description', 'msrp', 'brand_id', 'category_id');
// how many products are in pending orders
$orders = 0;
// assume not admin must be display = 1
$display = 1;
// if logged in add more fields
if(Auth::check()) {
// add these fields to the query if dealer
array_push($fields, 'price_dealer', 'quantity');
// if admin add these fields
if (Session::get("admin")) {
$display = 0;
array_push($fields, 'cost', 'display', 'crate_quantity_threshold', 'price_crate');
}
}
$product = Product::with('images', 'brand', 'category', 'docs')
->select($fields)
->where('display', '>=', $display)
->find($id);
if(Auth::check()) {
// make orders obj
// we need to see how many orders
// there are pending for this product
$obj = new OrderItem;
$orderCount = $obj->newQuery();
$orderCount->where('product_id', '=', $id);
$orderCount->whereHas('order', function($query) {
$query->whereRaw("status IN ('pending', 'prepaid')");
});
$product->orders = $orderCount->sum('quantity') > 0 ? $orderCount->sum('quantity') : 0;
// dd(\DB::getQueryLog());
}
if ($product) {
return Response::json(array(
'product' => json_decode($product)
),
200
);
} else {
return Response::json(array(
'flash' => "Not found"
),
500
);
}
}
In Order model:
public function products()
{
return $this->belongsToMany('Product', 'order_items', 'order_id', 'product_id');
}
Short answer: Upgrade to 4.1.11+ due to:
4.1.7 - not implemented method
4.1.11 - method in place

Magento Fatal error: Call to a member function setCurPage() on a non-object

I created a block with a toolbar, but an error happened:
Fatal error: Call to a member function setCurPage() on a non-object
I did quite some search-queries but can’t find the solution.
Is there someone who knows the reason?
Please see my code below:
class test_Promotion_Block_List extends Mage_Catalog_Block_Product_List {
public function __construct() {
parent::__construct();
$collection = Mage::getModel('catalog/product')
->getCollection()
->joinField('category_id', 'catalog/category_product', 'category_id', 'product_id = entity_id', null, 'left')
->addAttributeToSelect('*')
->addAttributeToFilter('category_id', array('finset' => '98'))
->addAttributeToSort('created_At', 'desc')
;
$this->setCollection($collection);
}
protected function _prepareLayout() {
parent::_prepareLayout();
$toolbar = $this->getToolbarBlock();
// called prepare sortable parameters
$collection = $this->getCollection();
// use sortable parameters
if ($orders = $this->getAvailableOrders()) {
$toolbar->setAvailableOrders($orders);
}
if ($sort = $this->getSortBy()) {
$toolbar->setDefaultOrder($sort);
}
if ($dir = $this->getDefaultDirection()) {
$toolbar->setDefaultDirection($dir);
}
$toolbar->setCollection($collection);
$this->setChild('toolbar', $toolbar);
$this->getCollection()->load();
return $this;
}
public function getDefaultDirection() {
return 'asc';
}
public function getAvailableOrders() {
return array('name' => 'Name', 'position' => 'Position', 'children_count' => 'Sub Category Count');
}
public function getSortBy() {
return 'name';
}
public function getToolbarBlock() {
$block = $this->getLayout()->createBlock('testpromotion/toolbar', microtime());
return $block;
}
public function getMode() {
return $this->getChild('toolbar')->getCurrentMode();
}
public function getToolbarHtml() {
return $this->getChildHtml('toolbar');
}
}
Error sniffing:
Magento Product_List blocks are "pagination aware". They take URL paging parameters and apply it to the collection of products to be displayed.
That means that the error you're seeing occurs somewhere in the parent classes of your block. That method is called for collections so it means that the result of one of the selects is not an object but either an array or null.
It's more likely you're receiving an array response but you didn't initialize the collection with the response so calling the method on an array triggers this error.
Error info:
Please specify the full error info including file and line where it occurs. This will help find the source of the error.
Also use the following line next to (before / after any operation that might change the $collection variable) because you may be calling $this->setCollection(null).
var_dump(is_object($collection) ? get_class($collection) : get_type($collection));

Resources