Configuration
Overview
Data Lens uses a two-tier configuration system:
1. Per-Panel Settings (Plugin Methods)
Configure these independently for each Filament panel:
DataLensPlugin::make()
->slug('reports') // Navigation (Filament 4.x only)
->navigationLabel('Reports')
->apiEnabled() // Features
->exportFormats(['csv', 'xlsx'])
->schedulingEnabled()
->modelDirectories(['app/Models']) // Model discovery
Note: The ->slug() method is only available in Filament 4.x. For Filament 3.x, use the config file.
2. Global Settings (Config File)
Publish and configure system-wide settings:
php artisan vendor:publish --tag="data-lens-config"
This creates config/data-lens.php for:
- Resource slug (Filament 3.x only - use 'slug' => 'custom-reports')
- Security (IP whitelisting)
- Performance (cache, queue settings)
- Infrastructure (email, database)
- Multi-tenancy
Multi-Tenancy Configuration
For comprehensive multi-tenant setup guidance, see the Multi-Tenant Setup Guide
Basic Tenant Settings
'tenant_aware' => false, // Enable for multi-tenant applications
'tenant_context' => [
'key' => 'tenant_id', // Key used in execution context
],
Important: Enable tenant_aware before running migrations to ensure proper foreign key setup.
Tenant Foreign Key
'column_names' => [
'tenant_foreign_key' => 'tenant_id', // Customize if needed
],
See the Multi-Tenant Setup Guide for step-by-step configuration, tenant resolution strategies, and troubleshooting.
API Configuration
Per-Panel API Settings
// Enable/disable API per panel
DataLensPlugin::make()
->apiEnabled() // Enable API for this panel
Global API Settings
// In config/data-lens.php
'api' => [
'enabled' => false, // Default if not set per-panel
'path' => 'api/data-lens/reports', // Default API path
'middleware' => [DataLensApiAuth::class], // Default middleware
'hide_auth_ui' => false, // Hide auth UI in admin panel
'ip_whitelist' => null, // Array of IPs or CIDR ranges, null/[] = allow all
],
IP Whitelist Behavior:
- null or [] - Allow all IPs (no restrictions)
- Array with IPs - Only listed IPs can access
Per-Panel API Routing
Customize API paths and authentication per panel for enterprise deployments:
// Custom API path
DataLensPlugin::make()
->apiPath('system/api/reports')
// Custom middleware stack
DataLensPlugin::make()
->apiMiddleware([
'enterprise.auth',
'throttle:api',
])
// Hide authentication UI (when managed externally)
DataLensPlugin::make()
->hideAuthenticationUI()
// Disable API routes entirely
DataLensPlugin::make()
->disableApiRoutes()
Enterprise Example:
// Admin panel with custom enterprise auth
Panel::make()
->id('admin')
->plugin(
DataLensPlugin::make()
->apiPath('api/internal/reports')
->apiMiddleware(['enterprise.oauth', 'enterprise.audit'])
->hideAuthenticationUI()
);
// Public panel with standard auth
Panel::make()
->id('public')
->plugin(
DataLensPlugin::make()
->apiPath('api/public/reports')
->apiMiddleware(['throttle:10,1'])
);
Resource Slug Configuration
The URL slug for custom reports is configured differently between Filament versions:
Filament 4.x (Per-Panel)
// Each panel can have its own slug
DataLensPlugin::make()
->slug('admin-reports') // Admin panel uses /admin-reports
// Another panel
DataLensPlugin::make()
->slug('my-reports') // User panel uses /my-reports
Filament 3.x (Global Only)
// In config/data-lens.php
'slug' => 'custom-reports', // All panels use /custom-reports
Important: In Filament 3.x, all panels share the same slug because the resource uses static properties. This limitation is resolved in Filament 4.x.
User Model Configuration
'user_model' => App\Models\User::class,
Report Sharing Configuration
Share reports with other users in your application. When a report is shared, users receive both in-app and email notifications.
Basic Sharing
// In config/data-lens.php
'features' => [
'sharing' => [
'user_sharing_enabled' => true,
'user_selection' => [
'filter_query' => null,
'display_formatter' => null,
'searchable_columns' => ['name', 'email'],
'skip_auto_tenant_scope' => false,
],
'notifications' => [
'database' => true,
'email' => true,
],
],
],
Custom User Filtering
Filter which users appear in the sharing dropdown. Use a class for config:cache compatibility:
// app/DataLens/ActiveUserFilter.php
namespace App\DataLens;
use Illuminate\Database\Eloquent\Builder;
use Padmission\DataLens\Contracts\UserFilterContract;
use Padmission\DataLens\Models\CustomReport;
class ActiveUserFilter implements UserFilterContract
{
public function __invoke(Builder $query, ?CustomReport $report): Builder
{
return $query->where('is_active', true);
}
}
// In config/data-lens.php
'filter_query' => \App\DataLens\ActiveUserFilter::class,
Custom User Display
Customize how users appear in the dropdown:
// app/DataLens/UserDisplayFormatter.php
namespace App\DataLens;
use Illuminate\Database\Eloquent\Model;
use Padmission\DataLens\Contracts\UserDisplayFormatterContract;
class UserDisplayFormatter implements UserDisplayFormatterContract
{
public function __invoke(Model $user): string
{
return "{$user->name} ({$user->department}) - {$user->email}";
}
}
// In config/data-lens.php
'display_formatter' => \App\DataLens\UserDisplayFormatter::class,
Pivot Table Tenant Relationships
When users relate to tenants via a pivot table (not a direct foreign key), set skip_auto_tenant_scope to true and handle tenant filtering in your filter_query:
// app/DataLens/TeamUserFilter.php
namespace App\DataLens;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Builder;
use Padmission\DataLens\Contracts\UserFilterContract;
use Padmission\DataLens\Models\CustomReport;
class TeamUserFilter implements UserFilterContract
{
public function __invoke(Builder $query, ?CustomReport $report): Builder
{
$tenantId = Filament::getTenant()?->id;
if ($tenantId) {
$query->whereHas('teams', fn ($q) => $q->where('teams.id', $tenantId));
}
return $query;
}
}
// In config/data-lens.php
'user_selection' => [
'filter_query' => \App\DataLens\TeamUserFilter::class,
'skip_auto_tenant_scope' => true,
],
Notification Channels
Control how users are notified when reports are shared:
'notifications' => [
'database' => true, // In-app notifications
'email' => true, // Email notifications
],
Model Directories Configuration
Type: Per-Panel Setting
Configure multiple model directories independently for each panel:
// AdminPanelProvider.php
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
DataLensPlugin::make()
->modelDirectories([
'app/Models',
'app/Admin/Models',
]),
]);
}
// UserPanelProvider.php
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
DataLensPlugin::make()
->modelDirectories([
'app/Models',
'app/User/Models',
]),
]);
}
Third-Party Integrations
'integrations' => [
'custom_fields' => false, // Relaticle Custom Fields package
'advanced_tables' => false, // Advanced Tables package
],
Relationship Configuration
Eligible Relationships
'eligible_relationships' => [
BelongsTo::class,
HasOne::class,
HasOneThrough::class,
MorphOne::class,
HasMany::class,
HasManyThrough::class,
BelongsToMany::class,
],
Exclusions
'excluded_relationships' => [
// 'tenant', // Add relationship names to exclude
],
'excluded_models' => [
// \App\Models\Tenant::class,
],
Export Configuration
Per-Panel Export Settings
// Configure via plugin methods
DataLensPlugin::make()
->exportsEnabled() // Enable/disable exports
->exportFormats(['csv', 'xlsx']) // Available formats
->defaultExportFormat('xlsx') // Default format
->useTimestampsInFilename(false) // Timestamps in filenames
Global Export Settings
// In config/data-lens.php
'exports' => [
'enabled' => true, // Default if not set per-panel
'formats' => ['csv', 'xlsx'], // Default if not set per-panel
'default_format' => 'csv', // Default if not set per-panel
'chunk_size' => env('DATA_LENS_EXPORT_CHUNK_SIZE', 2000), // Global only
'timeout' => env('DATA_LENS_EXPORT_TIMEOUT', 600), // Global only
'use_timestamps_in_filename' => true, // Default if not set per-panel
'template' => 'report_{report_name}_{date}', // Global only
'queue' => env('DATA_LENS_QUEUE'), // Global only
'should_queue' => env('DATA_LENS_EXPORT_QUEUE', true), // Global only
],
Filename Templates
'filename_templates' => [
// Manual exports: {report_name}, {report_id}, {date}, {time}
'exports' => 'report_{report_name}_{date}',
// Scheduled: {report_name}, {report_id}, {date}, {time}, {schedule_name}, {schedule_id}
'scheduling' => 'report_{report_name}_{date}',
],
Scheduling Configuration
Per-Panel Scheduling
// Enable/disable scheduling per panel
DataLensPlugin::make()
->schedulingEnabled() // Enable for this panel
Global Scheduling Settings
// In config/data-lens.php - all settings are global
'scheduling' => [
'enabled' => false, // Default if not set per-panel
'from_email' => env('MAIL_FROM_ADDRESS'), // Global only
'from_name' => env('MAIL_FROM_NAME'), // Global only
'max_attachment_size' => 1024, // KB - Global only
'check_interval' => 1, // minutes - Global only
'max_runtime' => 300, // seconds - Global only
'retry_attempts' => 3, // Global only
'retry_delay' => 5, // minutes - Global only
'history_retention_days' => 30, // Global only
'max_recipients_per_schedule' => 50, // Global only
'download_link_expiry_days' => 7, // Global only
'queue' => env('DATA_LENS_QUEUE'), // Global only
],
Column Security
Excluded Columns
'excluded_columns' => [
'global' => [
'password',
'remember_token',
'deleted_at',
// 'api_token',
// 'two_factor_secret',
],
'models' => [
// \App\Models\User::class => ['social_security_number'],
],
],
Auto-Detection Command
# Scan all models for sensitive columns
php artisan data-lens:suggest-excluded-columns
# Get copy-pastable config
php artisan data-lens:suggest-excluded-columns --format=config
# Check specific model
php artisan data-lens:suggest-excluded-columns --model="App\Models\User"
Column Type Detection
'column_type_detection' => [
'money_field_patterns' => [
'price', 'cost', 'amount', 'balance', 'fee', 'payment',
'salary', 'total', 'budget', 'revenue', 'income', 'expense', 'tax',
],
'boolean_field_patterns' => [
'is_', 'has_', 'can_', 'should_', 'active', 'enabled', 'approved',
],
],
Cache Configuration
'cache' => [
'enabled' => env('DATA_LENS_CACHE_ENABLED', true),
'force_in_local' => env('DATA_LENS_CACHE_FORCE_IN_LOCAL', false),
'ttl' => [
'relationship_class' => env('DATA_LENS_CACHE_RELATIONSHIP_CLASS_TTL', 21600), // 6 hours
'relationship_type' => env('DATA_LENS_CACHE_RELATIONSHIP_TYPE_TTL', 21600),
'model_relationships' => env('DATA_LENS_CACHE_MODEL_RELATIONSHIPS_TTL', 21600),
'model_fields' => env('DATA_LENS_CACHE_MODEL_FIELDS_TTL', 21600),
'filter_type' => env('DATA_LENS_CACHE_FILTER_TYPE_TTL', 21600),
],
'prefix' => env('DATA_LENS_CACHE_PREFIX', 'data_lens'),
'tenant_resolver' => null, // Custom tenant resolver callback
],
Cache Management
# Clear all Data Lens cache
php artisan data-lens:clear-cache
# Clear specific cache type
php artisan data-lens:clear-cache --type=model_fields
# Skip confirmation
php artisan data-lens:clear-cache --force
Through Relationships
'through_relationships' => [
'max_depth' => env('DATA_LENS_THROUGH_MAX_DEPTH', 3),
'performance_threshold_ms' => env('DATA_LENS_THROUGH_PERFORMANCE_THRESHOLD', 1000),
'auto_index_suggestion' => env('DATA_LENS_THROUGH_AUTO_INDEX', true),
'cache_ttl' => env('DATA_LENS_THROUGH_CACHE_TTL', 43200), // 12 hours
'optimize_queries' => env('DATA_LENS_THROUGH_OPTIMIZE_QUERIES', true),
],
Database Tables
'table_names' => [
'custom_reports' => 'custom_reports',
'custom_report_user' => 'custom_report_user',
'custom_report_schedules' => 'custom_report_schedules',
'custom_report_schedule_history' => 'custom_report_schedule_history',
'custom_report_schedule_recipients' => 'custom_report_schedule_recipients',
],
Storage Configuration
'storage_disk' => env('FILAMENT_FILESYSTEM_DISK', 'local'),
Timezone Configuration
'timezone' => [
'default' => env('DATA_LENS_TIMEZONE', 'UTC'),
],
Custom Timezone Resolver
use Padmission\DataLens\DataLens;
// In AppServiceProvider boot method
DataLens::setTimezoneResolver(function () {
return tenant()?->timezone ?? config('app.timezone');
});
Custom Mailable Classes
'mailable_classes' => [
'report_email' => Padmission\DataLens\Mail\ReportEmail::class,
],
Programmatic Configuration
Custom Models
use Padmission\DataLens\DataLens;
// In AppServiceProvider boot method
DataLens::useCustomReportModel(CustomReport::class);
DataLens::useTenantModel(Tenant::class);
Table Configuration
DataLens::configureTableUsing(function (Table $table) {
return $table
->paginated([10, 25, 50, 100])
->striped();
});