Skip to content

Register a Source Safely

Use this page to register a source that exposes only intentional fields and executes safely in production.

Problem

You need a report source that is usable by product teams without exposing internal query details.

Prerequisites

  • Package installed
  • A model like Order

Steps

  1. Create an EloquentDataSource.
  2. Add explicit Field definitions.
  3. Add source scope and authorization rules.
  4. Register it in app boot.
php
<?php

use App\Models\Order;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Ihasan\ReportBuilder\DataSources\EloquentDataSource;
use Ihasan\ReportBuilder\Enums\AggregateFunction;
use Ihasan\ReportBuilder\Enums\FilterOperator;
use Ihasan\ReportBuilder\ReportBuilder;
use Ihasan\ReportBuilder\Support\Field;

$reportBuilder->registerDataSource(
    new EloquentDataSource(
        key: 'orders',
        label: 'Orders',
        model: Order::class,
        fields: [
            Field::string('customer_name')
                ->label('Customer Name')
                ->column('orders.customer_name')
                ->sortable()
                ->filterable([FilterOperator::Like]),
            Field::string('status')
                ->label('Order Status')
                ->column('orders.status')
                ->sortable()
                ->filterable([FilterOperator::Equals, FilterOperator::In]),
            Field::decimal('total_amount')
                ->label('Total Amount')
                ->column('orders.total_amount')
                ->sortable()
                ->groupable()
                ->filterable([FilterOperator::Equals, FilterOperator::Between])
                ->aggregates([AggregateFunction::Sum]),
            Field::dateTime('created_at')
                ->label('Created At')
                ->column('orders.created_at')
                ->sortable()
                ->filterable([
                    FilterOperator::DateAfter,
                    FilterOperator::DateBefore,
                    FilterOperator::ThisMonth,
                ]),
        ],
        scope: static function (Builder $query, Request $request): Builder {
            $tenantId = $request->user()?->tenant_id;

            if ($tenantId !== null) {
                $query->where('orders.tenant_id', $tenantId);
            }

            return $query;
        },
        authorization: static function (Request $request): bool {
            return $request->user()?->can('view_reports') === true;
        },
    )
);

Verify

Run a small preview against this source:

php
<?php

use Ihasan\ReportBuilder\DTOs\ReportDefinition;
use Ihasan\ReportBuilder\DTOs\SelectedColumn;
use Ihasan\ReportBuilder\Execution\PreviewRunner;

$preview = app(PreviewRunner::class)->preview(
    new ReportDefinition(
        sourceKey: 'orders',
        selectedColumns: [
            new SelectedColumn('customer_name'),
            new SelectedColumn('status'),
            new SelectedColumn('total_amount'),
        ],
    ),
    perPage: 5,
    page: 1,
);

Confirm that:

  • columns contains exactly your selected fields in order.
  • rows contains only tenant-scoped data.
  • pagination is returned.

Common mistakes

  • Registering sources in the wrong lifecycle location.
  • Using old enum names like FilterOperator::Eq.
  • Missing column() when the public key differs from the trusted DB column.
  • Overexposing fields that should stay private.
  • Forgetting authorization/scope, which can leak cross-tenant data.