Avoiding redundant data in an Eloquent model Instance

1 week ago 12
ARTICLE AD BOX

I encountered an issue while working on a Laravel project of mine, intended for property rentals. In the database, both the property owner’s and the tenant’s contact information are stored in the same table.

The MySQL table looks like this:

phpMyAdmin screenshot

Now, in the Eloquent model that represents a rental property record, I’ve added an attribute that displays the contact information for both parties.

Currently, although the model behaves as expected by the application, when inspecting a rental instance, the datosContacto attribute is displayed like this:

Current model result

In English it would be like:

contactData: App\Models\ContactData {#6726 #id: 42, #user_type: "contractor", #email: "[email protected]", #support_hours: "24x7", #phone: "11-3352-6425", #alt_phone: "4235-5532", #mobile: "11-3352-6425", #whatsapp: "(54) 11-3352-6425", #rental_id: 31, +contractor: App\Models\ContactData {#7043 id: 42, user_type: "contractor", email: "[email protected]", support_hours: "24x7", phone: "11-3352-6425", alt_phone: "4235-5532", mobile: "11-3352-6425", whatsapp: "(54) 11-3352-6425", rental_id: 31, }, +publisher: App\Models\ContactData {#6875 id: 43, user_type: "publisher", email: "[email protected]", support_hours: "24x7", phone: "11-3546-5888", alt_phone: "4701-1108", mobile: "11-3546-5888", whatsapp: "(54) 11-3546-5888", rental_id: 31, }, },

Even though it works, it includes unwanted redundant information, and perhaps the model code is not the most optimal.

Ideally, I would like it to look like this:

Desired result (edited screenshot)

Here's the code for my DatosContacto.php model:

<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use App\Models\Alquiler; use Illuminate\Database\Eloquent\Casts\Attribute; class DatosContacto extends Model { use HasFactory; protected $guarded = []; public $timestamps = false; protected $table = 'datos_contacto'; protected $appends = ['contratador', 'publicador']; protected $hidden = ['id','alquiler','tipo_usuario','email','horario_atencion', 'telefono','telefono_alt','celular','whatsapp','alquiler_id']; public function alquiler() { return $this->belongsTo(Alquiler::class, 'alquiler_id'); } protected function contratador(): Attribute { return new Attribute( get: function ($value) { $contratador = Self::where(['tipo_usuario' => 'contratador', 'alquiler_id' => $this->alquiler->id])->get()->first(); if ($contratador) $contratador->setHidden(['alquiler'])->setAppends([]); return $contratador; } ); } protected function publicador(): Attribute { return new Attribute( get: function ($value) { $publicador = Self::where(['tipo_usuario' => 'publicador', 'alquiler_id' => $this->alquiler->id])->get()->first(); if ($publicador) $publicador->setHidden(['alquiler'])->setAppends([]); return $publicador; } ); } }

Here's the code for my Alquiler.php model:

<?php namespace App\Models; //(...) use App\Models\DatosContacto; class Alquiler extends Model { use HasFactory; use HasSpatial; public function getRouteKeyName() { return 'slug'; } //Habilitamos la asignación masiva: //Podríamos hacerlo mediante $fillable -> protected $fillable = ['barrio','tipo','direccion','descripcion']; //Pero nos conviene hacerlo mediante $guarded: protected $guarded = []; protected $casts = ['disponible' => 'boolean']; //protected $hidden = ['coordenadas']; protected $appends = ['reputacion','ambientes']; protected $with = ['direccion','caracteristicas','fotos','servicios','aviso','datosContacto'];//'ambientes' protected $table = 'alquileres'; private $obj = null; public function recibirObj($obj) { $this->obj = $obj; return $this; } public function resetear() { $this->obj = null; return $this; } //Relaciones a nivel de modelo //Asocio el campo 'user_id' (FK de esta tabla) con el campo 'id' (PK) de la tabla 'users' public function publicador() { return $this->belongsTo(User::class, 'user_id'); } //Asocio el campo 'contratador_id' (FK de esta tabla) con el campo 'id' (PK) de la tabla 'users' public function contratador() { return $this->belongsTo(User::class, 'contratador_id'); } public function direccion() { return $this->hasOne(Direccion::class, 'alquiler_id'); } public function datosContacto() { return $this->hasOne(DatosContacto::class, 'alquiler_id'); } public function multimedia() { return $this->hasOne(Multimedia::class, 'alquiler_id'); } public function solicitudes() { return $this->hasMany(Solicitud::class, 'alquiler_id'); } public function caracteristicas() { return $this->hasOne(Caracteristicas::class, 'alquiler_id'); } public function aviso() { return $this->hasOne(Aviso::class, 'alquiler_id'); } public function servicios() { return $this->belongsToMany(Servicio::class); } public function fotos() { return $this->hasMany(Foto::class, 'alquiler_id'); } public function calificaciones() { return $this->morphMany(Calificacion::class, 'calificacionable'); } public function ambientes() { return $this->hasMany(Ambiente::class, 'alquiler_id'); } //(...) }

This works, but is there a better approach to achieve this? How can I improve or optimize this code?

Read Entire Article