Ad

Octobercms Component - Limit Results On Relation

- 1 answer

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 %}
Ad

Answer

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 %}
Ad
source: stackoverflow.com
Ad