Search code examples
laraveleloquentcustomcolumn

Laravel Model's custom column name


I'm developing a new software that will eventually replace an old one, still in production. The new software needs to access old's DB for specific models that will (in the future, not at this stage) will be replaced to local ones, but I'm developing using a naming scheme in English, and the old DB is in Spanish.

As an example, this is one of the models' class

class Country extends Model
{
    use HasFactory;

    // inherited table

    protected $connection = 'relevamiento';
    protected $table = 'pais';
    public $timestamps = false;

    protected $fillable = [
        'name',
        'code'
    ];

    protected $rules = [
        'name' => 'required|string:max:255',
        'code' => 'required|string:max:2'
    ];

    public function getNameAttribute()
    {
        return $this->nombre;
    }

    public function setNameAttribute($name)
    {
        $this->nombre = $name;
    }

    public function getCodeAttribute()
    {
        return $this->codigo31662;
    }

    public function setCodeAttribute($code)
    {
        $this->codigo31662 = $code;
    }

}

It works great, until I search by Name:

>>> \App\Models\Country::first()
=> App\Models\Country {#3980
     id: 1,
     nombre: "Argentina",
     codigo31662: "AR",
   }

>>> \App\Models\Country::first()->name
=> "Argentina"

>>> \App\Models\Country::first()->code
=> "AR"

>>> \App\Models\Country::where('name', 'Uruguay')->get()
Illuminate\Database\QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'name' in 'where clause' (SQL: select * from `pais` where `name` = Uruguay)'
>>> 

Is there a way to stay that the model's name attribute is the 'nombre' column?

The idea is, in the near future, make a migration to pull all the inherited info to local database, with the correct attribute/column's names, and in the mean time make all the related development using them (to make easier the switch in the future).

Thanks


Solution

  • This is because the where function uses the provided column name literally. (See https://github.com/laravel/framework/blob/49368f4f50e63c543511bad983e7bcef038e9794/src/Illuminate/Database/Query/Builder.php#L703)

    One option is to provide a translateColumn function to the model and use that

    class Country extends Model
    {
        ...
        public static function translateColumn(string $column) 
        {
            switch($column) {
                case 'name':
                    return 'nombre';
                default:
                    return $column;
            }
        }
        ...
    }
    

    And then use it like so:

    \App\Models\Country::where(\App\Models\Country::translateColumn('name'), 'Uruguay')->get()