anomaly/polymorphic-field_type
Polymorphic field type for the Streams platform that lets a single field reference records from multiple stream models, making relationships flexible and reusable across modules. A practical addition for Laravel projects built on Streams that need dynamic, multi-model references.
Reality check before you install: this addon was last released in August 2015, sits at 0 stars, 0 dependents, and targets the Streams Platform as it existed around PyroCMS 3.0 / Laravel 5.1–5.2. It is effectively abandoned. Treat it as a reference implementation to read and copy rather than a dependency you ship to production on a modern stack.
Install (on a period-correct project):
composer require anomaly/polymorphic-field_type
php artisan addon:install anomaly/polymorphic_field_type
Because the package predates Laravel 5.5 package auto-discovery, you may need to register the service provider manually in config/app.php:
Anomaly\PolymorphicFieldType\PolymorphicFieldTypeServiceProvider::class,
Where to look first:
src/PolymorphicFieldType.php — the field type class. This is where the column type, validation rules, form input, and value accessor live.src/PolymorphicFieldTypeServiceProvider.php — registration, routes, bindings, view namespaces.resources/config/config.php — the field type's configurable options (typically which streams are selectable). This tells you what you can actually put in a stream's field config.resources/views/ — the form input and any display partials you can override per-namespace.resources/lang/ — labels/placeholders, which tell you the intended UX vocabulary.First use case: a "Related Content" field on a Pages stream where an editor can point at either a Blog Post or a Product. Create the field via the admin Streams UI (Fields → Add Field → choose the Polymorphic type), assign it to the stream, then confirm the generated column exists and the form renders before writing any code against it.
Defining the field in a migration/repository. If you manage streams in code rather than through the admin, add the field in your stream migration and pass the addon type slug in snake_case (polymorphic) along with the config the field type expects:
$stream->addField('related', [
'type' => 'anomaly.field_type.polymorphic',
'config' => [
'streams' => ['posts', 'products'], // confirm key name against config.php
],
]);
Read resources/config/config.php before guessing config keys — there is no guaranteed schema documentation and the keys are whatever the 2015 author chose.
Reading values in your own code. Field types typically expose the resolved value through the entry's magic attribute. Always null-check and normalize, because a polymorphic field can legitimately hold zero, one, or many targets across heterogeneous streams:
$related = $entry->related; // may be an array, a collection, or null
foreach ((array) $related as $item) {
// $item may be a Streams entry, an Eloquent model, or a raw id, depending on the implementation
dump($item->getId(), $item->getStreamSlug());
}
Rendering in Twig (PyroCMS):
{% if entry.related is not empty %}
<ul>
{% for item in entry.related %}
<li><a href="{{ item.route('view') }}">{{ item.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
The value returned by a polymorphic field is not guaranteed to have a route('view'); guard per stream or render a generic link.
Saving from a custom form. If you bypass the Streams form builder, don't hand-roll the write. Use the field type's own handling path ($fieldType->setEntry($entry)->setValue($input), or simply save through the entry repository) so the storage format matches what the accessor expects. Writing raw ids into the column is the fastest way to produce a field that renders fine but reads as empty.
Integration tips:
$entry->presenter()->relatedItems()) so the day the package is replaced, you only edit one class.morphTo / morphMany instead. That's a first-class, maintained feature and covers the same ground for model-level work.FieldType base class API all changed after 2015. Expect fatal errors on install before you write a single line. Check composer.json for the actual illuminate/* and Streams version constraints.src/ directory — it's small enough to audit in twenty minutes, which is the right move.stream:id pairs. Everything downstream (queries, search, eager loading) depends on it, and there are no foreign keys protecting you from orphaned references when a target entry is deleted.'', '[]', or null inconsistently depending on the path taken.php artisan view:clear, php artisan cache:clear, and the Streams compile command if present in your version). Stale compiled field type classes make it look like your edits did nothing.PolymorphicFieldType to change validation or presentation. Given the package's age, subclassing is safer than editing vendor/ — but if you find yourself subclassing heavily, you've written the replacement already.morphTo relations or a purpose-built field type you control.How can I help you explore Laravel packages today?