Skip to content
View as Markdown

Contacts Query

FluentCrm\App\Services\ContactsQuery

The ContactsQuery class provides a builder-pattern interface for querying contacts with filters, sorting, and pagination. It wraps the Subscriber model and supports both simple and advanced filter modes.

php
use FluentCrm\App\Services\ContactsQuery;

Basic Usage

php
// Get all subscribed contacts with tag ID 5
$query = new ContactsQuery([
    'statuses' => ['subscribed'],
    'tags'     => [5],
    'sort_by'  => 'first_name',
    'sort_type'=> 'ASC'
]);

$contacts = $query->get();

Constructor Arguments

The constructor accepts an $args array with the following keys:

KeyTypeDefaultDescription
witharray['tags', 'lists']Eloquent relations to eager-load
filter_typestring'simple''simple' or 'advanced'
searchstring''Full-text search across name, email, and optionally custom fields
sort_bystring'id'Column to sort by (must be a fillable field or 'id')
sort_typestring'DESC'Sort direction: 'ASC' or 'DESC'
tagsarray[]Filter by tag IDs (simple mode)
listsarray[]Filter by list IDs (simple mode)
statusesarray[]Filter by subscription statuses (validated against allowed statuses)
sms_statusesarray[]Filter by SMS statuses
company_idsarray[]Filter by company IDs
contact_idsarray[]Restrict to specific contact IDs
contact_statusstring''Single status filter (e.g., 'subscribed')
has_commerceboolfalseEager-load commerce relations from the active provider
custom_fieldsboolfalseAppend custom field values to each contact in results. Also enables searching custom fields when combined with search
filters_groups_rawarray[]Raw advanced filter groups (from the UI filter builder)
limitint|falsefalseLimit number of results
offsetint|falsefalseOffset for pagination

Methods

get()

Executes the query and returns a collection of contacts. Applies limit and offset if set.

  • Returns: Collection of Subscriber models
php
$contacts = (new ContactsQuery([
    'tags'   => [1, 3],
    'limit'  => 50,
    'offset' => 0
]))->get();

foreach ($contacts as $contact) {
    echo $contact->email;
}

paginate()

Executes the query with WordPress-style pagination (uses $_GET['page'] and default per-page).

  • Returns: LengthAwarePaginator
php
$paginated = (new ContactsQuery([
    'statuses' => ['subscribed']
]))->paginate();

$contacts = $paginated->items();
$total = $paginated->total();

getModel()

Returns the raw underlying Subscriber query builder for custom chaining.

  • Returns: Builder — Eloquent query builder instance
php
$query = new ContactsQuery(['statuses' => ['subscribed']]);
$model = $query->getModel();

// Add custom conditions
$model->where('created_at', '>=', '2024-01-01');
$results = $model->get();

Filter Modes

Simple Filters

In simple mode (default), you pass filter arrays directly:

php
$query = new ContactsQuery([
    'filter_type' => 'simple',
    'tags'        => [1, 5],
    'lists'       => [2],
    'statuses'    => ['subscribed', 'pending'],
    'company_ids' => [10]
]);

Advanced Filters

In advanced mode, you pass raw filter groups from the UI filter builder. These are processed by registered filter providers via fluentcrm_contacts_filter_{provider} action hooks.

php
$query = new ContactsQuery([
    'filter_type'        => 'advanced',
    'filters_groups_raw' => [
        // Group 1 (conditions within a group are AND)
        [
            [
                'source'   => ['contacts', 'status'],
                'operator' => 'in',
                'value'    => ['subscribed']
            ],
            [
                'source'   => ['contacts', 'created_at'],
                'operator' => 'date_after',
                'value'    => '2024-01-01'
            ]
        ],
        // Group 2 (groups are OR'd together)
        [
            [
                'source'   => ['contacts', 'tags'],
                'operator' => 'in_all',
                'value'    => [1, 5]
            ]
        ]
    ]
]);

Real-World Examples

Search with custom fields

php
$query = new ContactsQuery([
    'search'        => '[email protected]',
    'custom_fields' => true
]);

$contacts = $query->get();
// Each contact has ->custom_fields populated

Paginated list with commerce data

php
$query = new ContactsQuery([
    'statuses'     => ['subscribed'],
    'has_commerce' => true,
    'sort_by'      => 'last_activity',
    'sort_type'    => 'DESC'
]);

$paginated = $query->paginate();

Custom query chaining

php
$query = new ContactsQuery([
    'tags'     => [5],
    'statuses' => ['subscribed']
]);

$model = $query->getModel();
$model->whereNotNull('phone')
      ->where('created_at', '>=', '2024-06-01');

$contacts = $model->limit(100)->get();