PHPackages                             popphp/pop-form - 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. popphp/pop-form

ActiveLibrary

popphp/pop-form
===============

Pop Form Component for Pop PHP Framework

4.2.6(6mo ago)1317.7k↑106.3%32BSD-3-ClausePHPPHP &gt;=8.3.0CI passing

Since Jul 23Pushed 6mo ago1 watchersCompare

[ Source](https://github.com/popphp/pop-form)[ Packagist](https://packagist.org/packages/popphp/pop-form)[ Docs](https://github.com/popphp/pop-form)[ RSS](/packages/popphp-pop-form/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (7)Versions (70)Used By (2)

pop-form
========

[](#pop-form)

[![Build Status](https://github.com/popphp/pop-form/workflows/phpunit/badge.svg)](https://github.com/popphp/pop-form/actions)[![Coverage Status](https://camo.githubusercontent.com/a18c537935e1a2270c050a33a7b820e4613d46224174b175147f851be29db63e/687474703a2f2f63632e706f707068702e6f72672f636f7665726167652e7068703f636f6d703d706f702d666f726d)](http://cc.popphp.org/pop-form/)

[![Join the chat at https://discord.gg/TZjgT74U7E](https://camo.githubusercontent.com/acad7b0eeb78b78d08ffd2b85681ab243436388b5f86f8bcb956a69246e53739/68747470733a2f2f6d656469612e706f707068702e6f72672f696d672f646973636f72642e737667)](https://discord.gg/TZjgT74U7E)

- [Overview](#overview)
- [Install](#install)
- [Quickstart](#quickstart)
- [Field Elements](#field-elements)
- [Field Configurations](#field-configurations)
    - [Fieldsets](#fieldsets)
    - [Legends](#legends)
- [Field Containers](#field-containers)
- [Filtering](#filtering)
- [Validation](#validation)
- [Dynamic Fields](#dynamic-fields)
- [ACL Forms](#acl-forms)

Overview
--------

[](#overview)

`pop-form` is a robust component for managing, rendering and validating HTML forms. With it, you can have complete control over how a form looks and functions as well as granular control over field validation. Features include:

- Field element creation and configuration
- Validation
    - Use any callable validation object, such as `pop-validator` or custom validators
- Filtering
- Dynamic field generation based on the fields of a database table

`pop-form`is a component of the [Pop PHP Framework](https://www.popphp.org/).

[Top](#pop-form)

Install
-------

[](#install)

Install `pop-form` using Composer.

```
composer require popphp/pop-form

```

Or, require it in your composer.json file

```
"require": {
    "popphp/pop-form" : "^4.2.6"
}

```

[Top](#pop-form)

Quickstart
----------

[](#quickstart)

The most basic way to wire up a form object is through a simple configuration.

```
use Pop\Form\Form;

$fields = [
    'username' => [
        'type'     => 'text',
        'label'    => 'Username:',
        'required' => true
    ],
    'email' => [
        'type'  => 'email',
        'label' => 'Email:'
    ],
    'submit' => [
        'type'  => 'submit',
        'value' => 'SUBMIT'
    ]
];

$form = Form::createFromConfig($fields);

if ($_POST) {
    $form->setFieldValues($_POST);
    if (!$form->isValid()) {
        echo $form; // Has errors
    } else {
        echo 'Valid!';
    }
} else {
    echo $form;
}
```

The form rendered will look like:

```

                Username:

                Email:

```

Upon submit, if the form values do not pass validation, the form will re-render with the errors (note the error `div` under the username field):

```

                Username:

                This field is required.

                Email:

```

The form object will default to `POST` as the method and the current `REQUEST_URI`as the action, but those values can be changed in a number of ways:

```
$form = new Form($fields, , '/form-action', 'GET');
```

```
$form = Form::createFromConfig($fields, '/form-action', 'GET');
```

```
$form->setMethod('GET')
    ->setAction('/form-action');
```

[Top](#pop-form)

Field Elements
--------------

[](#field-elements)

A form can be wired up by interfacing directly with form element objects and the form object itself.

```
use Pop\Form\Form;
use Pop\Form\Element\Input;
use Pop\Validator;

$form = new Form();
$form->setAttribute('id', 'my-form');

$username = new Input\Text('username');
$username->setLabel('Username:')
    ->setRequired(true)
    ->setAttribute('size', 40)
    ->addValidator(new Validator\AlphaNumeric());

$email = new Input\Email('email');
$email->setLabel('Email:')
    ->setRequired(true)
    ->setAttribute('size', 40);

$submit = new Input\Submit('submit', 'SUBMIT');

// Add a single field
$form->addField($username);

// Add multiple fields
$form->addFields([$email, $submit]);

if ($_POST) {
    $form->setFieldValues($_POST);
    if (!$form->isValid()) {
        echo $form; // Has errors
    } else {
        echo 'Valid!';
    }
} else {
    echo $form;
}
```

There are number of different concepts happening in the above example:

1. We created the form object and gave it an `id` attribute.
2. We created the individual field elements setting their name, label, attributes, validators, etc.
3. We added the field elements to the form object.
4. We checked for a `$_POST` submission. If not detected, we just render the form for the first time.
5. If a `$_POST` submission is detected:
    1. Set the field values with the values in the $\_POST array (a bad idea without any [filtering](#filtering))
    2. Check if the form object passes validation. If not, re-render the form with the errors. If it does pass, then you're good to go.

On the first pass, the form will render like this:

```

                Username:

                Email:

```

If it fails validation, it will render with the errors. In this case, the username was not alphanumeric:

```

                Username:

                The value must only contain alphanumeric characters.

                Email:

```

[Top](#pop-form)

Field Configurations
--------------------

[](#field-configurations)

We can do the same thing as above with a field configuration array, which helps streamline the process:

```
use Pop\Form\Form;
use Pop\Validator;

$fields = [
    'username' => [
        'type'       => 'text',
        'label'      => 'Username:',
        'required'   => true,
        'attributes' => [
            'size' => 40
        ],
        'validators' => [
            new Validator\AlphaNumeric()
        ]
    ],
    'email' => [
        'type'       => 'email',
        'label'      => 'Email:',
        'required'   => true,
        'attributes' => [
            'size' => 40
        ]
    ],
    'submit' => [
        'type'  => 'submit',
        'value' => 'SUBMIT'
    ]
];

$form = Form::createFromConfig($fields);
$form->setAttribute('id', 'my-form');

if ($_POST) {
    $form->setFieldValues($_POST);
    if (!$form->isValid()) {
        echo $form; // Has errors
    } else {
        echo 'Valid!';
    }
} else {
    echo $form;
}
```

[Top](#pop-form)

### Fieldsets

[](#fieldsets)

Multiple fieldset configurations can be used to generate a larger form with more organized elements. This requires the config to contain multiple arrays of field configurations:

```
use Pop\Form\Form;

$fields = [
    [
        'username' => [
            'type'       => 'text',
            'label'      => 'Username:',
            'required'   => true,
        ],
        'email' => [
            'type'       => 'email',
            'label'      => 'Email:',
            'required'   => true,
        ],
        'submit' => [
            'type'  => 'submit',
            'value' => 'SUBMIT'
        ]
    ],
    [
        'first_name' => [
            'type'  => 'text',
            'label' => 'First Name:',
        ],
        'last_name' => [
            'type'  => 'text',
            'label' => 'Last Name:',
        ],
    ],
    [
        'submit' => [
            'type'  => 'submit',
            'value' => 'SUBMIT'
        ]
    ]
];

$form = Form::createFromFieldsetConfig($fields);
```

Which produces the following HTML with the appropriate `fieldset` grouping:

```

                Username:

                Email:

                First Name:

                Last Name:

```

[Top](#pop-form)

### Legends

[](#legends)

If you'd like to label each of the multiple fieldsets, that can be done by using `legend` values as the array keys in the config:

```
use Pop\Form\Form;

$fields = [
    'Account Info' => [
        'username' => [
            'type'       => 'text',
            'label'      => 'Username:',
            'required'   => true,
        ],
        'email' => [
            'type'       => 'email',
            'label'      => 'Email:',
            'required'   => true,
        ],
        'submit' => [
            'type'  => 'submit',
            'value' => 'SUBMIT'
        ]
    ],
    'Personal Info' => [
        'first_name' => [
            'type'  => 'text',
            'label' => 'First Name:',
        ],
        'last_name' => [
            'type'  => 'text',
            'label' => 'Last Name:',
        ],
    ],
    [
        'submit' => [
            'type'  => 'submit',
            'value' => 'SUBMIT'
        ]
    ]
];

$form = Form::createFromFieldsetConfig($fields);
```

Which produces the following HTML with the appropriate `fieldset` grouping:

```

        Account Info

                Username:

                Email:

        Personal Info

                First Name:

                Last Name:

```

[Top](#pop-form)

Field Containers
----------------

[](#field-containers)

The default fieldset HTML containers for the form elements is a combination of `dl`, `dt` and `dd` tags. If alternate container tags are needed, you can set them like these examples below.

##### Using `table`:

[](#using-table)

```
$form = Form::createFromConfig($fields, 'table');
```

```

                    Username:

                    Email:

```

##### Using `div` (or any other single element container):

[](#using-div-or-any-other-single-element-container)

```
$form = Form::createFromConfig($fields, 'div');
```

```

            Username:

            Email:

```

[Top](#pop-form)

Filtering
---------

[](#filtering)

As mentioned above, when dealing user-submitted values, it's a bad idea to use them or display them back on the screen without filtering them. A common set a filters to employ would be `strip_tags` and `htmlentities`. So in the first example, we would add filters to the $\_POST block:

```
use Pop\Filter\Filter;

/** ... Code to create form **/

if ($_POST) {
    $form->addFilter(new Filter('strip_tags'))
         ->addFilter(new Filter('htmlentities', [ENT_QUOTES, 'UTF-8']));
    $form->setFieldValues($_POST);
    if (!$form->isValid()) {
        echo $form; // Has errors
    } else {
        $form->clearFilters();
        $form->addFilter(new Filter('html_entity_decode', [ENT_QUOTES, 'UTF-8']));
        echo 'Valid!';
    }
} else {
    echo $form;
}
```

Of course, the `strip_tags` filter will strip out any possible malicious tags. The `htmlentities`filter is useful if the form has to render with the values in it again:

```

```

Without the `htmlentities` filter, the quotes within the value would break the HTML of the input field. Of course, if you want to use the values after the form is validated, then you have to call `clearFilters()`and filter the values with `html_entity_decode`.

[Top](#pop-form)

Validation
----------

[](#validation)

Of course, one of the main reasons for using a form component such as this one is the leverage the validation aspect of it. You've already seen the use of a basic validator from the `pop-validator`component and those are easy enough to use. But, you can create your own custom validators by either extending the `pop-validator` component with your own or just writing your own custom callable validators. The only real rule that needs to be followed is that the custom validator must return null on success or a string message on failure that is then used in error display. Here are some examples:

##### Using a closure

[](#using-a-closure)

```
$username = new Input\Text('username');
$username->addValidator(function ($value) {
    if (strlen($value) < 6) {
        return 'The username value must be greater than or equal to 6.';
    }
});
```

##### Using a validator

[](#using-a-validator)

```
use Pop\Validator\AlphaNumeric;

$username = new Input\Text('username');
$username->addValidator(new AlphaNumeric());
```

##### Using a custom class

[](#using-a-custom-class)

```
class MyValidator
{
    public function validate($value)
    {
        if (strlen($value) < 6) {
            return 'The username value must be greater than or equal to 6';
        }
    }
}

$username = new Input\Text('username');
$username->addValidator([new MyValidator(), 'validate']);
```

##### Validation-only forms

[](#validation-only-forms)

There is a `FormValidator` class that is available for only validating a set of field values. The benefit of this feature is to not be burdened with the concern of rendering an entire form object, and to only return the appropriate validation messaging. This is useful for things like API calls, where the form rendering might be handled by another piece of the application (and not the PHP server side).

```
use Pop\Form\FormValidator;
use Pop\Validator;

$validators = [
    'username' => new Validator\AlphaNumeric(),
    'password' => new Validator\LengthGte(6)
];

$form = new FormValidator($validators);
$form->setValues([
    'username' => 'admin$%^',
    'password' => '12345'
]);

if (!$form->validate()) {
    print_r($form->getErrors());
}
```

If the field values are bad, the `$form->getErrors()` will return an array of errors like this:

```
Array
(
    [username] => Array
        (
            [0] => The value must only contain alphanumeric characters.
        )

    [password] => Array
        (
            [0] => The value length must be greater than or equal to 6.
        )

)

```

[Top](#pop-form)

Dynamic Fields
--------------

[](#dynamic-fields)

The `pop-form` comes with the functionality to very quickly wire up form fields that are mapped to the columns in a database. It does require the installation of the `pop-db` component to work. Consider that there is a database table class called `Users` that is mapped to the `users` table in the database. It has six fields: `id`, `username`, `password`, `first_name`, `last_name` and `email`.

(For more information on using `pop-db` [click here](https://github.com/popphp/pop-db).)

```
use Pop\Form\Form;
use Pop\Form\Fields;
use MyApp\Table\Users;

// The 4th parameter is an 'omit' to prevent certain fields from displaying
$config = Fields::getConfigFromTable(Users::getTableInfo(), null, null, 'id');
$form   = Form::createFromConfig($config);
echo $form;
```

This will render like:

```

                Username:

                Password:

                First Name:

                Last Name:

                Email:

```

You can set element-specific attributes and values, as well as set fields to omit, like the 'id' parameter in the above examples. Any `TEXT` column type in the database is created as textarea objects and then the rest are created as input text objects.

[Top](#pop-form)

ACL Forms
---------

[](#acl-forms)

ACL forms utilize the `pop-acl` component and are an extension of the regular form class that take an ACL object with its roles and resources and enforce which form fields can be seen and edited. Consider the following code below:

```
use Pop\Form;
use Pop\Acl;

$acl      = new Acl\Acl();
$admin    = new Acl\AclRole('admin');
$editor   = new Acl\AclRole('editor');
$username = new Acl\AclResource('username');
$password = new Acl\AclResource('password');

$acl->addRoles([$admin, $editor]);
$acl->addResources([$username, $password]);

$acl->deny($editor, 'username', 'edit');
$acl->deny($editor, 'password', 'view');

$fields = [
    'username' => [
        'type'  => 'text',
        'label' => 'Username'
    ],
    'password' => [
        'type'  => 'password',
        'label' => 'Password'
    ],
    'first_name' => [
        'type'  => 'text',
        'label' => 'First Name'
    ],
    'last_name' => [
        'type'  => 'text',
        'label' => 'Last Name'
    ],
    'submit' => [
        'type'  => 'submit',
        'value' => 'Submit'
    ]
];

$form = Form\AclForm::createFromConfig($fields);
$form->setAcl($acl);
```

The `$admin` has no restrictions. However, the `$editor` role does have restrictions and cannot edit the `username` field and cannot view the `password` field. Setting the `$editor`as the form role and rendering the form will look like this:

```
$form->addRole($editor);
echo $form;
```

```

                Username

                First Name

                Last Name

```

There is no `password` field and the `username` field has been made `readonly`. Switch the role to `$admin` and the entire form will render with no restrictions:

```
$form->addRole($admin);
echo $form;
```

```

                Username

                Password

                First Name

                Last Name

```

###  Health Score

58

—

FairBetter than 98% of packages

Maintenance67

Regular maintenance activity

Popularity35

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity93

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 98% 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 ~58 days

Recently: every ~66 days

Total

65

Last Release

196d ago

Major Versions

2.2.3 → 3.0.02017-03-23

v2.x-dev → 3.1.72018-02-06

3.6.6 → 4.0.02023-12-18

PHP version history (8 changes)2.0.0PHP &gt;=5.4.0

3.0.0PHP &gt;=5.6.0

3.2.0PHP &gt;=7.1.0

3.6.0PHP &gt;=7.3.0

3.6.2PHP &gt;=7.4.0

4.0.0PHP &gt;=8.1.0

4.2.1PHP &gt;=8.2.0

4.2.6PHP &gt;=8.3.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/c19dee900e9e20039c723cc403f76b5c22ac2dddb3f86773ae64fb082d4949e2?d=identicon)[nicksagona](/maintainers/nicksagona)

---

Top Contributors

[![nicksagona](https://avatars.githubusercontent.com/u/898670?v=4)](https://github.com/nicksagona "nicksagona (197 commits)")[![localheinz](https://avatars.githubusercontent.com/u/605483?v=4)](https://github.com/localheinz "localheinz (3 commits)")[![ben91082](https://avatars.githubusercontent.com/u/6204778?v=4)](https://github.com/ben91082 "ben91082 (1 commits)")

---

Tags

phpform validationFormspoppop phphtml formsform generation

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/popphp-pop-form/health.svg)

```
[![Health](https://phpackages.com/badges/popphp-pop-form/health.svg)](https://phpackages.com/packages/popphp-pop-form)
```

###  Alternatives

[popphp/popphp-framework

The Pop PHP Framework - Full Installation

686.5k1](/packages/popphp-popphp-framework)[popphp/pop-db

Pop Db Component for Pop PHP Framework

1814.6k11](/packages/popphp-pop-db)[popphp/pop-pdf

PHP PDF library for generating and importing PDF documents. A component of the Pop PHP Framework

207.8k1](/packages/popphp-pop-pdf)[popphp/pop-http

Pop Http Component for Pop PHP Framework

1018.5k13](/packages/popphp-pop-http)

PHPackages © 2026

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