PHPackages                             mindplay/kissform - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. mindplay/kissform

ActiveLibrary[Validation &amp; Sanitization](/categories/validation)

mindplay/kissform
=================

Model-driven form rendering and input validation

0.3.4(8y ago)413.6k2[2 issues](https://github.com/mindplay-dk/kissform/issues)MITPHPPHP &gt;=5.5

Since May 14Pushed 8y ago3 watchersCompare

[ Source](https://github.com/mindplay-dk/kissform)[ Packagist](https://packagist.org/packages/mindplay/kissform)[ RSS](/packages/mindplay-kissform/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (6)Dependencies (3)Versions (8)Used By (0)

mindplay/kissform
=================

[](#mindplaykissform)

Model-driven form rendering and input validation.

[![PHP Version](https://camo.githubusercontent.com/5f0c3c8d952d50a65a0e14d33d6a368f80eed503b2f95d15e93d845edd0776bd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d352e352532422d626c75652e737667)](https://packagist.org/packages/mindplay/kissform)[![Build Status](https://camo.githubusercontent.com/c2bdadc1603fe5d17e6b40e2c149cbc68703d1bdb70aac2a3b9f93b9271bea11/68747470733a2f2f7472617669732d63692e6f72672f6d696e64706c61792d646b2f6b697373666f726d2e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/mindplay-dk/kissform)[![Code Coverage](https://camo.githubusercontent.com/ee99615882f6d6fb2942e775cd4bec5c3352a54bc1fc8ab4dd61154f30d0bb9b/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6d696e64706c61792d646b2f6b697373666f726d2f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/mindplay-dk/kissform/?branch=master)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/ba629fb80cf176bb65daf0ef1047593801e8f82a4e205faed4f6c2669d71896f/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6d696e64706c61792d646b2f6b697373666f726d2f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/mindplay-dk/kissform/?branch=master)

Model-driven means it's driven by models - that means, step one is building a model that describes details of the rendered inputs on the form, and how the input gets validated.

Model-driven in this library does *not* mean "baked into your domain model", it means building a dedicated model describing aspects of form input/output.

Concepts
--------

[](#concepts)

The library consists of the following types, with the following responsibilities:

- **`Field`** classes describe the possible input elements on a form - what they are, what they look like, and how they behave; *not* their state.
- **`InputModel`** contains the state of the form - the values in the input elements and any error-messages. This is a thin wrapper around raw `$_GET`or `$_POST` data, combined with error state - it can be serialized, which means you can safely store it in a session variable.
- **`InputRenderer`** renders HTML elements (basic inputs, labels, etc.) and/or delegates more complex rendering to `Field` instances - it provides fields with an `InputModel` instance (form values and errors) at the time of rendering.
- **`InputValidation`** manages the validation process by running validators against fields.
- **`ValidatorInterface`** defines the interface of validator types, which implement validation logic for e.g. e-mail addresses, numbers, date/time, etc.

Most `Field` types are capable of producing some built-in validators - these can be created and checked by calling `InputValidation::check()`. For example, setting the `$min_length` property of a `TextField` will cause it to create a `CheckMinLength` validator.

This design is based on the idea that there are no overlapping concerns between form rendering and input validation - one is about output, the other is about input.

Assuming you use [PRG](http://en.wikipedia.org/wiki/Post/Redirect/Get), when the form is rendered initially, there is no user input, thus nothing to validate; if the form fails validation, the validation occurs during a POST request, and the actual form rendering occurs during a separate GET request. In other words, form rendering and validation never actually occur during the same request.

Usage
-----

[](#usage)

A basic form model might look like this:

```
class UserForm
{
    /** @var TextField */
    public $first_name;

    /** @var TextField */
    public $last_name;

    public function __construct()
    {
        $this->first_name = new TextField('first_name');
        $this->first_name->setLabel('First Name');
        $this->first_name->setRequired();

        $this->last_name = new TextField('last_name');
        $this->last_name->setLabel('Last Name');
        $this->last_name->setRequired();
    }
}
```

Use the model to render form inputs:

```
$form = new InputRenderer(@$_POST['user'], 'user');

$t = new UserForm();

?>

```

Reuse the form model to validate user input:

```
$model = InputModel::create($_POST['user']);

$validator = new InputValidation($model);

$validator->check([$t->first_name, $t->last_name]);

if ($model->isValid()) {
    // no errors!
} else {
    var_dump($model->errors); // returns e.g. array("first_name" => "First Name is required")
}
```

Note that only one error is recorded per field - the first one encountered.

Once the input has passed validation, you can extract values from the individual fields:

```
$first_name = $form->first_name->getValue($model);
$last_name = $form->last_name->getValue($model);
```

To implement editing of existing data with a form, you can also inject state into the form model:

```
$form->first_name->setValue($model, "Rasmus");
$form->last_name->setValue($model, "Schultz");
```

Note that the `getValue()` and `setValue()` methods of every `Field` type are type-aware - for example, the `IntField` returns `int`, `CheckboxField` returns `bool`, and so on.

Only valid values of the appropriate types can be exchanged with Fields in this manner - if you need access to possiby-invalid, raw input-values, use the `getInput()` and `setInput()` methods of `InputModel` instead.

This demonstrates the most basic patterns - please see the [demo](examples/demo.php) for a working example of the post/redirect/get cycle and CSRF protection.

Other Features
--------------

[](#other-features)

This library has other expected and useful features, including:

- Comes preconfigured with Bootstrap class-names as defaults, because, why not.
- Adds `class="has-error"` to inputs that have an error message.
- Adds `class="is-required"` to inputs that are required.
- Creates `name` and `id` attributes, according to really simple rules, e.g. prefix/suffix, no name mangling or complicated conventions to learn.
- Field titles get reused, e.g. between `` tags and error messages, but you can also customize displayed names in error messages, if needed.
- Default error messages can be localized/customized.
- A basic error-summary can be generated with `InputRenderer::errorSummary()`.

It deliberately does not implement any of the following:

- Trivial elements: things like ``, `` and `` - you don't need code to help you create these simple tags, just type them out; your templates will be easier to read and maintain.
- Form layout: there are too many possible variations, and it's just HTML, which is really easy to do in the first place - it's not worthwhile.
- A plugin architecture: you don't need one - just use everyday OO patterns to solve problems like a thrifty programmer. Extend the renderer and validator as needed for your business/project/module/scenario/model, etc.

This library is a tool, not a silver bullet - it does as little as possible, avoids inventing complex concepts that can describe every detail, and instead deals primarily with the repetitive/error-prone stuff, and gets out of your way when you need it to.

There is very little to learn, and nothing needs to fit into a "box" - there is little "architecture" here, no "plugins" or "extensions", mostly just simple OOP.

You can/should extend the form renderer with your application-specific input types, and more importantly, extend that into model/case-specific renderers - it's just one class, so apply your OOP skills for fun and profit!

### Why input validation, as opposed to (domain) model validation?

[](#why-input-validation-as-opposed-to-domain-model-validation)

- Because domain validation is usually specific to a scenario - you might as well do it with simple if-statements in a controller or service, and then manually add errors to the validator.
- Because input validation is simpler - it's just one class, and you can/should extend the class with case-specific validations, since you're often going to have validations that pertain to only one scenario/model/case. Bulding reusable domain validation rules as components would be a lot more complicated - many of these would be applicable to only on scenario/case and would never actually get reused, so they don't even benefit from this complexity.
- There are simple scenarios in which a domain model isn't even useful, such as contact or comment forms, etc.

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance10

Infrequent updates — may be unmaintained

Popularity25

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 94.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~171 days

Recently: every ~164 days

Total

7

Last Release

2995d ago

PHP version history (2 changes)0.1.0PHP &gt;=5.3.0

0.2.0PHP &gt;=5.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/9445f567f43ee7a963270651e40e533634586f959e4df3d5398d001b1cb49be8?d=identicon)[mindplay.dk](/maintainers/mindplay.dk)

---

Top Contributors

[![mindplay-dk](https://avatars.githubusercontent.com/u/103348?v=4)](https://github.com/mindplay-dk "mindplay-dk (32 commits)")[![boan-jfm](https://avatars.githubusercontent.com/u/13201214?v=4)](https://github.com/boan-jfm "boan-jfm (1 commits)")[![thomasnordahl-dk](https://avatars.githubusercontent.com/u/5709900?v=4)](https://github.com/thomasnordahl-dk "thomasnordahl-dk (1 commits)")

###  Code Quality

TestsCodeception

### Embed Badge

![Health badge](/badges/mindplay-kissform/health.svg)

```
[![Health](https://phpackages.com/badges/mindplay-kissform/health.svg)](https://phpackages.com/packages/mindplay-kissform)
```

###  Alternatives

[webmozart/assert

Assertions to validate method input/output with nice error messages.

7.6k894.0M1.2k](/packages/webmozart-assert)[bensampo/laravel-enum

Simple, extensible and powerful enumeration implementation for Laravel.

2.0k15.9M104](/packages/bensampo-laravel-enum)[swaggest/json-schema

High definition PHP structures with JSON-schema based validation

48612.5M73](/packages/swaggest-json-schema)[stevebauman/purify

An HTML Purifier / Sanitizer for Laravel

5325.6M19](/packages/stevebauman-purify)[ashallendesign/laravel-config-validator

A package for validating your Laravel app's config.

217905.3k5](/packages/ashallendesign-laravel-config-validator)[crazybooot/base64-validation

Laravel validators for base64 encoded files

1341.9M8](/packages/crazybooot-base64-validation)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
