Skip to content

Incorrect relation queries #549

@smirnov-e

Description

@smirnov-e

Description

Related queries created to query main table instead of related one.

Sample classes

final class BrazilCep extends ActiveRecord
{
    public string $cep;

    public ?int $city_id;

    public function getTableName(): string
    {
        return '{{%brazil_cep}}';
    }

    public static function query(ActiveRecordInterface|string|null $modelClass = null): BrazilCepQuery
    {
        return new BrazilCepQuery(static::class);
    }

    public function relationQuery(string $name): ActiveQueryInterface
    {
        return match ($name) {
            'city'  => $this->hasOne(BrazilCity::class, ['id' => 'city_id']),
            default => parent::relationQuery($name),
        };
    }

    public function getCity(): ?BrazilCity
    {
        return $this->relation('city');
    }
}

final class BrazilCity extends ActiveRecord
{
    public int $id;

    public string $name;

    public function getTableName(): string
    {
        return '{{%brazil_city}}';
    }
    
    public static function query(ActiveRecordInterface|string|null $modelClass = null): BrazilCityQuery
    {
        return new BrazilCityQuery(static::class);
    }
}

final class BrazilCityQuery extends BaseActiveQuery
{
}

final class BrazilCepQuery extends BaseActiveQuery
{
}

Code to reproduce

$cep = BrazilCep::query()->byCep($cep)->one(); 
// exists, $cep->city_id === 8966.


$cityName = $cep->getCity()?->name; 
// SQL Error: Undefined column: 7 ERROR:  column \"id\" does not exist  SELECT * FROM \"brazil_cep\" WHERE \"id\"=8966

$query = $cep->relationQuery('city')
// returns BrazilCepQuery instead of BrazilCityQuery

the root cause is \Yiisoft\ActiveRecord\AbstractActiveRecord::createQuery:

public function createQuery(ActiveRecordInterface|string|null $modelClass = null): ActiveQueryInterface
{
     // for `city` relation it's called with `BrazilCity` as argument from `BrazilCep` class instance, so BrazilCepQuery is created instead of correct BrazilCityQuery
     return static::query($modelClass ?? $this); 
}

proposed fix:

public function createQuery(ActiveRecordInterface|string|null $modelClass = null): ActiveQueryInterface
{
     $source = $modelClass ?? $this;
     return source::query(source);
}

Package version

1.0.2

PHP version

8.4.14

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions