dspitzle dspitzle - 1 year ago 44
PHP Question

Laravel 5 eager loading dropping leading zeros from foreign key

I believe that I've encountered a bug in how Laravel 5.3 handles eager loading when the foreign key is a string which contains zerofilled numbers.

I have two models (using a mysql backend),

School
and
Student
. The
id
field in
School
is a string, and contains 5-digit numbers assigned by the state, which include leading zeros.
Student
BelongsTo
School
, and contains a
school_id
field which is defined identically to the
id
field in
School
. I have done some testing, and I'm finding that when I call
Student::with('school')
I get the expected
School
models as long as the
school_id
in
Student
is free of leading zeroes, but it returns no
School
models for
school_id
values with leading zeroes.

I've done direct testing with freshly minted
School
records, and the values are being stored correctly with leading zeroes in both database tables, and when I try directly querying the tables the leading zeroes work fine, but as soon as
with()
enters the equation, things break. I've attempted to reproduce the failure through other means, even manually constructing
whereIn()
calls to mirror syntax of the queries constructed by
with()
, but everything else correctly returns the expected records.

This code worked fine prior to climbing the Laravel upgrade ladder from 4.1 to 5.3, so I'm wondering what may have changed. I've gone as far as digging into the GitHub repository for BelongsTo, and none of the parameter handling seems to strip leading zeroes, so I'm really at a loss as to why
with()
is breaking in this way.

So, does anybody have any insights they can share? I'm stumped, and would rather not have to engineer around
with()
. I'll also state up front that I can't drop the leading zeroes from the
id
field, it's not an option, they must actually be stored, and not just displayed as with ZEROFILL.

UPDATE: I've attached an example that establishes that the
school_id
stored in
Student
can successfully connect to the corresponding
School
when used separately from the
with()
statement:

$interventions = Intervention::with('school')->where('id','=',780)->get();
$schools = School::whereIn('id',$interventions->pluck('school_id')->all())->get();
throw new \Exception(print_r($interventions,true).'|'.print_r($schools,true));


Here are the (edited for brevity) results of the \Exception:

Exception in AdminController.php line 273:
Illuminate\Database\Eloquent\Collection Object
(
[items:protected] => Array
(
[0] => App\Models\Student Object
(
[attributes:protected] => Array
(
[id] => 780
[school_id] => 01234
)
[relations:protected] => Array
(
[school] =>
)
)
)
)


Illuminate\Database\Eloquent\Collection Object
(
[items:protected] => Array
(
[0] => App\Models\School Object
(
[attributes:protected] => Array
(
[id] => 01234
[school] => Test1
[district_id] => 81000
[inactive] => 0
[see] => 0
)
)
)
)


So, while
Student::with('school')
fails to pull up the corresponding
School
, feeding the same
Student->school_id
values to
School::whereIn()
succeeds. I remain mystified.

Answer Source

You are not showing the model classes, but my guess is you need public $incrementing = false; in the School Eloquent model. Otherwise it will be coerced to int when matching the relationship, losing all leading zeroes.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download