Skip to content

Model relations fail if property name is not camel case #1949

@nunntom

Description

@nunntom

Tempest version

2.14

PHP version

8.4

Operating system

Linux

Description

When a multi-word property for a has-many or has-one relationship is not camel case, the property seems to get treated as a DTO column rather than a relationship. Doc comments and HasMany/HasOne attributes don't seem to have any effect on this.

Steps to reproduce

This works fine:

final class Pirate
{
    use IsDatabaseModel;

    public string $name;

    /** @var \Tests\Tempest\Fixtures\Models\TreasureChest[] */
    public array $treasureChests = []; // <-- camel case
}

final class TreasureChest
{
    use IsDatabaseModel;

    public string $name;

    public Pirate $pirate;
}

$pirate = Pirate::create(
    name: 'Long John Silver',
);

$pirate = Pirate::findById($pirate->id)->load('treasureChests');

But this doesn't:

final class Pirate
{
    use IsDatabaseModel;

    public string $name;

    /** @var \Tests\Tempest\Fixtures\Models\TreasureChest[] */
    public array $treasure_chests = []; // <- snake case
}

// TreasureChest model as before

$pirate = Pirate::create(
    name: 'Blackbeard',
);

/*
Tempest\Database\Exceptions\QueryWasInvalid: SQLSTATE[HY000]: General error: 1 table pirates has no column named treasure_chests

INSERT INTO `pirates` (`name`, `treasure_chests`) VALUES ('Blackbeard', '[]')
*/

$pirate = Pirate::findById($pirate->id)->load('treasure_chests');

/*
Tempest\Database\Exceptions\QueryWasInvalid: SQLSTATE[HY000]: General error: 1 no such column: pirates.treasure_chests

SELECT pirates.id AS `pirates.id`, pirates.name AS `pirates.name`, pirates.treasure_chests AS `pirates.treasure_chests` FROM `pirates` WHERE `pirates`.`id` = '0'
*/

Adding an explicit HasMany attribute does not have any effect.

I would expect the casing of the property name to be irrelevant to the function of it, and the doc comment/attributes to override any implied/derived interpretation of what the property is anyway.

I'm not clear why ->camel() is here in this function but I have tried removing it (along with the similar one in getBelongsTo and getHasOne and for what it's worth it did not break any of the integration tests and removing them resolved my issue. Can anyone shed any light as to why they might be necessary? If not maybe I'll make a PR?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions