anomaly/email-field_type
An email field type for the PyroCMS Streams platform on Laravel, adding a reusable, validated email input to custom fields and entry forms so modules can capture and store addresses consistently.
This is not a standalone Laravel package — it is a PyroCMS 3 / Streams Platform field type. Requiring it into a plain Laravel app gives you nothing but a transitive dependency on anomalylabs/streams-platform. Its entire surface area is: a FieldType class that adds the email validation rule, an input view that renders <input type="email">, and a presenter with a mailto helper.
If you are on PyroCMS 3, you probably already have it — anomaly.field_type.email ships in the default field type set. Verify with:
php artisan addon:list | grep email
php artisan addon:install anomaly.field_type.email # only if missing
Read these three files first, in order — they are the whole package:
src/EmailFieldType.php — $rules, $config, and any getInputView() override.resources/views/input.twig — what actually renders in a form.src/EmailFieldTypePresenter.php — what you can chain in Twig.First use case: add an email field to an existing stream. php artisan make:stream scaffolds a migration with $fields / $assignments arrays; drop this in:
protected $fields = [
'email' => [
'type' => 'anomaly.field_type.email',
'config' => [
'default_value' => null,
],
],
];
protected $assignments = [
'email' => [
'required' => true,
'unique' => true,
],
];
For a stream that already exists, create the field and assignment through Streams → Fields / Assignments in the control panel rather than a migration. Once assigned, the field appears in every form and table builder bound to that stream with no extra wiring.
(continued — first render)
In a form builder the email input comes from the field type's view; in Twig you get the presenter:
{{ contact.email }} {# raw address via __toString #}
{{ contact.email.mailto|raw }} {# <a href="mailto:...">…</a> — note |raw #}
Let the assignment carry the rules, not the type. The field type contributes email. required, unique, nullable, and messages belong in the assignment config — that is where per-stream intent lives, and it is what the form builder reads when it hydrates $rules.
Validation you get for free vs. validation you need to add. The browser-side type="email" catches typos in the UI, and the server-side rule catches API/CLI submissions through the streams repository. What you do not get: MX lookup, disposable-domain blocking, or confirmation matching. Add those as a custom rule in a form handler, e.g. in a FormHandler onSaving/onValidating callback, or as an extra rule passed into the assignment.
Presenter helpers in table builders. Table columns print the raw value. If you want clickable mailtos in the admin listing:
$builder->column('email')->wrapper('<a href="mailto:{value}">{value}</a>');
or use the column value callback for the same effect.
Querying. Nothing special — it is a plain string column, so the streams repository behaves normally:
$leads = $streams->entries('leads')
->where('email', 'like', '%@acme.com')
->get();
Normalising on save. If you care about case ([email protected] vs [email protected]), normalise in your model/form handler rather than in the field type — mutating the addon is a maintenance trap. A Saving hook that calls strtolower() on the attribute is enough, and it keeps the field type interchangeable with a future custom one.
Extension point: subclass, don't patch. If you need a different input view or extra rules, create your own addon field type extending Anomaly\EmailFieldType\EmailFieldType, override $rules or getInputView(), and point the assignment at your type slug. vendor/ edits get wiped by composer update, and PyroCMS's field type collection is discovered from installed addons, so a subclass registers cleanly.
Form-level usage. A FormBuilder bound to the stream picks up the email input and the email rule automatically; you do not hand-write 'email' => 'required|email' unless you are bypassing the Streams UI layer entirely (in which case just do that and skip this package).
anomalylabs addon, so it is stable in the narrow sense that it does one thing; but with 0 dependents and no activity, treat it as frozen. Check its composer.json constraint against your streams-platform version before upgrading PyroCMS — field types break quietly when the platform's FieldType base class signature moves.email rule fails on an empty string. If the field is optional, make sure the assignment is nullable or that your form handler converts '' to null, otherwise you will get spurious "not a valid email" errors on blank submissions.|raw is mandatory for mailto. It returns an HTML anchor; without |raw Twig escapes it and you render a literal <a href=...> string. The same applies inside table builder wrappers, which are not escaped — don't pass user-controlled output through an unescaped wrapper.default_value is static. It is a literal default applied when the field has no value; it is not evaluated per-entry and cannot be computed. For per-entry defaults, use a form handler.php artisan addon:reinstall anomaly.field_type.email, then php artisan view:clear. View cache is the usual culprit after editing input.twig.How can I help you explore Laravel packages today?