Call to undefined method whereHas() in laravel 5.5 - laravel

I am upgrading and refactoring my site to laravel 5.5, and this code is giving me a problem at the moment. I searched in the laravel github docs and didn't find any breaking changes that might affect this.
What I am trying to do is Related To section in my site, In every recipe page I want to display some more recipes that has the same category.
Here is my code:
public static function getRelatedRecipes($recipe){
$related_category_ids = $recipe->category()->pluck('categories.id');
return $relatedRecipes =
Recipe::whereHas('categories', function ($q)use($related_category_ids){
$q->whereIn('category_id', $related_category_ids);
})
->where('id', '<>', $recipe->id)
->take(4)
->inRandomOrder()
->get();
}
This is the recipe model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Recipe extends Model
{
protected $guarded=[];
/**
* Get the route key name for Laravel.
*
* #return string
*/
public function getRouteKeyName()
{
return 'slug';
}
public function category()
{
return $this->belongsToMany('App\Category');
}
}
What could be the problem?
Thanks,
P.S
If any other code that you think is needed to resolve this, please tell me and I will post it here. :)

First of all make sure, Recipe you use in the method is the model, so instead of
Recipe::whereHas('categories', function ($q)use($related_category_ids){
use
\App\Recipe::whereHas('categories', function ($q)use($related_category_ids){
The other thing is this categories relationship. In model you don't have categories relationship, you have only category relationship

Related

Laravel- Eloquent many to many get unattached data

I have User, Shop and Product model on my app. And relationship like this:
User
public function products(){
return $this->hasMany("App\Product");
}
public function shops(){
return $this->hasMany("App\Shop");
}
Shop
public function user(){
return $this->belongsTo("App\User");
}
public function products(){
return $this->belongsToMany("App\Product");
}
Product
public function user(){
return $this->belongsTo('App\User');
}
public function shops(){
return $this->belongsToMany("App\Shop");
}
So, user can add Products and Shops and then attach a product to many shop. Now I can get all of the attached shops by $product->shops on product page and auth users all shop by auth()->user()->shops. Actually, I want to show the auth users shop that is not attached to this Product on the Product page. According to Laravel documentation, I write some code but for some reason it doesn't work. My code is :
auth()->user()->shops()->whereDoesntHave('products', function (Builder $query) {
$query->where('id','!=', $product->id);
})->get();
Error:
Any help will be appreciated.
Thanks
Converting comment to an answer here.
Firstly, the usage of function(Builder $query) is targeting the incorrect version of Builder (likely a namespacing issue), so simply removing Builder from the function should allow it to resolve.
Secondly, to use $product in scope of the new function, it needs to be passed use use($product), otherwise you'll get an Undefined variable $product error.
Altogether, the new function should look like this:
auth()->user()->shops()->whereDoesntHave('products', function ($query) use($product) {
$query->where('id','!=', $product->id);
})->get();

withTrashed on hasManyThrough relation

How can withTrashed be applied on a hasManyThrough relation ?
$this->hasManyThrough('App\Message', 'App\Deal')->withTrashed();
returns
Call to undefined method Illuminate\Database\Query\Builder::withTrashed()
when i'm doing:
$messages = Auth::user()->messages()->with('deal')->orderBy('created_at', 'DESC')->get();`
Here is my Deal model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Deal extends Model
{
use SoftDeletes;
/* ... */
protected $dates = ['deleted_at'];
public function user() {
return $this->belongsTo('App\User');
}
public function messages() {
return $this->hasMany('App\Message'); // I've tried to put withTrashed() here, there is no error but it doesn't include soft deleting items.
}
}
To all those coming to this late, there is now a native way of doing this with Laravel.
$this->hasManyThrough('App\Message', 'App\Deal')->withTrashedParents();
This is not well documented but can be found in Illuminate\Database\Eloquent\Relations\HasManyThrough
The error is thrown because you are requesting a messages with deleted ones without using SoftDelete trait in Message model.
After I check the hasManyThrough relation code I found that there is no way to do it in this way, you should play around.
Ex:
get the deals of user with messages instead
$deals = Auth::user()->deals()->withTrashed()->with('messages')->get();
foreach($deals as $deal) {
//Do your logic here and you can access messages of deal with $deal->messages
}

How to access my model in laravel?

I can't seem to figure out what's wrong with this code. I'm running laravel 5.4.
The error:
https://www.dropbox.com/s/64ioxdf4mv6ps1w/Screenshot%202017-02-28%2020.11.33.png?dl=0
The Controller function:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Thread;
class ThreadController extends Controller
{
public function show($id) {
return Thread::where('id', '=', $id)->messages();
}
}
The Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Thread extends Model
{
public function messages()
{
return $this->hasMany(Message::class)->get();
}
}
I suggest adding your error code instead of linking to image (right now AWS is down, thus I'm unable to view the image).
Regardless, the messages method is defining a relationship and as such, is an instance of the query builder. Rather than chaining the get method there, I suggest a slightly different approach:
In your controller
public function show($id)
{
// Use first() instead of get() since you're returning a
// specific model by its primary key (I assume)
return Thread::where('id', $id)->with('messages')->first();
}
And in your model
public function messages()
{
// This returns a query builder instance, which is what you want.
// It defines the relationship between Thread and Message
return $this->hasMany(Message::class);
}
This will eager load your messages along with your Thread model.
Hope it helps!
Regarding Joel's question in the comments...
User::find(1)->messages->create($request->only('body'));
Is not calling the 'messages function' you mentioned and not returning the relationship. Instead, it is calling the messages property, which is something different.

laravel model relation not working

I have created a laravel api for my application.I have used Pingpong module package for different modules.I am having hard time establishing many-to-many relation.I have 3 tables:roles,groups,group_roles.And my models are:
Group.php
namespace Modules\User\Entities;
use Illuminate\Database\Eloquent\Model;
class Group extends Model {
protected $fillable = [];
protected $table='groups';
public static function roles(){
return $this->belongsToMany('Modules\User\Entities\Role','group_roles','group_id','role_id');
}
}
Role.php
namespace Modules\User\Entities;
use Illuminate\Database\Eloquent\Model;
class Role extends Model {
protected $fillable = [];
protected $table='roles';
public function groups(){
return $this->belongsToMany('Modules\User\Entities\Group','group_roles','group_id','role_id');
}
}
And my controller
namespace Modules\User\Http\Controllers;
use Pingpong\Modules\Routing\Controller;
use Modules\User\Entities\Group;
use Modules\User\Entities\Role;
use Illuminate\Http\Request;
use App\Login;
use Input;
use Validator;
use Hash;
use Response;
class UserController extends Controller {
public function getGroupById(Request $request){
$groups=Group::with('roles')->get();
return Response::json ([
'status'=>'ok',
'group'=>$groups
],200);
}
}
The problem is I am not able to establish the relation between the models and the getGroupById returns 500 internal error response.$group=Group::all(); $group=Group::find($request['id']); returns fine but it is not returning related roles.
Similar structure and codes work fine on app without the use pingpong.
Your relationships are currently like this:
// not sure why this is static?
public static function roles(){
return $this->belongsToMany('Modules\User\Entities\Role', 'group_roles', 'group_id', 'role_id');
}
public function groups(){
return $this->belongsToMany('Modules\User\Entities\Group', 'group_roles', 'group_id', 'role_id');
}
Please note from the docs, regarding the belongsToMany method:
The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to...
So with this in mind I think your relationships may be incorrect due to using the wrong arguments on your belongsToMany method calls. I think it should be like this:
public function roles(){
return $this->belongsToMany('Modules\User\Entities\Role', 'group_roles', 'group_id', 'role_id');
}
public function groups(){
return $this->belongsToMany('Modules\User\Entities\Group', 'group_roles', 'role_id', 'group_id');
}
Also if you have intermediate table columns you'd need to declare those on the belongsToMany call.
Hope that helps!
Edit
Firstly, you said getGroupById returns 500 internal error response. Have you tried checking what the actual error is!? 500 internal error doesn't provide much info, I'm sure you'd get to the bottom of things a lot faster if you found out the exact issue through laravel's usual error response page.
I assume you're doing this through an ajax request so you could use the network tab if you're using chrome then click on the 500 request to see the error laravel returns or you can use something like postman and hit the url through that.
If I wanted to quickly check the functionality of the models relationship methods, I'd do the following:
After setting up some data for a group and relationship, could you try running this in tinker or a route for testing/debugging.
$g = Group::first(); // get the first group, or you could use find($id) if you had a specific group in mind
// if you're in tinker
$g->roles; // show the roles
// if you're running on a route
dd($g->roles); // show the roles
While haakym's answer is very detailed, but you can also try changing your mapping table name to convention based 'group_role' instead of 'group_roles'. With this method you will have to supply only one argument to belongsToMany call.
Note that in general it should not matter if the other arguments are correct, but its just another step to debug!

Issue with Laravel hasMany relation

I’m having an issue with relations in two of my models in a Laravel application. My models are:
class Invoice extends Eloquent {
protected $table = 'invoices';
public function line_items()
{
return $this->hasMany('LineItem');
}
}
And:
class LineItem extends Eloquent {
protected $table = 'line_items';
public function invoice()
{
return $this->belongsTo('Invoice');
}
}
In my controller, I fetch an Invoice row with the following:
$invoice = Invoice::find($id);
However, if I try and access the line_items property to fetch the LineItem rows relating to my invoice, I get the following error:
Invalid argument supplied for foreach()
Why is this? I’ve set my models up as per Laravel’s documentation: http://laravel.com/docs/eloquent#one-to-many
change
public function line_items()
for
public function lineItems()
and it will work , tested in Laravel 4.1 :)
Check your tables relations... (Schema)
Your FK must be lineitem_id... You have modified this? Laravel will configure automatically... Don't change this...
Then, try
$invoice->line_items() or $invoice->line_items in 4.1
Check for line_items before the foreach loop:
if(! $invoice->line_items->isEmpty()){
foreach($invoice->line_items as $line_item){
//do stuff
}
}
Also, it won't hurt to explicitly mention the FK, although laravel will automatically try to do it for you provided you use proper names for your table fields.
//Invoice Model
return $this->hasMany('LineItem', 'invoice_id');
//LineItem Model
return $this->belongsTo('Invoice', 'invoice_id');

Resources