Search code examples
laravellaravel-7eloquent-relationship

Laravel - HasMany relation not loading


I'm having an issue with a hasMany-relation in my Laravel application. I'm sure, it is a simple question, but currently I'm struggling with it and can't find the reason.

I have a Model called LandingPage:

<?php

namespace app\Models\LandingPage;

class LandingPage extends \App\Models\Base
{
    public $table = "landing_pages";

    protected $fillable = [
        'name',
        'event_id',
        'url_id',
        'is_update_needed',
        'view',
        'created_at',
        'updated_at',
    ];

    protected $hidden = [
    ];

    protected $appends = [
        'app_icon',
        'landing_page_url_base_path'
    ];

    ...

    public function app_info() {
        return $this->hasOne(\App\Models\App\AppInfo::class, "landing_page_id", "id");
    }

    public function app_images() {
        return $this->hasMany(\App\Models\App\AppImage::class, "landing_page_id", "id");
    }

    public function app_texts() {
        return $this->hasMany(\App\Models\App\AppText::class, "landing_page_id", "id");
    }

    ...
}

The problem is on app_texts(). I doesn't load the app_texts of my landing page. As you can see there are similar relations app_info & app_images. I've copy/pasted the relation from app_images to app_texts. app_images is working fine. Here is the Model of AppText:

<?php
namespace app\Models\App;

class AppText extends \App\Models\Base
{
    public $table = "app_texts";

    protected $fillable = [
        'text',
        'type',
        'landing_page_id',
        'created_at',
        'updated_at'
    ];

    protected $hidden = [
    ];

    public function landing_page() {
        return $this->hasOne(\App\Models\LandingPage\LandingPage::class, "id", "landing_page_id");
    }
}

In the database is everything correctly set up:

landing_pages: enter image description here

app_texts: enter image description here

I also can see in the Laravel Debugbar, that the query is not being executed to load the app_texts:

enter image description here

Have I forgotten something, or have I got something wrong?

Update

The landing page is part of another Model (guests). I call there the property landing_page, but without calling the relations explicitly. It works for app_images or app_info, so I don't think, I need to call app_texts explicitly.

This is the controller section where it is called:

public function showEvent(\Illuminate\Http\Request $request, string $eventName, string $guestIdentifierToken) {
        $guest = $this->guestRepository->getByIdentifierToken($guestIdentifierToken);
        if($guest != null) {
            if($guest->landing_page->is_update_needed == 1) {
                //...
                //do some stuff
            }
            return view('event.landingpage', [
                'eventUrl' => url()->current(),
                'guest' => $guest,
                'event' => $guest->event,
                'landingPage' => $guest->landing_page 
            ]);
        }
        else {
            return redirect('/notFound');
        }
    }

It works, if I call the property explicitly:

$guest->landing_page->app_texts = $guest->landing_page->app_texts;

But why do I need to this for app_texts and not for app_images or app_info?


Solution

  • Your LandingPage model has two appends on it:

    protected $appends = [
        'app_icon',
        'landing_page_url_base_path'
    ];
    

    When your LandingPage model is converted to json, these two fields will be included, meaning that their associated accessors will be called. My guess is that you are using your app_info and app_images relationships inside your getAppIconAttribute() and getLandingPageUrlBasePathAttribute() accessor functions.

    Since the relationships are used in those accessors, they will be included in the json output. However, since the app_texts relationship is never used, it will not be included.

    If you want your app_texts relationship included in your json output, you will need to load it before you convert to json. The quickest solution for you is to just load it in your inside your showEvent() function:

    $guest->landing_page->load('app_texts');