anomaly/select-field_type
Anomaly Select Field Type adds a configurable dropdown/select field to Anomaly Streams, letting you define options and store a single choice on entries. Useful for statuses, categories, and other fixed-value fields in Laravel/PHP-powered Anomaly projects.
composer require anomaly/select-field_type
php artisan addon:install anomaly/select-field_type
This is a Streams Platform (PyroCMS) field type addon, not a standalone form package. It does nothing on its own — it registers a select field type that you attach to a stream. If you are not running Streams/Pyro, stop here; there is no generic Laravel integration path.
Look at these files first, in order:
src/SelectFieldType.php — the config keys, getOptions(), and any handler resolution logic.resources/config/config.php — the defaults the admin form will show you.resources/views/input.twig — how options are handed to the form control.resources/lang/en/ — the labels used in the control panel.First use case — a status dropdown in a stream migration:
$fields->add('status', 'anomaly.field_type.select', [
'config' => [
'options' => [
'draft' => 'Draft',
'review' => 'In Review',
'published' => 'Published',
],
'default_value' => 'draft',
],
]);
Then php artisan migrate and php artisan streams:compile. You now have entry.status in Twig and a dropdown in the admin form.
Static options in the field config. The simple case: an associative array of stored_value => human_label defined either in a migration, in a seeder, or through the field's control-panel form. Labels are best supplied as translation keys ('anomaly.module.x::field.status.draft') if you need multi-language.
Dynamic options via a handler. For options that depend on the database (a list of categories, users, enum tables), the field type resolves a handler config value to a class and calls it for options. The pattern is a small plain PHP class in your module/extension namespace:
namespace Company\Module\Products\Support;
class StatusOptions
{
public function options()
{
return [
'draft' => 'Draft',
'published' => 'Published',
];
}
}
Set 'handler' => StatusOptions::class (or its string namespace, depending on the version) in the field config. Confirm the exact method name and return shape against getOptions() in SelectFieldType.php — handlers in Streams addons vary between returning arrays, Collections, or Option objects.
Admin-side configuration. Once the field is assigned, the control panel renders the addon's config form. That is where editors pick options for a field created through the UI. Treat the migration/UI config as the source of truth and keep them in sync; a config edited in the UI is stored with the field, not read from your migration after install.
Twig usage. The raw value prints via {{ entry.status }}. If the addon ships a presenter, {{ entry.status.label }} gives the human label — verify against src/SelectFieldTypePresenter.php before relying on it in templates. For conditionals, compare the raw value: {% if entry.status == 'published' %}.
Validation. Do not assume the field type validates against its own option keys on submit. Attach rules to the assignment:
'config' => [
'options' => [...],
'rules' => ['required', 'in:draft,review,published'],
],
For handler-driven options you will need a custom Rule object, because the valid set is not known at config time.
Cross-field wiring. The stored value is a scalar, so it works cleanly with anomaly/relationship-field_type lookups, query scopes (where('status', 'published')), and Streams' where filters in Twig/query builders. Keep the select for small, stable enums; reach for a relationship field when the option set is large or user-managed.
anomaly/streams-platform in composer.json and treat upgrades as manual work. Read composer.json's version constraint before assuming compatibility with your Streams major version — field types break silently across majors.'1' => 'One' to ['1' => ...] as an integer key. If you store database IDs as option keys, comparisons after retrieval ('1' !== 1) will bite you in Twig and in validation rules. Store a prefixed string key or cast consistently.php artisan streams:compile and php artisan cache:clear. A dropdown that "still shows the old options" is almost always this.dd() inside getOptions() or dump {{ field_type.options|json_encode }} in the view before hunting elsewhere.null or '' depending on the control and config. Normalize before comparing, and decide explicitly whether "no selection" is meaningful in your domain.SelectFieldType.php only as a last resort, and note it in your upgrade checklist if you do.How can I help you explore Laravel packages today?