Filter items by category in Laravel October

- 1 answer

Ad

I have a document model with a $belongsTo categories relationship, everything is working well and I'm able to assign categories to documents and list them all on the frontend, but what I'm struggling with is filtering the results by category.

I have 3 categories and 3 col-md-4 columns, in each column, the documents should be listed and filtered via their category, how do I do this with twig using components?

My documents.default component file looks like this:

 {% set documents = __SELF__.documents %} 
 <ul class="record-list list-unstyled ">  
     {% for document in documents %}
        <li class="ul-text-black">      
              {{document.name }}
        </li>
     {% endfor %}
 </ul>

My documents component code:

 <?php namespace Myplugin\Documents\Components;

  use Cms\Classes\ComponentBase;
  use Myplugin\Documents\Models\Document;

  class Documents extends ComponentBase
  {
  public function componentDetails(){
    return [
        'name' => 'Documents List',
        'description' => 'Custom Component to list documents by category'
    ];
}

public function defineProperties(){
    return [
        'results' => [
            'title' => 'Number of Documents',
            'description' => 'How many documents do you want to display?',
            'default' => 24,
            'validationPattern' => '^[0-9]+$',
            'validationMessage' => 'Only numbers allowed'
        ],
        'sortOrder' => [
            'title' => 'Sort Documents',
            'description' => 'Sort documents',
            'type' => 'dropdown',
            'default' => 'name asc',
        ]];
  }

public function getSortOrderOptions(){
    return [
        'name asc' => 'Name (ascending)',
        'name desc' => 'Name (descending)',
    ];
}

public function onRun()
{
    $this->documents = $this->loadDocuments();
}

protected function loadDocuments(){
    $query = Document::all();
    if ($this->property('sortOrder') == 'name asc') {
        $query = $query->sortBy('name');
    }
    if ($this->property('sortOrder') == 'name desc') {
        $query = $query->sortByDesc('name');
    }
    if ($this->property('results') > 0) {
        $query = $query->take($this->property('results'));
    }
    return $query;
}
public $documents;
}

My page looks like this

 <div class="row">
    <div class="col-md-4">
         <p class="text-black">
              <strong>FINANCIAL</strong>
         </p>
           {% component 'documents' %}  // Only documents from financial category
    </div>

    <div class="col-md-4">
         <p class="text-black">
             <strong>ANALYTICS</strong>
         </p>
         {% component 'documents' %}  // Only documents from analytics category
    </div>

    <div class="col-md-4"> 
         <p class="text-black">
             <strong>INVESTMENT</strong>
         </p>
         {% component 'documents' %}  // Only documents from investment category
    </div>

How do I display the documents list but filter them by category? Something like this? {% partial "documents-financials" category="Financials" %}

Ad

Answer

Ad

You should be able to access the properties in your Documents component using $category = $this->property('category');

There's documentation on accessing component properties on the OctoberCMS website: https://octobercms.com/docs/plugin/components#component-properties

I can then see that you're loading all documents and filtering them using the Laravel Collection. I would suggest changing this and doing it on the database first. It'll be far more efficient.

$category = $this->property('category');    
$results = $this->property('results');    

$documents = Document::whereHas('category', function ($query) use ($category) {
        return $query->where('name', $category);
    })
    ->orderBy('name', 'ASC')
    ->take($results)
    ->get();

If you want to group your documents and then output them, you could do the following:

$this->documents = Document::with('category')
    ->orderBy('name', 'ASC')
    ->take($results)
    ->get()
    ->groupBy('category.name');

See https://laravel.com/docs/5.3/collections#method-groupby

Then in your component template:

<div class="row">
    {% for group in documents %}
        <div class="col-md-4">
            <p class="text-black">
                <strong>FINANCIAL</strong>
            </p>

            <ul class="record-list list-unstyled">  
                {% for document in group %}
                    <li class="ul-text-black">{{document.name }}</li>
                {% endfor %}
            </ul>
        </div>
    {% endfor %}
</div>
Ad
source: stackoverflow.com
Ad