I want to make some simple admin panel application in Symfony. I see that since version 2.3 Symfony introduced a Bootstrap’s form theming, which is great, but I want to create custom submit field called SaveType which should have default class attr set to btn-primary instead of btn-default.
So, from documentation I read that I can create that custom field type and set its parent to SubmitType
SaveType custom field
<?php namespace AppBundleFormCustom; use SymfonyComponentFormAbstractType; use SymfonyComponentFormExtensionCoreTypeSubmitType; use SymfonyComponentOptionsResolverOptionsResolver; /** * Class SaveType * @package AppBundleForm */ class SaveType extends AbstractType { /** * @param OptionsResolver $resolver * @return OptionsResolver|void */ public function configureOptions(OptionsResolver $resolver) { return $resolver->setDefaults( [ 'attr' => [ 'class' => 'btn-primary', ], ] ); } /** * @return string */ public function getParent() { return SubmitType::class; } }
Product entity
<?php namespace AppBundleEntity; /** * Product */ class Product { /** * @var int */ private $id; /** * @var string */ private $name; /** * @var int */ private $price; /** * @var bool */ private $enabled; /** * Get id * * @return int */ public function getId() { return $this->id; } /** * Set name * * @param string $name * * @return Product */ public function setName($name) { $this->name = $name; return $this; } /** * Get name * * @return string */ public function getName() { return $this->name; } /** * Set price * * @param integer $price * * @return Product */ public function setPrice($price) { $this->price = $price; return $this; } /** * Get price * * @return int */ public function getPrice() { return $this->price; } /** * Set enabled * * @param boolean $enabled * * @return Product */ public function setEnabled($enabled) { $this->enabled = $enabled; return $this; } /** * Get enabled * * @return bool */ public function getEnabled() { return $this->enabled; } }
ProductType which uses SaveType
<?php namespace AppBundleForm; use AppBundleFormCustomSaveType; use SymfonyComponentFormAbstractType; use SymfonyComponentFormExtensionCoreTypeMoneyType; use SymfonyComponentFormFormBuilderInterface; use SymfonyComponentOptionsResolverOptionsResolver; /** * Class ProductType * @package AppBundleForm */ class ProductType extends AbstractType { /** * @param FormBuilderInterface $builder * @param array $options */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name') ->add('price', MoneyType::class, [ 'currency' => 'PLN', 'divisor' => 100, ]) ->add('enabled') ->add('submit', SaveType::class, [ 'label' => 'Save', ]); } /** * @param OptionsResolver $resolver */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => 'AppBundleEntityProduct', )); } }
The problem
Rendering that form throws following error:
Neither the property "submit" nor one of the methods "getSubmit()", "submit()", "isSubmit()", "hasSubmit()", "__get()" exist and have public access in class "AppBundleEntityProduct".
Note
Creating a SubmitTypeExtension is working fine, but I don’t want to change behavior of standard SubmitType in the whole application.
Advertisement
Answer
The solution is actually very simple, as I found out with this issue. You have to implement the SubmitButtonTypeInterface
so it uses SubmitButtonBuilder
instead of the regular FormBuilder
.
This is what you button class will look like:
namespace AppBundleFormCustom; use SymfonyComponentFormAbstractType; use SymfonyComponentFormExtensionCoreTypeSubmitType; use SymfonyComponentFormSubmitButtonTypeInterface; use SymfonyComponentOptionsResolverOptionsResolver; class SaveType extends AbstractType implements SubmitButtonTypeInterface { public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'label' => ' ', 'attr' => [ 'title' => 'Save', 'data-toggle' => "tooltip", 'data-placement' => "bottom" ], 'icon' => 'ok' ]); } public function getParent() { return SubmitType::class; } }