I have a question about service and Form in Symfony2,so I created my calss form and I hope to add a multiselect list of cities then I want to get list of cities from another class "city",so how I can call my class "city" in my form using "Service" to get a function "getcities" to return me a list of cities? (I dont use Doctrine here)...
Edit
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class CityType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'choices' => array( /**
* Here I will call function getcities(return list of cities)
*/
)
));
}
public function getParent()
{
return 'choice';
}
public function getName()
{
return 'gender';
}
}
class City.php :
Class City {
/**
* here i will get list of cities
*/
public function getcities()
{
.....
return $Listcities;
}
}
So I would like to use "Service" to call function "getcities" in form?
The form objects are not container-aware...at least, they're not meant to be. That said, your controller should use the service to get the cities, and then it should pass that list into the form object either through a constructor or a method.
Controller:
class SomethingController
{
public function someAction()
{
...
$cities = $this->get("citiesService")->getCities();
$form = $this->createForm(new SomeType($cities), $someEntity);
...
}
}
Form:
class SomeType extends AbstractType
{
private $cities;
public function __construct($cities)
{
$this->cities = $cities;
}
public function buildForm(FormBuilder $builder, array $options)
{
// Now you have access to $this->cities, so you can use it to build the form
}
}
Do you can set City object as form data object?
so it can looks like that...
$form = $this->createForm(new SomeType(), new City());
class SomeType extends AbstractType
{
public buildForm(FormBuilderInterface $builder, array $options)
{
$formFactory = $builder->getFormFactory();
$builder->addEventListener(
FormsEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formFactory) {
$event->getForm()->add(
$formFactory->createNamed(
'gender',
'choice',
null,
array(
'choices' => $event->getData()->getCites()
)
)
);
}
);
}
}
Related
I'm trying to populate form from database by using two entities. Here's the code I use
CategoryType
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
}
public function configureOptions(OptionsResolver $options)
{
return array(
'data_class' => 'AppBundle\Entity\Category',
);
}
public function getName()
{
return 'questionnaire';
}
}
ProductType
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
}
public function configureOptions(OptionsResolver $options)
{
return array(
'data_class' => 'AppBundle\Entity\Product',
);
}
public function getName()
{
return 'questionnaire';
}
}
CommonType
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use AppBundle\Form\CategoryType;
use AppBundle\Form\ProductType;
class CommonType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('category', new CategoryType());
$builder->add('product', new ProductType());
}
public function getName()
{
return 'app_common_type';
}
}
DefaultController
<?php
namespace AppBundle\Controller;
use AppBundle\Form\CommonType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
$data = $this->getDoctrine()->getRepository('AppBundle:Product')->findOneBy(['id' => 2]);
$form = $this->createForm(new CommonType(), $data);
return $this->render('AppBundle:Default:index.html.twig', ['form' => $form->createView()]);
}
}
But I get this error
The form's view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class Proxies\__CG__\AppBundle\Entity\Category. You can avoid this error by setting the "data_class" option to "Proxies\__CG__\AppBundle\Entity\Category" or by adding a view transformer that transforms an instance of class Proxies\__CG__\AppBundle\Entity\Category to scalar, array or an instance of \ArrayAccess.
So what I'm doing wrong and is this the correct way to populate form based on two or more entities?
Your Common form's model data format is an array (as far as no data_class given). So the right data to set is an array with product and category keys:
$product = $this->getDoctrine()->getRepository('AppBundle:Product')->findOneBy(['id' => 2]);
$form = $this->createForm(new CommonType(), ['product' => $product]);
tl;dr:
Is there any way to have the 'context' option auto-cascade through all form types ? It would NOT be leasable to pass it along manually in the form types like this:
$builder->add('organizer', 'organizer_type', array('context' => $options['context']));
Hello everybody,
I have written an extension to ALL Symfony form types:
class ContextExtension extends AbstractTypeExtension
{
protected $context;
public function __construct(SecurityContextInterface $context)
{
$this->context = $context->getToken()->getUser()->getContext();
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'context' => $this->context
]);
$resolver->setAllowedTypes(['context' => 'GOC\Bundle\FrameworkBundle\Model\ContextInterface']);
}
/**
* Returns the name of the type being extended.
*
* #return string The name of the type being extended
*/
public function getExtendedType()
{
return 'form';
}
}
I have validated that it is registered and working (for the most part). I only face one problem. When I set my new option ('context') in a form type like this:
class EventType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'eventgroup', 'eventgroup_type', array(
'context' => $context,
)
)
}
public function getName()
{
return 'event';
}
}
I receive the option in the event group form type and can work with it there:
class EventGroupType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->log($options['context']);
$builder
->add('name', 'text')
->add('comment', 'text')
->add('organizer', 'organizer_type')
;
}
public function getName()
{
return 'eventgroup_type';
}
}
However, it appears that the options does not cascade any further and is therefore not usable in the text or organizer type. Is there any way to have the 'context' option auto-cascade through all form types ? It would NOT be leasable to pass it along manually in the form types like this:
$builder->add('organizer', 'organizer_type', array('context' => $options['context']));
I am trying to create a form by merging 2 form types as following.
Teacher Entity that has a one to one relation with User Entity.
I am using FOSUserBundle and i want to merge the ResettingFormType with my custom TeacherFormType, to end up with a form that both fields from my custom & fos reset password form.
1- Teacher Entity:
/**
* #var \User
*
* #ORM\OneToOne(targetEntity="ITJari\UserBundle\Entity\User", fetch="EAGER")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*
*/
private $user;
public function getUser() {
return $this->user;
}
public function setUser($user) {
$this->user = $user;
return $this;
}
2- Extending FOS Reset password:
namespace ITJari\SchoolBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class ResettingFormType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
}
public function getParent() {
return 'fos_user_resetting';
}
public function getName() {
return 'ragab';
}
}
3- Teacher Form Type
namespace ITJari\SchoolBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TeacherFormType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'ITJari\SchoolBundle\Entity\Teacher',
));
}
public function getParent() {
return 'fos_user_resetting';
}
public function getName() {
return 'teacherform';
}
}
4- Inside controller:
$teacher = new \ITJari\SchoolBundle\Entity\Teacher();
$teacher->setUser($user);
$form = $this->createForm('teacherform', $teacher);
But i got the following error:
Neither the property "plainPassword" nor one of the methods "getPlainPassword()", "isPlainPassword()", "hasPlainPassword()", "__get()" exist and have public access in class "ITJari\SchoolBundle\Entity\Teacher".
500 Internal Server Error - NoSuchPropertyException
I added a form event to my Symfony Form. The problem is that this event seems to be fired twice. When I am debugging, it goes twice into the method and I don't know why.
I have a form Type that uses another form type. I have a VideoFileType form that is adding a field of ImageType. Both of these forms need some process to be done once the form is submitted.
ImageType
<?php
# src/Acme/PhotoBundle/Form/Type/ThumbnailType.php
namespace OSC\MediaBundle\Form\Type;
use OSC\MediaBundle\Manager\ImageManager;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ImageType extends AbstractType
{
private $imageManager;
public function __construct(ImageManager $imageManager) {
$this->imageManager = $imageManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', 'file');
$builder->addEventListener(
FormEvents::POST_SUBMIT,
array($this, 'onPostSetData')
);
}
public function getDefaultOptions(array $options) {
return array('data_class' => 'OSC\MediaBundle\Entity\Image');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'OSC\MediaBundle\Entity\Image'
));
}
public function onPostSetData(FormEvent $event) {
$image = $event->getData();
$form = $event->getForm();
//We need here to update the image file with the new content
$image = $this->imageManager->uploadImage($image);
$event->setData($image);
}
public function getName()
{
return 'image';
}
}
VideoFileType
<?php
# src/Acme/PhotoBundle/Form/Type/ThumbnailType.php
namespace OSC\MediaBundle\Form\Type;
use OSC\MediaBundle\Manager\VideoFileManager;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class VideoFileType extends AbstractType
{
public $container;
public $videoPresets = [];
public $videoFileManager;
public function __construct(VideoFileManager $videoFileManager, Container $container) {
$this->container = $container;
$videoPresets = $container->getParameter('osc_media.video.presets');
foreach ($videoPresets as $key => $videoPreset) {
array_push($this->videoPresets, $key);
}
$this->videoFileManager = $videoFileManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('thumbnail', 'image');
$builder->add('file', 'file');
$builder->add('videoPreset', 'choice', array(
'choices' => $this->videoPresets,
'multiple' => false,
'required' => true
));
$builder->addEventListener(
FormEvents::POST_SUBMIT,
array($this, 'onPostSetData')
);
$builder->add('save', 'submit');
}
public function onPostSetData(FormEvent $event) {
$videoFile = $event->getData();
$form = $event->getForm();
//We upload the video file
$videoFile = $this->videoFileManager->uploadVideoFile($videoFile);
$event->setData($videoFile);
}
public function getDefaultOptions(array $options) {
return array('data_class' => 'OSC\MediaBundle\Entity\VideoFile');
}
public function getName()
{
return 'video_file';
}
}
I don't know why the onPostSetData method is called twice...
In refference to my question I asked a few hours ago, I will try to ask more specific question now.
I have followed guidelines from official cookbook, and this article.
I have added new class MyType extends AbstractType in Me\MyBundle\Controller\Form\Type direcory.
I have created a template for that custom field type.
I have added proper entry in config.yml in order to use new template in forms.
But how can I use that custom field?
Let's say I have controller which looks like this:
namespace Me\MyBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Me\MyBundle\Form\Type\MyType;
class DefaultController extends Controller
{
public function indexAction()
{
$form = $this->createFormBuilder()
->add('my_type', new MyType(), array('param' => 0))
->getForm()
;
return $this->render('MyBundle::index.html.twig', array(
'form' => $form->createView(),
));
}
}
Line ->add('my_type', new MyType(), array('param' => 0)) does not seem to have any affect on generating form. There is also no errors.
How can I make my custom field to be reused in the same form multiple times, with different params?
Edit:
MyType class looks like this:
class MyType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'param' => 1,
)
));
}
public function getParent()
{
return 'text';
}
public function getName()
{
return 'my_type';
}
}
May try to implements buildForm method :
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options
{
$builder->add(...);
}