Create form from variable classnames with parameters - php

I have a controller ment to give the user the correct form type using variable classnames.
There is a entity named EntityForm which stores data of all forms avaible, with methods to give class name and form type names:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="entity_form")
*/
class EntityForm
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #var string
*
* #ORM\Column(length=12)
*/
protected $url;
/**
* #var string
*
* #ORM\Column
*/
protected $name;
/**
* #var string
*
* #ORM\Column(name="class_name")
*/
protected $className;
/**
* #var string
*
* #ORM\Column(name="description")
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set url
*
* #param string $url
*
* #return Form
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* Get url
*
* #return string
*/
public function getUrl()
{
return $this->url;
}
/**
* Set name
*
* #param string $name
*
* #return Form
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set className
*
* #param string $className
*
* #return Form
*/
public function setClassName($className)
{
$this->className = $className;
return $this;
}
/**
* Get className
*
* #return string
*/
public function getClassName()
{
return $this->className;
}
public function createEntity()
{
$entity = sprintf('%s\%s', __NAMESPACE__, $this->getClassName());
return new $entity;
}
public function createType()
{
return sprintf('AppBundle\Form\%sType', $this->getClassName());
}
/**
* Set description
*
* #param string $description
*
* #return Form
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
}
The action mend to create proper forms looks like this:
/**
* #Route("/form/ent/{url}", name="entity_form")
* #Method("GET")
*/
public function formAction(EntityForm $entityForm)
{
$form = $this->createForm($entityForm->createType())
->add('Dodaj!', SubmitType::class, array(
'attr' => array(
'class' => 'btn-info'
)
))
;
return $this->render('default/form.html.twig', [
'form_name' => $entityForm->getName(),
'form_description' => $entityForm->getDescription(),
'form' => $form->createView(),
]);
}
This controller links to a proper form type ie. for the cyclicNewsletter
class CyclicNewsletterType extends AbstractType
{
private $doctrine;
public function __construct($doctrine)
{
$this->doctrine = $doctrine;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$currencies = $this->doctrine->getRepository('AppBundle:Currency')->findAll();
$currenciesFormat = array();
foreach($currencies as $currency){
$currenciesFormat += array($currency->getName() .' ('. $currency->getShortName() . ')' => $currency);
}
$cycles = $this->doctrine->getRepository('AppBundle:Cycle')->findAll();
$cyclesFormat = array();
foreach($cycles as $cycle){
$cyclesFormat += array($cycle->getName() => $cycle);
}
$builder
->add('currency', ChoiceType::class, array(
'label' => 'Waluta',
'choices' => $currenciesFormat,
))
->add('cycle', ChoiceType::class, array(
'label' => 'Cykl',
'choices' => $cyclesFormat,
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => CyclicNewsletter::class,
));
}
}
Now with a simple POST action i can eaisly add new values to the database without writing separate actions for all forms:
/**
* #Route("/form/ent/{url}", name="form_entity_post")
* #Method("POST")
*
*/
public function formPostAction(EntityForm $entityForm, Request $request)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm($entityForm->createType())
->add('Dodaj!', SubmitType::class)
;
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$formData = $form->getData();
$formData->setUser($this->container->get('security.token_storage')->getToken()->getUser());
$em->persist($formData);
$em->flush();
return $this->redirectToRoute('form_complete', ['url' => $entityForm->getUrl(), 'entityId' => $formData->getId()]);
}
var_dump('problem ' . $form->getErrors());
exit;
}
However
I cant seem to get the method to work for injecting an already created object into the form builder for editing.
What i mean is write a form create with variables classnames that would also store one instance of entity, which values will be already set in the form.
Is such way possible in symfony?

You will need to add the id of the entity you are editing into your url, and make it optional.
* #Route("/form/ent/{url}/{id}", name="form_entity_post", defaults={"id" = null})
In your controller, when you are building the form you need to get that object from the database and pass it to createForm method as the second argument.
/**
* #Route("/form/ent/{url}/{id}", name="form_entity_post", defaults={"id" = null})
* #Method("POST")
*
*/
public function formPostAction(EntityForm $entityForm, Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = null;
if ($id) {
$entity = $em->getRepository($entityForm->getClassName)->find($id);
}
$form = $this->createForm($entityForm->createType(), $entity)
->add('Dodaj!', SubmitType::class)
;

Related

Symfony form choice default value from entity

I having some troubles with symfony forms.
I have a boolean variable in my entity. I cant find a way to set that value in my form when i'm editing it.
Entity
namespace AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="pages")
*/
class Page
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="text")
*/
protected $slug;
/**
* #ORM\Column(type="text")
*/
protected $title;
/**
* #ORM\Column(type="text")
*/
protected $content;
/**
* #ORM\Column(name="creation_date", type="datetime")
*/
protected $creationDate;
/**
* #ORM\Column(name="is_active", type="boolean")
*/
protected $isActive = true;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set slug
*
* #param string $slug
*
* #return Page
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set title
*
* #param string $title
*
* #return Page
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set content
*
* #param string $content
*
* #return Page
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* #return string
*/
public function getContent()
{
return $this->content;
}
/**
* Set creationDate
*
* #param \DateTime $creationDate
*
* #return Page
*/
public function setCreationDate($creationDate)
{
$this->creationDate = $creationDate;
return $this;
}
/**
* Get creationDate
*
* #return \DateTime
*/
public function getCreationDate()
{
return $this->creationDate;
}
/**
* Set isActive
*
* #param boolean $isActive
*
* #return Page
*/
public function setIsActive($isActive)
{
$this->isActive = $isActive;
return $this;
}
/**
* Get isActive
*
* #return boolean
*/
public function getIsActive()
{
return $this->isActive;
}
}
Controller function
public function editAction(Request $request, $pageId)
{
$em = $this->getDoctrine()->getManager();
$page = $em->getRepository('AdminBundle:Page')->find($pageId);
$form = $this->createForm('app_page', $page);
$form->handleRequest($request);
if($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($page);
$em->flush();
return $this->redirectToRoute('admin_pages');
}
return $this->render('AdminBundle::editPage.html.twig', array('page' => $page, 'form' => $form->createView()));
}
PageFormType
namespace AdminBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class PageFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title', 'text');
$builder->add('slug', 'text');
$builder->add('isActive', 'choice', array('choices' => array(
'true' => 'Active',
'false' => 'Inactive'
)));
$builder->add('content', 'textarea', array('required' => false));
}
public function getName()
{
return 'app_page';
}
}
As you can see i wrote my self in FormType class what choices it has. And now it is always displaying "Active" instead of displaying Entity's value. How should i do that?
Thanks!
Try to change your isActive in the Entity like
protected $isActive ;
and if you want to make a default true you can make it at the construct like :
public function __construct() {
$this->setIsActive = true ;
}
$builder->add('isActive', ChoiceType::class, [
'choices' => [
'Active' => true,
'Inactive' => false
],
'choices_as_values' => true,
'multiple' => true,
'expanded' => true,
'data' => array(true)
]);
A 2021 Solution: setting form choice default value (data) from entity
Sometimes your choice field values exist in another entity table, which means you cannot populate them using default form data_class. You only get the string value that saved in the form entity, resulting to error: ...must be an object or null, string given...
protected EntityManagerInterface $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
// In your form
->add('membershipType', EntityType::class, [
'class' => MembershipType::class,
'label' => 'Enter membership type here',
'data' => $this->em->getRepository(MembershipType::class)->findOneBy([
'name' => $your_value_here
])
])

Symfony Data Transform and Update Form With The Data

Between 2 entities exists OneToMany relationship. First is User Entity second is Domains entities. One user can have multiple domains.
This is Users Entity (removed other fields because unrelated with subject):
class Users extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="\UsersBundle\Entity\UserDomains" , mappedBy="user" , cascade={"all"})
*/
protected $domains;
/**
* Add domain
*
* #param \UsersBundle\Entity\UserDomains $domain
*
* #return Users
*/
public function addDomain(\UsersBundle\Entity\UserDomains $domain)
{
$this->domains[] = $domain;
return $this;
}
/**
* Remove domain
*
* #param \UsersBundle\Entity\UserDomains $domain
*/
public function removeDomain(\UsersBundle\Entity\UserDomains $domain)
{
$this->domains->removeElement($domain);
}
}
This is UserDomains Entity (some fields has been removed):
class UserDomains
{
public function __construct() {
$this->setCreatedAt(new \DateTime());
}
public function __toString()
{
return $this->name;
}
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="AffiliateBundle\Entity\Users", inversedBy="domains")
* #ORM\JoinColumn(name="user", referencedColumnName="id", onDelete="CASCADE")
*/
private $user;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set user
*
* #param integer $user
*
* #return UserDomains
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return integer
*/
public function getUser()
{
return $this->user;
}
/**
* Set name
*
* #param string $name
*
* #return UserDomains
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
}
Must be add a domain when register user to system. I have got RegisterType for registration form. This type form class has got DataTransformer for adding domain which register user.
RegisterType class is here:
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('fullName', 'text', array('attr' => array('class' => 'form-control'), 'label' => 'user_register.fullname', 'translation_domain' => 'UsersBundle'))
->add('domains', 'text', array('attr' => array('class' => 'form-control select2', 'id' => 'select2_sample1')))
;
$builder->get('domains')->addModelTransformer(new CallbackTransformer(
function(){
return '';
},
function($data){
$arrCollection = new ArrayCollection();
if (strpos($data, ",") !== false) {
$expData = explode(',', $data);
foreach ($expData as $domain) {
$domainObj = new UserDomains();
$domainObj->setName($domain);
$domainObj->setEnabled(true);
$arrCollection->add($domainObj);
}
} else if (!empty($data)) {
$domain = new UserDomains();
$domain->setName($data);
$domain->setEnabled(true);
$arrCollection->add($domain);
}
return $arrCollection;
}
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MyBundle\Entity\Users',
'intention' => 'registration',
));
}
public function getParent()
{
return 'fos_user_registration';
// Or for Symfony < 2.8
// return 'fos_user_registration';
}
public function getName()
{
return 'user_registration';
}
}
So anyone fill the register form and submit. User created and adding the domains to user_domains table but doesn't update the user field which must be new user's id. How to do this with automatically? Or have you got any idea to update this user column of user_domains table with the new user's id?
Thanks for helps to all StackoverFlow :)
Add __construct like this to RegistrationType:
class RegistrationType extends AbstractType
{
private $user;
public function __construct(Users $user) {
$this->user = $user;
}
add setUser function to your DataTransform like this:
$domainObj->setUser($this->user);
//and
$domain->setUser($this->user);
finally update your controller like this:
$form = $this->createForm(new RegistrationType($userEntity), $userEntity);

Symfony - Integrity constraint violation: 1062 Duplicate entry

I tried to find an answer for my question but it was unsuccessful. I'm using Symfony (Ive been using it 2 months) and I have a problem when I want to make many to many relationship.
I have homes and I have services. One home can have a lot of services and one service can have a lot of homes. Everything is ok and I understand the way many to many works with the doctrine, i persisted all values before flush in my controller, but i always get this message:
An exception occurred while executing 'INSERT INTO homess_services (home_id, service_id) VALUES (?, ?)' with params [25, 7]:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '25' for key 'home_id'
My codes are (home entity):
<?php
namespace Filip\SymfonyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Filip\SymfonyBundle\FilipSymfonyBundle;
/**
* Home
*
* #ORM\Table(name="homes")
* #ORM\Entity
*
*
*/
class Home
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Service", inversedBy="homes")
* #ORM\JoinTable(name="homess_services")
*/
protected $services;
public function __construct() {
$this->photos = new ArrayCollection();
$this->services = new ArrayCollection();
}
/**
* Renders a publication as a string
*
* #return string
*/
public function __toString (){
return $this->getName();
}
/**
* Add services
*
* #param \Filip\SymfonyBundle\Entity\Service $services
* #return Home
*/
public function addService(\Filip\SymfonyBundle\Entity\Service $services)
{
$this->services[] = $services;
return $this;
}
/**
* Remove services
*
* #param \Filip\SymfonyBundle\Entity\Service $services
*/
public function removeService(\Filip\SymfonyBundle\Entity\Service $services)
{
$this->services->removeElement($services);
}
/**
* Get services
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getServices()
{
return $this->services;
}
Service entity:
<?php
namespace Filip\SymfonyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Filip\SymfonyBundle\FilipSymfonyBundle;
/**
* Service
*
* #ORM\Table("services")
* #ORM\Entity
*/
class Service
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Home", mappedBy="services")
*/
protected $homes;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM
\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="category", type="string", length=45)
*/
private $category;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=45)
*/
private $name;
/**
* Renders a service as a string
*
* #return string
*/
/**
* Get id
*
6
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set category
*
* #param string $category
* #return Service
*/
public function setCategory($category)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return string
*/
public function getCategory()
{
return $this->category;
}
/**
* Set name
*
* #param string $name
* #return Service
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
public function __construct()
{
$this->homes = new ArrayCollection();
}
/**
* Add homes
*
* #param \Filip\SymfonyBundle\Entity\Home $homes
* #return Service
*/
public function addHome(\Filip\SymfonyBundle\Entity\Home $homes)
{
$this->homes[] = $homes;
return $this;
}
/**
* Remove homes
*
* #param \Filip\SymfonyBundle\Entity\Home $homes
*/
public function removeHome(\Filip\SymfonyBundle\Entity\Home $homes)
{
$this->homes->removeElement($homes);
}
/**
* Get homes
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getHomes()
{
return $this->homes;
}
}
Form(HomeType):
<?php
namespace Filip\SymfonyBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class HomeType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('city')
->add('region')
->add('phone')
->add('address')
->add('email')
->add('website')
->add('content')
->add('youtubeApi')
->add('premium')
->add('services' , 'entity' , array(
'class' => 'FilipSymfonyBundle:Service' ,
'property' => 'name' ,
'expanded' => true ,
'multiple' => true ,
));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Filip\SymfonyBundle\Entity\Home'
));
}
/**
* #return string
*/
public function getName()
{
return 'filip_symfonybundle_home';
}
}
Home controller:
/**
* Creates a new Home entity.
*
* #Route("/", name="home_create")
* #Method("POST")
* #Template("FilipSymfonyBundle:Home:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Home();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$services = $entity->getServices();
foreach($services as $service) {
$entity->addService($service);
$em->persist($service);
}
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('home_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Creates a form to create a Home entity.
*
* #param Home $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Home $entity)
{
$form = $this->createForm(new HomeType(), $entity, array(
'action' => $this->generateUrl('home_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
in the if($form->isValid()) part you don't need to call the addService() method in the foreach loop as Symfony will do this for you on the handleRequest() call.
If the Home entity is at the owning side of the ManyToMany relation you don't need to persist every Service object too. So you can try to remove the whole foreach loop too.

Symfony2 relationship between two entities

I want to make a relationship between two entities but for some reason I am getting NULL on one of the values...
So in my skin entity I have an email_registration_id field with the relationship :
/**
* #ORM\ManyToOne(targetEntity="Project\UserBundle\Entity\Email")
* #ORM\JoinColumn(name="email_registration_id", referencedColumnName="id")
*/
protected $email_registration_id;
/**
* Set email_registration_id
*
* #param \Project\UserBundle\Entity\Email $email_registration_id
* #return Skin
*/
public function setEmailRegistrationId(\Project\UserBundle\Entity\Email $email_registration_id = null)
{
$this->email_registration_id = $email_registration_id;
return $this;
}
/**
* Get email_registration_id
*
* #return \Project\UserBundle\Entity\Email
*/
public function getEmailRegistrationId()
{
return $this->email_registration_id;
}
And this is the Email entity:
/**
* Project\UserBundle\Entity\Email
*
* #ORM\Entity
* #ORM\Table(name="email")
*/
class Email {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string $title
*
* #ORM\Column(name="title", type="string")
*/
protected $title;
/**
* #var string $registration_content
*
* #ORM\Column(name="registration_content", type="string")
*/
protected $registration_content;
/**
* #var string $confirmation_apuestas
*
* #ORM\Column(name="confirmation_apuestas", type="string")
*/
protected $confirmation_apuestas;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function setId() {
$this->id = null;
}
/**
* Set title
*
* #param string $title
* #return Email
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set registration_content
*
* #param string $registration_content
* #return Email
*/
public function setRegistrationContent($registration_content)
{
$this->registration_content = $registration_content;
return $this;
}
/**
* Get registration_content
*
* #return string
*/
public function getRegistrationContent()
{
return $this->registration_content;
}
/**
* Set $confirmation_apuestas
*
* #param string $confirmation_apuestas
* #return Email
*/
public function setConfirmationApuestas($confirmation_apuestas)
{
$this->confirmation_apuestas = $confirmation_apuestas;
return $this;
}
/**
* Get $confirmation_apuestas
*
*
#return string
*/
public function getConfirmationApuestas()
{
return $this->confirmation_apuestas;
}
}
Now in my cms i create a new email like this:
/**
* #Route("/new", name="cms_email_new")
* #Method({"GET"})
* #Template()
*/
public function newAction() {
$item = new Email();
$form = $this->createForm(new EmailType($this->container->getParameter("langs")), $item);
return array('form' => $form->createView(), 'item' => $item);
}
The form:
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'));
$builder->add('registration_content', 'textarea', array('label' => 'cms.registration.content'));
$builder->add('confirmation_apuestas', 'textarea', array('label' => 'cms.confirmation.apuestas'));
}
public function getDefaultOptions(array $options) {
return array(
'data_class' => 'Project\UserBundle\Entity\Email',
);
}
This is how I persist the Email to the database:
/**
* #Route("/save", name="cms_email_save")
* #Template("ProjectUserBundle:EmailAdmin:new.html.twig")
* #Method({"POST"})
*/
public function saveAction(Request $request) {
$item = new Email();
$type = new EmailType($this->container->getParameter("langs"));
$form = $this->createForm($type, $item);
$form->bind($request);
$em = $this->getEntityManager();
if ($form->isValid()) {
$this->upload($form, $item);
$em->persist($item);
$em->flush();
return $this->redirect($this->generateUrl('cms_skin_email_list', array('skin_id' => $item->getId())));
}
return array('form' => $form->createView(), 'item' => $item);
}
The problem is that it creates an email, but in my skin entity, the email_registration_id is just NULL and not the same as emails Id... Maybe I missed something?
UPDATE
So this is what I made according to the responses I got:
class Email {
/**
* #ORM\OneToMany(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email_registration_id")
*/
protected $skin;
/**
* Set skin
*
* #param string $skin
* #return Email
*/
public function setSkin(\Project\SkinBundle\Entity\Skin $skin = null)
{
$this->skin = $skin;
return $this;
}
/**
* Get skin
*
* #return string
*/
public function getSkin()
{
return $this->skin;
}
And the form:
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'));
$builder->add('registration_content', 'textarea', array('label' => 'cms.registration.content'));
$builder->add('confirmation_apuestas', 'textarea', array('label' => 'cms.confirmation.apuestas'));
$builder->add('skin', 'entity', array(
'class' => 'ProjectSkinBundle:Skin',
'property' => 'id',
));
}
However when i am trying to flush to the database I get this error:
ContextErrorException: Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in C:\wamp\www\Company\front\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php on line 528 and defined in C:\wamp\www\Company\front\vendor\doctrine\collections\lib\Doctrine\Common\Collections\ArrayCollection.php line 48
It's normal that the creation of a new email is not associated to a skin object. How could it ? The relation is unidirectional, and only works when you create a skin and you give it an email. To create an email and give it a skin, you have to make the relation bidirectional, and add it to your email form.
To do this, I'd do the following :
/*
* Class Project\UserBundle\Entity\Email
*/
class Email {
...
/**
* #ORM\OneToMany(targetEntity="Project\SkinBundle\Entity\Skin", mappedBy="email_registration_id")
*/
protected $skin;
and in your form :
public function buildForm(FormBuilderInterface $builder, array $option) {
$builder->add('title', 'text', array('label' => 'cms.Title'))
->add('registration_content', 'textarea', array('label' => 'cms.registration.content'))
->add('confirmation_apuestas', 'textarea', array('label' => 'cms.confirmation.apuestas'))
->add('skin')
;
}
And PS : You should not use the bind() method to handle the request, it is deprecated. Instead use :
$form->handleRequest($request);
UPDATE 1 : Don't forget to also update your ManyToOne annotation adding the inversedBy part :
#ORM\ManyToOne(targetEntity="Project\UserBundle\Entity\Email", inversedBy="skin")
And also, of course, update your database.

Error with file upload in symfony 2

trying to setup a file upload form attached to a Doctrine entity, according to this cookbook recipe:
http://symfony.com/doc/2.0/cookbook/doctrine/file_uploads.html
Here's my entity/model class:
<?php
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* Invoice
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="TechPeople\InvoiceBundle\Entity\InvoiceRepository")
* #ORM\HasLifecycleCallbacks
*/
class Invoice
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="User", inversedBy="user_invoices")
* #ORM\JoinColumn(name="vendor_id", referencedColumnName="id")
*/
private $vendor;
/**
* #var string
*
* #ORM\Column(name="month", type="string", length=255)
*/
private $month;
/**
* #var integer
*
* #ORM\Column(name="year", type="smallint")
*/
private $year;
/**
* #var boolean
*
* #ORM\Column(name="expenses", type="boolean")
*/
private $expenses;
/**
* #var \DateTime
*
* #ORM\Column(name="due", type="date")
*/
private $due;
/**
* #var \DateTime
*
* #ORM\Column(name="paid", type="date")
*/
private $paid;
/**
* #var \DateTime
*
* #ORM\Column(name="created", type="datetime")
*/
private $created;
/**
* #var float
*
* #ORM\Column(name="expense_amount", type="decimal")
*/
private $expense_amount;
/**
* #var float
*
* #ORM\Column(name="total_amount", type="decimal")
*/
private $total_amount;
/**
* #var UploadedFile
*
* #Assert\File(maxSize="6000000")
*/
public $attachment;
/**
* #var string
*
* #ORM\Column(name="attachment_path", type="string", length=255)
*/
private $attachment_path;
/**
* #ORM\OneToMany(targetEntity="InvoiceItem", mappedBy="invoice")
*/
protected $invoice_items;
/**
* Constructor for Invoice Entity class
*/
public function __construct()
{
$this->products = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set month
*
* #param string $month
* #return Invoice
*/
public function setMonth($month)
{
$this->month = $month;
return $this;
}
/**
* Get month
*
* #return string
*/
public function getMonth()
{
return $this->month;
}
/**
* Set year
*
* #param integer $year
* #return Invoice
*/
public function setYear($year)
{
$this->year = $year;
return $this;
}
/**
* Get year
*
* #return integer
*/
public function getYear()
{
return $this->year;
}
/**
* Set expenses
*
* #param boolean $expenses
* #return Invoice
*/
public function setExpenses($expenses)
{
$this->expenses = $expenses;
return $this;
}
/**
* Get expenses
*
* #return boolean
*/
public function getExpenses()
{
return $this->expenses;
}
/**
* Set due
*
* #param \DateTime $due
* #return Invoice
*/
public function setDue($due)
{
$this->due = $due;
return $this;
}
/**
* Get due
*
* #return \DateTime
*/
public function getDue()
{
return $this->due;
}
/**
* Set paid
*
* #param \DateTime $paid
* #return Invoice
*/
public function setPaid($paid)
{
$this->paid = $paid;
return $this;
}
/**
* Get paid
*
* #return \DateTime
*/
public function getPaid()
{
return $this->paid;
}
/**
* Set created
*
* #param \DateTime $created
* #return Invoice
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* #return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set expense_amount
*
* #param float $expenseAmount
* #return Invoice
*/
public function setExpenseAmount($expenseAmount)
{
$this->expense_amount = $expenseAmount;
return $this;
}
/**
* Get expense_amount
*
* #return float
*/
public function getExpenseAmount()
{
return $this->expense_amount;
}
/**
* Set total_amount
*
* #param float $totalAmount
* #return Invoice
*/
public function setTotalAmount($totalAmount)
{
$this->total_amount = $totalAmount;
return $this;
}
/**
* Get total_amount
*
* #return float
*/
public function getTotalAmount()
{
return $this->total_amount;
}
/**
* Set attachment
*
* #param string $attachment
* #return Invoice
*/
public function setAttachment($attachment)
{
$this->attachment = $attachment;
return $this;
}
/**
* Get attachment
*
* #return string
*/
public function getAttachment()
{
return $this->attachment;
}
/**
* Set vendor
*
* #param \TechPeople\InvoiceBundle\Entity\User $vendor
* #return Invoice
*/
public function setVendor(\TechPeople\InvoiceBundle\Entity\User $vendor = null)
{
$this->vendor = $vendor;
return $this;
}
/**
* Get vendor
*
* #return \TechPeople\InvoiceBundle\Entity\User
*/
public function getVendor()
{
return $this->vendor;
}
/**
* Add invoice_items
*
* #param \TechPeople\InvoiceBundle\Entity\InvoiceItem $invoiceItems
* #return Invoice
*/
public function addInvoiceItem(\TechPeople\InvoiceBundle\Entity\InvoiceItem $invoiceItems)
{
$this->invoice_items[] = $invoiceItems;
return $this;
}
/**
* Remove invoice_items
*
* #param \TechPeople\InvoiceBundle\Entity\InvoiceItem $invoiceItems
*/
public function removeInvoiceItem(\TechPeople\InvoiceBundle\Entity\InvoiceItem $invoiceItems)
{
$this->invoice_items->removeElement($invoiceItems);
}
/**
* Get invoice_items
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getInvoiceItems()
{
return $this->invoice_items;
}
/**
* Get path for attachment
*
* #param string $type Can return web path, or absolute path, web is default
* #return null|string
*/
public function getAttachmentPath($type='web')
{
if($type == 'absolute') {
return null === $this->attachment_path
? null
: $this->getUploadRootDir().'/'.$this->attachment_path;
} else {
return null === $this->attachment_path
? null
: $this->getUploadDir().'/'.$this->attachment_path;
}
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded
// documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/invoice/attachments';
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->attachment) {
// do whatever you want to generate a unique name
$filename = sha1(uniqid(mt_rand(), true));
$this->attachment = $filename.'.'.$this->attachment->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->attachment) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->attachment->move($this->getUploadRootDir(), $this->path);
unset($this->attachment);
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAttachmentPath('absolute')) {
unlink($file);
}
}
}
I get the following error when I try to submit an edit form (the edit form was generated by doctrine:generate:crud):
Fatal error: Call to a member function move() on a non-object
Might be the same as:
Symfony forms. File upload
But that question isn't answered. I hope it doesn't violate etiquette to post a second question.
I'm pretty new to Symfony2, just trying to learn my way around, and this has me stumped. I can post any other info you need, just let me know what.
Here's the form class:
<?php
namespace TechPeople\InvoiceBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class InvoiceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('month')
->add('year')
->add('expenses')
->add('due')
->add('paid')
->add('created')
->add('expense_amount')
->add('total_amount')
->add('attachment')
->add('vendor')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'TechPeople\InvoiceBundle\Entity\Invoice'
));
}
public function getName()
{
return 'techpeople_invoicebundle_invoicetype';
}
}
And here's the controller:
<?php
namespace TechPeople\InvoiceBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use TechPeople\InvoiceBundle\Entity\Invoice;
use TechPeople\InvoiceBundle\Form\InvoiceType;
/**
* Invoice controller.
*
*/
class InvoiceController extends Controller
{
/**
* Lists all Invoice entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('TechPeopleInvoiceBundle:Invoice')->findAll();
return $this->render('TechPeopleInvoiceBundle:Invoice:index.html.twig', array(
'entities' => $entities,
));
}
/**
* Finds and displays a Invoice entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('TechPeopleInvoiceBundle:Invoice')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Invoice entity.');
}
$deleteForm = $this->createDeleteForm($id);
return $this->render('TechPeopleInvoiceBundle:Invoice:show.html.twig', array(
'entity' => $entity,
'delete_form' => $deleteForm->createView(), ));
}
/**
* Displays a form to create a new Invoice entity.
*
*/
public function newAction()
{
$entity = new Invoice();
$form = $this->createForm(new InvoiceType(), $entity);
return $this->render('TechPeopleInvoiceBundle:Invoice:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Creates a new Invoice entity.
*
*/
public function createAction(Request $request)
{
$entity = new Invoice();
$form = $this->createForm(new InvoiceType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('invoice_show', array('id' => $entity->getId())));
}
return $this->render('TechPeopleInvoiceBundle:Invoice:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Displays a form to edit an existing Invoice entity.
*
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('TechPeopleInvoiceBundle:Invoice')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Invoice entity.');
}
$editForm = $this->createForm(new InvoiceType(), $entity);
$deleteForm = $this->createDeleteForm($id);
return $this->render('TechPeopleInvoiceBundle:Invoice:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Edits an existing Invoice entity.
*
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('TechPeopleInvoiceBundle:Invoice')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Invoice entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createForm(new InvoiceType(), $entity);
$editForm->bind($request);
if ($editForm->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('invoice_edit', array('id' => $id)));
}
return $this->render('TechPeopleInvoiceBundle:Invoice:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Deletes a Invoice entity.
*
*/
public function deleteAction(Request $request, $id)
{
$form = $this->createDeleteForm($id);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('TechPeopleInvoiceBundle:Invoice')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Invoice entity.');
}
$em->remove($entity);
$em->flush();
}
return $this->redirect($this->generateUrl('invoice'));
}
private function createDeleteForm($id)
{
return $this->createFormBuilder(array('id' => $id))
->add('id', 'hidden')
->getForm()
;
}
}
It's all pretty basic stuff, straight from the docs, because, as I said, I'm just learning Symfony. Any help much appreciated.
$this->attachment must be an UploadedFile object.
But in your method preUpload() you do a mistake and override it for a string:
$this->attachment = $filename.'.'.$this->attachment->guessExtension();
Then, upload() method is called and you check if $this->attachment if not null, that's true because it's a string:
if (null === $this->attachment) {
return;
}
And executing ->move() on a string display an error ;)
So to answer, in preUpload() method replace this line:
$this->attachment= $filename.'.'.$this->attachment->guessExtension();
For:
$this->path = $filename.'.'.$this->attachment->guessExtension();

Categories