In Laravel Eloquent, I am using select
to get specific columns only in a collection:
$tickets = Tickets
::select('id', 'title', 'date') // so only these columns
->limit(100)
->get();
but I also have a custom attribute in the "Ticket" model that uses different columns:
public function getStatusAttribute() {
if ($this->payment == $this->total & $this->active) {
return "paid";
} else {
return "unpaid";
}
}
then when doing
foreach ($tickets as $ticket) {
echo $ticket->id
. $ticket->title
. $ticket->date
. $ticket->status // <- custom attribute
;
}
as I tell query to only select 'id', 'title', 'date', at what point Laravel gets additional columns from database (specifically the 'payment', 'total', 'active')? Does it runs additional queries for each row?
I only see main query (without columns from custom attribute being selected), when trying to log them either with dump(DB::getQueryLog());
or directly in MySQL:
SET GLOBAL log_output = "FILE";
SET GLOBAL general_log_file = "c:/AAA/logfile.log";
SET GLOBAL general_log = 'ON';
So I do not understand at what point Laravel gets additional columns from the database? My concern is to have 1 query and not 100.
In Laravel Eloquent, I am using select
to get specific columns only in a collection:
$tickets = Tickets
::select('id', 'title', 'date') // so only these columns
->limit(100)
->get();
but I also have a custom attribute in the "Ticket" model that uses different columns:
public function getStatusAttribute() {
if ($this->payment == $this->total & $this->active) {
return "paid";
} else {
return "unpaid";
}
}
then when doing
foreach ($tickets as $ticket) {
echo $ticket->id
. $ticket->title
. $ticket->date
. $ticket->status // <- custom attribute
;
}
as I tell query to only select 'id', 'title', 'date', at what point Laravel gets additional columns from database (specifically the 'payment', 'total', 'active')? Does it runs additional queries for each row?
I only see main query (without columns from custom attribute being selected), when trying to log them either with dump(DB::getQueryLog());
or directly in MySQL:
SET GLOBAL log_output = "FILE";
SET GLOBAL general_log_file = "c:/AAA/logfile.log";
SET GLOBAL general_log = 'ON';
So I do not understand at what point Laravel gets additional columns from the database? My concern is to have 1 query and not 100.
Share Improve this question asked Nov 26, 2024 at 22:48 LannalinaLannalina 31 bronze badge 1- Just advice - if this attribute MATTER - check real fields for null and throw exception on null. Queries will mot perform as answered below. – Maksim Commented Nov 27, 2024 at 1:13
2 Answers
Reset to default 0The status attribute is never queried from the DB. The value is calculated after the query is run when you request the value using $ticket->status
or when the instance of the model is serialised.
If you have retrieved your instance using your query builder code:
Tickets::select('id', 'title', 'date') // so only these columns
->limit(100)
->get();
Then I would expect your getStatusAttribute
to return "paid"
but you need to understand why:
The query will result in an instance where
$this->payment
is NULL
$this->total
is NULL
and $this->active
is NULL
Because you're not getting those values from the database.
When you call $this->payment == $this->total & $this->active
You're saying NULL == NULL & NULL
Note: Be careful with your logic here as NULL & NULL
will evaluate to 0
whereas NULL && NULL
will evaluate to false
Therefore you need to either be more defensive in your getStatusAttribute
logic. You could consider returning NULL if the required columns are all NULL but you probably want to make sure those values are always queried.
$tickets = Tickets::select('id', 'title', 'date', 'payment', 'total', 'active')
->limit(100)
->get();
The above would do the job but the overhead of querying columns you don't explicitly need is negligible so you could just drop the select entirely and use:
$tickets = Tickets::limit(100)
->get();
If there are values in there you want to prevent the model showing when serialised I would recommend using the Eloquent Model's "hidden" property
hope my solution solves your problem. To ensure the status attribute works correctly, modify your query to include the columns needed for the accessor:y and avoid additional queries.
$tickets = Tickets::select('id', 'title', 'date', 'payment', 'total', 'active')
->limit(100)
->get();
This way, all the necessary data for the custom attribute is fetched in the initial query.
Thanks