Considere la relación entre libros y autores . Cada libro pertenece a un autor y 1 autor tiene muchos libros. La tabla de libros tiene campos como (Id, Título, Versión, etc.) y los autores tienen campos como (Id, Nombre, Dirección, etc.). Tenga en cuenta que las columnas DB no siguen la convención de nomenclatura predeterminada de laravel.
Ahora; Quiero buscar algunos campos de ambas tablas. Más específico, quiero campos de título, versión, nombre y dirección . Esta es la salida deseada:
{ Title: "Oxford Maths", Version: "2.5", author: "John Doe", }1er ensayo:
return Book::with('author')->get()->map(function ($book) { return collect($book)->only( [ 'Title', 'Version', "author" ]); });Primera salida de prueba:
{ Title: "Oxford Maths", Version: "2.5", author: { Id: 1, Name: "John Doe", Address: "Tanzania", deleted_at: null } }2da prueba: Intenté esto;
return Book::with([ 'author' => function($query){ $query->select('Name','Id'); } ])->get()->map(function ($data) { return collect($data)->only( [ 'Title', 'Version', "author" ]); });Y esto;
return Book::with('authority:name,Id')->get()->map(function ($data) { return collect($data)->only( [ 'Title', 'Version', "author" ]); });2da salida de prueba:
{ Title: "Oxford Maths", Version: "2.5", author: { Name: "John Doe", Id: 1 } }3er ensayo:
return Book::with([ 'author' => function($query){ $query->select('Name'); // *Removed foreignKey* } ])->get()->map(function ($data) { return collect($data)->only( [ 'Title', 'Version', "author" ]); });Tercera salida de prueba:
{ Title: "Oxford Maths", Version: "2.5", author: null }¿Qué puedo hacer para obtener el resultado deseado?
Por supuesto, puede hacerlo después en la colección, pero tiene más sentido hacerlo directamente en la consulta. Intentas reflejar eso en tu tercer intento. Sin embargo, en mi opinión, ahí es donde Laravel se comporta un poco extraño . Para realizar la carga ansiosa, necesita su clave externa. Aunque, eso es lógico, es humano olvidarse de eso de todos modos. Pero si olvida incluir la clave externa, Laravel no le dice esto y en su lugar devuelve null . Así que asegúrese de que todas las claves primarias y externas necesarias estén siempre incluidas en su relación.
return Book::with([ 'author' => function($query){ $query->select('id', 'Name'); // *Removed foreignKey* } ])->get([ 'title' , 'version' ]);Una cosa que me gusta hacer cuando una relación debe devolver principalmente solo uno de sus valores:
class Author extends Model { public function __toString() { return $this->Name; } } Para hacer que esto se serialice automáticamente de esta manera, puede cambiar __toString() a jsonSerialize()
class Author extends Model implements JsonSerializable { public function jsonSerialize() { return $this->Name; } }tal vez te ayude
en modelo
protected $appends = [ 'author_name', 'address' ]; protected $fillable = [ 'title', 'version', ]; public function author(){ return $this->belongsTo(Author::class); } public function getAuthorNameAttribute(){ return $this->author->name; } public function getAddressAttribute(){ return $this->author->address; }y en el controlador usa esto
return Book::query()->with('author')->first()->makeHidden(['author','author_id']);Producción:
{ "id": 1, "title": "book", "version": "v1", "created_at": null, "updated_at": null, "author_name": "komeyl", "address": "Iran" }Terminé usando el truco sugerido por @komeyl-dev. Este es un código de muestra:
//Book.php class Book extends Model { protected $appends = ['author_name']; // appended so I can access it as json public function author(){ return $this->belongsTo(Author::class,'author_id'); } public function getAuthorNameAttribute(){ return $this->author->name; } } //Testing in web.php (Note: No eager loading here) Route::get('url', function () { return Book::get()->map(function ($data) { return collect($data)->only( [ 'Title', 'Version', "author_name" ]); }); });Gracias @shaedrich y @komeyl-dev