Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Symfony2 standalone Form component example
<?php
/**
* @author Nicolas Clavaud <nclavaud@gmail.com>
* http://n.clavaud.free.fr/blog/index.php?article31/symfony2-standalone-form-component-tutorial
*/
namespace Me\MyApp;
use Symfony\Component\ClassLoader\UniversalClassLoader;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormFactory;
use Symfony\Component\Form\Extension\Core\CoreExtension;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Templating\TemplateNameParser;
use Symfony\Component\Templating\TemplateNameParserInterface;
use Symfony\Component\Templating\TemplateReference;
use Symfony\Component\Templating\Loader\FilesystemLoader;
use Symfony\Component\Templating\PhpEngine;
use Symfony\Component\Translation\MessageSelector;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper;
use Symfony\Bundle\FrameworkBundle\Templating\Helper\TranslatorHelper;
// validation
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Validator\Validator;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\ClassMetadataFactory;
use Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader;
use Symfony\Component\Validator\ConstraintValidatorFactory;
use Symfony\Component\Validator\Constraints as Constraints;
/**
* Load and configure autoloader
* @see http://symfony.com/doc/2.0/cookbook/tools/autoloader.html
*/
require_once 'Symfony/Component/ClassLoader/UniversalClassLoader.php';
$loader = new UniversalClassLoader();
$loader->register();
$loader->registerNamespace('Symfony', __DIR__.'/');
/**
* Parameters
*/
$locale = null;
/**
* Entity
*/
class Message
{
public $sender;
public $recipient;
public $message;
// validation
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
$metadata->addPropertyConstraint('sender', new Constraints\NotBlank());
$metadata->addPropertyConstraint('sender', new Constraints\Email());
$metadata->addPropertyConstraint('recipient', new Constraints\NotBlank());
$metadata->addPropertyConstraint('recipient', new Constraints\Email());
$metadata->addPropertyConstraint('message', new Constraints\NotBlank());
$metadata->addPropertyConstraint('message', new Constraints\MinLength(10));
}
}
/**
* Form Class
* @see http://symfony.com/doc/2.0/book/forms.html#creating-form-classes
*/
class MessageType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('sender', 'email')
->add('recipient', 'email')
->add('message', 'textarea');
}
public function getName()
{
return 'message';
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Me\MyApp\Message',
);
}
}
/**
* Template name parser
* @see Symfony\Bundle\FrameworkBundle\Tests\Templating\Helper\Fixtures\StubTemplateNameParser
*
* Needed to load the templates used for rendering form items.
*/
class StubTemplateNameParser implements TemplateNameParserInterface
{
private $root;
private $rootTheme;
public function __construct($root, $rootTheme)
{
$this->root = $root;
$this->rootTheme = $rootTheme;
}
public function parse($name)
{
list($bundle, $controller, $template) = explode(':', $name);
if ($template[0] == '_') {
$path = $this->rootTheme.'/Custom/'.$template;
} elseif ($bundle === 'TestBundle') {
$path = $this->rootTheme.'/'.$controller.'/'.$template;
} else {
$path = $this->root.'/'.$controller.'/'.$template;
}
return new TemplateReference($path, 'php');
}
}
/**
* Create an entity
*/
$message = new Message();
$message->sender = 'nclavaud@gmail.com';
/**
* Build a form from a form factory
*/
$form_factory = new FormFactory(array(
new CoreExtension(),
// validation
new ValidatorExtension(
new Validator(
new ClassMetadataFactory(
new StaticMethodLoader()
),
new ConstraintValidatorFactory()
)
)
));
$form = $form_factory->create(new MessageType(), $message);
/**
* Create a PHP template engine
*/
$root = realpath(__DIR__ . '/Symfony/Bundle/FrameworkBundle/Resources/views');
$rootTheme = realpath(__DIR__ . '/Symfony/Bundle/FrameworkBundle/Resources');
$templateNameParser = new StubTemplateNameParser($root, $rootTheme);
$loader = new FilesystemLoader(array());
$engine = new PhpEngine($templateNameParser, $loader);
/**
* This helper will help rendering form items
*/
$form_helper = new FormHelper($engine, array(
'FrameworkBundle:Form',
));
/**
* Bind it to the engine
*/
$engine->setHelpers(array(
$form_helper,
new TranslatorHelper(new Translator($locale, new MessageSelector())),
));
/**
* Bind submitted data
*/
$submitted = false;
$valid = null;
if (isset($_POST[$form->getName()])) {
$form->bind($_POST[$form->getName()]);
$submitted = true;
// validation
if ($valid = $form->isValid()) {
// you may want to redirect at this state
}
}
/**
* Create the form view
*/
$form_view = $form->createView();
/**
* Now, it's time to render HTML!
*/
header('Content-type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html>
<body>
<form action="" method="post"
<?php print $form_helper->enctype($form_view) ?>
novalidate="novalidate">
<?php print $form_helper->widget($form_view) ?></div>
<input type="submit" />
</form>
<?php if ($submitted && $valid) : ?>
<p><strong>Submitted form is valid.</strong></p>
<?php endif; ?>
<p><em>Message object:</em></p>
<pre><?php print print_r($message, true); ?></pre>
</body>
</html>
@michael-bouvy

This comment has been minimized.

Copy link

@michael-bouvy michael-bouvy commented Apr 24, 2012

Thanks Nicolas for this great example, it's been very useful and works great !

There's only 1 tiny mistake line #178, as FormHelper expects an instance of a class implementing CsrfProviderInterface (or null) as second argument.

Replacing lines #178-180 by the following ones works fine :

$form_helper = new FormHelper($engine, null, array(
    'FrameworkBundle:Form',
));
@nclavaud

This comment has been minimized.

Copy link
Owner Author

@nclavaud nclavaud commented Apr 24, 2012

Thanks for your feedback @michael-bouvy. I've tried to update the code so it could work with Symfony Components in their latest version, but validation fails (actually it always validate). Need to dig in a bit...

@onema

This comment has been minimized.

Copy link

@onema onema commented May 8, 2013

I tried this example with the latest version of the form component ("symfony/form": "2.3.*@dev"). Unfortunately this example didn't work, specifically the form creation fails because the arguments for the constructors have changed compare the old code vs the new one.

Any ideas on how to get the latest code of the forms component working outside of symfony?

@juanmf

This comment has been minimized.

Copy link

@juanmf juanmf commented Jun 23, 2013

http://api.symfony.com/2.3/Symfony/Component/Form/Forms.html

Here there's an explanation of how to add all needed Extensions to the Form Component, so it can be rendered in a template, validated, Csrf Protected, Translated, etc...

protected function getFormExtensions()
{
// should be moved to the Form component once absolute file paths are supported
// by the default name parser in the Templating component
$reflClass = new \ReflectionClass('Symfony\Bundle\FrameworkBundle\FrameworkBundle');
$root = realpath(dirname($reflClass->getFileName()).'/Resources/views');
$rootTheme = realpath(DIR.'/Resources');
$templateNameParser = new FrameworkBundle\Tests\Templating\Helper\Fixtures\StubTemplateNameParser($root, $rootTheme);
$loader = new \Symfony\Component\Templating\Loader\FilesystemLoader(array());

    $this->_TemplateEngine = new \Symfony\Component\Templating\PhpEngine(
        $templateNameParser, $loader
    );
    $this->_TemplateEngine->addGlobal('global', '');
    $this->_TemplateEngine->setHelpers(array(
        new FrameworkBundle\Templating\Helper\TranslatorHelper(
            new FrameworkBundle\Tests\Templating\Helper\Fixtures\StubTranslator()
        ),
    ));
    $secret = 'SomeSecreteSecret';
    // $session = new \Symfony\Component\HttpFoundation\Session\Session();
    $validator = \Symfony\Component\Validator\Validation::createValidator();
    $csrfProvider = new \Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider(
            $secret
        );
    return array(
        new \Symfony\Component\Form\Extension\Validator\ValidatorExtension($validator),
        new \Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension(),
        new \Symfony\Component\Form\Extension\Csrf\CsrfExtension(
            $csrfProvider
        ),
        new \Symfony\Component\Form\Extension\Templating\TemplatingExtension(
            $this->_TemplateEngine, $csrfProvider, 
            array('FrameworkBundle:Form')
        ),
    );
}

// Then in your home made Framework __constructor
$this->_formFactory = \Symfony\Component\Form\Forms::createFormFactoryBuilder()
        ->addExtensions($this->getFormExtensions())
        ->getFormFactory();

Then you just need acces to the PhpEngine->get('form') helper's form() method with an instance of a $formView

My compser.json "require": { "symfony/form": "_", "symfony/validator": "_", "symfony/http-foundation": "_", "symfony/framework-bundle": "_", "symfony/routing": "_", "symfony/http-kernel": "_", "symfony/event-dispatcher": "*" },
@ivanchuryumov

This comment has been minimized.

Copy link

@ivanchuryumov ivanchuryumov commented Apr 30, 2014

Thanks nclavaud for this example, it's been very useful for me!

@MacDada

This comment has been minimized.

Copy link

@MacDada MacDada commented Sep 9, 2014

Big thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment