visiosoft/multiple-field_type
A field type addon for the Streams platform that adds a Multiple field type, letting you store and manage several values within a single field so editors can select or enter multiple items without extra scaffolding. A small convenience for Streams-based Laravel applications.
Minimal setup:
composer require visiosoft/multiple-field_typecomposer dump-autoload so the Streams Platform discovers the addon.php artisan addon:list (or the Addons page in the control panel). If the form UI renders but repeat rows don't work, run php artisan publish:assets.Where to look first:
src/MultipleFieldType.php — input/output, getValue()/setValue(), modifier/column type.src/*Presenter.php) — how stored rows are exposed to views/twig.resources/config/configuration.php — the config schema (fields, min, max, and any per-row options).resources/views/ — input/form rendering for the repeatable group.Typical stream field config (verify the exact fields shape against your installed version):
'type' => 'visiosoft.field_type.multiple',
'config' => [
'min' => 1,
'max' => null, // unlimited
'fields' => [
['handle' => 'label', 'type' => 'anomaly.field_type.text'],
['handle' => 'url', 'type' => 'anomaly.field_type.url'],
],
],
Assign via migrations/streams: $stream->addField('contacts', ['type' => 'visiosoft.field_type.multiple', 'config' => $config]). The type slug is the field-type slug; namespace-qualify if the registry requires it.
Raw access: $entry->contacts returns the JSON-decoded array/collection of row objects — handy for API resources and exports.
Presenter access: sub-field handles become properties on the row, resolved through the underlying field type's presenter: $entry->presenter()->contacts->first()->label.
Twig iteration:
{% for contact in entry.contacts %}
<a href="{{ contact.url }}">{{ contact.label }}</a>
{% endfor %}
Forms: the field type delegates each sub-field to its registered field type, so any installed field type addon can be used as a row member. Keep handles unique — they become array keys in stored JSON.
Validation: sub-field rules are defined per row; if you validate manually, use wildcard rules like multiple.*.url.url and multiple.*.label.required.
Programmatic writes: $entry->contacts = [['label' => 'Home', 'url' => 'https://…']] then save(). Prefer this over composing JSON by hand.
Seeding: useful for shipping structured defaults (e.g., default spec rows) alongside the stream definition.
Custom sub-fields: installing additional field type addons automatically makes them available inside the group — this is the main extension point.
where(); filter in PHP after hydration, or mirror hot fields into real columns on the stream.configuration.php in your installed version instead of trusting online examples.composer.lock, test upgrades, and don't assume forward compatibility.min/max are enforced at form/validation level, not the database. Add server-side validation if the data matters.dd($field->getValue()) or log $entry->contacts to see the raw stored JSON; inspect the config/value columns on streams_fields/streams_assignments when the form misbehaves.php artisan publish:assets.resources/views/* for custom layouts; extend the presenter in your own service provider for derived accessors (e.g., primaryContact).How can I help you explore Laravel packages today?