Laravel hasMany relationship returning undefined method - php

I have a Laravel Model:
class Order extends Eloquent{
protected $table = 'orders';
public function orderItems(){
return $this->hasMany('OrderItem');
}
public static function findByUserMonthYear($user_id, $month, $year){
return Order::where('user_id', '=', $user_id)
->where('month', '=', $month)
->get();
// ->where('year', '=', $year);
}
}
And of course I have an OrderItem class
class OrderItem extends Eloquent{ ...
But if I do:
$order = Order::findByUserMonthYear(Auth::user()->id, Date::getDate(), 2014);
$order->orderItems();
I get the following:
Call to undefined method Illuminate\Database\Eloquent\Collection::orderItems()
What am I doing wrong? If I were to change the statement to Order::with('orderItems') the relationship seems to work fine, but I'd like to delete all the orderItems associated to the current Order.

Your ->get() within you findByUserMonth is returning a Collection. If this query returns only one collection then use the ->first() instead, but if your query returns multiple results then eager load the results of orderItems like so;
public static function findByUserMonthYear($user_id, $month, $year){
return self::with('orderItems')->where('user_id', '=', $user_id)
->where('month', '=', $month)
->get();
// ->where('user_id', '=', $year);
}
Then you can access the results like so;
#foreach($orders as $order)
{{$order->orderItem}}
#endforeach
This is because the return being a collection, so you have to loop through them. The use {{$order->orderItem}} to access the results
Im not too sure on this but i think you can delete all the models within a hasMany like so; $order->orderItem()->delete(); as the return of orderItem() is a Query\Builder instance.

your second class must be extends Order class
use this line for OrderItem class :
class OrderItem extends Order {

Related

laravel eloquent complex select inside where statement

halo, i have data and want to display it like picture below
there are two models relationship, Person and Installment.
this is Person model:
class Person extends Model
{
protected $table = 'person';
public function angsuran()
{
return $this->hasMany(Installment::class);
}
}
this is Installment model:
class Installment extends Model
{
protected $table = 'installment';
public function person()
{
return $this->belongsTo(Person::class);
}
}
and this is my controller to querying and display data
$data = Person::with('angsuran')
->whereHas('angsuran', function ($q) {
$q->whereBetween('installment_date', [\DB::raw('CURDATE()'), \DB::raw('CURDATE() + INTERVAL 7 DAY')])
->where('installment_date', '=', function () use ($q) {
$q->select('installment_date')
->where('status', 'UNPAID')
->orderBy('installment_date', 'ASC')
->first();
});
});
return $data->get();
it show error unknow colum person.id in where clause
please help. thanks.
As the comment said, you need to put $q as a parameter to the Closure.
When using subqueries, it's useful to tell the query builder which table it is supposed to query from.
I've rewritten your query. It should achieve what you're looking for. Also, changed the CURDATE to Carbon objects.
today() returns a datetime to today at 00:00:00 hours. If you need the hours, minutes and seconds, replace today() by now().
$data = Person::with('angsuran')
->whereHas('angsuran', function ($subquery1) {
$subquery1->where('installment_date', function ($subquery2) {
$subquery2->from('installment')
->select('created_at')
->where('status', 'UNPAID')
->whereBetween('installment_date', [today(), today()->addWeeks(1)])
->orderBy('installment_date')
->limit(1);
});
});
Using with and whereHas you will end up with two query even if you have limit(1) in your subQuery and the result will show all 4 installment related to the person model. also I don't think you can order on the subquery, it should be before the ->get
so here's i've rewritten your code
$callback = function($query) {
$query->whereBetween('installment_date', [today(), today()->addDays(7)])
->where('status', 'UNPAID')
->orderBy('installment_date');
};
$data = Person::whereHas('angsuran', $callback)->with(['angsuran' => $callback])->get();
or you can use query scope. please see this answer Merge 'with' and 'whereHas' in Laravel 5

Laravel withCount use function in model

I have model Post:
protected $guarded = [];
public function reviews() {
return $this->hasMany(Review::class);
}
My reviews table have a column type with values: 1(good),2(comment),3(negative).
I need get count reviews for every type. I need globally get these counts. I know that I can do in model something like this:
protected $withCount = ['reviews'];
But this get me all reviews. But I need get count only for every type.
You could use the withCount method and do sub queries inside:
$counts = Post::withCount([
'reviews',
'reviews as good_reviews' => function ($query) {
$query->where('type', 1);
}],
'reviews as bad_reviews' => function ($query) {
$query->where('type', 3);
}],
}])->get();
You can access the count like this:
echo $counts[0]->good_reviews;
For more info: Docs
you can use GroupBy method for it.
Something like this:
DB::table('reviews')
->select('type', DB::raw('count(*) as total'))
->groupBy('type')
->get();

Laravel paginate pivot tables

I have collections which contains custom products I need to paginate those collections products but I receive error.
data
With this query I can get my collection and it's products but I'm not able to paginate products.
$collection = Collection::where('slug', $slug)->where('status',
'active')->with('products')->first();
With this query I receive error
$collection = Product::with('collections')->whereHas('collections',
function($query) use($slug) { $query->where('slug',
$slug)->where('status', 'active')->first(); });
Error
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'shopping.product_id' doesn't exist (SQL: select * from `collection_products` inner join `product_id` on `collection_products`.`id` = `product_id`.`collection_product_id` where `products`.`id` = `product_id`.`product_id` and `slug` = test and `status` = active limit 1)
Code
Product model
public function collections()
{
return $this->belongsToMany(CollectionProduct::class, 'product_id');
}
Collection model
public function collection(){
return $this->belongsToMany(CollectionProduct::class);
}
public function products(){
return $this->belongsToMany(Product::class, 'collection_products', 'collection_id', 'product_id');
}
CollectionProduct model
public function collection()
{
return $this->belongsTo(Collection::class, 'collection_id','id');
}
Controller default query
public function single($slug){
$collection = Collection::where('slug', $slug)->where('status', 'active')->with('products')->first();
return view('front.collections.single', compact('collection'));
}
Question
How can I get my collection products with pagination ability?
Couple things:
You are trying to call the first() method inside of a relationship query in this line:
$collection = Product::with('collections')->whereHas('collections', function($query) use($slug) { $query->where('slug', $slug)->where('status', 'active')->first(); });
The methods first() and get() are used to execute the query, so you should keep them at the end of the chain of eloquent methods:
$collection = Product::with('collections')
->whereHas('collections', function($query) use($slug) {
$query->where('slug', $slug)->where('status', 'active');
})
->get();
https://laravel.com/docs/5.7/eloquent#retrieving-models
However, if you want to paginate the list of products, then what you really want is the paginate() method:
$collection = Product::with('collections')
->whereHas('collections', function($query) use($slug) {
$query->where('slug', $slug)->where('status', 'active');
})
->paginate(20); // will return 20 products per page
https://laravel.com/docs/5.7/pagination
Also, the collections() method on your Product model has product_id listed as the join table, and is joining to the CollectionProduct model instead of the Collection model.
Try this instead for your Product model:
public function collections()
{
return $this->belongsToMany(Collection::class, 'collection_products', 'product_id', 'collection_id');
}
i use following code and working very well
the first step get product
$product = Product()->find($product_id);
than i get collections and pagination
$collections = Product::find($product_id)->collections->paginate(20);
for example i used above code in this site.

php/laravel - select other table's column using the belongsToMany of laravel

This is my code on patient model:
class Patient extends Model
{
protected $primaryKey = 'PatientID';
public function users()
{
return $this->belongsToMany('App\Vaccine', 'immunizations', 'patient_id', 'vaccine_id');
}
}
and this is my query
$patients = Patient::whereDoesntHave('users', function ($q) use ($vaccine_id) {
$q->where('vaccine_id', '=', $vaccine_id);
})->get();
In my current situation I can only get the Patient model column data but not the other tables. Where should I put the select() method to select the rows and columns of the immunizations table because i want to set a chain where()or condition which is where('immunizations_id', 1) but it doesn't work because the immunizations table is not selected.
or does anyone here knows how to convert it without using a closure like make it
Patient::wheredoesnthave(join('table')); so i can freely manipulate it
We will get other relationship table using 'with()'
$patients = Patient::whereDoesntHave('users', function ($q) use ($vaccine_id) {
$q->where('vaccine_id', '=', $vaccine_id);
$q->with('Vaccine', 'immunizations');
})->get();
Try this.

Laravel 4 model method failed with "Call to undefined method"

My models extends "\BaseModel" which in its turn extends the Eloquent.
class BaseModel extends Eloquent {
public function foo($attribute)
{
//some code
}
In my collection, where the model being instanced I'm trying to access the "foo()" method, but it responses me with "Call to undefined method".
$data = IncomeDoc::with('details')
->where('type', '!=', 2)
->get();
$data = $data->foo();
Moreover, I tried to place the method "foo" in the model itself, but there was no difference.
Thanks for all
Basically get() method returns a Collection of instances. Assume more than 1 model satisfy type != 2 condition. If you want to get first model under the condition just use first() instead.
$data = IncomeDoc::with('details')
->where('type', '!=', 2)
->first();
$data = $data->foo();
Otherwise:
$collection = IncomeDoc::with('details')
->where('type', '!=', 2)
->get();
$data = [];
foreach($collection as $item) {
$data[] = $data->foo();
}
Actually get() returns a collection, an instance of Illuminate\Database\Eloquent\Collection and in this collection there is no foo method but to call the method that you declared in your model, you need to access the model, so first model in the collection would be 0 and to get it you may use $data->first() or $data->get(0), to get the second item (model) from the collection you may use $data->get(1) and so on but you may also use a loop, for example:
$data = IncomeDoc::with('details')->where('type', '!=', 2)->get();
$dataArray = array();
$data->each(function($item) use (&$dataArray){
$dataArray[] = $item->foo();
});
return View::make('viewname')->with('data', $dataArray);
Also, you may directly pass the $data to your view and can apply the function call from the view within a loop but not recommended.

Categories