laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.5k stars 11.01k forks source link

Eloquent: custom generated name is laravel_reserved_0, when checking for deleted_at the generated name is prefixed #43049

Closed jessealkema closed 2 years ago

jessealkema commented 2 years ago

Description:

When making use of eloquent models with a parent reference to itself eloquent automatically makes a customized table name. If the model uses the soft deletes trait the check on the deleted_at column should take place with the custom table name. But the prefix is added to the custom table name.

In short, custom generated name is laravel_reserved_0, when checking for deleted_at the generated name is fin_laravel_reserved_0.

/**
* @return HasMany
*/
public function rows(): HasMany
{
    return $this->hasMany(Row::class, 'invoice_id', 'id')
       ->whereDoesntHave('group')
       ->orderBy('invoiceable_id');
}

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'fin_laravel_reserved_0.deleted_at' in 'where clause' (SQL: select from fin_invoice_rows where fin_invoice_rows.invoice_id = 5137 and fin_invoice_rows.invoice_id is not null and not exists (select from fin_invoice_rows as laravel_reserved_0 where laravel_reserved_0.id = fin_invoice_rows.parent_id and fin_laravel_reserved_0.deleted_at is null) and fin_invoice_rows.deleted_at is null order by invoiceable_id asc)

Steps To Reproduce:

  1. Generate a table with a constrained with itself and soft delete
  2. Make an model with the soft delete trait
  3. Query the reference with a whereHas or whereDoesnt query
  4. The error should appear
jessealkema commented 2 years ago

We maintain our own internal modules through packages and handle table prefixes through a base model in the module. It seems that the eloquent function getTable is called to retrieve the generated name. To fix this problem for now I've added laravel_ to the prefix checker.

<?php

namespace Noardcode\Compass\Financial\Models;

use Illuminate\Support\Str;

/**
 * Financial base model.
 */
abstract class Model extends \Noardcode\Compass\Core\Models\Model
{
    public function getTable()
    {
        if (Str::startsWith($this->table, ['fin_', 'laravel_'])) {
            return $this->table;
        }

        return 'fin_' . ($this->table ?? Str::snake(Str::pluralStudly(class_basename($this))));
    }
}
driesvints commented 2 years ago

Heya, thanks for reporting.

We'll need more info and/or code to debug this further. Can you please create a repository with the command below, commit the code that reproduces the issue as separate commits on the main/master branch and share the repository here? Please make sure that you have the latest version of the Laravel installer in order to run this command. Please also make sure you have both Git & the GitHub CLI tool properly set up.

laravel new bug-report --github="--public"

Please do not amend and create a separate commit with your custom changes. After you've posted the repository, we'll try to reproduce the issue.

Thanks!

driesvints commented 2 years ago

I'll re-open once you provided a repo. Thanks