I try to save new data (when I modify, it's works ok) in embed form, but allow_add doesn't work.
When i send data throw prototype inputs, the request->request is:
ads[adsCapPublisher][new_created_0][publisher]:2302
ads[adsCapPublisher][new_created_0][dailyLimit]:2
ads[adsCapPublisher][edit_0][publisher]: 5201
ads[adsCapPublisher][edit_0][dailyLimit]: 5
The edit_0 was good procesed and creates the AdsType with the AdsCapPublisherType, but when i added new inputs throws javascript, when procesed the data, fails in $request->handleRequest():
Catchable fatal error: Argument 1 passed to addAdsCapPublisher() must be an instance of AdsCapPublisher, null given in Ads.php on line 721
The data is null. And when if I set allow_add to false, the edit entities are procesed good but the news return a form error:
this form should not contain extra fields
Here my clases:
Ads.php
class Ads{
/**
* #ORM\OneToMany(targetEntity="AdsCapPublisher", mappedBy="ad", cascade={"persist", "remove"})
**/
protected $adsCapPublisher;
public function addAdsCapPublisher(AdsCapPublisher $adCapPublisher)
{
$this->adsCapPublisher[] = $adCapPublisher;
return $this;
}
public function removeAdsCapPublisher(AdsCapPublisher $adCapPublisher)
{
$this->adsCapPublisher->removeElement($adCapPublisher);
}
public function getAdsCapPublisher()
{
return $this->adsCapPublisher;
}
public function setAdsCapPublisher($adsCapPublisher)
{
$this->adsCapPublisher = $adsCapPublisher;
return $this;
}
[...]
}
AdsCapPublisher.php
class AdsCapPublisher{
/**
* #var Users
*
* #ORM\ManyToOne(targetEntity="Users", fetch="LAZY")
* #ORM\JoinColumn(name="id_publisher", referencedColumnName="id_user")
*/
protected $publisher;
/**
* #var decimal $dailyLimit
*
* #ORM\Column(name="daily_limit", type="decimal", nullable=false)
*/
protected $dailyLimit;
[...]
}
AdsType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$entityId= $builder->getData();
$builder->add('adsCapPublisher', 'collection', array(
'type' => new AdsCapPublisherType(),
'required' => false,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false
))
AdsCapPublisherType.php
class AdsCapPublisherType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// -- SECTION: General
$builder
->add('publisher', 'hidden', array(
'attr' => array(
'class' => 'js-field-popup-publisher-added'
)))
->add('dailyLimit', 'text', array(
'required' => false,
'attr' => array(
'class' => 'js-field-popup-budget-added form-control k-input-field k-is-input-text k-ellipsis k-has-currency-inside-input',
'min' => 0,
)
));
}
public function getName()
{
return 'adsCapPublisher';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'csrf_protection' => false,
'data_class' => 'Entity\AdsCapPublisher',
'csrf_field_name' => '_token',
'intention' => 'ads',
'translation_domain' => 'ads',
'empty_data' => null
));
}
}
Any help? :S
Related
Can I specify how the form field shold be mapped on data class?
Let's say I have form with check box and on my data entity the field is stored as string.
class FormType extends AbstractType {
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => DataEntity::class,
]);
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('issueType', CheckboxType::class, [
'label' => 'issueType',
]);
}
}
class DataEntity {
/** #var string Either PLASTIC or PAPER */
private $issueType;
public function getIssueType() {
return $this->issueType;
}
public function setIssueType($issueType) {
$this->issueType = $issueType;
}
}
Can I made the checkbox to be mapped as 'PLASTIC' if ture and 'PAPER' if false?
You can use data transformer to cast bolean to the string. See this tutorial: https://symfony.com/doc/current/form/data_transformers.html.
$builder->get('issueType')
->addModelTransformer(new CallbackTransformer(
function ($type) {
// your logic here
return $type;
},
function ($type) {
// your logic here
return $type;
}
));
try :
$builder->add('newsletter', 'choice', array(
'label' => 'Newsletter erhalten',
'attr' => array(
'class' => 'form-control',
),
'choices' => array(array('yes' => 'plastic'), array('no' => 'paper')),
'expanded' => true,
'multiple' => true,
'required' => false,
));
also check the answer here Symfony2 Change checkbox values from 0/1 to 'no'/'yes'
I'm trying to create a form for the creation of a product in sylius. I want to add a collection of "PackItem".
However,only the last item is added and when I add "by_reference" => false I've got this issue
Could not determine access type for property "products".
This is my code
#ProductTypeExtension.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
/** #var PackItem $packItem */
$packItem = new PackItem();
$packItem->setParent($builder->getData());
$builder
->add('products', CollectionType::class, [
'entry_type' => PackItemType::class,
'allow_add' => true,
'allow_delete' => true,
'entry_options' => [
'data' => $packItem
],
'by_reference' => false,
]);
}
/**
* {#inheritdoc}
*/
public function getExtendedType()
{
return ProductType::class;
}
PackItemType.php
#PackItemType.php
final class PackItemType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('child', 'entity', [
'label' => 'winzana.ui.token',
'class' => Product::class,
'query_builder' => function(EntityRepository $er) {
$qr = $er->createQueryBuilder('t')
->leftJoin('t.products', 'p')
->having('COUNT(p.parent) = 0')
->groupBy('t.id')
->orderBy('t.code', 'ASC')
;
return $qr;
}
])
->add('quantity', IntegerType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => PackItem::class
]);
}
Product :
class Product extends BaseProduct
{
/**
* #ORM\OneToMany(targetEntity="XXXX\PackBundle\Entity\PackItem", mappedBy="parent", cascade={"persist"})
* #var ArrayCollection|PackItem $products
*/
private $products;
Thank you for your time
You can try to initialise your products in the __construct() method of your class product
public function __construct()
{
$this->products= new ArrayCollection();
}
if it does not correct the problem, then check if you set correctly the getProducts(), setProducts() and addProduct().
You can check this page for information,
http://symfony.com/doc/current/best_practices/business-logic.html#doctrine-mapping-information
regards.
The problem was solved by this change
/**
* #param ArrayCollection|PackItem[] $products
*/
public function setProducts($products)
{
$this->products = $products;
}
I don't use the setter so I didn't made it however by_references needs it.
Now I've got an other problem, only the last Item is saved.
My application show this error
Type error: Too few arguments to function AppBundle\Form\ActualiteType::__construct(), 0 passed in /Applications/MAMP/htdocs/SyndicNous/vendor/symfony/symfony/src/Symfony/Component/Form/FormRegistry.php on line 90 and exactly 2 expected
My formType
class ActualiteType extends AbstractType
{
/**
* #var bool $admin
*/
private $admin;
/**
* #var User $user
*/
private $user;
/**
* ActualiteType constructor.
* #param bool|false $admin
*/
public function __construct($admin = false, $user)
{
$this->admin = $admin;
$this->user = $user;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$categories = array(
'Travaux' => 'Travaux',
'Voisinage' => 'Voisinage',
);
$builder
->add('title')
->add('category')
->add('content')
->add('datePublish')
->add('category', ChoiceType::class, array(
'choices' => $categories
)
);
if ($this->user->getResidence() != null) {
$builder->add('residence', EntityType::class, array(
'class' => 'AppBundle:Residence',
'choices' => $this->user->getResidence(),
));
} else {
$builder->add('residence', 'entity', array(
'class' => 'AppBundle:Residence',
'choice_label' => 'name'
));
};
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Actualite'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_actualite';
}
}
Do you have any idea where the problem would come from? Thank you
I do not understand what you're trying to do. You do not need to use the constructor to pass parameters to your formType. There is the second parameter of the buildForm method for this ($options).
In your controller, create your form like this :
$form = $this->createForm(ActualiteType::class, $actualite, [
'admin' => $admin,
'user' => $user
]);
And modify your formType like that :
class ActualiteType extends AbstractType {
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$admin = $options['admin']; // Not used ?
$user = $options['user'];
$categories = array(
'Travaux' => 'Travaux',
'Voisinage' => 'Voisinage',
);
$builder->add('title')
->add('category')
->add('content')
->add('datePublish')
->add('category', ChoiceType::class, array(
'choices' => $categories
)
);
if ($user->getResidence() != null) {
$builder->add('residence', EntityType::class, array(
'class' => 'AppBundle:Residence',
'choices' => $user->getResidence(),
));
} else {
$builder->add('residence', 'entity', array(
'class' => 'AppBundle:Residence',
'choice_label' => 'name'
));
};
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Actualite',
'admin' => null, // Default
'user' => null // Default
));
}
}
Do not forget to put the default values of your options in configureOptions method.
I just recently updated to 2.8 and now I get the following error when calling the create function of the Form Factory.
Error: Class Symfony\Component\Form\Extension\Core\Type\FormType contains 1
abstract method and must therefore be declared abstract or implement the
remaining methods (Symfony\Component\Form\FormTypeInterface::setDefaultOptions)
The call of the FormFactory looks like this:
$this->formFactory->create(
get_class(new ProductType()),
$product,
[
'method' => 'POST',
'type' => $type,
'locales' => $context->shop->getLocales(),
'product' => $product,
'numberDataTransformer' => $this->numberTransformerFactory->createFromLocale(
$context->user->getLocale(),
$context->shop->getDefaultLocale()
),
'priceType' => $context->shop->getConfiguration()->getProductConfiguration()->getPricesBackend(),
'isShortDescriptionEnabled' => $context->shop->getConfiguration()->getProductConfiguration()->isShortDescriptionEnabled()
]);
I tried several ways to pass the ProductType to the function, but none seems to work. I always get one out of two results: Either the result is that the type cannot be found or the error is returned that the FormType does not implement setDefaultOptions.
What did I miss?
EDIT:
Here are some additional code:
The declaration of the formFactory parameter:
public function __construct(Request $request, FormFactoryInterface $formFactory)
{
$this->request = $request;
$this->formFactory = $formFactory;
}
The ProductType class
<?php
namespace CustomNamespace\BackendBundle\Product\Form;
use CustomNamespace\BackendBundle\Common\NumberDataTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use CustomNamespace\BackendBundle\Product\Form\ImageType;
use ShopwareEasy\BackendBundle\Product\Form\AttachmentType;
use Symfony\Component\Validator\Exception\InvalidOptionsException;
/**
* Form element type for products.
*/
class ProductType extends AbstractType
{
/**
* #var string
*/
private $method;
/**
* #var string
*/
private $type;
/**
* #var array
*/
private $locales;
/**
* #var Product
*/
private $product;
/**
* #var \CustomNamespace\BackendBundle\Common\NumberDataTransformer
*/
private $numberDataTransformer;
/**
* #var string
*/
private $priceType;
/**
* #var bool
*/
private $isShortDescriptionEnabled;
/**
* #param FormBuilderInterface $builder
* #param array $options
* #return void
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->setMethod($this->method);
$regionType = new RegionShippingTimeType();
if ($this->type == 'download') {
$regionType->enableForDownloadableProduct();
}
$builder->add('regions', 'collection', array(
'type' => $regionType,
'label' => false,
'options' => array(
'required' => false,
'attr' => array('class' => 'email-box')
),
));
$builder->add('vendor', 'text', ['label' => 'form_product_vendor']);
if ($this->type == 'normal') {
$builder->add(
'mainVariant',
new MainVariantNormalType(
$this->method,
$this->locales,
$this->product,
$this->numberDataTransformer,
$this->priceType,
$this->isShortDescriptionEnabled
),
['error_bubbling' => false, 'label' => false]
);
} elseif ($this->type == 'download') {
$builder->add(
'mainVariant',
new MainVariantDownloadType(
$this->method,
$this->locales,
$this->product,
$this->numberDataTransformer,
$this->priceType,
$this->isShortDescriptionEnabled
),
['error_bubbling' => false, 'label' => false]
);
} elseif ($this->type == 'variant') {
$builder->add(
'mainVariant',
new MainVariantVariantType(
$this->method,
$this->locales,
$this->product,
$this->numberDataTransformer,
$this->priceType,
$this->isShortDescriptionEnabled
),
['error_bubbling' => false, 'label' => false]
);
}
if ($this->method == 'PUT') {
$builder->add(
'images',
new ImageType(),
['error_bubbling' => true, 'label' => false]
);
$builder->add(
'attachments',
new AttachmentType(),
['error_bubbling' => true, 'label' => false]
);
}
}
/**
* #param \Symfony\Component\OptionsResolver\OptionsResolverInterface $resolver
*/
public function configureOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'CustomNamespace\\BackendBundle\\Product\\Product',
'csrf_protection' => false,
'error_bubbling' => false,
'cascade_validation' => true,
'method' => 'POST',
'type' => 'normal'
)
);
parent::configureOptions($resolver);
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
/** #var OptionResolver $resolver */
$this->configureOptions($resolver);
}
public function getName() {
return get_class($this);
}
}
The problem was produced by files that were not updated at all.. The implementation of setDefaultOptions should still exist in the Symfony 2.8 classes - but they didn't.
After destroying my vagrant and recreating it again, everything worked just fine.
But thanks everyone for the help!
I have a problem with collection form type. My entities:
User
use Doctrine\Common\Collections\ArrayCollection;
/**
* #OneToMany(targetEntity="Comment", mappedBy="user")
*/
protected $comments;
public function __construct() {
$this->comments= new ArrayCollection();
}
Comment
/**
* #ManyToOne(targetEntity="User", inversedBy="comments")
* #JoinColumn(name="user_id", referencedColumnName="id")
**/
protected $user;
Formbuilder:
$form = $silex['form.factory']->createBuilder('form', $user)
->add('comments', 'collection', array(
'type' => 'text',
'options' => array(
'required' => false,
'data_class' => 'Site\Entity\Comment'
),
))
->getForm();
and is returned error:
Catchable fatal error: Object of class Site\Entity\Comment could not be converted to string in C:\XXX\vendor\twig\twig\lib\Twig\Environment.php(331) : eval()'d code on line 307 Call Stack
I think that you might struggle to use a text type collection field here, since you want a field which is a collection of complex entities and not just one which is an array of strings.
I would suggest adding a new Form type for the Comment Entity:
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class CommentType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('text', 'text', array());
}
public function getName() {
return 'comment';
}
public function getDefaultOptions(array $options) {
return array(
'data_class' => 'Site\Entity\Comment'
);
}
}
Then in the original Formbuilder, reference this type:
$form = $silex['form.factory']->createBuilder('form', $user)
->add('comments', 'collection', array(
'type' => new CommentType(),
'options' => array(
'required' => false,
'data_class' => 'Site\Entity\Comment'
'allow_add' => true,
'allow_delete' => true
),
))
->getForm();