I have created a custom list view in sonata admin to display a calendar.
I'm trying to add events to the calendar dynamically, but I'm getting an error with the CSRF token being invalid.
I have the following code:
public function listAction()
{
if (false === $this->admin->isGranted('LIST')) {
throw new AccessDeniedException();
}
$datagrid = $this->admin->getDatagrid();
$formView = $datagrid->getForm()->createView();
// set the theme for the current Admin Form
$this->get('twig')->getExtension('form')->renderer->setTheme($formView, $this->admin->getFilterTheme());
$em = $this->getDoctrine()->getManager();
$events = $em->getRepository('BMCrmBundle:Event')->findAll();
$event = new Event();
$formEvent = $this->createForm(new EventType(), $event );
return $this->render($this->admin->getTemplate('list'), array(
'action' => 'list',
'form' => $formView,
'datagrid' => $datagrid,
'csrf_token' => $this->getCsrfToken('sonata.batch'),
'events' => $events,
'formEvent' => $formEvent->createView()
));
}
view
var url = "{{ path('create_event', { _sonata_admin: 'bm.crm.admin.event'} ) }}";
$.post(url, form.serialize(), function(data) {
alert(data);
});
This always returns that the CSRF token is invalid
Any ideas?
Check if in your view, you have the following line:
{{ form_rest(form) }}
because I believe that you are rendering form fields one by one and not the whole form at once and forgot to render the rest of the form, which contains the CSRF token.
Related
I'm wondering if I could submit forms inside a collection separately? I have very long form collection with buttons to save each subform (Basically filling and validating the form at once would be difficult). So clicking the button suppose to only submit corresponding subform, but it submits whole collection.
getDoctrine()->getManager();
$user = $this->getUser();
if(!count($user->getApplicants())) {
$app = new Applicant();
$app->setUser($user);
$user->setApplicants($app);
}
if(!count($user->getAddresses())) {
$address = new Address();
$address->setUser($user);
$user->setAddresses($address);
}
if(!count($user->getCompanies())) {
$company = new Company();
$company->setUser($user);
$user->setCompanies($company);
}
if(!count($user->getDirectors())) {
$director = new Director();
$director->setUser($user);
$user->setDirectors($director);
}
$form = $this->createForm('AppBundle\Form\UserType', $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($form->getClickedButton() && 'submitApplicants' === $form-
>getClickedButton()->getName()) {
$applicant = $form->getData()->getApplicants()[0];
$applicant->setUser($user);
$em->persist($applicant);
$em->flush();
return $this->render('admin/index.html.twig', [
'form' => $form->createView()
]);
}
if ($form->getClickedButton() && 'submitAddresses' === $form-
>getClickedButton()->getName()) {
$address = $form->getData()->getAddresses()[0];
$em->persist($address);
$em->flush($address);
return $this->render('admin/index.html.twig', [
'form' => $form->createView()
]);
}
if ($form->getClickedButton() && 'submitCompanies' === $form-
>getClickedButton()->getName()) {
$company = $form->getData()->getCompanies()[0];
$em->persist($company);
$em->flush($company);
return $this->render('admin/index.html.twig', [
'form' => $form->createView()
]);
}
if ($form->getClickedButton() && 'submitDirectors' === $form-
>getClickedButton()->getName()) {
$director = $form->getData()->getDirectors()[0];
$em->persist($director);
$em->flush($director);
return $this->render('admin/index.html.twig', [
'form' => $form->createView()
]);
}
//$em->flush();
}
return $this->render('admin/index.html.twig', [
'form' => $form->createView()
]);
}
}
My opinion is that you need to submit the subform via Javascript. Add some js code to the submit button to:
Perform an ajax POST request to a controller action
Make some checks to the form data
Return back either an error message or some HTML (whatever you want)
Do something with that message
That way you will be able to submit each form separately.
Also change the type of the submit button to plain button. Otherwise you will trigger a form submit for the whole page.
I'm starting to investigate Symfony2 framework and it seems that I've messed up some things in my mind.
I am trying to do a relatively simple thing; Dynamically add an extra field to a form depending on the value of a select box. Let's assume for simplicity that I don't have my form attached to any entity, so what I eventually want to get back is an array of values.
So, as a simple example I would have this controller:
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
$form = $this->createFormBuilder(null, array('allow_extra_fields' => true))
->add('test', 'Symfony\Component\Form\Extension\Core\Type\TextType')
->add('select', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array(
'choices' => array(
'Maybe' => null,
'Yes' => true,
'No' => false,
),
'choices_as_values' => true,
))
->add('submit', 'Symfony\Component\Form\Extension\Core\Type\SubmitType')
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
dump($form->getData());
die;
}
return $this->render('default/index.html.twig', array(
'form' => $form->createView()
));
}
/**
* #Route("/test", name="test")
*/
public function AddFieldAction(Request $request)
{
return new JsonResponse($request->get('form'));
}
And the javascript of the view could be:
$('document').ready(function(){
$('#form_select').change(function(){
var form = $(this).closest('form');
var value = $(this).val();
var data = {};
data[$(this).attr('name')] = value;
$.ajax({
url: "{{ url("test") }}",
type: 'POST',
data: data,
dataType: 'json'
}).done(function (response) {
console.log(response);
if (response.select == 1) {
$('#form').append("<label> extra field </label> <input type='text' id='extra_field' name="form[extra_field]"></input>");
}
}).fail(function (jqXHR, textStatus) {
});
})
})
Now this would return the field correctly, as this would invoke the AddFieldAction and it would add the appropriate HTML in the form. When i would try to submit the form, in the $form->isValid part, I could get all the submitted data with the $form->getData() and $form->getExtraData() methods.
Question is, is this the optimal way to do it? Should (and could) I use Form Events instead? I was trying to use form events but it becomes a mess and I get lost easily in the hierarchy of PRE_SUBMIT or PRE_SET_DATA conficting each other.
I am trying to execute and then display a cookie in my nav header template.
Currently my controller checks if a user is logged in. If not logged in then checks for a cookie. If no cookie exists a generic cookie is created. And then finally the template is loaded.
Currently the cookie is being created and template is loaded just fine, but the value passed when rendering the template does not show up after the page loads. I can see the cookie is created, and if I reload the page a 2nd time everything works as intended.
So I know this means the headers are not being sent as expected correct? But I cannot figure out the proper way to do this in Symfony2.
Here is my controller code:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Cookie;
class navController extends Controller {
public function displayNavAction() {
$userState = '';
$userZipcode = '';
if ($this->container->get('security.context')->getToken() != null) {
// To check if user is authenticated or anonymous
if ($this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY') === true) {
$user = $this->getUser();
$userCity = $user->getCity();
$userState = $user->getState();
$userZipcode = $user->getZipcode();
} else {
//User is not logged in, so check for cookie.
$request = $this->get('request');
$cookies = $request->cookies;
if ($cookies->has('city'))
{
//User not logged in, but cookie exists. So use cookie.
$userCity = $cookies->get('city');
} else {
//User not logged in, and no existing cookie. So create cookie.
$cookieGuest = array(
'name' => 'city',
'value' => 'seattle',
'path' => '/',
'time' => time() + 3600 * 24 * 7,
false,
false
);
$cookie = new Cookie($cookieGuest['name'], $cookieGuest['value'], $cookieGuest['time'], $cookieGuest['path']);
$response = new Response();
$response->headers->setCookie($cookie);
$response->sendHeaders();
$userCity = $cookies->get('city');
}
}
}
return $this->render(
'trrsywxBundle:Default:nav.html.twig', array('city' => $userCity, 'state' => $userState, 'zipcode' => $userZipcode, 'tempjunk' => $userCity));
}
}
You are not using the response you created that's the problem try this :
$userCity = $cookies->get('city');
$response = new Response($this->render(
'trrsywxBundle:Default:nav.html.twig',array(
'city' => $userCity,
'state' => $userState,
'zipcode' => $userZipcode,
'tempjunk' => $userCity
)));
$cookie = new Cookie($cookieGuest['name'], $cookieGuest['value'],$cookieGuest['time'], $cookieGuest['path']);
$response->headers->setCookie($cookie);
$response->sendHeaders();
return $response;
then you can get cookie value in your twig using the request global {% app.request.cookies %}
How to apply some code to each entity being displayed in Admin's list view?
For example, if I have a TagManager and need to load tags for each entity being displayed, how do I do that? Is there a method to override in entity's Admin or can I bind to some list form event? I could not find a place to do that.
I don't wan't to bind to entity's onLoad event.
EDIT: In your entityAdminController :
public function listAction()
{
if (false === $this->admin->isGranted('LIST')) {
throw new AccessDeniedException();
}
$datagrid = $this->admin->getDatagrid();
$formView = $datagrid->getForm()->createView();
foreach($datagrid->getResults() as $object)
{
//do what you want with $object
}
// set the theme for the current Admin Form
$this->get('twig')->getExtension('form')->renderer->setTheme($formView, $this->admin->getFilterTheme());
return $this->render($this->admin->getTemplate('list'), array(
'action' => 'list',
'form' => $formView,
'datagrid' => $datagrid
));
}
How to limit the number of embedded form with the type "sonata_type_collection" ?
$formMapper->add('phones', 'sonata_type_collection',
array(
'required' => true,
'by_reference' => false,
'label' => 'Phones',
),
array(
'edit' => 'inline',
'inline' => 'table'
)
I would like limit to last five phones, I found only this solution for now, limit the display in the template twig "edit_orm_one_to_many", but i don't like that.
I found a solution by rewriting the edit action in the controller,
such in the documentation sonataAdminBundle I created my admin controller class:
class ContactAdminController extends Controller
{
public function editAction($id = null)
{
// the key used to lookup the template
$templateKey = 'edit';
$em = $this->getDoctrine()->getEntityManager();
$id = $this->get('request')->get($this->admin->getIdParameter());
// $object = $this->admin->getObject($id);
// My custom method to reduce the queries number
$object = $em->getRepository('GestionBundle:Contact')->findOneAllJoin($id);
if (!$object)
{
throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
}
if (false === $this->admin->isGranted('EDIT', $object))
{
throw new AccessDeniedException();
}
$this->admin->setSubject($object);
/** #var $form \Symfony\Component\Form\Form */
$form = $this->admin->getForm();
$form->setData($object);
// Trick is here ###############################################
// Method to find the X last phones for this Contact (x = limit)
// And set the data in form
$phones = $em->getRepository('GestionBundle:Phone')->findLastByContact($object, 5);
$form['phones']->setData($phones);
// #############################################################
if ($this->get('request')->getMethod() == 'POST')
{
$form->bindRequest($this->get('request'));
$isFormValid = $form->isValid();
// persist if the form was valid and if in preview mode the preview was approved
if ($isFormValid && (!$this->isInPreviewMode() || $this->isPreviewApproved()))
{
$this->admin->update($object);
$this->get('session')->setFlash('sonata_flash_success', 'flash_edit_success');
if ($this->isXmlHttpRequest())
{
return $this->renderJson(array(
'result' => 'ok',
'objectId' => $this->admin->getNormalizedIdentifier($object)
));
}
// redirect to edit mode
return $this->redirectTo($object);
}
// show an error message if the form failed validation
if (!$isFormValid)
{
$this->get('session')->setFlash('sonata_flash_error', 'flash_edit_error');
}
elseif ($this->isPreviewRequested())
{
// enable the preview template if the form was valid and preview was requested
$templateKey = 'preview';
}
}
$view = $form->createView();
// set the theme for the current Admin Form
$this->get('twig')->getExtension('form')->renderer->setTheme($view, $this->admin->getFormTheme());
return $this->render($this->admin->getTemplate($templateKey), array(
'action' => 'edit',
'form' => $view,
'object' => $object,
));
}
}