Eloquent count of single object is wrong - laravel

I have a method that only changes one small thing based on if an object of one item is passed through, vs a single object, but the count() is wrong on single items...
Assuming I have 25 entries in my table...
$contacts = Contact::all();
dd("Count = " . $contacts->count());
Count = 25
$contact = Contact::where('individual_id', '=', $id)->first();
dd("Count = " . $contact->count());
Count = 25
Why is it showing a count of objects in the table instead of just the number that were returned?
Laravel v9.19
PHP v8.0.2

Let's analyze your code:
$contact = Contact::where('individual_id', '=', $id)->first();
$contact will either be an instance of your Contact model, or null.
If it is a Model instance, then calling ->count() is basically calling this:
Contact::count(); // 25
$contact = Contact::where('individual_id', '=', $id)->first();
$contact->count() == Contact::count(); // true
Models have a count() method, so you can do things like $model->where(...)->count(), etc.
If $contact is null, then your code will fail:
$contact = null;
$contact->count(); // Error: `null->count()` is invalid.
So, for your case, there is basically no reason to ever call Contact::where(...)->first()->count(), as that will not return 1, unless there is legitimately 1 record in your contacts table (pretty scary false-positive).
The other answer suggests to use ->get(), which is valid, as a Collection has a count() method that outputs the length of the underlying Array:
$contact = Contact::where('individual_id', '=', $id)->get();
$contact->count(); // 1
It will return 1, unless you have multiple records in the database where individual_id is equal to $id.
So, TL;DR: ->first() returns a single Contact instance or null and shouldn't use ->count() after, while ::all() or ->get() returns multiple and can use ->count() after.

When you are using first() it is returning MODEL.You have to use get() so that you can use count() as get() will return collection.
$contact = Contact::where('individual_id', '=', $id)->get();
dd("Count = " . $contact->count());
It will give you the desired result.
also you can do this...
$count = Contact::where('individual_id', '=', $id)->count();
dd("Count = " . $count);

Related

laravel does not exist on this collection instance

$orders = Orders::select('orders.id as order_id', 'collection_color.color_name as color', 'collection_color.id as collection_color_id', DB::raw('SUM(order_piece.piece) As piece'))
->join('order_piece', 'order_piece.order_id', '=', 'orders.id')
->join('collection_color_size_barcode', 'collection_color_size_barcode.id', '=', 'order_piece.collection_color_size_barcode_id')
->join('collection_color', 'collection_color.id', '=', 'collection_color_size_barcode.collection_color_id')
->whereIn('orders.id', $request->order_id)
->groupBy('order_piece.order_id')
->orderBY('orders.delivery_date', 'ASC')
->get();
return $orders; => [{"order_id":30,"color":"Kahverengi","collection_color_id":21,"piece":"500"}]
return $ccfc = CollectionColorFabricColor::whereIn('collection_color_id', $orders->collection_color_id)->get();
Property [collection_color_id] does not exist on this collection instance. i am getting error can you help me
The error is most likely due to this in your second code snippet: $orders->collection_color_id. $orders is a collection, so the property doesn't exist in that object. What you actually need is to pluck those values from that collection like so:
return $ccfc = CollectionColorFabricColor::query()
->whereIn('collection_color_id', $orders->pluck('collection_color_id'))
->get();
Because your $orders is collection, you need to get collection_color_id array like this :
$arrayColors = $orders->pluck('collection_color_id')->toArray();
then
return $ccfc = CollectionColorFabricColor::whereIn('collection_color_id', $arrayColors)->get();

Laravel query is not working with multiple IDs

I am trying to fetch multiple rows of selected IDs from db. Here is my controller code
$products = new product;
$products = $products->select('products.*', 'categories.category_name')->join('categories', 'products.product_category', '=', 'categories.id');
$products = $products->whereIn('products.id', [$request->list]); //$request->list is post value (12,13)
$products = $products->get();
Here $request->list is post value which contains 12,13. Mentioned code works fine if I manually type IDs like this.
$products = $products->whereIn('products.id', [12,13]);
But if I try to call same with variable or directly with request post then it is returning only one result.
$products = $products->whereIn('products.id', [$request->list]);
//OR
$id = $request->list;
$products = $products->whereIn('products.id', $id);
Why it is giving only one result when I use variable, any idea?
$request->list contains comma separated values, so convert it to an array. Change it as below:
$products = $products->whereIn('products.id', explode(',',$request->list));
Here is a full query:
$products = product::select('products.*', 'categories.category_name')
->join('categories', 'products.product_category', '=', 'categories.id')
->whereIn('products.id',explode(',',$request->list))
->get();

How to use where clause with local variable without passing a parameter in Laravel

I joined 2 tables and I want to display document_name from parent table(document_control_reviews) whose ID is currently posted in a child table (initial_approvals). The foreign key that holds the child document is 3.
If I hardcode the query with the ID = 3, I get the correct result just for testing purposes. But I want the documents to be display dynamically using $id instead of 3.
This hardcode test works fine when I use 3 as ID:
public function initial_approval(){
$approval_files = DB::table('document_control_reviews')
->leftJoin('initial_approvals', 'initial_approvals.document_control_review_id', '=', 'document_control_reviews.id')
->leftJoin('files', 'document_control_reviews.file_id', '=', 'files.id')
->select('document_control_reviews.*', 'initial_approvals.*', 'files.*')
->where('initial_approvals.document_control_review_id', '=', 3)
->get();
}
But I need a dynamic ID which is a local variable $id (as showed below):
public function initial_approval(){
$id = 3 //hardcoded. Here is where I'm stuck.
$docId = DocumentControlReview::find($id);
$approval_files = DB::table('document_control_reviews')
->leftJoin('initial_approvals', 'initial_approvals.document_control_review_id', '=', 'document_control_reviews.id')
->leftJoin('files', 'document_control_reviews.file_id', '=', 'files.id')
->select('document_control_reviews.*', 'initial_approvals.*', 'files.*')
->where('initial_approvals.document_control_review_id', '=', $id)
->get();
}
This is what I don't want. I dont need to pass any parameter. I don't need any argument in the method call.
public function initial_approval($id){
$approval_files = DB::table('document_control_reviews')
->leftJoin('initial_approvals', 'initial_approvals.document_control_review_id', '=', 'document_control_reviews.id')
->leftJoin('files', 'document_control_reviews.file_id', '=', 'files.id')
->select('document_control_reviews.*', 'initial_approvals.*', 'files.*')
->where('initial_approvals.document_control_review_id', '=', $id)
->get();
}
This piece of code won't work the way you intend to because here id is a collection not an integer.
$id = DB::table('document_control_reviews')->select('id')->get();
You think id will be an integer like $id = 3 but in fact here $id = Collection({"id"=>3},...) get() always return a collection.
What you are trying to do is unclear please elaborate with an example.
I finally figured it out. I simply use the where clause in my query where the child ID is a positive integer. And I get exactly what I wanted in this code below:
$approval_files = DB::table('document_control_reviews')
->leftJoin('initial_approvals', 'initial_approvals.document_control_review_id', '=', 'document_control_reviews.id')
->select('initial_approvals.*', 'document_control_reviews.*')
->where('initial_approvals.id', '>', 0)
->get();

Eloquent accessing array inside object

I have a get formule that returns some nested relationships in an array. I was wondering how to access them in a where statement.
The initial get
$taken = UserWork::with('work.place')
->with('user')
->with('work.timeslot')
->get();
I tried something like this
$taak = $taken->where('work.timeslot[0].start_hour',"17:00:00")->first();
json result from $taken
Using with will endup with two queries. if you want to bring the user with timeslot null then there no need to add whereHas
$callback = function($query) {
$query->where('start_hour',"17:00:00");
};
$taken = UserWork::whereHas('work.timeslot', $callback)
->with(
['work.place', 'user', 'work.timeslot' => $callback]
)->get();

Laravel eloquent and relationship

I have a code:
$response = $this->posts
->where('author_id', '=', 1)
->with(array('postComments' => function($query) {
$query->where('comment_type', '=', 1);
}))
->orderBy('created_at', 'DESC')
->limit($itemno)
->get();
And when I logged this query with:
$queries = \DB::getQueryLog();
$last_query = end($queries);
\Log::info($last_query);
In log file I see follow:
"select * from `post_comments` where `post_comments`.`post_id` in (?, ?, ?, ?) and `comment_type` <> ?"
Why is the question mark for comment_type in the query?
Update #1:
I replaced current code with following and I get what I want. But I'm not sure it is OK. Maybe exists many better, nicer solution.
$response = $this->posts
->where('author_id', '=', 1)
->join('post_comments', 'post_comments.post_id', '=', 'posts.id')
->where('comment_type', '=', 1)
->orderBy('created_at', 'DESC')
->limit($itemno)
->get();
Behind the scene the PDO is being used and it's the way that PDO does as a prepared query, for example check this:
$title = 'Laravel%';
$author = 'John%';
$sql = "SELECT * FROM books WHERE title like ? AND author like ? ";
$q = $conn->prepare($sql);
$q->execute(array($title,$author));
In the run time during the execution of the query by execute() the ? marks will be replaced with value passed execute(array(...)). Laravel/Eloquent uses PDO and it's normal behavior in PDO (PHP Data Objects). There is another way that used in PDO, which is named parameter/placeholder like :totle is used instead of ?. Read more about it in the given link, it's another topic. Also check this answer.
Update: On the run time the ? marks will be replaced with value you supplied, so ? will be replaced with 1. Also this query is the relational query, the second part after the first query has done loading the ids from the posts table. To see all the query logs, try this instead:
$queries = \DB::getQueryLog();
dd($queries);
You may check the last two queries to debug the queries for the following call:
$response = $this->posts
->where('author_id', '=', 1)
->with(array('postComments' => function($query) {
$query->where('comment_type', '=', 1);
}))
->orderBy('created_at', 'DESC')
->limit($itemno)
->get();
Update after clarification:
You may use something like this if you have setup relation in your Posts model:
// $this->posts->with(...) is similar to Posts::with(...)
// if you are calling it directly without repository class
$this->posts->with(array('comments' =. function($q) {
$q->where('comment_type', 1);
}))
->orderBy('created_at', 'DESC')->limit($itemno)->get();
To make it working you need to declare the relationship in your Posts (Try to use singular name Post if possible) model:
public function comments()
{
return $this->hasmany('Comment');
}
Your Comment model should be like this:
class Comment extends Eloquent {
protected $table = 'post_comments';
}

Resources