0

I am using OctoberCMS and I have created a custom component. I am trying to create a frontend filter to filter Packages by the Tour they are assigned to.

This is what I have so far. The issue is that the code is looking for a tour field within the packages table rather than using the tour relationship. Does anyone have any ideas?

<?php namespace Jakefeeley\Sghsportingevents\Components;

use Cms\Classes\ComponentBase;
use JakeFeeley\SghSportingEvents\Models\Package;
use Illuminate\Support\Facades\Input;

class FilterPackages extends ComponentBase
{


    public function componentDetails()
    {
        
        return [
            'name'        => 'Filter Packages',
            'description' => 'Displays filters for packages'
        ];

    }


    public function onRun() {

        $this->packages = $this->filterPackages();
    
    }


    protected function filterPackages() {
        
        $tour = Input::get('tour');
        $query = Package::all();
        
        if($tour){
            $query = Package::where('tour', '=', $tour)->get();
        }
        
        return $query;
    
    }


    public $packages;


}

I really appreciate any help you can provide.

Alex Posterns
  • 23
  • 1
  • 8

2 Answers2

1

Try to query the relationship when the filter input is provided.

This is one way to do it;

public $packages;

protected $tourCode;

public function init()
{
    $this->tourCode = trim(post('tour', '')); // or input()
    $this->packages = $this->loadPackages();
}

private function loadPackages()
{
    $query = PackagesModel::query(); 

    // Run your query only when the input 'tour' is present.
    // This assumes the 'tours' db table has a column named 'code'
    $query->when(!empty($this->tourCode), function ($q){
        return $q->whereHas('tour', function ($qq) {
            $qq->whereCode($this->tourCode);
        });
    });

    return $query->get();
}

If you need to support pagination, sorting and any additional filters you can just add their properties like above. e.g;

protected $sortOrder;

public function defineProperties(): array
{
    return [
        'sortOrder' => [
            'title' => 'Sort by',
            'type' => 'dropdown',
            'default' => 'id asc',
            'options' => [...], // allowed sorting options
        ],
    ];
}


public function init()
{
    $filters = (array) post();
    $this->tourCode =  isset($filters['tour']) ? trim($filters['tour']) : '';
    $this->sortOrder = isset($filters['sortOrder']) ? $filters['sortOrder'] : $this->property('sortOrder');
    $this->packages = $this->loadPackages();
}

If you have a more complex situation like ajax filter forms or dynamic partials then you can organize it in a way to load the records on demand vs on every request.e.g;

public function onRun()
{
    $this->packages = $this->loadPackages();
}

public function onFilter()
{
    if (request()->ajax()) {
        try {
            return [
                "#target-container" => $this->renderPartial("@packages", 
                    [
                        'packages' => $this->loadPackages()
                    ]
                ),
            ];
        } catch (Exception $ex) {
            throw $ex;
        }
    }
    return false;
}
// call component-name::onFilter from your partials..
Raja Khoury
  • 3,015
  • 1
  • 20
  • 19
0

You are looking for the whereHas method. You can find about here in the docs. I am not sure what your input is getting. This will also return a collection and not singular record. Use ->first() instead of ->get() if you are only expecting one result.

$package = Package::whereHas('tour', function ($query) {
    $query->where('id', $tour);
})->get();
Pettis Brandon
  • 875
  • 1
  • 6
  • 8