Estoy tratando de escribir una consulta que seleccione columnas de un modelo y luego seleccione algunas columnas de una tabla de relaciones de transformación. Pero no tengo idea de seleccionar columnas, y las tablas de relaciones tienen columnas diferentes. Entonces, algunas columnas no tienen slug, otras sí.
public function index() { $menus = Menu::whereActive(true) ->with([ 'menuable' => function ($q) { // This gives error if there is no relation Pages model $q->whereActive(true)->select('pages.id', 'pages.slug'); // Below not working // if($q->type === Page::class){ // $q->whereActive(true)->select('pages.id', 'pages.slug'); // } else if($q->type === Category::class){ // $q->whereActive(true)->select('categories.id', 'categories.slug'); // } } ]) ->get(['id', 'menuable_id', 'menuable_type', 'name']); $response = [ 'menus' => $menus, ]; return $this->sendResponse($response); }Modelos
class Menu extends Model { public function menuable() { return $this->morphTo(); } } class Page extends Model { public function menu() { return $this->morphOne(Menu::class, 'menuable'); } } class Category extends Model { public function menu() { return $this->morphOne(Menu::class, 'menuable'); } }¿Cómo puedo seleccionar columnas específicas de la relación de transformación al verificar el tipo de transformación? Estoy usando Laravel versión 8.
La relación polimórfica es algo de lo que Eloquent es consciente, y DBMS no ha implementado esta función en él. por lo tanto, no puede haber una consulta sql que una una tabla a otras tablas en función de la columna morph.
por lo tanto, debe usar consultas distintas para cada relación de unión polimórfica en sus modelos:
//you can retrieve distinct menu based on their relation Menu::whereActive(true)->hasPage()->with('pages'); //and having the ralations in the menu model: public function posts Menu::whereActive(true)->hasCategory(); //scope in menu class can be like: public function scopePage($query){ return $query->where('menuable_type',Page::class); } public function scopeCategory($query){ return $query->where('menuable_type',Category::class); } //with these you can eager load the models Menu::whereActive(true)->hasPage()->with('page'); Menu::whereActive(true)->hasCategory()->with('category'); public function page(){ return $this->belongsTo(Page::class); } public functioncategory(){ return $this->belongsTo(Category::class); }si desea una interfaz común para usar uno de estos dinámicamente. puedes usar:
$menu->menuable->id $menu->menuable->slug No estoy seguro de qué columnas desea responder, pero como puedo adivinar por su pregunta, supongo que desea id y slug de ambos modelos.
public function index(){ $pagedMenu = Menu::whereActive(true)->hasPage()->with('page'); $categoriedMenu = Menu::whereActive(true)->hasCategory()->with('category'); $menues = $pagedMenu->merge($categoriedMenu); $response = [ 'menus' => $menus, ]; return $this->sendResponse($response); }Puede realizar filtros separados basados en la clase morph. Esto se puede lograr con whereHasMorph ( https://laravel.com/docs/8.x/eloquent-relationships#querying-morph-to-relationships ).
Si necesita resolver automáticamente la relación, puede usar with . Esto precargará morphables automáticamente en su colección resultante.
El siguiente ejemplo usa un orWhere con 2 consultas separadas por morphable.
$menus = Menu::whereActive(true) ->whereHasMorph('menuable', [Page::class], function (Builder $query) { // perform any query based on page-related entries }) ->orWhereHasMorph('menuable', [Category::class], function (Builder $query) { // perform any query based on category-related entries }) ->with('menuable') ;Una forma alternativa es pasar ambas clases al segundo argumento. En ese caso, puede verificar el tipo dentro de su cierre.
$menus = Menu::whereActive(true) ->whereHasMorph('menuable', [Page::class, Category::class], function (Builder $query, $type) { // perform any query independently of the morph-target // $q->where... if ($type === (new Page)->getMorphClass()) { // perform any query based on category-related entries } if ($type === (new Category)->getMorphClass()) { // perform any query based on category-related entries } }) ->with('menuable')Si es necesario, también puede precargar relaciones anidadas. ( https://laravel.com/docs/8.x/eloquent-relationships#nested-eager-loading-morphto-relationships )
$menus = Menu::whereActive(true) ->with(['menuable' => function (MorphTo $morphTo) { $morphTo->morphWith([ Page::class => ['calendar'], Category::class => ['tags'], ]); }])