Skip to content

Option providers

Use an option provider when a select, radio group or checkbox group should list rows from your database, such as active services. You register a named source once, and any form, including forms stored as schemas, can use it.

Example

A model method that returns options as id => name:

app/Models/ServiceModel.php
<?php

declare(strict_types=1);

namespace App\Models;

use CodeIgniter\Model;

class ServiceModel extends Model
{
    protected $table         = 'services';
    protected $returnType    = 'array';
    protected $allowedFields = ['name', 'active'];

    /**
     * Active services as id => name, for option providers.
     *
     * @return array<int|string, string>
     */
    public function dropdown(): array
    {
        $rows = $this->select('id, name')->where('active', 1)->orderBy('name')->findAll();

        return array_column($rows, 'name', 'id');
    }
}

Register it under a name in app/Config/Forms.php:

app/Config/Forms.php
    public array $optionProviders = [
        'services' => [ServiceModel::class, 'dropdown'],
    ];

Use it in a form with optionsFrom():

app/Forms/ServiceRequestForm.php
<?php

declare(strict_types=1);

namespace App\Forms;

use Ephraitech\Forms\Form;

class ServiceRequestForm extends Form
{
    protected function define(): void
    {
        $this->text('full_name', 'Full name')->rules('required');

        // Options come from the "services" provider in app/Config/Forms.php.
        $this->select('service_id', 'Service')
            ->optionsFrom('services')
            ->placeholder('Choose a service')
            ->rules('required');

        $this->submit('Send request');
    }
}

In a schema, the same field is {"type": "select", "name": "service_id", "options_from": "services"}.

How it works

Registering
A provider is [ClassName::class, 'method'], 'ClassName::method', or a closure assigned in the configuration's constructor. Models are loaded with model(); other classes must not need constructor arguments, and the method must be public and take no arguments. The method returns value => label pairs; a select may also receive groups ('Group' => [value => label]).
Called lazily, once
The provider runs the first time the options are needed, when the form is rendered or validated, and only once per field. Building a form, or loading and checking a schema, never calls it.
Options are checked
A submitted value must be one the provider returned. In the example, an inactive service is not an option, so it is rejected even if someone sends its id.
Named, not coded
A schema can only name a registered provider. It cannot pass arguments, choose a table or run code, which keeps forms written by admins safe.

Common mistakes

Returning a list instead of id => name. findColumn('name') returns names without their ids. Use array_column($rows, 'name', 'id') as in the example.

Exposing data that should stay private. Forms written by admins can use every registered provider unless their policy narrows the list. Register only data that is safe on any form, or block a provider for admins with SchemaPolicy::restricted()->disallowProviders('staff').

Using a provider name that is not registered. optionsFrom() fails at once with the list of registered names, and schemas get a "did you mean" suggestion.