Milk Admin

SearchBuilder Extensions

SearchBuilder Extensions allow you to add custom search fields, filters, and action lists to the search interface without modifying the SearchBuilder class itself. They extend the AbstractSearchBuilderExtension class.

Creating a SearchBuilder Extension

namespace Extensions\MyExtension;

use App\Abstracts\AbstractSearchBuilderExtension;

class SearchBuilder extends AbstractSearchBuilderExtension
{
    // Configuration parameters
    protected string $label = 'Status:';
    protected string $filter_name = 'status_filter';

    // Hook called during builder configuration
    public function configure(object $builder): void
    {
        // Add search fields and filters
        $builder->actionList(
            $this->filter_name,
            $this->label,
            ['active' => 'Active', 'inactive' => 'Inactive'],
            'active'
        );
    }
}

Accessing the Model

Get the model instance from the SearchBuilder:

public function configure(object $builder): void
{
    // Get the model
    $model = $builder->getModel();

    // Access model properties
    $fields = $model->getFields();

    // Get loaded model extensions
    $soft_del_ext = $model->getLoadedExtension('SoftDelete');
    if ($soft_del_ext) {
        $field_name = $soft_del_ext->field_name;
    }
}

Available Hooks

Hook Parameters Return Description
configure() object $builder void Add search fields, filters, and action lists

SearchBuilder Methods

Common methods available in the SearchBuilder:

Method Parameters Description
actionList() string $name, string $label, array $options, mixed $default Add a dropdown filter with predefined options
addSearchField() string $name, string $label, string $type = 'text' Add a search input field
getModel() - Get the associated model instance

Extension Parameters

Define configurable parameters as protected properties:

class SearchBuilder extends AbstractSearchBuilderExtension
{
    // Default values
    protected string $label = 'Status:';
    protected string $filter_name = 'show_deleted';
}

// Override in module configuration
$rule_builder->addExtension('SoftDelete', [
    'label' => 'Record Status:',
    'filter_name' => 'custom_filter'
]);

Example 1: SoftDelete SearchBuilder Extension

Adds a filter to show active or deleted records:

namespace Extensions\SoftDelete;

use App\Abstracts\AbstractSearchBuilderExtension;

class SearchBuilder extends AbstractSearchBuilderExtension
{
    protected string $label = 'Status:';
    protected string $filter_name = 'show_deleted';

    public function configure(object $builder): void
    {
        // Add action list filter
        $builder->actionList(
            $this->filter_name,
            $this->label,
            [
                'active' => 'Active',
                'deleted' => 'Deleted'
            ],
            'active'
        );
    }
}

Example 2: Status Filter Extension

Add a filter for record status (published, draft, archived):

namespace Extensions\PublishStatus;

use App\Abstracts\AbstractSearchBuilderExtension;

class SearchBuilder extends AbstractSearchBuilderExtension
{
    protected string $label = 'Status:';
    protected string $filter_name = 'status';

    public function configure(object $builder): void
    {
        $builder->actionList(
            $this->filter_name,
            $this->label,
            [
                'all' => 'All',
                'published' => 'Published',
                'draft' => 'Draft',
                'archived' => 'Archived'
            ],
            'all'
        );
    }
}

Example 3: Category Filter Extension

Add a dynamic filter based on database categories:

namespace Extensions\CategoryFilter;

use App\Abstracts\AbstractSearchBuilderExtension;
use App\Get;

class SearchBuilder extends AbstractSearchBuilderExtension
{
    protected string $label = 'Category:';
    protected string $filter_name = 'category_id';

    public function configure(object $builder): void
    {
        // Get categories from database
        $categories = $this->getCategories();

        if (empty($categories)) {
            return;
        }

        // Add filter with dynamic options
        $builder->actionList(
            $this->filter_name,
            $this->label,
            $categories,
            'all'
        );
    }

    private function getCategories(): array
    {
        $categories = ['all' => 'All Categories'];

        try {
            $db = Get::db();
            $results = $db->select('categories')
                ->fields(['id', 'name'])
                ->where('status = ?', ['active'])
                ->order('name ASC')
                ->getResults();

            foreach ($results as $cat) {
                $categories[$cat->id] = $cat->name;
            }
        } catch (\Exception $e) {
            // Fallback to empty list
        }

        return $categories;
    }
}

Example 4: Date Range Filter Extension

Add search fields for filtering by date range:

namespace Extensions\DateRange;

use App\Abstracts\AbstractSearchBuilderExtension;

class SearchBuilder extends AbstractSearchBuilderExtension
{
    protected bool $add_date_from = true;
    protected bool $add_date_to = true;

    public function configure(object $builder): void
    {
        if ($this->add_date_from) {
            $builder->addSearchField(
                'date_from',
                'From Date:',
                'date'
            );
        }

        if ($this->add_date_to) {
            $builder->addSearchField(
                'date_to',
                'To Date:',
                'date'
            );
        }
    }
}

Example 5: User Filter Extension

Add a filter to show records by specific user (author, assignee, etc.):

namespace Extensions\UserFilter;

use App\Abstracts\AbstractSearchBuilderExtension;

class SearchBuilder extends AbstractSearchBuilderExtension
{
    protected string $label = 'Created By:';
    protected string $filter_name = 'created_by';
    protected bool $show_all_option = true;

    public function configure(object $builder): void
    {
        // Get list of users
        $users = $this->getUsersList();

        if (empty($users)) {
            return;
        }

        $builder->actionList(
            $this->filter_name,
            $this->label,
            $users,
            'all'
        );
    }

    private function getUsersList(): array
    {
        $users = [];

        if ($this->show_all_option) {
            $users['all'] = 'All Users';
        }

        try {
            $userModel = new \Modules\Auth\UserModel();
            $allUsers = $userModel->order('username')->getResults();

            foreach ($allUsers as $user) {
                $users[$user->id] = $user->username ?? "User #{$user->id}";
            }
        } catch (\Exception $e) {
            // Fallback to empty list
        }

        return $users;
    }
}

Common Use Cases

  • Status filters - Filter by record status (active/inactive, published/draft)
  • Soft delete filters - Show/hide deleted records
  • Category filters - Filter by categories or tags
  • User filters - Filter by author, assignee, or related user
  • Date filters - Filter by date ranges or specific periods
  • Priority filters - Filter by priority levels (high, medium, low)
  • Type filters - Filter by content type or record type

Best Practices

  • Use descriptive labels that clearly indicate the filter purpose
  • Provide sensible default values (often 'all' or 'active')
  • Use protected properties for configurable options
  • Keep filter names consistent with field names when possible
  • Handle database errors gracefully when loading dynamic options
  • Consider performance when loading large option lists

See Also

Loading...