Skip to content

Can't add a where clause to a relationship table inside whereHas in a Model that has relationship with itself. #54794

@crazynds

Description

@crazynds

Laravel Version

11.43.2

PHP Version

8.3.6

Database Driver & Version

Mysql

Description

I had the following problem:

  • I had a Model called PunchRegistry like follows:
<?php
class PunchRegistry extends Model
{
    public $timestamps = false;

    protected $guarded = [];

    public function pair()
    {
        return $this->belongsTo(PunchRegistry::class, 'punch_registry_id');
    }
}
  • I needed to find all registries that have a pair to check the hours diference between then, so I created the following query:
<?php
$registries = PunchRegistry::whereHas('pair', function (Builder $query) {
                $driver = DB::getDriverName(); // Get Database
                $query->where('punch_registries.type', 1);
                if ($driver === 'mysql') {
                    $query->whereRaw('TIMESTAMPDIFF(HOUR, punch_registries.record_at, laravel_reserved_0.record_at) >=  8');
                } elseif ($driver === 'pgsql') {
                    $query->whereRaw('EXTRACT(HOUR FROM (laravel_reserved_0.record_at - punch_registries.record_at)) >=  8' );
                }
            })
            ->with(['pair'])
            ->orderBy('record_at', 'asc')
            ->lazy();
  • As you can see, I'm using the laravel_reserved_0 table to refer to the pair.

That works normally in dev mode, but when I launched it in the test enviroment with laravel octane, I got error 500 in my logs because the table 'laravel_reserved_0' is not defined. Reading the source you can find the following lines in \Illuminate\Database\Eloquent\Relations\Relation class:

/**
* The count of self joins.
*
* @var int
*/
protected static $selfJoinCount = 0;

/**
* Get a relationship join table hash.
*
* @param bool $incrementJoinCount
* @return string
*/
public function getRelationCountHash($incrementJoinCount = true)
{
return 'laravel_reserved_'.($incrementJoinCount ? static::$selfJoinCount++ : static::$selfJoinCount);
}

As we can see, each new call to this request increases the table number. For the development environment, this can be ignored, since the value of the static variable is always reset to zero. However in octane, according to this docs, static variables are not reset every request, so Relation::$selfJoinCount keeps increasing every request.

I can suggest three possible fixes for this problem, and send a PR if it is needed:

  • Create an extra parameter to whereHas to add the alias name to that table. (Hard to code I think, but the best solution)
  • Add a way to make Relation::$selfJoinCount unique for each complete query (Principal query and sub queries).
  • Add a way to reset Relation::$selfJoinCount manually.

Steps To Reproduce

1- Create a self reference model;
2- Create a query with whereHas that has a condition that need to use laravel_reserved_0 table.
3- Start octane.
4- Make multiple requests to the same route, the first will work as intented and the next ones will throw a error.

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