GithubHelp home page GithubHelp logo

gregwar / formidable Goto Github PK

View Code? Open in Web Editor NEW
120.0 8.0 20.0 1.4 MB

The PHP pragmatic forms library

License: MIT License

PHP 93.13% JavaScript 0.58% HTML 6.29%
php-form php constraints csrf html-form forms php-library captcha

formidable's Introduction

Formidable

PHP 7 PHP 7.1 PHP 7.2 Build status paypal

Formidable is a PHP library to handle forms. It parses an HTML form and allows you to manipulate it from your PHP code, and then render it.

How does it work?

Step 1: Download & install Formidable

Via composer:

{
    "require": {
        "gregwar/formidable": "dev-master"
    }
}

Or with a clone of the repository:

git clone https://github.com/Gregwar/Formidable.git

Or downloading it:

Step 2: Write your form in HTML

First, you have to write your code in HTML, for instance:

<!-- forms/example.html -->
<form method="post">
    Enter your name: 
    <input type="text" name="name" /><br />
    <input type="submit" />
</form>

Step 3: Give it to Formidable

In your PHP code, give your form to Formidable:

<?php
session_start();
include('vendor/autoload.php');

// Formidable will parse the form and use it to check integrity
// on the server-side
$form = new Gregwar\Formidable\Form('forms/example.html');

$form->handle(function() {
    echo "Form OK!";
}, function($errors) {
    echo "Errors: <br/>";
    foreach ($errors as $error) {
        echo "$error<br />";
    }
});

echo $form;

Simple, right?

Step 4: Enjoy the magic

You can then use the Formidable API to play with your form:

<?php

// Will set the value of the field
$form->name = "Bob";

// Will get the value of the field
$name = $form->name;

// Adds a constraint on the name
$form->addConstraint('name', function($value) {
    if (strlen($value) < 10) {
        return 'Your name should be at least 10 characters!';
    }
});

// Adds a constraint on the whole form
$form->addConstraint(function($form) {
    if ($form->getValue('pass1') != $form->getValue('pass2')) {
        return 'The passwords are different';
    }
});

You can also try to change your form and add constraint directly in the HTML code:

<input type="text" name="name" minlength="10" />

This will force the text to be at least 10 characters long when the server-side constraints will be checked.

Want a CAPTCHA to secure your form?

<input type="captcha" name="code" />

This will generate an image and an input field on the client-side, and use session on the server-side to check that the code is correct.

Note that this will use the dependency with Gregwar/Captcha library (you will have to install dependencies using composer).

Types

The following input types are supported:

  • input tags, with types:
    • text
    • number or numeric, see min and max attributes
    • int or integer, see min and max attributes
    • file
    • checkbox
    • radio
    • hidden
    • password
    • captcha, will automatically generate an image
    • date, will generate three selects, and return a DateTime as data
    • multiradio and multicheckbox (see the source section)
  • textarea
  • select

Attributes

Note that some attributes are not HTML-valid, like maxlength:

<input type="text" name="name" maxlength="10" />

It will not be rendered in the HTML form, but will be used to check integrity.

Here is the list of available attributes:

  • minlength: the minimum length of the value
  • maxlength: the maximum length of the value
  • regex: the regexp that the value should respect
  • min (for numbers): the minimum value
  • max (for numbers): the maximum value
  • required: tell that the field is required
  • readonly: the field is readonly and should not be modifier
  • value: the default value for the field
  • min-entries: specify the minimum number of entries that you should provide for a multiple (see below)
  • max-entries: specify the maximum number of entries that you can provide for a multiple (see below)
  • entries: specify both minimum and maximum number of entries for a multiple (see below)

API

You can call these method on your $form object:

  • posted(): return true if the form was posted
  • check(): check the form and return an array of validity errors
  • handle($callback, $errorCallback), this shortcut method call posted and check(), and will call $callback if the form is valid, $errorCallback else
  • setAttribute($field, $attr, $value): sets an extra attribute on a field
  • getAttribute($field, $attr): gets an extra attribute on a field
  • source($source, $values): feed a source (see the "Source" section)
  • setPlaceholder($name, $value): sets a placeholder value (see below)
  • addConstraint($field, $callback): adds a custom constraint on a field, the callback will be called with the field value and should return false if no problem, or an error string. If you just pass a closure to it, the closure will be called with the form passed as argument and can then do some tests involving multiple fields or form information.
  • setValue($field, $value): set the value of a field
  • getValue($field): gets the value of a field
  • setValues(array $values): set the values for some fields
  • getValues(): get the values of all fields

CSRF protection

An additional CSRF token is automatically inserted in the form and checked when it's submitted. Thus, all your forms will be secured.

The presence and validity of CSRF token is used to check that a form was posted when calling posted method (it's used internally in handle)

If you specify the name attribute in the form, the CSRF token will be different for this specific form, this will allow Formidable to make the difference of which form is submitted if there is multiple form on the same page.

Languages

The language for the errors can be set with setLanguage():

<?php

// Will set the language to french for errors
$form->setLanguage(new Gregwar\Formidable\Language\French);

Check that your language is supported in the Language directory, don't hesitate to participate!

Source

You can use the sourcing system to populate dynamically a select, a multiradio or a multicheckbox:

<input type="multicheckbox" name="colours" source="colours" />

Then populate it with source:

<?php
$form->source('colours', array('red', 'yellow', 'blue'));

This will be rendered by some checkboxes.

You can do it this way with select:

<select name="colour">
    <options source="colours" />
    <option value="other">Other</option>
</select>

And then source it with the same method

Creating form from string

You can create form from a file or from a string, this will be detected automatically:

<?php

$form = new Gregwar\Formidable\Form('<form method="post">
    <select name="colour">
        <option value="blue">Blue</option>
        <option selected value="red">Red</option>
        <option value="green">Green</option>
    </select>
    </form>');

echo $form->getValue('colour') . "\n";
// red

// Sets the color to blue
$form->setValue('colour', 'blue');

echo $form;
/* Will display:
<form method="post">
    <select name="colour" >
        <option selected="selected" value="blue">Blue</option>
        <option value="red">Red</option>
        <option value="green">Green</option>
    </select>
    <input type="hidden" name="posted_token" value="d293dc38017381b6086ff1a856c1e8fe43738c60" />
</form>
*/

Mapping

You can also use mapping attribute to populate your form or to get back the form data in an array or in an object, for instance:

<?php

class Person
{
    protected $name;
    public function getName() { return $this->name; }
    public function setName($name) {
        $this->name = $name;
    }
}

$person = new Person;
$person->setName('Jack');

$form = new Gregwar\Formidable\Form('<form method="post">
    <input type="text" name="name" mapping="name" />
    </form>');

$form->setData($person);

echo $form;
/*
Will output something like:

<form method="post">
    <input required="required" type="text" name="name" value="Jack" />
    <input type="hidden" name="posted_token" value="aa27f437cc6127c244db14361fd614af51c79aac" />
</form>
*/

Note that the mapping uses the Symfony PropertyAccessor, you can then use accessor as in the example above to populate properties.

You can use:

  • getData($entity = array()): populate and return entity with data populated
  • setData($entity): populate the form with the entity attributes

Creating multiple sub-forms

You can add multiple sub-forms to a page using the <multiple> tag:

<form method="post">
    Film name: <input type="text" name="film_name" mapping="name" />

    <h2>Actors</h2>
    <multiple name="actors" mapping="actors">
        First name: <input name="first_name" mapping="firstName" /><br />
        Last name: <input name="last_name" mapping="lastName" /><br />
    </multiple>
    <input type="submit" />
</form>

With this, the <multiple> can be used exactly like a field, but it will contains an array of elements.

Some JS will be injected in the page and allow you to add/remove some elements.

You can use min-entries and max-entries constraint to set limits on the number of entries in a multiple.

If you specify the same value for min-entries and max-entries, or specify a value for entries (which is actually an alias to do it), the number ofr inputs will be fixed and no javascript will be required.

Adding dynamic data into the form

In some case, you'll want to add custom data into the form, there is two way to do this.

First way: using the placeholders

The {{ something }} syntax allow you to simply inject data from the code, like this:

<?php

$form = new Gregwar\Formidable\Form('<form method="post">
    Hello {{ name }}!
    </form>');

$form->setPlaceholder('name', 'Bob');

echo $form;

In the example above, the {{ name }} will be rendered as Bob.

Note that placeholders may be used anyway excepted in the <form> and input tags:

<?php

$form = new Gregwar\Formidable\Form('<form method="post">
    <span style="color:{{ color }}">Hello</span>
    </form>');

$form->setPlaceholder('color', 'red');

echo $form;

Second way: using PHP form

You can also write your form using PHP, like a template, for instance:

<form>
    <?php echo $label; ?>: <input type="text" name="name" />
    <input type="submit" />
</form>

And then instanciate your form passing the template variables as a second argument:

<?php

$form = new Gregwar\Formidable\Form('the-above-form.php', array('label' => 'Your name'));

The $label will be interpreted using PHP.

Caching

For performances reasons, you may want to cache the parsed forms.

To do this, simply pass true as the third argument of the constructor:

<?php

/**
 * Parsed data for the form will be serialized and stored in a cache file,
 * if you use this form often, this will offer you better performances.
 */
$form = new Gregwar\Formidable\Form('form.html', null, true);

This will use the Gregwar/Cache system, you will need to get the composer dependencies of this repository or install it manually. By default, cache files will be wrote in the cache directory from where the script is run.

Try to run the performances.php script in the examples/ directory, this will give you an example of performance gain with cache.

You can also pass an instance of Gregwar\Cache\Cache as the third parameter, which will allow you to set the cache directory.

License

Gregwar\Formidable is under MIT License, have a look at the LICENSE file for more information.

History

V2.0.0 End support for PHP <5.6

V2.1.0 Remove hard dependency on Captcha library

formidable's People

Contributors

albinodrought avatar amekusa avatar chippyash avatar dominikstiller avatar drewm avatar gregwar avatar maikel-predikkta avatar mmf-amarcos avatar nicolasroehm avatar peter279k avatar roland-d avatar thomas-jackson avatar timothybjacobs avatar tolgaulas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

formidable's Issues

<select> elements lose the "required" HTML attribute after parsing

Hey, the required attribute on <select> elements seems to work well during validation, but it is not emitted into the generated HTML. (which I think is valid? correct me if I'm wrong, not 100% sure here)

Here's a tiny testcase, PR should be coming soon:

Input:

<form method="post">
    <select name="city" required="required">
        <option value="pa">Paris</option>
        <option value="la">Los Angeles</option>
        <option value="ny">New York</option>
    </select>
</form>

Expected Output:

<form method="post">
    <select name="city" required="required">
        <option value="pa">Paris</option>
        <option value="la">Los Angeles</option>
        <option value="ny">New York</option>
    </select>
</form>

Actual Output:

<form method="post">
    <select name="city" >
        <option value="pa">Paris</option>
        <option value="la">Los Angeles</option>
        <option value="ny">New York</option>
    </select>
</form>

The required="required" attribute is not found in the actual output.

minlength attribute is not output in HTML

The minlength attribute is not rendered in the HTML because it's not added to $this->attributes. This requires a one line fix in Field.php line 143 to match line 147:

        case 'minlength':
            $this->minlength = $value;
            break;
        case 'maxlength':
            $this->maxlength = $value;
            $this->attributes['maxlength'] = $value;
            break;

multiple select is not supported

When creating a multiple select, i.e. <select multiple>, it is not possible to set the value of the field. The existing code of the Select Field supposes that the value is a single string, which cannot match more than 1 <option>.

For the moment I'm using an <input type="multicheckbox"> as a workaround, but I really wished the multiple select worked so that I could use the select2 library to have a searchable input.

If you cannot fix it for now, I've forked the repo and might be able to push it in the coming months.

Option to return callback result from handle()

At the moment, the Form::handle() method returns an array of errors. If there are no errors, the array is empty.

If a callback for success or error is passed in, it's executed but the result is discarded. If the callback does anything interesting, it's hard to then control logic flow through your code.

What would you think to adding a third boolean argument to handle() that says the return value of the callbacks should be returned to the calling code? This would maintain backwards compatibility (defaulting to false), but provide a flexible option for those who want it.

Happy to submit a PR.

Use the same placeholder multiple times

I cannot use a placeholder more than once :

HTML

<form>
    <h1>Hello {{ name }}</h1>
    <p>{{ name }}</p>
    <!-- ... -->
</form>

PHP

$form = new Gregwar\Formidable\Form('forms/myform.html');
$form->setPlaceholder('name', 'Bob');
echo $form;

RESULT

<form method="post">
    <h1>Hello </h1>
    <p>Bob</p>
    <!-- ... -->
</form>

Is it possible to allow such behavior, please ?
Thank you for sharing this library, it's very useful and working well! :)

Source put data on other order

Hi,

I've a array of options to Estado field:

array:28 [▼
  "AC" => "Acre"
  "AL" => "Alagoas"
  "AP" => "Amapá"
  "AM" => "Amazonas"
  "BA" => "Bahia"
  "CE" => "Ceara"
  "DF" => "Distrito Federal"
  "ES" => "Espirito Santo"
  "GO" => "Goiás"
  "MA" => "Maranhão"
  "MT" => "Mato Grosso"
  "MS" => "Mato Grosso do Sul"
  "MG" => "Minas Gerais"
  "PA" => "Para"
  "PB" => "Paraiba"
  "PR" => "Parana"
  "PE" => "Pernambuco"
  "PI" => "Piaui"
  "RN" => "Rio Grande do Norte"
  "RS" => "Rio Grande do Sul"
  "RJ" => "Rio de Janeiro"
  "RO" => "Rondônia"
  "RR" => "Roraima"
  "SC" => "Santa Catarina"
  "SE" => "Sergipe"
  "SP" => "São Paulo"
  "TO" => "Tocantins"
  "EX" => "Exterior"
]

And I'm set like a documentation:

$form2->source('estados', $estados);

And in html I use:

<select name="estado" id="estado">
                    <option value="">- selecione -</option>
                    <options source="estados" />
                </select>

But the form html returne with options in reverse order and with a empty in first position:

<select name="estado" id="estado" >
<option value=""></option><option selected="selected" value="">- selecione -</option>
<option value="EX">Exterior</option>
<option value="TO">Tocantins</option>
<option value="SP">São Paulo</option>
<option value="SE">Sergipe</option>
<option value="SC">Santa Catarina</option>
<option value="RR">Roraima</option>
<option value="RO">Rondônia</option>
<option value="RJ">Rio de Janeiro</option>
<option value="RS">Rio Grande do Sul</option>
<option value="RN">Rio Grande do Norte</option>
<option value="PI">Piaui</option>
<option value="PE">Pernambuco</option>
<option value="PR">Parana</option>
<option value="PB">Paraiba</option>
<option value="PA">Para</option>
<option value="MG">Minas Gerais</option>
<option value="MS">Mato Grosso do Sul</option>
<option value="MT">Mato Grosso</option>
<option value="MA">Maranhão</option>
<option value="GO">Goiás</option>
<option value="ES">Espirito Santo</option>
<option value="DF">Distrito Federal</option>
<option value="CE">Ceara</option>
<option value="BA">Bahia</option>
<option value="AM">Amazonas</option>
<option value="AP">Amapá</option>
<option value="AL">Alagoas</option>
<option value="AC">Acre</option>
</select>

Any solution?

Attributes with single quotes not working in form

Any maintainers still checking this repo?

It seems like currently any attributes with single quotes turn into the attribute name, i.e. class='page-wrapper' will turn into class="class".

Single quotes are valid in html for attributes, and, more importantly for me, in our project we have data-json='{"json":"values"}' which will become data-json="data-json".

No phpunit specified in composer

Hi
You should specify the phpunit dependency and version in require-dev in composer. Just forked your lib to make some changes (and a PR to you,) but don't know which version of phpunit you are using.

In the meantime, can you tell me which version you are using please?

Thanks.

Warnings with "Select" field in "multiple" mode

File: Select.php
Function: getHtml()
Line: 116

Using a select-field in multiple mode with the option "required" set.
This causes the output of php-warnings, when none of the given options are preselected.
This is because $this->value is set to null and in_array(...) expects an array as second parameter instead.

Workaround is removing the option required, but this inserts an empty element at the top of the list, which is not desired in this case.

I have extended the if-condition to fix this case:

        if (!is_null($this->value)
            && (($this->multiple && in_array($option->getValue(), $this->value))
              || (!$this->multiple && $option->getValue() == $this->value)))

Regards,
Robert

Placeholder: Regexp matches end of line

File: Parser.php
Line: 223

modify from
while (preg_match('#^(.+){{([^}]+)}}(.+)$#mUsi', $part, $match)) {

to
while (preg_match('#^(.+){{([^}]+)}}(.+)$#Usi', $part, $match)) {

in order to make $match[3] match the entire remaining string. The current version uses the 'm' modifier, causing the '$' operator to match at the end of line. The remaining string, if present, is being lost.

Regards,
Robert

<select><option ... is not processed correctly

The below code:

    <select name="colour">
        <option value="blue">Blue</option><br />
        <option selected value="red">Red</option><br />
        <option value="green">Green</option><br />
    </select>

is displayed as

    <select name="" >
<option selected="selected" value=""></option>
<option selected="selected" value=""></option>
<option selected="selected" value="">BlueRedGreen</option>
</select>

also, the examples/multiple.php is not displayed correctly.

Add a cache system

Parsed forms should be cached to avoid re-parsing them

This is why the ParserData class was introduced

Support for input type button

Hello,

Thank you for this cool library. I managed quite easily to get it to work but the one issue I am running into is that the input type button is not supported.

My question is, is there any reason why the button type is not supported?

Thank you.

Include composer.lock file

You should include the composer.lock file in the repo. That way, when end user does composer install they will get the versions of dependencies that you used in the commit.

see this article on why composer.lock should be included.

Regards
A

lazy parse

Hi, can we (if we can, how?) pass the form content (file or string) after the class initiation. I instantiate the class in another class and later on populate/use it on it's childs. At the time of construction, the content/file is not present but later on it's introduced. May be what i need is beyond the formidable's context.

Using placeholder creates odd markup

I'm getting some odd behaviour when using placeholders ...

HTML

<form>
    <h1>Hello {{ name }}</h1>
    <div>
        <label for="name">Enter your name:</label>
        <input type="text" name="name" id="name" />
    </div>
    <div>
        <label for="age">Enter your age:</label>
        <input type="text" name="age" id="age" />
    </div>
    <button type="submit">Submit</button>
</form>

PHP

$form = new Gregwar\Formidable\Form('forms/myform.html');
$form->setPlaceholder("name", "Bob");
echo $form;

RESULT

<form method="post">
    <h1>Hello Bob</h1>
        <input id="name" type="text" name="name" />
    </div>
    <div>
        <label for="age">Enter your age:</label>
        <input id="age" type="text" name="age" />
    </div>
    <button type="submit">Submit</button>
    <input type="hidden" name="posted_token" value="fd6355e491e82ed91deaf3b42661bf0fb0882065" />
</form>

Form does not consider new fields

Hi again :)
When I created a javascript funtion that add new fields (without using the "multiple" tag that generates fields dynamically), and then sent them, the form doesn't see them, I took a look at your code and I think that the problem might be in the seValues() function in Form.php line 244:

foreach ($this->getFields() as $name => $field) {
//---fill data here 
}

Here you loop through the fields that already parsed by the form (before sending data) and fill them with values without checking if there is new fields added to the form (via javascrip for example).

Date field doesn't processing default value

If I add something like this:
$default_value = date('Y-m-d'); <input id="id" name="dateee" type="date" value="'.$default_value.'">
and will be trying to render form with today date I'll get 1-1-1898 selects. That's wrong. I'm unable to set date without using setValue function(but another fields set well).

May be we need some option to get HTML5 fields(date/datetime/..) like text?

Add support for additional input types

It does not appear to be possible to specify an input with a type of tel and url without extending the Factory class. Although these types (and probably others) simply fall back to a text input where they are unsupported, many forms benefit from utilizing these to present things like phone keypads and/or perform validation.

Regex should output HTML "pattern" attribute on inputs

Please output the "pattern" attribute in the HTML, on input type="text" only, if regex is set, to provide consistent client-side validation. The value should be the regex. This should not be output on type="url" or type="email" even if regex is set. Presently I have to duplicate the regex definition and add pattern attributes everywhere I have the regex attribute on text inputs.

Render of 'date' input is incorrect

The rendering of an <input type="date"/> is incorrect. You are over riding with three drop down selectors. This should be pulled out as browsers know how to render. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date

The problem is with the current solution is that it if your markup specifies an id for the field (not uncommon if you are using <label for.../>) ,the id is repeated for the day, month and year selectors.

Also, year is restricted to max of current year.

You'd almost be better to rely on jquery date, but that brings in a dependency you may not want.

So, suggest you a/ enable an option that allows no library rendering of date field and b/ appends .day, .month and .year to the id if present to prevent html syntax failures and c/ allow specification of min and max dates.

Posting with file upload gives 500 error

Having problems using this with file uploads.

Here is the demo form & associated code. Unfortunately I am getting a 500 Server Error but nothing in the error_log regardless of verbosity of logging.

test.html

<form method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="text" name="name" />
    <button type="submit" value="Submit">Submit</button>
</form>

test.php

<?php 

error_reporting(E_ALL);
ini_set("display_errors", 1);
include('vendor/autoload.php');

$form = new Gregwar\Formidable\Form('test.html');

$form->handle(function() {
    echo "Form OK!";
}, function($errors) {
    echo "Errors: <br/>";
    foreach ($errors as $error) {
        echo "$error<br />";
    }
});
echo $form;

?>

Source functionality for attributes

The source functionality isn't available to set attributes, whereas it could be useful for title="" or placeholder="" for instance, when we use i18n in our app.

It may be done using namespaced attributes that automatically use the source name as a value. For instance: <input source:placeholder="namePlaceholder" />.

Input type="number" constraint validation

Hi @Gregwar, It seems that constraint acts weird in some cases, as you mentioned here.

When I set the following fields to 0 and submit the form :

  • The text input throw the desired error (greater than zero)
  • The number input does not throw this error

HTML

<form>
  <input type="text"   name="items_per_page_1">
  <input type="number" name="items_per_page_2">
  <!-- ... -->
</form>

PHP

$form = new Gregwar\Formidable\Form('forms/myform.html');
$form->addConstraint('items_per_page_1', function($value)
{
  if (!is_numeric($value))
    return 'NUMERIC_ONLY';
  if ((int)$value <= 0)
    return 'GREATER_THAN_ZERO';
});
$form->addConstraint('items_per_page_2', function($value) { /* Same constraint */ });
echo $form;

Language / Validation messages

Great package.

I'm using the English Language file but I'd like to change some of the validation messages just so it reads differently.

I was hoping to do this using $form->addConstraint()* but it makes more sense to overwrite the whole language file. I don't want to edit the repo, so is there a way to pick a custom language file that's in my app?

  • This also doesn't work, as it doesn't overwrite the internal validation :(

Using <multiple> without the possibility to add new rows

The usage would be more of a use case, when we want a field to be repeated a given number of times, this number depending of the data we're sending to the form.

For instance, let's say the user has 3 friends, and we want it to add a comment for each friend, the add/remove rows functionality doesn't have any sense.

Sending array from the form without multiple tag

Hi, I hope you are doiing well :)
First of all thnx for this component realy usefull
Second I was trying to send an array via the form without using the "multiple" tag but it's not working well
this is my code :

Path: <input type="file" name="fiches[0][path]" /><br />
Desc: <input name="fiches[0][desc]" /><br />
Desc2: <input name="fiches[0][descr]" /><br />

and this is the result I get when I do var_dump($form->getvalues()):

'fiches' => 
    array (size=3)
      '0][path' => 
        object(Gregwar\Formidable\Fields\FileField)[180]
          protected 'datas' => 
            array (size=5)
              ...
          protected 'maxsize' => null
          protected 'filetype' => null
          protected 'type' => string 'file' (length=4)
          protected 'name' => string 'fiches' (length=6)
          protected 'index' => string '0][path' (length=7)
          protected 'hook' => null
          protected 'attributes' => 
            array (size=0)
              ...
          protected 'value' => null
          protected 'required' => boolean false
          protected 'regex' => null
          protected 'minlength' => null
          protected 'maxlength' => null
          protected 'prettyname' => null
          protected 'readonly' => boolean false
          protected 'valueChanged' => boolean false
          protected 'constraints' => 
            array (size=0)
              ...
          protected 'mapping' => null
          protected 'language' => 
            object(Gregwar\Formidable\Language\English)[148]
              ...
      '0][desc' => string '' (length=0) //---why empty ?!
      '0][descr' => string '' (length=0) //---why empty ?!

The file input has been sent well but the two other inputs it seems that the form doesn't see them !
I hope you help me with this and thnx in advance :)

input type checkbox generating value attribute twice

The checkbox input type appears to be generating the value attribute in the HTML twice. Once with the value set in my form template and again with an empty value for the value attribute.

For example, given:
<input type="checkbox" name="certification1" id="certification1" regex="^[A-Za-z0-9,\. ]+$" value="whatever blah blah" required />
the output is:
<input id="certification1" pattern="^[A-Za-z0-9,\. ]+$" value="whatever blah blah" required="required" type="checkbox" name="certification1" value="" />

MulticheckboxField getValue and setValue are incompatible.

Unless I'm mistaken, the MulticheckboxField::get_value() and MulticheckboxField::set_value() functions seem to be incompatible with each other. That is, I have to reformat my values before passing them to the form. Specifically I have to flip the result.

Input:

[ 'option1' => 1, 'option2' => 1 ]

Output:

[ 0 => 'option1', 1 => 'option2' ]

::getValue() makes the most sense to me, so ::setValue() should be updated. Perhaps, to avoid a BC break, ::setValue() can detect if an associative array if being used and use the current functionality, and if a numerically indexed array is used, use the ::getValue() format.

Happy to submit a patch if this sounds right to you.

Use the same source multiple times

Hi Grégoire, as you described here, we cannot use a "source" more than once :

HTML

<form>
    <select name="home_template">
        <option value=""></option>
        <options source="templates" />
    </select>
    <select name="custom_template">
        <option value=""></option>
        <options source="templates" />
    </select>
    <!-- ... -->
</form>

PHP

$form = new Gregwar\Formidable\Form('forms/myform.html');
$this->form->source('templates', [ 'home', 'full-width', 'default' ]);
echo $form;

RESULT

<form method="post">
    <select name="home_template">
        <option selected="selected" value=""></option>
    </select>
    <select name="custom_template">
        <option selected="selected" value=""></option>
        <option value="home">home</option>
        <option value="full-width">full-width</option>
        <option value="default">default</option>
    </select>
    <!-- ... -->
</form>

Will it be possible to do so ? :)

Handling Checkboxes with [] as name

When a group of checkboxes are names with [] such as

<input type="checkbox" name="chk[]" value="1">
<input type="checkbox" name="chk[]" value="2">

The getValues function should return an array with a member named "chk", not "chk[]". The data is not being returned at all because of the incorrect name.

Constraints involving several fields

It would be interesting to be able to add constraints involving several fields. It could be done by giving access for the field being verified to the other fields' values.

Typical use case:

  • "Choose your password"
  • "Type your password again"

The constraint would here check the equality between the two.

Use of 'source=""' for select in 'multiple' doesn't work

I have

           <multiple name="entries" min-entries="2">
            <tr>
                <td><select name="nominal"><options source="nominals"/></select></td>
                <td><input name="dr" type="number"></td>
                <td><input name="cr" type="number"></td>
                <td><button class="btn.del" value="Del"/></td>
            </tr>
            </multiple>

This fails to set the options correctly with $form->source('nominals', $this->nominals); and instead renders as

            <div class="multiple">
<div id="multiple152640179011218686025afb0afe01ff2" class="multiple-forms">
<div class="multiple-element" id="multiple15264017906284506685afb0afe020d3"/>
            <tr>
                <td><select name="entries[0][nominal]" source="nominals" >
</select>
</td><td><input step="any" type="number" name="entries[0][dr]" /></td><td><input step="any" type="number" name="entries[0][cr]" /></td><td><button class="btn.del" value="Del"/></td></tr>
<span class="multiple-remove"><a href="javascript:Formidable.removeInput('multiple15264017906284506685afb0afe020d3')">Remove</a><br /></span></div><div class="multiple-element" id="multiple152640179014166551895afb0afe02190"/>
            <tr>
                <td><select name="entries[1][nominal]" source="nominals" >
</select>
</td><td><input step="any" type="number" name="entries[1][dr]" /></td><td><input step="any" type="number" name="entries[1][cr]" /></td><td><button class="btn.del" value="Del"/></td></tr>
<span class="multiple-remove"><a href="javascript:Formidable.removeInput('multiple152640179014166551895afb0afe02190')">Remove</a><br /></span></div></div>
<div class="multiple-buttons"><script type="text/javascript">var multiple152640179011218686025afb0afe01ff2_code = "\n            <tr>\n                <td><select name=\"entries[{number}][nominal]\" source=\"nominals\" >\n<\/select>\n<\/td><td><input step=\"any\" type=\"number\" name=\"entries[{number}][dr]\" \/><\/td><td><input step=\"any\" type=\"number\" name=\"entries[{number}][cr]\" \/><\/td><td><button class=\"btn.del\" value=\"Del\"\/><\/td><\/tr>\n";
Formidable.multiple["multiple152640179011218686025afb0afe01ff2"] = 2;
</script><a href="javascript:Formidable.addInput('multiple152640179011218686025afb0afe01ff2', multiple152640179011218686025afb0afe01ff2_code);">Add</a></div></div>

instead of filling in the select options as expected.

I can see in 'Form.php'

    /**
     * Values sourcing
     */
    public function source($source, $data)
    {
        $sources = $this->parserData->getSources();

        $sources[$source]->source($data);
    }

This is only getting the sources for the outer form, not any multiples within it.

This could be changed to recurse into any multiples but then there is the consideration of what the javascript is going to do on row addition etc.

Can you suggest a sensible workaround, or point me in the right direction to create a PR?

Cheers

Many constraints validation per fields

Hi @Gregwar,

I've a case with 2 constraints but only 1 is returned in check:

$form2->addConstraint('quantidade_assentos', function($form) {
            if (empty($form->getValue('quantidade_assentos'))) {
                return 'Quantidade de assentos é obrigatória!';
            }

            return null;
        });

        $form2->addConstraint('quantidade_assentos', function($form) {
            if (!is_numeric($form->getValue('quantidade_assentos'))) {
                return 'Quantidade de assentos deve ser número inteiro!';
            }

            return null;
        });

Dump of getFields():

"quantidade_assentos" => NumberField {#613 ▼
    #type: "number"
    #min: "1"
    #max: null
    #step: "1"
    #name: "quantidade_assentos"
    #index: null
    #hook: null
    #attributes: array:3 [▶]
    #value: ""
    #required: true
    #regex: null
    #minlength: null
    #maxlength: null
    #prettyname: null
    #readonly: false
    #valueChanged: true
    #constraints: array:2 [▼
      0 => Closure {#606 ▶}
      1 => Closure {#605 ▶}
    ]
    #mapping: null
    #language: English {#625 ▶}
  }

Dump of errors:

array:1 [▼
  0 => Error {#604 ▼
    -field: NumberField {#613 ▶}
    -message: array:2 [▼
      0 => "value_required"
      1 => "quantidade_assentos"
    ]
    #language: English {#625 ▶}
  }
]

In my view, there should be 2 errors because a empty value "" is catched in both constraints.

Any error in my logic?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.