Laravel loading relations - framework bug?

Viewed 128

I have encountered something strange which I consider might be a bug in the framework itself so I'm wondering if there were similar experiences with it.

I have two entities: Contact and Media in a 1:M relationship. Relationship is defined as:

public function media()
{
    return $this->hasMany(Media::class);
}

Now the issue I see is that when I go on show controller method and load the relation like this:

public function show(Contact $contact)
{
    $contact->load('media');
    return response()->json($contact);
}

The contact is resolved fine, with media relationship in the following way:

"first_name": "Melisa",
...
"media": [
    {
        "id": 50,
    ...

However if I modify the case of the relationship so that I call:

public function show(Contact $contact)
{
    $contact->load('mEdIa');
    return response()->json($contact);
}

It returns:

"first_name": "Melisa",
...
"m_ed_ia": [
    {
        "id": 50,
    ...

...which is really disturbing. Is it supposed to happen?

2 Answers

This behaviour should be noted in the documentation of Laravel, which is indeed not the case. If I were you, I would open an issue on updating the documentation about this behaviour, and see what the response will be.

But to come to terms, this is a feature, not a bug.

The nature of PHP is sensitive and insensitive in many ways. For classes and methods; PHP is insensitive.

class Contact {
    public function media() {
        return .. relationship;
    }
}

// valid
new CONTACT();
(new contact())->mediA();
// valid reflection
$r = \ReflectionClass('contact');
$r->hasMethod('mediA'); // true

So this quirky stuff is all valid. Now to the point you said:

.. from my perspective mEdia shouldn't be allowed. My relationship function name is media, and I want it to be used as such.

Then you have to write it as such. You have to because Laravel depends on it.

  • PHP is simply unable to validate/verify.
  • Laravel has to change the nature of a programming language where its sensitivity is deliberately designed by choice.
  • The expectation here is; you (as a programmer) should know about PHP's sensitivity, so in this case, there is absolutely no need to validate the given input.
  • The overhead to validate/verify such a thing would be tremendous and would not make sense.
$class = 'contact';
$method = 'mediA';

$r = new \ReflectionClass($class);
if($class !== $r->getName()) {
    throw new \Exception('unknown class');
}
if(!in_array($method, array_map(function($method) {
    return $method->name;
}, $methods))) {
    throw new \Exception('unknown method');
}

// valid from here

From all points of view, the usage of $contacts->with('mediA') is completely valid.

The fact that mediA becomes medi_a using Str::snake('mediA') when converting to an array (as such), is simply a feature of Laravel you have to deal with.

There is such behaviour in Laravel. To get the same key 'mEdIa' - you have to add to media model.

public static $snakeAttributes = false;

Related