Milk Admin

GetDataBuilder Extensions

GetDataBuilder Extensions allow you to modify data retrieval behavior, add filters, columns, and custom actions to data lists without modifying the GetDataBuilder class itself. They extend the AbstractGetDataBuilderExtension class.

Creating a GetDataBuilder Extension

namespace Extensions\MyExtension;

use App\Abstracts\AbstractGetDataBuilderExtension;

class GetDataBuilder extends AbstractGetDataBuilderExtension
{
    // Configuration parameters
    protected bool $auto_filter = true;

    // Hook called during builder configuration
    public function configure(object $builder): void
    {
        // Add columns, filters, actions
    }

    // Hook called before data retrieval
    public function beforeGetData(): void
    {
        // Modify query before execution
    }

    // Hook called after data retrieval
    public function afterGetData(array $data): array
    {
        // Modify data array
        return $data;
    }
}

Accessing the Model

Get the model instance from the GetDataBuilder:

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

    // Access model properties
    $primary_key = $model->getPrimaryKey();
    $table = $model->getTable();

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

Accessing Builder Properties

Access common builder properties and settings:

public function configure(object $builder): void
{
    // Get current page name
    $page = $builder->getPage();

    // Get current filters
    $filters = $builder->getFilters();

    // Get database instance for query building
    $db = Get::db();

    // Add a WHERE condition
    $builder->where($db->qn('status') . ' = ?', ['active']);
}

Available Hooks

Hook Parameters Return Description
configure() object $builder void Add columns, filters, actions during builder configuration
beforeGetData() - void Modify query before data retrieval
afterGetData() array $data array Modify data array after retrieval

Extension Parameters

Define configurable parameters as protected properties:

class GetDataBuilder extends AbstractGetDataBuilderExtension
{
    // Default values
    protected bool $auto_filter = true;
    protected string $field_name = 'status';
}

// Override in module configuration
$rule_builder->addExtension('MyExtension', [
    'auto_filter' => false,
    'field_name' => 'custom_status'
]);

Example 1: Author GetDataBuilder Extension

Filters records to show only those created by the current user when they have "manage_own_only" permission:

namespace Extensions\Author;

use App\Abstracts\AbstractGetDataBuilderExtension;
use App\{Get, Permissions};

class GetDataBuilder extends AbstractGetDataBuilderExtension
{
    public function configure(object $builder): void
    {
        // Initialize Auth to load user permissions
        Get::make('Auth');

        // Administrators see all records
        if (Permissions::check('_user.is_admin')) {
            return;
        }

        $page = $builder->getPage();

        // Check if user has "manage_own_only" permission
        if ($page && Permissions::check($page . '.manage_own_only')) {
            $user = Get::make('Auth')->getUser();
            $current_user_id = $user->id ?? 0;

            if ($current_user_id > 0) {
                $db = Get::db();

                // Filter to show only own records
                $builder->where(
                    $db->qn('created_by') . ' = ?',
                    [$current_user_id]
                );
            }
        }
    }
}

Example 2: Adding Custom Columns

Add computed columns or modify existing ones:

namespace Extensions\ProductStats;

use App\Abstracts\AbstractGetDataBuilderExtension;

class GetDataBuilder extends AbstractGetDataBuilderExtension
{
    protected bool $show_stock_status = true;

    public function configure(object $builder): void
    {
        if (!$this->show_stock_status) {
            return;
        }

        // Add a custom column showing stock status
        $builder->field('stock_status')
            ->label('Stock Status')
            ->fn(function($row) {
                $quantity = $row['quantity'] ?? 0;

                if ($quantity <= 0) {
                    return '<span class="badge bg-danger">Out of Stock</span>';
                } elseif ($quantity < 10) {
                    return '<span class="badge bg-warning">Low Stock</span>';
                }

                return '<span class="badge bg-success">In Stock</span>';
            });
    }
}

Example 3: Modifying Data After Retrieval

Process data array after retrieval to add computed values:

namespace Extensions\OrderTotals;

use App\Abstracts\AbstractGetDataBuilderExtension;

class GetDataBuilder extends AbstractGetDataBuilderExtension
{
    public function afterGetData(array $data): array
    {
        // Add computed total to each row
        foreach ($data as &$row) {
            $price = $row['price'] ?? 0;
            $quantity = $row['quantity'] ?? 0;
            $tax_rate = $row['tax_rate'] ?? 0;

            // Calculate total with tax
            $subtotal = $price * $quantity;
            $tax = $subtotal * ($tax_rate / 100);
            $row['total'] = $subtotal + $tax;
        }

        return $data;
    }
}

Example 4: Adding Filters

Add dynamic filters to the query based on request parameters:

namespace Extensions\DateFilter;

use App\Abstracts\AbstractGetDataBuilderExtension;

class GetDataBuilder extends AbstractGetDataBuilderExtension
{
    protected string $date_field = 'created_at';

    public function configure(object $builder): void
    {
        $field = $this->date_field;

        // Add a filter for date ranges
        $builder->filter('date_range', function($query, $value) use ($field) {
            switch ($value) {
                case 'today':
                    $query->where("DATE($field) = CURDATE()");
                    break;
                case 'week':
                    $query->where("$field >= DATE_SUB(NOW(), INTERVAL 7 DAY)");
                    break;
                case 'month':
                    $query->where("$field >= DATE_SUB(NOW(), INTERVAL 30 DAY)");
                    break;
            }
        });
    }
}

Common Use Cases

  • Access control - Filter data based on user permissions
  • Soft delete filtering - Hide/show deleted records
  • Status filtering - Filter by record status (active/inactive)
  • Computed columns - Add calculated fields to the data list
  • Data enrichment - Add related data from other tables
  • Custom actions - Add row actions (restore, archive, etc.)
  • Dynamic filtering - Apply filters based on request parameters

Best Practices

  • Use configure() for modifying the builder structure (columns, filters, actions)
  • Use beforeGetData() for query modifications (WHERE clauses, JOINs)
  • Use afterGetData() for post-processing data (calculations, formatting)
  • Always check permissions before applying filters
  • Use protected properties for configurable parameters
  • Quote database identifiers with $db->qn() for security

See Also

Loading...