Here is my problem.
I am curently learning Symfony and I have created a form with a formType file and a formHandler.
I'd like now to use values of the form in my handler but I can't figure how to call those values, which method can I use? I've tried many method of the request class but it doesn't work.
Could you help me please?
Here is my handler. Some of my try are still in it commented, it's quiet simple, I'm just trying to do an echo.
class adminFormHandler
{
protected $form;
protected $request;
protected $em;
public function __construct(Form $form, Request $request, EntityManager $em)
{
$this->form = $form;
$this->request = $request;
$this->em = $em;
}
public function process()
{
if( $this->request->getMethod() == 'POST' )
{
$this->form->bindRequest($this->request);
//if( $this->form->isValid() )
//{
//echo $this->request->get('nom');
//$param = $this->request->request->keys();
//$param = $this->form->getData(nom);
//echo $param;
$myfield = $form->getAttribute('nom');
echo $myfield->getData();
//echo $param;//$this->form->get('nom')->getText();
//$this->onSuccess($this->form->getData());
return true;
//}
}
return false;
}
public function onSuccess1(/*Students $students*/)
{
//$this->em->persist($students);
//$this->em->flush();
echo'on success 1';
}
public function onSuccess2()
{
//$this->em->persist($students);
//$this->em->flush();
echo'on success 2';
}
}
You can use:
$data = $this->form->getData();
$myfield = $data['nom'];
or
$myfield = $this->form->get('nom')->getData();
Related
I'm writing a method in my Symfony 3 application for bulk user creation. The flux is uploading a csv file with all the necessary data.
I created a Service, into I write all the logic of this operation. This is my Service:
class BulkRegistration
{
private $em;
private $validator;
private $session;
public function __construct(EntityManagerInterface $em, ValidatorInterface $validator, SessionInterface $session)
{
$this->em = $em;
$this->validator = $validator;
$this->session = $session;
}
public function run(BulkRegistrationData $bulkRegistrationData){
//todo rimuovere dipendenza nascosta
$serializer = new Serializer([new ObjectNormalizer()], [new CsvEncoder()]);
$datas = $serializer->decode(file_get_contents($bulkRegistrationData->csv), 'csv');
$this->em->getConnection()->beginTransaction();
try{
foreach($datas as $data)
{
$userData = UserData::create($data);
$this->validate($userData, 'newUser');
$userCreate = User::create($userData->user);
$this->em->persist($userCreate);
$this->em->flush();
}
$this->em->getConnection()->commit();
} catch (\Exception $e) {
$this->em->getConnection()->rollback();
$this->em->close();
$this->session->getFlashBag()->add('error', $e->getMessage());
return false;
}
return true;
}
private function validate ($entity, $validationGroup = null){
if($validationGroup){
$errors = $this->validator->validate($entity, null, [$validationGroup]);
}else{
$errors = $this->validator->validate($entity);
}
if (count($errors) > 0) {
$errorMessage = '';
foreach($errors as $error)
{
$errorMessage .= $error->getMessage();
}
throw new \Exception($errorMessage);
}
return;
}
}
Also I wrote this EmailSubscriber, for sending an activation email each time the entity User is persisted:
class EmailSubscriber implements EventSubscriber
{
private $activationEmail;
public function __construct(SendActivationEmail $activationEmail)
{
$this->activationEmail = $activationEmail;
}
public function getSubscribedEvents()
{
return array(
Events::postPersist,
);
}
public function postPersist(LifecycleEventArgs $args)
{
$entity = $args->getObject();
$entityManager = $args->getObjectManager();
if ($entity instanceof User)
{
$this->activationEmail->send($entity);
}
}
}
And this is question:
The EventSubscriber catch the persisted event before the transaction commit.
I want or persist all the row in my db, or response with violation and ask to User to modify his csv file.
Because this, one of the useCase can be some activation email sended but no persisting the User in DB, for example for some validate violation of one of the csv row.
I hope I was crearl, the case is a bit intricate.
I think you need to adjust the foreach to only flush if there were no errors:
foreach($datas as $data) {
$userData = UserData::create($data);
try {
$this->validate($userData, 'newUser');
} catch (\Exception $e) {
$this->em->getConnection()->rollback();
$this->em->close();
$this->session->getFlashBag()->add('error', $validation);
return false;
}
$userCreate = User::create($userData->user);
$this->em->persist($userCreate);
}
$this->em->flush();
$this->em->getConnection()->commit();
return true;
Goal : redirect a user depending on a status, on the whole website when the user is logged.
I need to force the user to be on one page until he has changed his profile
So i try to make a redirection with the event kernel but i've got an infinite loop. however I tried to avoid doing this redirection once the page wanted
So please find what i try to do
class TokenSubscriber implements EventSubscriberInterface {
private $user;
private $tokenStorage;
private $router;
protected $redirect;
public function __construct(TokenStorageInterface $tokenStorage, RouterInterface $router
) {
$this->tokenStorage = $tokenStorage;
$this->router = $router;
}
public function onKernelController(FilterControllerEvent $event) {
$controller = $event->getController();
if (!is_array($controller)) {
return;
}
$this->user = $this->tokenStorage->getToken()->getUser();
if ($this->user->getValider() == 3 && $controller[1] == 'indexUserAction' && $controller[0] instanceof DefaultUserController) {
$this->redirect = null;
} else {
$this->redirect = 'user_index';
}
}
public function onKernelResponse(FilterResponseEvent $event) {
if (null !== $this->redirect) {
$url = $this->router->generate($this->redirect);
$event->setResponse(new RedirectResponse($url));
}
}
public static function getSubscribedEvents() {
return array(
KernelEvents::CONTROLLER => 'onKernelController',
KernelEvents::RESPONSE => 'onKernelResponse',
);
}
}
Now the redirection works but when the page is loaded all my css et javascript are not loader , because the redirection i think.
I work just in the kernel response.
public function onKernelResponse(FilterResponseEvent $event){
if ($event->getRequest()->get('_route') != null && $event->getRequest()->get('_route') != 'user_index') {
$url = $this->router->generate('user_index');
$event->setResponse(new RedirectResponse($url));
}
}
You could try this, but using ->get('_route') should normally only be used for debugging. You should dump the Event and the Response to find out what else you can use.
public function onKernelRequest(GetResponseEvent $event)
if($event->getRequest()->get('_route') != 'user_index'){
$event->setResponse(new Response('[NOT_ALLOWED]'));
}
}
This should solve your issue
public function onKernelController(FilterControllerEvent $event) {
$controller = $event->getController();
if (!is_array($controller)) {
return;
}
$this->user = $this->tokenStorage->getToken()->getUser();
if ($this->user->getValider() == 3 && $controller[1] == 'indexUserAction' && $controller[0] instanceof DefaultUserController) {
$this->redirect = null;
} else {
$this->redirect = 'user_index';
}
// Add this to Empty redirect if on already same page
if($event->getRequest()->get('_route') == 'user_index'){
$this->redirect = null;
}
}
How to render a template outside a controller or in a service?
I've been following the documentation of Symfony2. Doc
namespace Acme\HelloBundle\Newsletter;
use Symfony\Component\Templating\EngineInterface;
class NewsletterManager
{
protected $mailer;
protected $templating;
public function __construct(
\Swift_Mailer $mailer,
EngineInterface $templating
) {
$this->mailer = $mailer;
$this->templating = $templating;
}
// ...
}
This is where i call my helper :
$transport = \Swift_MailTransport::newInstance();
$mailer = \Swift_Mailer::newInstance($transport);
$helper = new MailHelper($mailer);
$helper->sendEmail($from, $to, $subject, $path_to_twig, $arr_to_twig);
So the first thing here missing is the second parameter of the construct method in :
$helper = new MailHelper($mailer);
But how would i instantiate the EngineInterface?
Of course it can't be :
new EngineInterface();
I'm totally lost here.
All what i need to do is render a template for the email that is being sent.
Inject only #twig and pass the rendered template to the mailer body:
<?php
namespace Acme\Bundle\ContractBundle\Event;
use Acme\Bundle\ContractBundle\Event\ContractEvent;
class ContractListener
{
protected $twig;
protected $mailer;
public function __construct(\Twig_Environment $twig, \Swift_Mailer $mailer)
{
$this->twig = $twig;
$this->mailer = $mailer;
}
public function onContractCreated(ContractEvent $event)
{
$contract = $event->getContract();
$body = $this->renderTemplate($contract);
$projectManager = $contract->getProjectManager();
$message = \Swift_Message::newInstance()
->setSubject('Contract ' . $contract->getId() . ' created')
->setFrom('noreply#example.com')
->setTo('dev#example.com')
->setBody($body)
;
$this->mailer->send($message);
}
public function renderTemplate($contract)
{
return $this->twig->render(
'AcmeContractBundle:Contract:mailer.html.twig',
array(
'contract' => $contract
)
);
}
}
Here's my code:
$form = $this->createFormBuilder($signupAttempt)
->add('email', 'text', array("label" => "your email:"))
->add('password', 'password', array("label" => "your password:"))
->add('passwordRepeat', 'password', array("label" => "repeat password:"))
->getForm();
if ($request->isMethod('POST')) {
$form->bindRequest($request);
$attempt = $form->getData();
$this->changeSomeAttributesOfSignupAttempt($attempt); // this does not work
if ($form->isValid()) { // this is not taking into account the modification made inside changeSomeAttributesOfSignupAttempt
return new Response("data provided are valid - u signiged up!");
}
}
See my problem? I'd like to make some changes to the entity and expect the form to be aware of such changes. Unfortunately it looks like the changes that I make are not perceived and, as a result, the rules defined in validaition.xml for the class SignupAttempt are not fulfilled.
here's my validation.xml for the entity SignupAttempt:
<getter property="emailInUseAlready">
<constraint name="False">
<option name="message">signup_attempt.whole.email_in_use</option>
</constraint>
</getter>
and the entity class itself:
class SignupAttempt {
protected $id = null;
protected $email = null;
protected $password = null;
protected $passwordRepeat = null;
protected $emailInUseAlredy = true;
public function __construct($email = null, $password = null, $passwordReapeat = null) {
$this->email = $email;
$this->password = $password;
$this->passwordRepeat = $passwordReapeat;
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getEmail() {
return $this->email;
}
public function setEmail($email) {
$this->email = $email;
}
public function getPassword() {
return $this->password;
}
public function setPassword($password) {
$this->password = $password;
}
public function getPasswordRepeat() {
return $this->passwordRepeat;
}
public function setPasswordRepeat($passwordRepeat) {
$this->passwordRepeat = $passwordRepeat;
}
public function setEmailInUseAlready($bool) {
$this->emailInUseAlredy = $bool;
}
public function isEmailInUseAlready() {
return $this->emailInUseAlredy;
}
public function isSecondPasswordMatching() {
return $this->password === $this->passwordRepeat;
}
public function import(array $data) {
throw new \RuntimeException("implement this");
}
}
any idea?
When one performs $form->isValid(), the returned (boolean) value is in fact pre-evaluated at the time when the request was bound to the form.
As a result, changing values of the entity returned by $form->getData() is totally useless as validation happens beforehand and on the initial values held by the entity object when it is originally created.
I am trying to test a method on the bind event of a custom form type.
Here is the code
public function bind(DataEvent $event)
{
$form = $event->getForm();
if($form->getNormData() instanceof BaseFileInterface && !$event->getData() instanceof UploadedFile) {
$event->setData($form->getNormData());
}
if($event->getData() instanceof UploadedFile) {
$hander = $this->handlerManager->getHandler(
$form->getParent()->getConfig()->getDataClass(),
$form->getName()
);
$datas = $hander->createBaseFile($event->getData());
$event->setData($datas);
}
if(is_string($event->getData())) {
$event->setData(null);
}
}
and the form builder of the type :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->addEventSubscriber(new BaseFileListener($this->handlerManager))
->addViewTransformer(new BaseFileToStringTransformer())
;
}
My test class inherits from Symfony\Component\Form\Tests\FormIntegrationTestCase and is doing this :
protected function setUp()
{
parent::setUp();
$this->handlerManager = $this->getHandlerManagerMock();
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->builder = new FormBuilder(null, null, $this->dispatcher, $this->factory);
$this->form = $this->factory->create('my_file');
$this->form->setParent($this->getFormMock())->setData(new DummyEntity());
}
protected function getFormMock()
{
$mock = $this
->getMockBuilder('Symfony\Component\Form\Tests\FormInterface')
->disableOriginalConstructor()
->getMock()
;
return $mock;
}
public function testBindHandleNewFileWithNonEmptyField()
{
$data = $file = new UploadedFile(
__DIR__.'/../Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/../Fixtures/test.gif'),
null
);
$event = new FormEvent($this->form, $data);
$listener = new BaseFileListener($this->handlerManager);
$listener->bind($event);
$this->assertInstanceOf('My\FooBundle\Entity\BaseFileInterface', $event->getData());
$this->assertNotEquals($event->getData(), $this->form->getNormData());
}
The probleme is that the $form->getParent()->getConfig()->getDataClass() throws an exception on getDataClass ().
The question is how to build the form correctly to perform the bind test ?
Ok, answering my self :)
Here is the good mocking in phpunit :
protected function setUp()
{
parent::setUp();
$this->handlerManager = $this->getHandlerManagerMock();
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->builder = new FormBuilder(null, null, $this->dispatcher, $this->factory);
$this->form = $this->factory->create('my_file');
$this->form->setParent($this->getFormMock());
}
protected function getFormMock()
{
$mock = $this->getMock('Symfony\Component\Form\Tests\FormInterface');
$mock
->expects($this->any())
->method('getConfig')
->will($this->returnValue($this->getFormConfigMock()))
;
return $mock;
}
protected function getFormConfigMock()
{
$mock = $this->getMockBuilder('Symfony\Component\Form\FormConfigInterface')
->disableOriginalConstructor()
->getMock();
$mock
->expects($this->any())
->method('getDataClass')
->will($this->returnValue('My\FooBundle\Tests\DummyEntity'))
;
return $mock;
}
I thought I could manage to rebuild the entire form without using mock, but it seems impossible.
If someone has a better solution to offer I'm interested.