Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Multiple Field Type Laravel Package

anomaly/multiple-field_type

Anomaly Multiple Field Type adds a repeatable, multi-value field type to the Streams Platform for Laravel. It lets developers collect multiple entries of a chosen field type, enabling flexible content models and cleaner admin forms without custom code.

View on GitHub
Deep Wiki
Context7

Getting Started

anomaly/multiple-field_type is an addon for the Streams Platform (the data layer behind PyroCMS) that lets you bundle several field types under a single field slug — an "address" field made of street, city, postcode, country, for example. It is not a standalone Laravel package: it is one field type among many, and it only does anything inside a Streams-enabled app.

Minimal setup:

composer require anomaly/multiple-field_type
php artisan addon:install anomaly/multiple_field_type

You need anomaly/streams-platform already installed and a working streams migration set. The addon auto-registers its service provider in PyroCMS; in a bare Laravel + Streams app, check config/app.php or the addon manifest (anomaly/multiple-field_type in the addon registry) and run php artisan addon:publish anomaly.multiple_field_type if you want to override views.

Where to look first, in this order:

  1. src/MultipleFieldType.php — the field type class; confirm the $name, $category, and how it reads its configuration.
  2. resources/config/configuration.php — the config schema you'll be filling in when you assign the field.
  3. resources/views/ — the form input and the presenter/display view; this tells you exactly what shape the stored value has.
  4. resources/lang/ — labels and instructions, useful for knowing what the CP form expects.

The first use case to build: a profile or address field on an existing stream that groups three or four scalar sub-fields. Assign it via the control panel (Streams → Fields → New Field, type multiple) or in a migration, then render it in a view. That exercises the whole path — config → form → storage → presenter — before you lean on it for anything structural.

Implementation Patterns

Assigning via migration is the pattern you'll actually live with, because CP assignments don't survive environment promotion:

$this->assignments()->create([
    'stream_id'   => $stream->id,
    'namespace'   => 'anomaly.module.users',
    'slug'        => 'address',
    'field_type'  => 'anomaly.field_type.multiple',
    'config'      => [
        'fields' => [
            ['slug' => 'street',  'field_type' => 'anomaly.field_type.text'],
            ['slug' => 'city',    'field_type' => 'anomaly.field_type.text'],
            ['slug' => 'country', 'field_type' => 'anomaly.field_type.select',
             'config' => ['options' => ['us' => 'US', 'uk' => 'UK']]],
            ['slug' => 'postcode', 'field_type' => 'anomaly.field_type.text',
             'required' => true],
        ],
    ],
]);

The fields key is an array of assignments, not just slugs — each entry can carry its own config, required, instructions, and rules. Treat this array as the schema. If you're building a reusable addon, define it in a config/fields.php-style array and loop.

Reading values. The field returns a structured value keyed by sub-field slug, so day-to-day access looks like:

$entry->address;                    // array/collection of sub-values
$entry->address['city'] ?? null;
$entry->address->get('postcode');

Confirm the exact return shape in the field type's getValue() / presenter before you write accessors — some versions return an AssignmentCollection-backed array, others a plain array. Wrap it once in a model accessor or presenter method so the rest of your app doesn't care:

public function getFullAddressAttribute()
{
    $a = $this->address ?: [];
    return trim(implode(', ', array_filter([
        $a['street'] ?? null, $a['city'] ?? null, $a['postcode'] ?? null,
    ])));
}

Form integration. Use it like any other field in a Streams form: $form->addForm('entry', 'anomaly.module.x::entries.form') with the assignment present, or drop {{ form.field('address').input|raw }} into a custom view. The sub-fields render inside the parent's markup, so style them by targeting the nested input names (address[city]) rather than assuming flat name="city".

Pairing with repeaters. The most valuable composition is multiple-field-type inside a repeater (or repeater-inside-multiple) for things like line items. Keep the nesting one level deep; deeper combinations get brittle fast and the CP form becomes hard to validate.

Validation. Per-sub-field rules in the assignment config are enforced on the parent field. For anything conditional ("postcode required if country is US"), add a form request or a FormBuilder event listener that reaches into the array — don't try to express it in the config.

API/resource output. Because the value is already structured, serialise it directly rather than flattening: 'address' => $entry->address survives client-side changes better than a concatenated string.

Gotchas and Tips

  • This package is effectively unmaintained. Zero stars, zero dependents, and the Anomaly/Streams ecosystem has been quiet for years. It works, but pin it in composer.json, commit your composer.lock, and be prepared to fork. If you're starting fresh on Laravel 10/11, audit whether it even installs — the Streams Platform core is the real compatibility constraint, not this addon.
  • The config column is your schema, and it's JSON. Renaming a sub-field slug silently orphans the stored data. Add and deprecate; don't rename. Write a migration for any slug change that copies old keys to new ones across the stream's entries table.
  • Sub-field slugs must be unique within the parent and snake_case. Collisions with sibling top-level assignments are a common source of "the form renders but the value is empty."
  • Empty state is ambiguous. A freshly created entry may give you null, [], or an array of nulls depending on code path. Always ?: [] before array access; don't rely on isset($entry->address['city']) alone.
  • Validation doesn't cascade the way you expect. required on a sub-field generally means the parent is required if any sub-field is filled, not that every sub-field must be filled. Test the empty-form submission explicitly.
  • Debugging. When a field misbehaves, check three things in order: the row in streams_fields (is field_type correct and is config valid JSON?), the addon registration (php artisan addon:list), and whether the view is cached (php artisan view:clear). Nine times out of ten it's a malformed fields array in config.
  • Override the views, don't patch the package. Publish to resources/views/vendor/... for markup changes; the package's own views are the display contract and you'll want them intact for reference.
  • Extension points are narrow: a custom sub-field type (any registered Streams field type works inside it), the published form/display views, and the presenter. There's no documented event pipeline specific to this addon — if you need one, hook the Streams form/entry events at the platform level instead.
  • Translations. Sub-field labels come from each nested assignment's name/instructions, not from this addon's lang files. If you're shipping a multi-language CP, set those on the nested config, or the CP falls back to humanised slugs.
  • When not to use it. If the grouping is fixed and you control the schema, four separate top-level assignments are simpler to query, validate, and index. Reach for multiple when the set of sub-fields is variable or when you're building a generic addon that composes other people's field types — that's the problem it was designed for.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels