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

Repeater Field Type Laravel Package

anomaly/repeater-field_type

Repeater field type for the Anomaly Streams platform. Adds a repeatable field that lets editors build multi-row sets of sub-fields, such as lists, feature grids, or FAQ entries, directly in the control panel, with each row saved as structured data on the entry.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Streams Platform (PyroCMS 3.x) field type addon, not a standalone Laravel package. It gives a stream field a repeatable set of sub-fields stored as one serialized value — a lightweight "matrix"/"repeater" without a separate related stream. It is a small, single-purpose addon (1 star, no dependents), so treat it as an internal building block for a Streams project rather than a community-supported library.

Minimal setup inside an existing Streams/PyroCMS project:

composer require anomaly/repeater-field_type
php artisan addon:install anomaly.repeater_field_type
php artisan addon:publish anomaly.repeater_field_type

Then add the field to a stream in a migration (or via the admin Fields UI):

protected $fields = [
    'specs' => [
        'type'   => 'anomaly.field_type.repeater',
        'config' => [
            'fields' => [
                'label' => ['type' => 'anomaly.field_type.text'],
                'value' => ['type' => 'anomaly.field_type.text'],
            ],
        ],
    ],
];

Look first at:

  1. src/RepeaterFieldType.php — how config.fields is read and how the value is (de)serialized.
  2. resources/views/input.twig — the actual row markup and input naming convention.
  3. resources/config/config.php and resources/lang/en/addon.php — defaults and label keys.
  4. The JS asset (resources/js/*) — add/remove-row behavior and any events it emits.

First use case: a page/module stream with a "specs", "links", or "faq" repeater — 3–10 rows of simple scalar fields, rendered in Twig with a for loop and edited inline in the admin form.

Implementation Patterns

Define fields in config, not code. The whole shape of a repeater is the config.fields array. Keys become both the stored row keys and the labels (unless you supply config.label/lang keys), so name them like columns:

'config' => [
    'fields' => [
        'title' => ['type' => 'anomaly.field_type.text', 'config' => ['required' => true]],
        'link'  => ['type' => 'anomaly.field_type.url'],
        'open'  => ['type' => 'anomaly.field_type.boolean', 'config' => ['default_value' => false]],
    ],
],

Prefer the migration/config route over the admin UI: the field definition is then version-controlled with the stream, and code that reads $field->getConfig()['fields'] stays in sync with what the form renders.

Reading values in Twig. The stored value is an ordered list of associative rows, so iterate directly:

{% for spec in entry.specs %}
    <dt>{{ spec.label }}</dt>
    <dd>{{ spec.value }}</dd>
{% endfor %}

Because the rows are not real field-type presenters, nested values arrive as raw stored data — no automatic |nl2br, no presenter formatting, no relation expansion.

Reading values in PHP. Pull the raw array and normalize it yourself before doing anything with it:

$rows = $entry->specs; // array/collection of arrays — dump() before you trust the shape
foreach ($rows as $row) {
    // $row['title'], $row['link'], $row['open']
}

If the addon's presenter decorates rows, property access may work on some versions and not others; a small array_map(fn ($r) => (array) $r, ...) on read is cheap insurance.

Writing values programmatically (seeders, imports, API endpoints). Set the field to a plain array of rows with matching keys, then save the entry:

$entry->fill([
    'specs' => [
        ['label' => 'Weight', 'value' => '1.2 kg'],
        ['label' => 'Warranty', 'value' => '2 years'],
    ],
])->save();

Do not rely on the form layer for this; the form just collects the same array shape.

Building UI outside the default form. $field->getConfig()['fields'] gives you the sub-field definitions, so you can render read-only tables, generate CSV exports, or build an API response by mapping each row through the sub-field types you declared. That is the main "leverage" of this addon: one stream field, many ad-hoc table/list renderings.

Form reuse. The field can be added dynamically with $builder->add('specs', 'anomaly.field_type.repeater', $config) anywhere a Streams form builder is used, including custom admin controllers — useful for settings pages that need a variable-length list without a new stream.

Gotchas and Tips

  • Column size. Repeater values are serialized into a single column (typically text). A few dozen rows of short scalars are fine; hundreds of rows or long text will hit the 64KB MySQL TEXT limit. Use a dedicated related stream/module when the list is unbounded or large.
  • No nested-field validation. Rules declared on sub-fields are not automatically applied to the parent field. Add required/array rules on the repeater field, or validate the array in a form request/validator on save.
  • Orphaned keys on config change. Renaming or removing a key in config.fields leaves old data under the old key. There is no migration for the inner rows — write a one-off script that walks entries and rewrites the array before you change key names.
  • Nested relationship fields are not supported reliably. Sub-fields are instantiated for rendering, but they are not full stream entries; files, relations, and other fields that need an entry/module context often break or store IDs you must resolve manually.
  • Ordering is DOM order. Rows are saved in the order the browser submits them. If you need a persistent sort key, add an explicit order sub-field and sort on read; drag-and-drop depends on whatever JS ships in resources/js.
  • Assets must be published. If add/remove buttons do nothing in the admin UI, run php artisan addon:publish anomaly.repeater_field_type and clear caches (php artisan view:clear, php artisan cache:clear). Check the browser console for 404s on the addon's JS/CSS.
  • Streams caches field definitions. After editing config.fields, rebuild the stream cache (e.g. php artisan streams:compile) or the form will render the old sub-fields.
  • Debugging shape. Always dump($entry->getFieldValue('specs')) versus $entry->specs — the raw value and the presenter may differ. When in doubt, read the raw column with DB::table(...)->value(...) and json_decode it.
  • Extension points are thin. The practical customization surface is: your own config.fields, a custom Twig partial that loops the value, and a custom presenter class if the addon exposes one. For anything more (custom row rendering, reordering UI, conditional sub-fields), expect to fork the addon or build a bespoke field type — it is a 1-star, 0-dependent package with no real maintenance signal, so pin the version and keep a fork ready.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package