Search by

contenir / contenir-formbuilder

peptolab

Framework-agnostic form-builder engine for Contenir CMS — runtime-editable form definitions, builder-form construction, server-side submission validation.

Package info

github.com/contenir/contenir-formbuilder

pkg:composer/contenir/contenir-formbuilder

Statistics

Installs: 436

Dependents: 3

Suggesters: 0

Stars: 0

Open Issues: 0

v2.2.0 2026-10-05 20:09 UTC

README

Formerly contenir/formbuilder; the old package is abandoned in favour of this one.

Continuous Integration codecov

Framework-agnostic form-builder engine for Contenir CMS.

It turns a runtime-editable form definition (sections, groups, rows and fields, usually stored in a database) into a working Laminas\Form\Form, validates submissions against it, and renders the markup:

  • Definitions. Immutable value objects describing a form, its layout, notifications and webhooks.
  • Field types. 17 built-in types behind a registry you can extend.
  • Validators. A small curated vocabulary mapped onto Laminas validators.
  • Conditional logic. Show/hide rules evaluated on the server (and mirrored by the client).
  • Submission. CSRF, a honeypot spam trap, conditional gating, optional file uploads through contenir/contenir-storage, and observers (registrars) that persist or forward the result.
  • Rendering. Framework-free HTML for single-page or stepped forms.
  • Merge tags. {field:name}, {form:title}, {entry:fields} and custom namespaces for notification templates and redirect URLs.

This is the pure-PHP core. It has no opinion about how definitions are loaded or how submissions are stored. contenir/contenir-formbuilder-laminas-mvc wires it into a laminas-mvc application.

Requirements

  • PHP 8.3, 8.4 or 8.5
  • laminas-form 3.20+, laminas-inputfilter, laminas-validator, laminas-filter
  • laminas-session (backs the CSRF token)
  • ext-curl for webhooks
  • Optional: contenir/contenir-storage for the file field type

Installation

composer require contenir/contenir-formbuilder

The 0.x releases, which support PHP 8.1, remain available from the 0.x branch and v0.* tags; see UPGRADE-2.0.md.

Usage

use Contenir\FormBuilder\Definition\FieldDefinition;
use Contenir\FormBuilder\Definition\FormDefinition;
use Contenir\FormBuilder\Definition\GroupDefinition;
use Contenir\FormBuilder\Definition\RowDefinition;
use Contenir\FormBuilder\Definition\SectionDefinition;
use Contenir\FormBuilder\FieldType\FieldTypeRegistry;
use Contenir\FormBuilder\Registrar\WebhookRegistrar;
use Contenir\FormBuilder\Render\FormMarkup;
use Contenir\FormBuilder\Service\FormBuilderService;
use Contenir\FormBuilder\Service\FormSubmissionService;
use Contenir\FormBuilder\Validator\ValidatorFactory;

$definition = new FormDefinition(
    id: 1,
    slug: 'contact',
    title: 'Contact us',
    submitLabel: 'Send',
    sections: [new SectionDefinition(id: 1, key: 'main', groups: [
        new GroupDefinition(id: 1, rows: [new RowDefinition(id: 1, fields: [
            new FieldDefinition(id: 1, type: 'text', name: 'name', label: 'Name', required: true),
            new FieldDefinition(id: 2, type: 'email', name: 'email', label: 'Email', required: true),
        ])]),
    ])],
);

$builder = new FormBuilderService(new FieldTypeRegistry(), new ValidatorFactory());

// GET: render the form
$form = $builder->build($definition);
echo (new FormMarkup())->render($definition, $form);

// POST: validate and dispatch
$service = new FormSubmissionService($builder);
$service->attach(new WebhookRegistrar($logger));
$result = $service->submit($definition, $_POST, $_FILES, ['ip' => $_SERVER['REMOTE_ADDR'] ?? null]);

if ($result->valid) {
    // $result->values, $result->entryId
} elseif ($result->isSpam) {
    // answer as if it succeeded
} else {
    echo (new FormMarkup())->render($definition, $result->form); // with errors
}

The full public API is described in docs/:

Page Covers
Definitions FormDefinition, sections, groups, rows, fields, validators, notifications, webhooks
Field types The built-in types, FieldTypeRegistry, writing your own type
Validators ValidatorFactory vocabulary and options
Conditional logic RuleEvaluator, ConditionalRulesParser
Building and submitting FormBuilderService, FormSubmissionService, SubmissionResult, BuilderForm, observers, uploads
Rendering FormMarkup, FormContentSanitizer
Merge tags TokenReplacer
Webhooks WebhookRegistrar

Development

The QA toolchain is php-db/phpdb-qa-tools. Mago is a standalone binary, installed separately (brew install mago).

composer check             # everything below
composer cs-check          # mago format --check && mago lint
composer static-analysis   # mago analyze
composer test              # unit suite: no I/O, no session, no network
composer test-integration  # integration suite: in-memory session, temp files, a local HTTP server
composer test-coverage     # both suites, clover.xml for Codecov
composer mutation-test     # Infection over both suites (needs Xdebug or PCOV)

The webhook integration tests start PHP's built-in web server on a free loopback port.

License

MIT. See LICENSE.