Symfony2 create new entity error: NotFoundException - symfony

I am getting NotFoundHttpException error when I try to create new entity with form.
This is a code for creating form and entity - CategoryController:
/**
* Displays a form to create a new Category entity.
*
* #Route("/new", name="category_new")
* #Method({"GET"})
*/
public function newAction(Request $request)
{
$entity = new Category();
$form = $this->createCreateForm($entity);
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Creates a new Category entity.
*
* #Route("/", name="category_create")
* #Method("POST")
* #Template("AdminBundle:CategoryPanel:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Category();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('category_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Creates a form to create a Category entity.
*
* #param Category $entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Category $entity, ServiceCategory $parentCategory = null)
{
$form = $this->createForm(CategoryType::class, $entity, array(
'action' => $this->generateUrl('category_create'),
'method' => 'POST',
'parentCategory' => $parentCategory
));
$form->add('submit', SubmitType::class, array(
'label' => 'Create',
'attr' => array(
'class' => "btn btn-primary"
)
));
return $form;
}
CategoryType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', TextType::class, array('label' => 'Category name'));
$parentCategory = $options["parentCategory"];
if($parentCategory != null){
$builder->add('parent', 'entity', array(
'class' => "CoreBundle:ServiceCategory",
'choices' => array($parentCategory)
));
}else{
$builder->add('parent', 'entity', array(
'class' => "CoreBundle:ServiceCategory",
'query_builder' => function(ServiceCategoryRepository $cp){
$qb = $cp->createQueryBuilder('c');
return $qb;
},
));
}
}
Why this code is looking for entity when I am only attempting to create it?
UPDATE
new.html.twig
{% extends 'AdminBundle:AdminPanel:base.html.twig' %}
{% block body -%}
<h1>Category creation</h1>
{{ form_start(form) }}
{{ form_row(form.name) }}
{{ form_row(form.parent) }}
<ul class="record_actions">
<li style="display: inline-block">
{{ form_widget(form.submit) }}
</li>
<li style="display: inline-block">
<a href="{{ path('category_panel_index') }}">
<button type="button" class="btn btn-primary">
Back to the list
</button>
</a>
</li>
</ul>
{{ form_end(form) }}
{% endblock %}

This might be a conflict between multiple routes as it happened in my case.
You might have some other route may be in some other controller having similar path (with dynamic varaibles) making <>/new pointing somewhere else.
Please do a var_dump in your newAction Controller to check if the execution is coming right there.

Related

How can I add Commerce Wishlist share mail template variables from form?

I am trying to add 2 additional form fields to the Wishlist Share form where the user input will be rendered in the email. I have been able to add the fields to the form, but I am not sure how to add the user's input in the email twig template.
Here is how I have updated the form() function:
public function form(array $form, FormStateInterface $form_state) {
$form['#tree'] = TRUE;
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
// Workaround for core bug #2897377.
$form['#id'] = Html::getId($form_state->getBuildInfo()['form_id']);
$form['to'] = [
'#type' => 'email',
'#title' => $this->t('Recipient Email'),
'#required' => TRUE,
];
// COMBAK my edit
$form['sender_name'] = [
'#type' => 'textfield',
'#title' => $this->t('Your Name'),
'#required' => FALSE,
];
$form['sender_message'] = [
'#type' => 'textarea',
'#title' => $this->t('Your Message'),
'#required' => FALSE,
];
// COMBAK eo my edit
return $form;
}
/**
* {#inheritdoc}
*/
protected function actions(array $form, FormStateInterface $form_state) {
$actions['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Send email'),
'#submit' => ['::submitForm'],
];
if ($this->isAjax()) {
$actions['submit']['#ajax']['callback'] = '::ajaxSubmit';
}
return $actions;
}
/**
* {#inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
/** #var \Drupal\commerce_wishlist\Entity\WishlistInterface $wishlist */
$wishlist = $this->entity;
$to = $form_state->getValue('to');
// COMBAK: my added vars
$sender_name = $form_state->getValue('sender_name');
$sender_message = $form_state->getValue('sender_message');
$this->wishlistShareMail->send($wishlist, $to, $sender_name, $sender_message);
$this->messenger()->addStatus($this->t('Shared the wishlist to #recipient.', [
'#recipient' => $to,
]));
$form_state->setRedirectUrl($wishlist->toUrl('user-form'));
}
This is the function that calls the mailHandler that I have updated:
public function send(WishlistInterface $wishlist, $to, $sender_name, $sender_message) {
$owner = $wishlist->getOwner();
$subject = $this->t('Check out my #site-name wishlist', [
'#site-name' => $this->configFactory->get('system.site')->get('name'),
]);
$body = [
'#theme' => 'commerce_wishlist_share_mail',
'#wishlist_entity' => $wishlist,
// COMBAK: my added vars
'#sender_name' => $sender_name,
'#sender_message' => $sender_message,
];
$params = [
'id' => 'wishlist_share',
'from' => $owner->getEmail(),
'wishlist' => $wishlist,
];
return $this->mailHandler->sendMail($to, $subject, $body, $params);
}
And this is the preprocees function provided by the commerce wishlist module:
function template_preprocess_commerce_wishlist_share_mail(array &$variables) {
/** #var Drupal\commerce_wishlist\Entity\WishlistInterface $wishlist */
$wishlist = $variables['wishlist_entity'];
$wishlist_url = $wishlist->toUrl('canonical', ['absolute' => TRUE]);
$variables['wishlist_url'] = $wishlist_url->toString();
// COMBAK: my added vars
//$sender_name = $variables['sender_name'];
}
And finally the twig template for the email itself:
{#
/**
* #file
* Template for the wishlist share email.
*
* Available variables:
* - wishlist_entity: The wishlist entity.
* - wishlist_url: The wishlist url.
*
* #ingroup themeable
*/
#}
<p>
{% trans %}Check out my wishlist!{% endtrans %}
</p>
<p>
{% trans %}I use my wishlist for keeping track of items I am interested in.{% endtrans %} <br>
{% trans %}To see the list in the store and buy items from it, click here.{% endtrans %}
</p>
<p>
{% trans %}Thanks for having a look!{% endtrans %}
</p>
I haven't been able to figure out how to access the variables I added to the body[] array in the twig template.
Any help would be greatly appreciated.
Thanks!

Symfony Edit and persist multiple entities on one form

I have an entity called Objective and its property called 'weight' and I can edit one objective at a time.. and now i want to edit all weights in a single form and persist them in DB using Doctrine..
This issue helped me in bringing all objective weights on a single form..
Edit multiple entities in one form
Now I am trickling around on how to save all weight values from the form in DB with a single click of save button..
Below is my code so far..
This is the controller action:-
/**
* #Route("/mou/objectives/manage", name="objective_manage")
*/
public function manageAction(Request $request){
$objs = $this->getDoctrine()
->getRepository('AppBundle:Objective')
->findAll();
$form = $this->createFormBuilder()
->add('weight', 'collection', array(
'type' => new WeightType() ,
'allow_add' => false,
'allow_delete' => false,
'label' => false))
->add('save', 'submit')
->getForm();
$form->setData(array('weight' => $objs));
/* Till here things are fine */
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
/* **Here I need help how to persist all weight values.. maybe inside a loop.. hence This is the missing piece** */
foreach($objs as $obj){
$obj =new Objective();
$obj = $em->getRepository('AppBundle:Objective')->find($obj);
$obj->setWeight($obj);
$em->persist($obj);
}
$em->flush();
return $this->redirectToRoute('objective_manage');
}
return $this->render('keyobjective/manage.html.twig', array(
'objs' => $objs,
'form' => $form->createView()
));
}
This is the FormType:-
class WeightType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('weight','text', array('label' => false));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Objective'
//'data_class' => null
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_objective';
}
}
and this is twig template:-
{% extends 'base.html.twig' %}
{% block body %}
{{form_start(form)}}
{{form_label(form.weight,'Enter Weight')}}
{{form_widget(form.weight)}}
{{form_end(form)}}
{% endblock %}
Any suggested approach..!!
Somehow I figured this out.. after form handle request I created a loop to iterate through the number of objectives being edited and then inside of it another foreach loop which transforms the weight values received from the Form to the setWeight() method one by one:-
/**
* #Route("/mou/objectives/manage", name="objective_manage")
*/
public function manageAction(Request $request){
$objs = $this->getDoctrine()
->getRepository('AppBundle:Objective')
->findAll();
$count = count($objs);
for($i =0; $i < $count; $i++){
$objsarray = new Objective();
}
$form = $this->createFormBuilder()
->add('weight', 'collection', array(
'type' => new WeightType() ,
'allow_add' => false,
'allow_delete' => false,
'options' => array('label' => false),
))
->add('save', 'submit')
->getForm();
$form->setData(array('weight' => $objs));
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$em = $this->getDoctrine()->getManager();
for($i=0; $i < count($objs); $i++){
$obj = new Objective();
$obj = $em->getRepository('AppBundle:Objective')->find($objs[$i]);
$weight = $form->get('weight')->get($i)->getData();
foreach($weight as $val){
$obj->setWeight($val);
$em->persist($obj);
}
}
$em->flush();
$this->addFlash(
'notice',
'Objective weight updated'
);
return $this->redirectToRoute('objective_manage');
}
return $this->render('keyobjective/manage.html.twig', array(
'objs' => $objs,
'form' => $form->createView()
));
}

How do I stop Symfony 2 checkbox from returning null

On my Symfony 2 form I have 2 checkboxes. The documentation states
"if the box is checked, the field will be set to true, if the box is
unchecked, the value will be set to false"
which is what I'd like to happen but when the checkbox is unchecked I'm actually getting nothing back. I realise a checkbox on a HTML form will normally return nothing if unchecked and I'd usually add some logic to the back end to handle it but it sounds like Symfony should be doing that for me and isn't.
What am I doing wrong or have I missed?
My formtype looks like this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('fullname', 'text')
->add('screened', 'checkbox', array(
'label' => 'Enable screening emails?' ))
->add('dedupe', 'checkbox', array(
'label' => 'Enable live dedupeing?'))
);)
and the relevant bits of the twig template look like this:
<div class="form-group">
<div class="input-group col-sm-offset-2 col-sm-10">
<div class="checkbox col-sm-6">
{{ form_widget(form.screened) }}
{{ form_label(form.screened) }}
</div>
<div class="checkbox col-sm-6">
{{ form_widget(form.dedupe, {'attr': {'required': 'false'}}) }}
{{ form_label(form.dedupe) }}
</div>
</div>
</div>
The form is created in the controler here:
/**
* Creates a new User entity.
*
*/
public function createAction(Request $request)
{
$entity = new User();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$this->get('project_login.user_manager')->setUserPassword($entity, $form->get('password')->getData());
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('user_show', array('id' => $entity->getId())));
}
return $this->render('ProjectLoginBundle:User:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Creates a form to create a User entity.
*
* #param User $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(User $entity)
{
$form = $this->createForm(new UserType(), $entity, array(
'action' => $this->generateUrl('user_create'),
'method' => 'POST', 'validation_groups' => array('create')
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
If I understood well you need to handle when the field is not checked, because you're not getting a response when you're handling the form request
You can solve it in this way:
if ($form->isValid()) {
$form->handleRequest($request);
$em = $this->getDoctrine()->getManager();
$entity = $form->getData();
var_dump($entity->getScreened());
var_dump($entity->getFullname());
var_dump($entity->getDedupe());
// They should return you the values set on the create form
$em->persist($entity);
$em->flush();
}
In case that it is not getting the values try in this way, but is not the proper one...
if (!isset($form->get('screened')) {
$entity->setScreened(false);
}
if (!isset($form->get('dedupe')) {
$entity->setDedupe(false);
}
It will check if you're not receiving any data for dedupe and screened from the form, if it's this case you'll know that the value has not been checked

Symfony2 form filter for ManyToMany entity relation

I have 2 entities:
class Exercise
{
//entity
}
and
class Question
{
//entity
}
Their relationship is ManyToMany.
The question is: How I can filter (on the exercise form) the Question entities?
I have this form for Exercise:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('questions', null, array(
'property' => 'name',
'multiple' => true,
'expanded' => false,
'query_builder' => function(EntityRepository $er) use ($options) {
return $er->createQueryBuilder('u')
->where('u.level = :level')
->setParameter('level',$options['level'])
->orderBy('u.dateR', 'ASC');},
))
//other fields
->add('Save','submit')
;
}
I know that I can filter with the query_builder but, how I can pass the var $search?
Should I create another form?
Any help would be appreciated.
Best regards
EDIT: I have found the solution that I want. I put 2 forms on the Controller Action, one form for the entity and one form for filter.
//ExerciseController.php
public function FormAction($level=null)
{
$request = $this->getRequest();
$exercise = new Exercise();
//Exercise form
$form = $this->createForm(new ExerciseType(), $exercise,array('level' => $level));
//create filter form
$filterForm = $this->createFormBuilder(null)
->add('level', 'choice', array('choices' => array('1' => '1','2' => '2','3' => '3')))
->add('filter','submit')
->getForm();
//Manage forms
if($request->getMethod() == 'POST'){
$form->bind($request);
$filterForm->bind($request);
//If exercise form is received, save it.
if ($form->isValid() && $form->get('Save')->isClicked()) {
$em = $this->getDoctrine()->getManager();
$em->persist($exercise);
$em->flush();
return $this->redirect($this->generateUrl('mybundle_exercise_id', array('id' => $exercise->getId())));
}
//If filter form is received, filter and call again the main form.
if ($filterForm->isValid()) {
$filterData = $formFiltro->getData();
$form = $this->createForm(new ExerciseType(), $exercise,array('level' => $filterData['level']));
return $this->render('MyBundle:Exercise:crear.html.twig', array(
'ejercicio' => $ejercicio,
'form' => $form->createView(),
'formFiltro' => $formFiltro->createView(),
));
}
}
return $this->render('juanluisromanCslmBundle:Ejercicio:form.html.twig', array(
'exercise' => $exercise,
'form' => $form->createView(),
'formFiltro' => $filterForm->createView(),
));
}
Templating the forms
On the form.html.twig
{{ form_start(filterForm) }}
{{ form_errors(filterForm) }}
{{ form_end(filterForm) }}
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_end(form) }}
It works for me and it is that i was looking for.
What you probably want to do here, is to make use of the form builder:
$search = [...]
$form = $this->createForm(new AbstractType(), $bindedEntityOrNull, array(
'search' => $search,
));
here you can provide any list of arguments to the builder method of your AbstractType.
public function buildForm(FormBuilderInterface $builder, array $options)
as you may have guessed at this point you may access the options array throu the $option variable.
As a side note remember to provide a fallback inside the default option array. In your AbstractType you can do something like this:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'search' => 'some_valid_default_value_if_search_is_not_provided'
));
}
hope it helps, regards.

Showing name and saving id in symfony dropdown

I want to show the 'name' of my departments as a dropdown to my users and when they choose one, save its 'id' into the database. How can i do that? Below is my code. Currentlt its showing id and saving id.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('adress')
->add('city')
->add('area')
->add('departments', 'entity', array(
'empty_value' => '',
'class' => 'YdyaHospitalBundle:Department',
'query_builder' => function($repository) { return $repository->createQueryBuilder('t')->orderBy('t.id', 'ASC'); },
'property' => 'id',
'multiple' =>false,
'expanded' =>true,
))
;
}
Update
My controller action:
/**
* Creates a new Hospitals entity.
*
* #Route("/", name="hospitals_create")
* #Method("POST")
* #Template("YdyaHospitalBundle:Hospitals:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Hospitals();
$form = $this->createForm(new HospitalsType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('hospitals_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Displays a form to create a new Hospitals entity.
*
* #Route("/new", name="hospitals_new")
* #Method("GET")
* #Template()
*/
public function newAction()
{
$entity = new Hospitals();
$form = $this->createForm(new HospitalsType(), $entity);
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
You can either implement a __toString() for your entity, or specify the property to display with:
->add('departments', 'entity', array(
'empty_value' => '',
'class' => 'YdyaHospitalBundle:Department',
'query_builder' => function($repository) { return $repository->createQueryBuilder('t')->orderBy('t.id', 'ASC'); },
// 'property' => 'id', --> Remove this
'multiple' => false,
'expanded' => true,
'property' => 'name' // Property used to display the entity
))
In your Controller you'll still be able to save your entity or the id of your entity to the db.
See documentation: http://symfony.com/doc/current/reference/forms/types/entity.html#property

Resources