1

I have a plugin with 2 components. One is for 'posts', and the other is for a 'profile'. The profile belongs to a user and hasMany 'posts'.

However when I access the relationship it loads every post. I just want to load 5 then paginate or lazy load, how can I do this?

Profile.php model

public $hasMany = [
        'posts' => [
            'Redstone\Membership\Models\Post',
            'table' => 'redstone_membership_profiles_posts',
        ]
    ];

public $belongsTo = [
        'user' => [
            'Rainlab\User\Models\User',
        ]
    ];

Post.php model

public $belongsTo = [
        'profile' => ['Redstone\Membership\Models\Profile',
        'table' => 'redstone_membership_profiles_posts',
        ]
    ];

Profile.php component

protected function loadProfile()
    {
        $id = $this->property('profileUsername');

        $profile = new UserProfile

        $profile = $profile->where(['slug' => $id]);

        $profile = $profile->first();
        return $profile;
    }

profile/default.htm - component view

{% set profile = __SELF__.profile %}
{% set posts = __SELF__.profile.posts %}

 {% for post in posts %}
      <div class="card">
        <div class="card-header">
            <div class="ml-2">
                <div class="h5 m-0">{{ profile.title }}</div>
                  </div>
                  {{ post.published_at|date('M d') }}  
                </div>
              <div class="card-body  text-left">
                    {{ post.content|raw }}
            </div>
        </div>
 {% else %}

 <h1>This user has not made any posts.</h1>

 {% endfor %}
ServerSideSkittles
  • 2,713
  • 10
  • 34
  • 60

1 Answers1

1

Well you can either do something with the OctoberCMS pagination service or a php function or you could build a function through twig.

PHP using slice: This is assuming when you call $profile->posts you get a collection of posts. You could also add a query to the Url like example.com/profile?q=15 to change 5 to 10 15 etc I added an if statement to check to make sure the input is numeric and greater than 5.

protected function loadProfile()
{
    $id = $this->property('profileUsername');

    $profile = UserProfile::where(['slug' => $id])->first();

    if (is_numeric(Input::get('q')) == true && Input::get('q') > 5) {

        $profile->posts = $profile->posts->slice(0, Input::get('q'));

    } else { 

        $profile->posts = $profile->posts->slice(0, 5);

    }

    return $profile;
}

Twig using slice: This is done very similar to the PHP way but done in the htm file instead.

PHP -

protected function getQuery() 
{

    if (is_numeric(Input::get('q')) == true && Input::get('q') > 5) {
        return Input::get('q');
    } else {
        return 5;
    }

}

Twig -

{% set query = __SELF__.getQuery %}
{% set profile = __SELF__.profile %}
{% set posts = __SELF__.profile.posts | slice(0, query) %}

 {% for post in posts %}
      <div class="card">
        <div class="card-header">
            <div class="ml-2">
                <div class="h5 m-0">{{ profile.title }}</div>
                  </div>
                  {{ post.published_at|date('M d') }}  
                </div>
              <div class="card-body  text-left">
                    {{ post.content|raw }}
            </div>
        </div>
 {% else %}

 <h1>This user has not made any posts.</h1>

 {% endfor %}
Pettis Brandon
  • 875
  • 1
  • 6
  • 8
  • +1 Thanks for providing multiple examples! I had never even considered using a query to the URL. I saw the paginate options but thought that was not possible due to fetching ->first() for the profile. Is it possible to paginate results on a relation only using ->paginate(15)? Either way I love the idea of PHP using slice! – ServerSideSkittles Jul 31 '19 at 11:21
  • You are welcome. You could do more than just the query as well like a load more button or search for a specific for a specific post etc. The pagination service that October provides is pretty good but does take a bit of a learning curve and I wasn't sure if you wanted it. – Pettis Brandon Jul 31 '19 at 18:23