Custom Form Editing Setting Conent in Symfony - forms

I created the following Custom Form Type
<?php
namespace UserBundle\Form\Type;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\Request;
use UserBundle\Entity\Users;
class UserType extends AbstractType
{
const FORM = 'user';
/**
* #var
*/
protected $UserContext;
/**
* Construct
* #param $uc
*/
public function __construct($uc)
{
$this->UserContext = $uc;
}
/**
* Build Form
* #param \Symfony\Component\Form\FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('username','text',array('label'=>'username'))
->add('password','text',array('label'=>'password'))
->add('firstname','text',array('label'=>'firstname','required'=>false))
->add('lastname','text',array('label'=>'lastname','required'=>false))
->add('email','email',array('label'=>'email','required'=>true));
$roles = array(
'Guest'=>array(
'ROLE_GUEST' =>'ROLE_GUEST',
),
'Users'=>array(
'ROLE_USER' =>'ROLE_USER',
),
'Customers'=>array(
'ROLE_CUSTOMER' =>'ROLE_CUSTOMER',
),
);
if($this->UserContext->isGranted('Role_SUPERVISOR'))
{
$roles['Staff']['ROLE_STAFF'] = 'ROLE_STAFF';
$roles['Staff']['ROLE_SUPPORT'] = 'ROLE_SUPPORT';
}
if($this->UserContext->isGranted('ROLE_ADMIN'))
{
$roles['Staff']['ROLE_SUPERVISOR'] = 'ROLE_SUPERVISOR';
}
if($this->UserContext->isGranted('ROLE_SUPER_ADMIN'))
{
$roles['Staff']['ROLE_ADMIN'] = 'ROLE_ADMIN';
}
if($this->UserContext->isGranted('ROLE_GOD'))
{
$roles['Staff']['ROLE_SUPER_ADMIN'] = 'ROLE_SUPER_ADMIN';
$roles['Staff']['ROLE_GOD'] = 'ROLE_GOD';
}
$builder->add('role','choice',array(
'choices'=>$roles,
'required'=>true,
'label'=>'userrole'
))
->add('status','choice',array(
'choices'=>array(
'1'=>'account active',
'0'=>'account inactive',
),
'required'=>true,
'label'=>'status'
));
}
/**
* get Form Name
* #return string
*/
public function getName()
{
return self::FORM;
}
/**
* persist Form
* #param \Symfony\Component\HttpFoundation\Request $request
* #param \UserBundle\Entity\Users $user
* #param \Doctrine\ORM\EntityManager $em
*
* #return \UserBundle\Entity\Users
*/
public static function storeFormContent(Request $request,Users $user, EntityManager $em)
{
$formData = $request->request->get(self::FORM);
$isNew = (int)$user->getId()<1;
$user->setFirstname($formData['firstname']);
$user->setLastname($formData['lastname']);
$user->setUsername($formData['username']);
if(!empty($formData['password']) || $isNew)
{
$user->setPassword($formData['password']);
}
$user->setEmail($formData['email']);
$user->setRole($formData['role']);
$user->setActive($formData['status']);
if($isNew)
{
$em->persist($user);
}
$em->flush();
return $user;
}
}
In my Controller I added this method to edit a User:
/**
* #Route("/Administration/Users/Edit", name="admin_users_edit")
* #Template()
*/
public function editAction()
{
$this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');
$request = Request::createFromGlobals();
$userid = (int)$request->query->get('id', null);
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
$session = new Session();
$session->start();
$session->set('currentRoute',array('call'=>'admin_users_edit','parameters'=>array('id'=>$userid)));
throw $this->createAccessDeniedException();
}
$em = $this->getDoctrine()->getManager();
/** #var Users $user */
$user = $this->getDoctrine()
->getRepository('UserBundle\Entity\Users')
->find($userid);
if(empty($user) || !($user instanceof Users) || $user->getId() < 0)
{
return $this->redirectToRoute('admin_users_index', array('status' => 'user_does_not_exist'));
}
if($user->getRole()=='ROLE_ADMIN')
{
$this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN', null, 'Unable to access this page!');
}
if($user->getRole()=='ROLE_SUPER_ADMIN' or $user->getRole()=='ROLE_GOD')
{
$this->denyAccessUnlessGranted('ROLE_GOD', null, 'Unable to access this page!');
}
if(!($user instanceof Users))
{
return $this->redirectToRoute('admin_users_index', array('status' => 'not_found'));
}
$form = $this->createForm(new UserType($this->get('security.context'),$user));
$form->handleRequest($request);
if($form->isValid())
{
UserType::storeFormContent($request,$user,$this->getDoctrine()->getManager());
return $this->redirectToRoute('admin_users_index', array('status' => 'create_success'));
}
return array(
'activeMenu'=>'users',
'error'=>$request->query->get('error'),
'form'=>$form->createView(),
);
}
Everything works fine so far.
Creating Users Work without an issue.
But Editing them leaves me blank fields.
I can't see where the issue is comming from.
I appreceate any help.
Chris
P.S.:
I have to seperate the Form into a Custom Type, because I will need to reuse it on several locations.
I will also reuse the twig part of the form for this.
^^

I just discovered that $form->setData() works for you, because you forgotten to add setDefaultOptions method to your form type:
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
...
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'UserBundle\Entity\Users',
));
}
You can remove $form->setData();

Related

Issue with the ParamConverter annotation

I am working on a mailbox between two users for my application. I made the controller, the form and the view, everything is working except when I add the entity Ad in the MessageController to return informations about the ad, for the view.
The error message is :
App\Entity\Ad object not found by the #ParamConverter annotation.
I did exactly the same thing when I managed the booking of an ad, it all worked perfectly fine, I really don't get what's wrong with the rest.
For example, my BookingController which is working :
/**
* #Route("/ads/{id}/booking", name="ad_booking")
* #IsGranted("ROLE_USER")
*
* #return Response
*/
public function booking(Ad $ad, Request $request, ObjectManager $manager)
{
$booking = new Booking;
$form = $this->createForm(BookingType::class, $booking);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid())
{
$user = $this->getUser();
$booking->setBooker($user)
->setAd($ad)
;
if(!$booking->isAvailableDate())
{
$this->addFlash(
'warning',
'Attention, les dates que vous avez choisies ne sont pas disponibles, elles ont déjà été réservées.'
);
}
else
{
$manager->persist($booking);
$manager->flush();
$this->addFlash(
'success',
"Votre réservation a bien été effectuée !"
);
return $this->redirectToRoute('booking_show', [
'id' => $booking->getId(),
'withAlert' => true
]);
}
}
return $this->render('booking/booking.html.twig', [
'ad' => $ad,
'bookingForm' => $form->createView()
]);
}
My MessageController that doesn't work :
namespace App\Controller;
use App\Entity\Ad;
use App\Entity\Message;
use App\Form\MessageType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class MessageController extends AbstractController
{
/**
* #Route("/ads/{id}/message", name="message_provider")
* #IsGranted("ROLE_USER")
*
* #return Response
*/
public function message(Ad $ad, Request $request, ObjectManager $manager)
{
$message = New Message();
$form = $this->createForm(MessageType::class, $message);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$ad = $this->getAd();
$user = $this->getUser();
$message->setSender($user)
->setAd($ad)
;
$manager->persist($message);
$manager->flush();
$this->addFlash(
'success',
"Votre message n°{$message->getId()} a bien été envoyé."
);
return $this->redirectToRoute('message_show', [
'id' => $message->getId()
]);
}
return $this->render('message/new.html.twig', [
'form' => $form->createView()
]);
}
/**
* #Route("/message/{id}", name="message_show")
*
* #return Response
*/
public function showmessage(Message $message)
{
return $this->render('message/show.html.twig', [
'message' => $message,
]);
}
}
and my Message entity
namespace App\Entity;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\MessageRepository")
*/
class Message
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="text")
*/
private $content;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="messages")
* #ORM\JoinColumn(nullable=false)
*/
private $receiver;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="sentMessages")
* #ORM\JoinColumn(nullable=false)
*/
private $sender;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Ad", inversedBy="messages")
* #ORM\JoinColumn(nullable=false)
*/
private $ad;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
I still got the App\Entity\Ad object not found by the #ParamConverter annotation. error message, even when I tried to define the #ParamConverter in the annotation. I can't see what's wrong.
Not sure if it's related but it seems to me, you never use the object $ad created from {id} in your function message. I think you use the id of your Ad or an object Ad on the form $this->getAd() and you never use the one on the route {id}. Maybe it messed up, try to clarify what is $ad on this function (from the route {id} or from the form).
If I had to bet, I would say you don't need this line:$ad = $this->getAd(); because you don't identify you current used $ad on the form but on the route.
(It should be a comment but I can't comment yet)

Unit Test Form WIth Repository Method

I am attempting to unit test one of my forms that I have which includes an entity form type on it. I would like to test the full form, but I keep on running into the error message - Expected argument of type "Doctrine\ORM\QueryBuilder", "NULL" given
Which is obvious, I need to somehow mock Doctrine\ORM\QueryBuilder as the return type for the entity form type. I am not quiet sure how I go about doing that though.
Here is the code of the Form -
<?php
namespace ICS\BackEnd\BoardBundle\Form;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class BoardCollectionType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', 'text', array(
'disabled' => TRUE
))
->add('member', 'entity', array(
'class' => 'MemberBundle:Members',
'property' => 'fullName',
'query_builder' => function(EntityRepository $er) {
return $er->findAllActiveMembers();
},
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'ICS\BackEnd\BoardBundle\Entity\Board'
));
}
/**
* #return string
*/
public function getName()
{
return 'ics_boardbundle_board';
}
}
This is the test I am running on it -
<?php
namespace ICS\BackEnd\BoardBundle\Tests\Form;
use Doctrine\ORM\QueryBuilder;
use ICS\BackEnd\BoardBundle\Entity\Board;
use ICS\BackEnd\BoardBundle\Form\BoardCollectionType;
use Symfony\Component\Form\Forms;
use Symfony\Component\Form\PreloadedExtension;
use Symfony\Component\Form\Test\TypeTestCase;
class BoardCollectionTypeTest extends TypeTestCase {
protected $repository;
protected function setUp()
{
parent::setUp();
$this->factory = Forms::createFormFactoryBuilder()
->addExtensions($this->getExtensions())
->getFormFactory();
}
public function testSubmittedValueData()
{
$formData = array(
'member' => NULL,
);
$type = new BoardCollectionType();
$form = $this->factory->create($type);
$object = new Board();
$object->createFromArray($formData);
// submit the data to the form directly
$form->submit($formData);
$this->assertTrue($form->isSynchronized());
$this->assertEquals($object, $form->getData());
$view = $form->createView();
$children = $view->children;
foreach (array_keys($formData) as $key) {
$this->assertArrayHasKey($key, $children);
}
}
protected function getExtensions()
{
$this->repository = $this->getMockBuilder('Doctrine\ORM\EntityRepository')
->disableOriginalConstructor()
->getMock();
$mockEntityManager = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$mockEntityManager->expects($this->any())
->method('getRepository')
->will($this->returnValue($this->repository));
$classMetadata = $this->getMockBuilder('\Doctrine\Common\Persistence\Mapping\ClassMetadata')
->disableOriginalConstructor()
->getMock();
$mockEntityManager->expects($this->any())
->method('getClassMetadata')
->will($this->returnValue($classMetadata));
$mockRegistry = $this->getMockBuilder('Doctrine\Bundle\DoctrineBundle\Registry')
->disableOriginalConstructor()
->setMethods(array('getManagerForClass'))
->getMock();
$mockRegistry->expects($this->any())
->method('getManagerForClass')
->will($this->returnValue($mockEntityManager));
$mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
->setMethods(array('getName'))
->setConstructorArgs(array($mockRegistry))
->getMock();
$mockEntityType->expects($this->any())
->method('getName')
->will($this->returnValue('entity'));
$this->assertQueryBuilderCalled();
return array(new PreloadedExtension(array(
$mockEntityType->getName() => $mockEntityType,
), array()));
}
protected function assertQueryBuilderCalled()
{
$em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalConstructor()->getMock();
$repo = $this->getMockBuilder('ICS\BackEnd\MemberBundle\Entity\Repository\MembersRepository')
->disableOriginalConstructor()->getMock();
$repo->expects($this->once())->method('findAllActiveMembers')
->will($this->returnValue(new QueryBuilder($em)));
/*$qb = $this->getMockBuilder('Doctrine\ORM\QueryBuilder')
->disableOriginalConstructor()
->getMock();
$query = $this->getMockBuilder('Doctrine\ORM\AbstractQuery')
->disableOriginalConstructor()
->setMethods(array('execute'))
->getMockForAbstractClass();
$query->expects($this->any())
->method('execute')
->will($this->returnValue(array()));
$qb->expects($this->any())
->method('getQuery')
->will($this->returnValue($query));
$this->repository->expects($this->any())
->method('findAllActiveMembers')
->will($this->returnValue($query));
$this->repository->expects($this->any())
->method('createQueryBuilder')
->will($this->returnValue($qb));*/
}
}
Thanks for any help!
I resolved the issue by changing the entity form type to choice. It made the test much easier to read and do. I injected the "choices" into the options of the form type.

Symfony2 Asset GreaterThan didn't work

I have an issue actually.
The property "Quantity" in Invetory entity should not be negative.
So I try to use the GreaterThan or GreaterThanOrEqual assert in my entity declaration.
In fact, I can validate negative quantities.
I don't understand.
The Entity :
/* src/Clicproxy/***Bundle/Entity/Inventory.php */
<?php
namespace Clicproxy\***Bundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Inventory
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Clicproxy\***Bundle\Entity\InventoryRepository")
* #UniqueEntity(fields="audit, name", message="entity.inventory.unique")
*/
class Inventory
{
/* [...] */
/**
* #var integer
*
* #ORM\Column(name="quantity", type="integer", nullable=true)
* #Assert\GreaterThan(value = 1)
*/
private $quantity;
[...]
The FormType :
/* src/Clicproxy/***Bundle/Form/InventoryCollabType.php */
<?php
namespace Clicproxy\***Bundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class InventoryCollabType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('quantity', null, array('label' => 'entity.inventory.quantity'))
->add('pageCostBlack', null, array('label' => 'entity.inventory.pagecostblack'))
->add('pageCostColor', null, array('label' => 'entity.inventory.pagecostcolor'))
->add('avMonthPagesBlack', null, array('label' => 'entity.inventory.avmonthpagesblack'))
->add('avMonthPagesColor', null, array('label' => 'entity.inventory.avmonthpagescolor'))
;
}
/* [...] */
}
The Controller :
public function configAction (Request $request, $slug)
{
$em = $this->getDoctrine()->getManager();
$audit = $em->getRepository('Clicproxy***Bundle:Audit')->findOneBy(array('slug' => $slug));
if (!$audit instanceof Audit) {
throw $this->createNotFoundException('wizard.config.notfound');
}
$audit->addInventoriesFromEquipments($em->getRepository('Clicproxy***Bundle:Equipment')->findBy(array(), array('optimized' => 'ASC', 'name'=> 'ASC')));
$form = $this->createCreateConfigForm($audit);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($audit);
foreach ($audit->getInventories() as $inventory) {
$inventory->setAudit($audit);
$em->persist($inventory);
}
$em->flush();
/* [...] */
return $this->redirect($this->generateUrl('wizard_result', array('slug' => $audit->getSlug())));
}
/* [...] */
return array(
'audit' => $audit,
'form' => $form->createView(),
'tabactive' => 2,
);
}
Does anyone have an idea about my context ?
Thanks for your support,
David.
EDIT :
Finaly I've write this code below, your opinion ?
public function configAction (Request $request, $slug)
{
$em = $this->getDoctrine()->getManager();
$audit = $em->getRepository('Clicproxy***Bundle:Audit')->findOneBy(array('slug' => $slug));
if (!$audit instanceof Audit) {
throw $this->createNotFoundException('wizard.config.notfound');
}
$audit->addInventoriesFromEquipments($em->getRepository('Clicproxy***Bundle:Equipment')->findBy(array(), array('optimized' => 'ASC', 'name'=> 'ASC')));
$form = $this->createCreateConfigForm($audit);
$form->handleRequest($request);
if ($form->isValid()) {
$validator = $this->get('validator');
$errors_messages = array();
foreach ($audit->getInventories() as $inventory)
{
$violations = $validator->validate($inventory);
if (0 < $violations->count())
{
$error_message = substr($violations, strpos($violations, ':')+2);
if (! in_array($error_message, $errors_messages, true)) {
$errors_messages[] = $error_message;
$this->get('session')->getFlashBag()->add('error', $error_message);
}
}
}
if (! $this->get('session')->getFlashBag()->has('error'))
{
$em = $this->getDoctrine()->getManager();
$em->persist($audit);
foreach ($audit->getInventories() as $inventory) {
$inventory->setAudit($audit);
$em->persist($inventory);
}
$em->flush();
/* [...] */
return $this->redirect($this->generateUrl('wizard_result', array('slug' => $audit->getSlug())));
}
}
return array(
'audit' => $audit,
'form' => $form->createView(),
'tabactive' => 2,
);
}
Thanks for your support.
You aren't validating your entity, just your form.
It's a common mistake to assume that when you call $form->isValid() that your Doctrine entity is being validated, but that's not the case.
You need to explicitly call the validator service and handle that separately from the validation of your form.
That would looks something like this:
$validator = $this->get('validator');
$errors = $validator->validate($inventory);
if (count($errors) > 0) {
// Handle errors here
}
For more information, take a look at the validation documentation.

Testing symfony 2 forms

I develop new type, but I don't know how I can test it.
Assert annotation is not load and validations is not called.
Could any one please help me?
class BarcodeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->
add('price');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Bundles\MyBundle\Form\Model\Barcode',
'intention' => 'enable_barcode',
));
}
public function getName()
{
return 'enable_barcode';
}
}
A have following model for storing form data.
namepspace Bundles\MyBundle\Form\Model;
class Barcode
{
/**
* #Assert\Range(
* min = "100",
* max = "100000",
* minMessage = "...",
* maxMessage = "..."
* )
*/
public $price;
}
I develop some test like this, the form didn't get valid data but it is valid! (Because annotation is not applied)
I try adding ValidatorExtension but I dont know how can I set constructor paramaters
function test...()
{
$field = $this->factory->createNamed('name', 'barcode');
$field->bind(
array(
'price' => 'hello',
));
$data = $field->getData();
$this->assertTrue($field->isValid()); // Must not be valid
}
Not sure why you need to unit-test the form. Cant You unit test validation of Your entity and cover controller with your expected output?
While testing validation of entity You could use something like this:
public function testIncorrectValuesOfUsernameWhileCallingValidation()
{
$v = \Symfony\Component\Validator\ValidatorFactory::buildDefault();
$validator = $v->getValidator();
$not_valid = array(
'as', '1234567890_234567890_234567890_234567890_dadadwadwad231',
"tab\t", "newline\n",
"Iñtërnâtiônàlizætiøn hasn't happened to ", 'trśżź',
'semicolon;', 'quote"', 'tick\'', 'backtick`', 'percent%', 'plus+', 'space ', 'mich #l'
);
foreach ($not_valid as $key) {
$violations = $validator->validatePropertyValue("\Brillante\SampleBundle\Entity\User", "username", $key);
$this->assertGreaterThan(0, count($violations) ,"dissalow username to be ($key)");
}
}
Functional test. Given that you generate a CRUD with app/console doctrine:generate:crud with routing=/ss/barcode, and given that maxMessage="Too high" you can:
class BarcodeControllerTest extends WebTestCase
{
public function testValidator()
{
$client = static::createClient();
$crawler = $client->request('GET', '/ss/barcode/new');
$this->assertTrue(200 === $client->getResponse()->getStatusCode());
// Fill in the form and submit it
$form = $crawler->selectButton('Create')->form(array(
'ss_bundle_eavbundle_barcodetype[price]' => '12',
));
$client->submit($form);
$crawler = $client->followRedirect();
// Check data in the show view
$this->assertTrue($crawler->filter('td:contains("12")')->count() > 0);
// Edit the entity
$crawler = $client->click($crawler->selectLink('Edit')->link());
/* force validator response: */
$form = $crawler->selectButton('Edit')->form(array(
'ss_bundle_eavbundle_barcodetype[price]' => '1002',
));
$crawler = $client->submit($form);
// Check the element contains the maxMessage:
$this->assertTrue($crawler->filter('ul li:contains("Too high")')->count() > 0);
}
}
Include this line must be in Model and try it after include look like your model.
/* Include the required validators */
use Symfony\Component\Validator\Constraints as Assert;
namespace Bundles\MyBundle\Form\Model;
class Barcode
{
/**
* #Assert\Range(
* min = "100",
* max = "100000",
* minMessage = "min message here",
* maxMessage = "max message here"
* )
*/
public $price;
}

Symfony forms. File upload

Trying to manage file upload with Entity, but i get this error:
Fatal error: Call to a member function move() on a non-object in /home/projectpath/src/BS/MyBundle/Entity/Items.php on line 327 Call Stack: 0.0002 333264 1. {main}() /home/projectpath/web/app_dev.php:0 0.0450 1158160...
Here's the entity class:
namespace BS\BackstretcherBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
/**
* MB\MyBundle\Entity\Items
*
* #ORM\Table(name="items")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class Items
{
private $filenameForRemove;
/**
* #Assert\File(maxSize="60000000")
*/
public $file;
...
protected function getUploadDir()
{
return 'images/items/';
}
protected function getUploadRootDir()
{
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
public function getWebPath()
{
return null === $this->file ? null : $this->getUploadDir().'/'.$this->getNameEn();
}
public function getAbsolutePath()
{
return null === $this->file ? null : $this->getUploadRootDir().'/'.$this->getNameEn().'.jpg';
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file)
{
$this->file = $this->getId() .'.'. $this->file->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file)
{
return;
}
$this->file->move($this->getUploadRootDir(), $this->file);
unset($this->file);
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath())
{
unlink($file);
}
}
And the controller:
public function new_productAction(Request $request)
{
$product = new Items();
$product->setPrice(0);
$form = $this->createFormBuilder($product)
->add('Type', 'choice', array(
'choices' => array('1' => 'Product', '0' => 'Article'),
'required' => false,))
->add('Price', 'number')
->add('nameEn', 'text')
->add('file', 'file', array('label' => 'Image', 'required' => true))
->getForm();
if ($request->getMethod() == 'POST')
{
if ($form->isValid())
{
$form->bindRequest($request);
$em = $this->getDoctrine()->getEntityManager();
$em->persist($product);
$em->flush();
return new Response('<html><body>Success!</body></html>');
}
}
return $this->render('MyBundle:Default:admin_page.html.twig', array(
'form' => $form->createView(),
));
}
Symfony version: 2.1.0
Check your php.ini file and make sure both the post_max_size AND upload_max_filesize are set sufficiently large.
I don't suppose duke_nukem is worried about this anymore, 6 months down the line, but if someone else comes across this question, I was having the exact same problem and got a great answer to it here:
Error with file upload in symfony 2
Looks like duke_nukem and I made the same mistake. The preUpload() method should read:
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file)
{
$this->path = $this->getId() .'.'. $this->file->guessExtension();
}
}
The present code converts $this->file to a string, causing the error. The path should actually be assigned to $this->path.
Sybio in the other question figured this out, not me. I just want to spread the love.
it's weird
your code is wrong in your controller. You have to bind your request to your form before validation. After that, you can retrieve your data
if ($request->getMethod() == 'POST')
{
//Note: bindRequest is now deprecated
$form->bind($request);
if ($form->isValid())
{
//retrieve your model hydrated with your form values
$product = $form->getData();
//has upload file ?
if($product->getFile() instanceof UploadedFile){
//you can do your upload logic here wihtout doctrine event if you want
}
$em = $this->getDoctrine()->getEntityManager();
$em->persist($product);
$em->flush();
return new Response('<html><body>Success!</body></html>');
}
}