Note: each tutorial contains information about one specific part of Spoon. If something is unclear, post a comment.

Form - part 1

Written by Davy Hellemans -

This tutorial is a work in progress. Please comment if something is not clear

Prerequisites

What will you learn?

  • Create a form
  • Validate a form

Tutorial

Creating the form

At first we need to create the form and its element.

// fetch spoon
require_once 'spoon/spoon.php';

// create form
$frm = new SpoonForm('myForm'); // uitleg over action, method

// add name (input field)
$frm->addText('name');

// add email (input field)
$frm->addText('email')
	->setAttribute('type', 'email'); // html5 'email' type attribute

// add phone number (input field)
$frm->addText('phone')
	->setAttribute('placeholder', 'digits only') // html5 placeholder attribute
	->setAttribute('required'); // html5 'required' attribute

// add bio (textarea)
$frm->addTextarea('bio');

// add date of birth
$frm->addDate('date_of_birth', null, 'd/m/Y'); // @todo uitleg over mogelijke masks
$frm->addTime('time_of_birth');

// add gender
$gender = array();
$gender[] = array('label' => 'Male', 'value' => 'male');
$gender[] = array('label' => 'Female', 'value' => 'female');
$frm->addRadiobutton('gender', $gender, 'male');

// add subscribe to newsletter (single checkbox)
$frm->addCheckbox('subscribe', true);

// add programming languages (multi checkbox)
$languages = array();
$languages[] = array('label' => 'PHP', 'value' => 'php');
$languages[] = array('label' => 'Ruby', 'value' => 'ruby');
$languages[] = array('label' => 'C#', 'value' => 'c_sharp');
$frm->addMultiCheckbox('languages', $languages, 'php');

// add country (dropdown)
$frm->addDropdown('country', SpoonLocale::getCountries(), 'BE');

// add cartoon characters (multi select dropdown)
$cartoons['Smurfs']['papa'] = 'Papa smurf';
$cartoons['Smurfs']['smurfette'] = 'Smurfette';
$cartoons['Smurfs']['brainy'] = 'Brainy smurf';
$cartoons['Smurfs']['jokey'] = 'Jokey smurf';
$cartoons['Simpsons']['homer'] = 'Homer';
$cartoons['Simpsons']['marge'] = 'Marge';
$cartoons['Simpsons']['bart'] = 'Bart';
$cartoons['Simpsons']['lisa'] = 'Lisa';
$frm->addDropdown('toons', $cartoons, array('homer', 'bart'), true);

// add pdf (file)
$frm->addFile('pdf');

// add photo (image)
$frm->addImage('photo');

// add preferred password (password)
$frm->addPassword('password');

// add hidden value(s)
$frm->addHidden('preferences', 'random value');

// add submit button
$frm->addButton('submit', 'Submit');

The template

Now we're going to make the html template that will hold our form fields. You can either type all this manually or use a built-in method to provide you with the basics. I personally start by copy pasting the generated code from SpoonForm::getTemplateExample(). In this example I took that generated code and modified it to suit my needs.

The code below needs to go in your 'form.tpl' file.

{form:myForm}
	{$hidPreferences}
	<p>
		<label for="name">Name*</label><br />
		{$txtName} {$txtNameError}
	</p>
	<p>
		<label for="email">Email*</label><br />
		{$txtEmail} {$txtEmailError}
	</p>
	<p>
		<label for="phone">Phone</label><br />
		{$txtPhone} {$txtPhoneError}
	</p>
	<p>
		<label for="bio">Bio*</label><br />
		{$txtBio} {$txtBioError}
	</p>
	<p>
		<label for="dateOfBirth">Date of birth*</label><br />
		{$txtDateOfBirth} {$txtDateOfBirthError}
	</p>
	<p>
		<label for="timeOfBirth">Time of birth*</label><br />
		{$txtTimeOfBirth} {$txtTimeOfBirthError}
	</p>
	<p>
		Gender*<br />
		{iteration:gender}
			<label for="{$gender.id}">{$gender.rbtGender} {$gender.label}</label>
		{/iteration:gender}
		{$rbtGenderError}
	</p>
	<p>
		{$chkSubscribe} <label for="subscribe">Subscribe to our newsletter*</label>
		{$chkSubscribeError}
	</p>
	<p>
		Languages*<br />
		{iteration:languages}
			<label for="{$languages.id}">{$languages.chkLanguages} {$languages.label}</label>
		{/iteration:languages}
		{$chkLanguagesError}
	</p>
	<p>
		<label for="country">Country*</label><br />
		{$ddmCountry} {$ddmCountryError}
	</p>
	<p>
		<label for="toons">Cartoon characters</label><br />
		{$ddmToons} {$ddmToonsError}
	</p>
	<p>
		<label for="pdf">Pdf*</label><br />
		{$filePdf} {$filePdfError}
	</p>
	<p>
		<label for="photo">Photo*</label><br />
		{$filePhoto} {$filePhotoError}
	</p>
	<p>
		<label for="password">Password</label><br />
		{$txtPassword} {$txtPasswordError}
	</p>
	<p>{$btnSubmit}</p>
{/form:myForm}

Validating the form

Now that we have a form and a template, we're going to validate the form and make sure it's rendered using 'form.tpl'.

// form was submitted
if($frm->isSubmitted())
{
	// name is required
	$frm->getField('name')->isFilled('Please fill out your name');

	// email is required
	$frm->getField('email')->isEmail('Please provide a valid email address.');

	// phone is NOT required
	if($frm->getField('phone')->isFilled())
	{
		// now that we know it's filled, it needs to be numeric!
		$frm->getField('phone')->isNumeric('Digits only please!');
	}

	// bio is required
	if($frm->getField('bio')->isFilled('Please tell us more about yourself.'))
	{
		// has to be at least 10 characters
		$frm->getField('bio')->isMinimumCharacters(10, 'Surely you can tell us more!');
	}

	// date is required (and needs to be valid)
	$frm->getField('date_of_birth')->isValid('Please provide a valid date. (dd/mm/yyyy)');

	// time needs to be valid
	$frm->getField('time_of_birth')->isValid('When exactly were u born? (hh:mm)');

	// gender is required
	$frm->getField('gender')->isFilled('Tell us your gender please.');

	// you HAVE to subscribe to our newsletter :)
	$frm->getField('subscribe')->isFilled('Please subscribe to our newsletter!');

	// you have to check at least 1 programming language
	$frm->getField('languages')->isFilled('Please choose at least 1 language.');

	// country is required
	$frm->getField('country')->isFilled('Please select your country.');

	/*
	 * Validate the pdf file. Following conditions need to be met:
	 * - pdf is required
	 * - file needs to have the 'pdf' extension
	 * - file needs to be smaller than 2MB
	 */
	if($frm->getField('pdf')->isFilled('Please upload a pdf.'))
	{
		// needs to be a pdf
		if($frm->getField('pdf')->getExtension() != 'pdf')
		{
			$frm->getField('pdf')->addError('You have to upload a pdf document.');
		}

		// it seems to be a .pdf file
		else
		{
			// may not be larger than 2MB
			$frm->getField('pdf')->isFilesize(2, 'mb', 'smaller', 'Too large. 2MB max');
		}
	}

	/*
	 * Validate the image. Following conditions apply:
	 * - image is required
	 * - image needs to be a jpeg or png
	 * - image needs to be smaller than 2MB
	 * - dimensions should exceed 640x480 pixels
	 */
	$image = $frm->getField('photo'); // just to shorten the code
	if($image->isFilled('Please upload an image.'))
	{
		// image has the jpg/png extension
		if($image->isAllowedExtension(array('jpg', 'png'), 'Only jpg/gif are allowed.'))
		{
			// image is not larger than 2MB
			if($image->isFilesize(2, 'mb', 'smaller', 'Too large. 2MB maximum'))
			{
				// dimensions are minium 640x480
				$image->hasMinimumDimensions(640, 480, 'Too small. 640x480 minimum');
			}
		}
	}

	// password is required
	$frm->getField('password')->isFilled('Please choose a password');

	/*
	 * The entire form was submitted correctly based on the iput validation
	 * we did above.
	 */
	if($frm->isCorrect())
	{
		// all the information that was submitted
		$data = $frm->getValues();

		// dump data for demo purpose
		Spoon::dump($data);
	}
}

/*
 * Now all we need to do is create a template and parse this
 * form into the template.
 */
$tpl = new SpoonTemplate();
$tpl->setForceCompile(true);
$tpl->setCompileDirectory('cache');
$frm->parse($tpl);
$tpl->display('form.tpl');

Final output

You can now view your form in your browser. Play with it to see how the error messages react and if everything is filled out correctly you should get output similar to the one below

array(15) {
  ["form"] => string(6) "myForm"
  ["name"] => string(14) "Davy Hellemans"
  ["email"] => string(22) "davy@spoon-library.com"
  ["phone"] => string(10) "1234567890"
  ["bio"] => string(93) "I don't really like clowns. They just assume they're funny"
  ["date_of_birth"] => string(10) "03/08/1983"
  ["time_of_birth"] => string(5) "13:37"
  ["gender"] => string(4) "male"
  ["subscribe"] => bool(true)
  ["languages"] => array(1) {
    [0] => string(3) "php"
  }
  ["country"] => string(2) "BE"
  ["toons"] => array(2) {
    [0] => string(9) "smurfette"
    [1] => string(5) "homer"
  }
  ["password"] => string(4) "leet"
  ["preferences"] => string(12) "random value"
  ["submit"] => string(6) "Submit"
}

Conclusion

Based on the example you should now be able to create some basic (and advanced) forms.

28 comments

Pieter Beulque wrote 2 years ago

Now how exactly do you handle the uploading and processing of the files associated with the file input?
SpoonFile?

Bauffman wrote 2 years ago

@pieter once you validated your uploaded files, you can move it to wherever you want by using.

http://www.spoon-library.com/docs/1.3/form/spoonformfile/movefile

Damith wrote 2 years ago

Hi...I set this way but its not worked for me....after submit that form, upload folder was empty...can't found uploaded PDF file there.....

//----------------- I put this line after PDF validation Code Block there ----------------------------

$frm->getField('pdf')->moveFile('c:\xampp\htdocs\spoon\upload', 755);

//-------------------------------------------------------------------------------------------------------------------------

Thanks

Bauffman wrote 2 years ago

@Damith
When you use the moveFile method it will return a boolean, telling you whether or not the move has succeeded. If you'd like to know what exactly fails, remove the @ from the moveFile method (see #373 in spoon/form/file.php)

Damith wrote 2 years ago

ah yes....Thanks for your reply...I fixed that my issue...

Now its moving file fine, using this way...I have to give ( upload directory path + file name ) also....
----------------------------------
$frm->getField('pdf')->moveFile("upload/" . $frm->getField('pdf')->getFileName(true), 755);
-----------------------------------

Thanks again...

Arnout wrote 2 years ago

I'm trying to retrieve all the data of a record and fill this in a form, but how can I add a value to an input field?
When I try...
----------------------
$frm->addText('test')->setAttribute('value', 'test');
----------------------
... I get following error: The key "value" is a reserved attribute and can NOT be overwritten.

Bauffman wrote 2 years ago

@Arnout

You should do this in this way: $frm->addText('test', 'my default value');

Arnout wrote 2 years ago

@Bauffman Thx, works fine now!

Martin wrote 2 years ago

How to clear all value in the form after submited?

Bauffman wrote 2 years ago

@martin
You could do the following right after the $frm->getCorrect statement
foreach($_POST as $key => $value)
{
unset($_POST[$key];
}

Arnout wrote 2 years ago

I have 2 dropdown boxes. When the first one is selected, the second is filled with value's true javascript based on the first dropdown. Now when I post the form the result of the second dropdown is always NULL.
Can't I use this kind of method to fill the dropdownboxes?

Bauffman wrote 2 years ago

By default dropdowns can not have their values filled by javascript. This is done to prevent you from getting values from dropdowns (or checkboxes, radiobuttons, etc) that were not in the original list.

You can however overrule this default behaviour. Check out this method:
http://www.spoon-library.com/docs/1.3/form/spoonformdropdown/setallowexternaldata

Martin wrote 2 years ago

@Bauffman
But if unset all $_POST key, dropdown default value will also deleted.
Hope Spoon can include a function to clear all submitted value in next version to easy the task :)

Bauffman wrote 2 years ago

@martin
SpoonForm always checks in two different ways to define what value should be used for the fields.

1. is the form submitted
1.1 yes it is submitted
1.2 was this field submitted
1.2.1 if this field was submitted, use that value from $_POST
1.2.2 if this field was NOT submitted, use the default value set in the code
1.2 no, the form was not submitted
1.2.1 use the default value set in the code

I will however add a method to clear all the $_POST values in the future. On a sidenote, in most cases what I do is set a template option around my form and when the form has been submitted, I don't assign the option so that you won't see the form after this is submitted. An information architect would tell you that that is the right way, because there can be no confusion since the form you submitted is gone, which makes clear that it must have been successful.

That would be something like this example
https://gist.github.com/1273391

antony wrote 2 years ago

Hi, In forms lets say approval form, where 2 submit buttons come, How can i get the different submit button values?

Bauffman wrote 2 years ago

@antony
You can add buttons to your form with $frm->addButton. It's possible to add more than 1 button. If you then do $frm->getValues() when your form is submitted, you will be able to see the values of those buttons.

see http://www.spoon-library.com/docs/1.3/form/spoonform/addbutton

Bruce wrote 2 years ago

How do I handle ISO 8859-1 characters? For example, if I enter the following title "Aktivitäten" into my form, $frm->getValues() gives me this - Aktivit&Atilde;&curren;ten (Aktivitäten) - instead of - Aktivit&auml;ten ?!

Bauffman wrote 2 years ago

@Bruce
Is the constant SPOON_CHARSET set to 'iso-8859-1'

Bruce wrote 2 years ago

@Bauffman - yes, that's what I had done first, but it did not work... hence my question on this forum. I have even tried forcing 'iso-8859-1' charset in the htmlspecialchars() & htmlentities() SpoonFilter functions, but that didn't work either... :-/

Bruce wrote 2 years ago

I've been fiddling and seem to have stumbled upon something! If I set SPOON_CHARSET to 'iso-8859-1' and then overload the htmlspecialchars() & htmlentities() SpoonFilter functions with 'utf-8' ... IT WORKS ... WTF?! #confused

Bauffman wrote 2 years ago

Pretty strange. I am going to look into it :)

Arnout wrote 2 years ago

How can you add a form element inside an iteration of checkboxes or radio buttons?

Something like this:
{iteration:languages}
<label for="{$languages.id}">{$languages.chkLanguages} {$languages.label}</label>
{* if the language is Dutch *}
{option:languages.dutch}
<p>
<label for="dateOfBirth">Date of birth*</label><br />
{$txtDateOfBirth} {$txtDateOfBirthError}
</p>
{/option:languages.dutch}

{/iteration:languages}
{$chkLanguagesError}

thermal imaging cameras for sale wrote 1 year ago

wonderful publish, very informative. I wonder why the other specialists
of this sector do not notice this. You should continue your writing.

I am confident, you have a great readers' base already!

Fettverbrennung wrote 1 year ago

Quality articles is the main to be a focus for the
visitors to pay a quick visit the web page, that's what this site is providing.

oreiller en sarrasin wrote 1 year ago

I do accept as true with all of the ideas you have offered
for your post. They are very convincing and
can definitely work. Nonetheless, the posts are too quick for newbies.

May you please lengthen them a little from subsequent time?

Thanks for the post.

Harrison wrote 1 year ago

It's very straightforward to find out any matter on net as compared to textbooks, as I found this piece of writing at this web site.

Składanie PIT 39 do Urzędu Skarbowego wrote 1 year ago

Excellent post. I was checking continuously this blog
and I am impressed! Extremely helpful information specially the last part :
) I care for such info much. I was seeking this certain information for a very long time.
Thank you and good luck.

Marcela wrote 1 year ago

When I originally left a comment I appear to have
clicked the -Notify me when new comments are added- checkbox and from now on
each time a comment is added I get 4 emails with the same comment.
Is there a way you can remove me from that service?
Thank you!