How do I persist my form to the database? - php

I need to persist my form to the database. I am using Symfony to do this and I have built a response entity:
<?php
namespace App\Entity;
use App\Repository\ResponseRepository;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\SerializedName;
use Symfony\Component\Validator\Constraints as Assert;
* )
* #ORM\Entity(repositoryClass=ResponseRepository::class)
*/
class Response
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(name="id", type="integer")
* #Groups({"response:read"})
*
*/
private $id;
/**
* #ORM\Column(name="answer", type="string", length=255)
* #Groups({"response:write", "response:read", "session:read"})
* #Assert\NotBlank()
*/
private $answer;
/**
* #ORM\ManyToOne(targetEntity=Session::class, inversedBy="responses")
* #ORM\JoinColumn(nullable=false)
* #Assert\Valid
*/
private $session;
/**
* #ORM\ManyToOne(targetEntity=Question::class, inversedBy="responses")
* #ORM\JoinColumn(nullable=false)
* #Groups({"response:read", "response:write"})
*/
private $question;
// /**
// * #ORM\OneToMany(targetEntity=QuestionsQuestionType::class, mappedBy="response")
// */
// private $questionsQuestionType;
public function __construct()
{
$this->questionsQuestionType = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getAnswer(): ?string
{
return $this->answer;
}
public function setAnswer(string $answer): self
{
$this->answer = $answer;
return $this;
}
public function getSession(): ?Session
{
return $this->session;
}
public function setSession(?Session $session): self
{
$this->session = $session;
return $this;
}
public function getQuestion(): ?Question
{
return $this->question;
}
public function setQuestion(?Question $question): self
{
$this->question = $question;
return $this;
}
A new response function in the ResponseController (please note QuizResponse is an alias of Response entity. This is to not confuse my response entity with Symfony Response) :
/**
* #Route("/new", name="response_new", methods={"GET", "POST"})
*/
public function new(Request $request, EntityManagerInterface $entityManager, QuestionRepository $questionRepository): Response
{
$questions = $questionRepository->findAll();
// dd($questions);
$response = new QuizResponse();
$form = $this->createForm(ResponseType::class, $response); // problem exists
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($response);
$entityManager->flush();
// $formData = $form->getData();
// dd($formData);
// echo 'this should work';exit;
return $this->redirectToRoute('response_index', [], Response::HTTP_SEE_OTHER);
}
return $this->renderForm('response/new.html.twig', [
'response' => $response,
'question' => $questions,
'form' => $form,
]);
}
A ResponseType form:
<?php
namespace App\Form;
use App\Entity\Response;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class ResponseType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Response::class,
]);
}
}
And here is my twig template (_form.html.twig):
{{ form_start(form) }}
<div class="mt-3">
{% for question in question %}
<input type="hidden" name="response[question][]" value="{{ question.id }}">
{% set name = 'response[answer]['~ question.id ~']' %}
{% if question.type == 'checkbox' %}
{% set name = name ~ '[]' %}
{% endif %}
{# {% if question.replies is defined %}#}
<div class="mb-3 mt-3 border">
<h3 class="mb-0" id="question-{{ question.id }}">{{ loop.index }}. {{ question.label }}</h3>
</div>
{% if question.type == 'checkbox' or question.type == 'radio' %}
<div class="answers p-1">
{% for answer in question.replies %}
{% set id = 'answer-' ~ answer.id %}
<label for="{{ id }}">{{ answer.answer }}</label>
<input type="{{ question.type }}" name="{{ name }}" id="{{ id }}">
{% endfor %}
</div>
{% elseif question.type == 'textarea' %}
<textarea name="{{ name }}" aria-labelledby="question-{{ question.id }}" cols="30" rows="5" class="form-control"></textarea>
{% elseif question.type == 'number' %}
<input type="number" name="{{ name }}" aria-labelledby="question-{{ question.id }}">
{% else %}
<input type="text" name="{{ name }}" aria-labelledby="question-{{ question.id }}" class="form-control">
{% endif %}
{# {% endif %}#}
{% endfor %}
</div>
<button class="btn btn-primary">{{ button_label|default('Submit') }}</button>
{#{{ form_end(form, {render_rest: false }) }}#}
{{ form_end(form) }}
It's completely detached from the responseType form which is why I believe it doesn't submit to the database... But I am not sure how to map the ResponseType form to the _form.html.twig

you dont use the form component - you have the class and the correct controller code, but in your template you print the form fields yourself.
Just define the fields in your formType, remove the formfields from your twig and use the supposed {{ form_*() }} methods.
To make this conditional rendering of your CollectionType work - you will have to write some twig code in your form theme. (but to explain this is outside of my time and scope of the question)

Related

spl_object_hash(): Argument #1 ($object) must be of type object, string given

I can create a record but when editing it throws me the error
I can also see the log
but not edit it
spl_object_hash(): Argument #1 ($object) must be of type object, string given
twig part of the view
{% extends 'layouts/layoutmodal.html.twig' %}
{% block content %}
<div class="row">
<div class="col-sm">
{{ form_row(form.created_at, { 'label': 'Fecha de Ingreso:' }) }}
</div>
<div class="col-sm">
{{ form_row(form.nombrecliente, { 'label': 'Nombre Cliente' }) }}
</div>
<div class="col-sm">
{{ form_row(form.nombrecomercio, { 'label': 'Nombre Comercio' }) }}
</div>
<div class="col-sm">
{{ form_row(form.telefono) }}
</div>
<div class="col-sm">
{{ form_row(form.email, { 'label': 'Correo Electronico' }) }}
</div>
</div>
<div class="row">
<div class="col-sm">
{{ form_row(form.documento, { 'label': 'Documento: RUC/DNI/CE' }) }}
</div>
<div class="col-sm">
{{ form_row(form.departamento) }}
</div>
<div class="col-sm">
{{ form_row(form.provincia) }}
</div>
<div class="col-sm">
{{ form_row(form.distrito) }}
</div>
Form controller used to edit all the data loaded in the operation
#[Route('ventas/{id}/editar', name: 'ventas/clientes/editar', methods: ['GET', 'POST'])]
public function editar(Request $request, Cliente $cliente): Response
{
$form = $this->createForm(ClienteType::class, $cliente);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('ventas');
}
return $this->render('ventas/clientes/editar.html.twig', [
'cliente' => $cliente,
'form' => $form->createView(),
]);
}
entity has ManyToOne relationship I don't think you have problems there:
since I can add and delete without any problem...
namespace App\Entity\Ventas;
use App\Repository\Ventas\ProvinciaRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=ProvinciaRepository::class)
*/
class Provincia
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $nombre;
/**
* #ORM\ManyToOne(targetEntity=Departamento::class, inversedBy="provincia")
*/
private $departamento;
/**
* #ORM\OneToMany(targetEntity=Distrito::class, mappedBy="provincia")
*/
private $distrito;
public function __toString()
{
return $this->nombre;
}
public function __construct()
{
$this->distrito = new ArrayCollection();
$this->nombre = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getNombre(): ?string
{
return $this->nombre;
}
public function setNombre(string $nombre): self
{
$this->nombre = $nombre;
return $this;
}
public function getDepartamento(): ?Departamento
{
return $this->departamento;
}
public function setDepartamento(?Departamento $departamento): self
{
$this->departamento = $departamento;
return $this;
}
/**
* #return Collection|Distrito[]
*/
public function getDistrito(): Collection
{
return $this->distrito;
}
public function addDistrito(Distrito $distrito): self
{
if (!$this->distrito->contains($distrito)) {
$this->distrito[] = $distrito;
$distrito->setProvincia($this);
}
return $this;
}
public function removeDistrito(Distrito $distrito): self
{
if ($this->distrito->removeElement($distrito)) {
// set the owning side to null (unless already changed)
if ($distrito->getProvincia() === $this) {
$distrito->setProvincia(null);
}
}
return $this;
}
}

Symfony, some field still blanks after handleRequest

I'm learning how yo use symfony, and my problem is, when I want to use the handleRequest function, it did not validate my email en message field, but it's good for name field.
Look the code:
Contact.php entity
<?php
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class Contact
{
/**
* #Assert\NotBlank
*/
private $name;
/**
* #Assert\NotBlank
*/
private $email;
/**
* #Assert\NotBlank
*/
private $message;
public function getName()
{
return $this->name;
}
public function getEmail()
{
return $this->email;
}
public function getMessage()
{
return $this->message;
}
public function setName($name)
{
$this->name = $name;
}
public function setEmail($email)
{
$this->name = $email;
}
public function setMessage($message)
{
$this->name = $message;
}
}
?>
BlogController.php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Article;
use App\Entity\Contact;
use App\Repository\ArticleRepository;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\HttpFoundation\Request;
class BlogController extends Controller
{
/**
* #Route("/blog", name="blog")
*/
public function blog(ArticleRepository $repo)
{
$articles = $repo->findAll();
return $this->render('blog/index.html.twig', [
'controller_name' => 'BlogController',
'articles' => $articles
]);
}
/**
* #Route("/", name="blog_home")
*/
public function home()
{
return $this->render('blog/home.html.twig');
}
/**
* #Route("/blog/articles/{id}", name="blog_show")
*/
public function show(Article $article)
{
return $this->render('blog/show.html.twig',[
'article' => $article
]);
}
/**
* #Route("/contact", name="blog_contact")
*/
public function contact(Request $request)
{
$contact = new Contact; /* Create the new contact object */
$form = $this->createFormBuilder($contact) /* Creating the form */
->add('name', TextType::class)
->add('email', TextType::class)
->add('message', TextareaType::class)
->getForm();
dump($contact);
$form->handleRequest($request);
dump($contact);
if($form->isSubmitted() && $form->isValid())
{
return $this->redirectToRoute('blog_home');
}
dump($request);
return $this->render('blog/contact.html.twig',[
'form' => $form->createView()
]);
}
}
contact.html.twig
{% extends 'base.html.twig' %}
{% block title %}BLOG - Contact{% endblock %}
{% block body %}
<h2>Me contacter !</h1>
<div class="row">
<div class="col-md-5">
{{ form_start(form) }}
<label>Nom:</label>
{{ form_widget(form.name) }}
<label>Email:</label>
{{ form_widget(form.email) }}
<label>Message:</label>
{{ form_widget(form.message) }}
<br>
<button type="submit" class="btn btn-info">Envoie</button>
{{ form_end(form) }}
</div>
<div class="col-md-1">
</div>
<div class="col-md-6">
<div class="card border-info mb-1" style="max-width: 20rem;">
<div class="card-header">Twitter: #Fergvae</div>
</div>
<div class="card border-dark mb-1" style="max-width: 20rem;">
<div class="card-header">Discord: Fergvae#0730</div>
</div>
<div class="card border-danger mb-1" style="max-width: 20rem;">
<div class="card-header">Youtube: Fergvae</div>
</div>
</div>
</div>
{% endblock %}
The only things that didn't work is the handleRequest it's why I made multiple dump.
you also can look the dumped content, the first is before handle and second after.
Dumped symfony content
Thanks to all people who answer this question !
Ok my bad, I just forget when I copy past to change the ^this->name in de setters ! Excuse me for the disturb
It's great that you have found your solution, but just in case:
If usage for classes, a better practice is to use a FormType, in there you can declare your class on which fields the form should be automatically created. Which Symfony will automatically catch all of the needed fields and will create the form for you, less code written and etc. Or you can create a custom form, and define all of your needed fields, including restrictions as not empty and etc..
To sum it up, if possible keep as less logic in the controllers as possible and move them deeper.

Symfony: Variable "user" does not exist

I get the variable does not exist error everytime I try to access a site on my blog.
the twig template:
{% extends '::base.html.twig' %}
{% block body %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title text-center">All Users</h3>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Username</th>
<th>Email Address</th>
<th>Password</th>
</tr>
</thead>
<tbody>
{% for user in userlist %}
<tr>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
<td>{{ user.password }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<button type="button" class="btn btn btn-info">
Edit profile
</button>
{% endblock %}
the Controller :
<?php
// src/BlogBundle/Controller/UserController.php
namespace BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use BlogBundle\Entity\Blog;
use BlogBundle\Entity\User;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
class UserController extends Controller
{
/**
*#Security("has_role('ROLE_ADMIN')")
* #Route("/users", name="users", requirements={"page": "\d+"})
*/
public function listAction()
{
$user = $this->getDoctrine()->getRepository('BlogBundle:User')->findBy(array(), array('username' => 'DESC'));
dump($user);
return $this->render('BlogBundle:user:userlist.html.twig', [
'userlist' => $user
]);
}
/**
* #Route("/users/edit/{id}", name="edit", requirements={"id" = "\d+"}, defaults={"id" = 0})
*#Security("has_role('ROLE_ADMIN')")
*/
public function editAction(Request $request, User $user) {
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('BlogBundle:User')->find($username);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($user);
$em->flush();
return $this->render('BlogBundle:user:userlist.html.twig', array(
'user' => $user,
'form' => $form->createView(),
'success' => true
));
}
return $this->render('FOSUserBundle:Profile:edit.html.twig');
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => 'BlogBundle\Entity\User'
]);
}
}
?>
and finally the User Entity:
<?php
// src/BlogBundle/Entity/User.php
namespace BlogBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
}
/**
* Get the value of Id
* #return mixed
*/
public function getId() {
return $this->id;
}
}
What I'm trying to do is, create a page that only the admin can access which displays a list of all users from my doctrine database. --> listAction()
next to that I would like to have the possibility to edit all the users information --> editAction()
any ideas?
the error occurs in the twig template line: "{{ path('edit', {'id':user.id}) }} ...
You put the button outside your loop, so yes, the variable user doesn't exist, simply put put
<button type="button" class="btn btn btn-info">
Edit profile
</button>
in the for loop

Sortable behavior in admin listing in Sonata Admin

I have a list of categories that I would like to sort (change the order). I use Sonata Admin for my backend. I've tried to provide this with the following tutorial.
This is my Category Entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation\SortablePosition;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* Category
*
* #ORM\Table(name="category", indexes={#ORM\Index(name="fk_category_category_idx", columns={"parent_category_id"})})
* #ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
*/
class Category
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
private $name;
/**
* #var boolean
*
* #ORM\Column(name="enabled", type="boolean", nullable=false)
*/
private $enabled = true;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \AppBundle\Entity\Category
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Category")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="parent_category_id", referencedColumnName="id")
* })
*/
private $parentCategory;
/**
* #Gedmo\SortablePosition
* #ORM\Column(name="position", type="integer")
*/
private $position;
public function __toString()
{
//return $this->getName();
if($this->getParentCategory()){
return '(' . $this->getParentCategory()->getName() . ')' . ' ' . $this->getName();
}
else{
return $this->getName();
}
}
/**
* Set name
*
* #param string $name
*
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set enabled
*
* #param boolean $enabled
*
* #return Category
*/
public function setEnabled($enabled)
{
$this->enabled = $enabled;
return $this;
}
/**
* Get enabled
*
* #return boolean
*/
public function getEnabled()
{
return $this->enabled;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set parentCategory
*
* #param \AppBundle\Entity\Category $parentCategory
*
* #return Category
*/
public function setParentCategory(\AppBundle\Entity\Category $parentCategory = null)
{
$this->parentCategory = $parentCategory;
return $this;
}
/**
* Get parentCategory
*
* #return \AppBundle\Entity\Category
*/
public function getParentCategory()
{
return $this->parentCategory;
}
/**
* Set position
*
* #param integer $position
*
* #return Category
*/
public function setPosition($position)
{
$this->position = $position;
return $this;
}
/**
* Get position
*
* #return integer
*/
public function getPosition()
{
return $this->position;
}
}
As you can see I have a property $position and also a getter and setter for it.
In services.yml I have:
services:
gedmo.listener.sortable:
class: Gedmo\Sortable\SortableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ "#annotation_reader" ] ]
And:
admin.category:
class: AppBundle\Admin\CategoryAdmin
arguments: [~, AppBundle\Entity\Category, 'PixSortableBehaviorBundle:SortableAdmin']
tags:
- { name: sonata.admin, manager_type: orm, label: Categorieën }
calls:
- [ setPositionService, ["#pix_sortable_behavior.position"]]
In my config.yml I have:
stof_doctrine_extensions:
orm:
default:
sortable: true
And in my CategoryAdmin I have:
<?php
namespace AppBundle\Admin;
use AppBundle\Entity\Category;
use AppBundle\Repository\CategoryRepository;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Route\RouteCollection;
class CategoryAdmin extends AbstractAdmin
{
public $last_position = 0;
private $positionService;
protected $datagridValues = array(
'_page' => 1,
'_sort_order' => 'ASC',
'_sort_by' => 'position',
);
public function setPositionService(\Pix\SortableBehaviorBundle\Services\PositionHandler $positionHandler)
{
$this->positionService = $positionHandler;
}
protected function configureFormFields(FormMapper $formMapper)
{
$entity = new Category();
$query = $this->modelManager->getEntityManager($entity)->createQuery('SELECT c FROM AppBundle\Entity\Category c WHERE c.parentCategory IS NULL');
$formMapper
->add('name', 'text', array('label' => 'Naam'))
->add('parentCategory', 'sonata_type_model', array('label' => 'Hoofdcategorie', 'required' => false, 'query' => $query, 'multiple' => false, 'btn_add' => false))
->add('enabled', 'checkbox', array('label' => 'Actief', 'required' => false));
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper->add('name');
}
protected function configureRoutes(RouteCollection $collection)
{
$collection->add('move', $this->getRouterIdParameter().'/move/{position}');
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name', null, array('label' => 'Naam'))
->add('enabled', null, array('label' => 'Actief'))
->add('parentCategory', null, array('label' => 'Hoofdcategorie'))
->add('_action', null, array(
'actions' => array(
'move' => array(
'template' => 'AppBundle:Sonata:_sort.html.twig'
),
)
)
);
//;
}
}
In the view _sort.html.twig I have:
{% if admin.isGranted('EDIT', object) and admin.hasRoute('edit') %}
{% set pix_position = sortableObjectPosition(object) %}
{% if pix_position < admin.last_position %}
<a class="btn btn-sm btn-default" href="{{ admin.generateObjectUrl('move', object, {'position': 'bottom'}) }}" title="{{ 'move_to_bottom'|trans }}">
{{- 'icon_move_to_bottom'|trans -}}
</a>
{% endif %}
{% if pix_position < admin.last_position %}
<a class="btn btn-sm btn-default" href="{{ admin.generateObjectUrl('move', object, {'position': 'down'}) }}" title="{{ 'move_down'|trans }}">
{{- 'icon_move_down'|trans -}}
</a>
{% endif %}
{% if pix_position > 0 %}
<a class="btn btn-sm btn-default" href="{{ admin.generateObjectUrl('move', object, {'position': 'up'}) }}" title="{{ 'move_up'|trans }}">
{{- 'icon_move_up'|trans -}}
</a>
{% endif %}
{% if pix_position > 0 %}
<a class="btn btn-sm btn-default" href="{{ admin.generateObjectUrl('move', object, {'position': 'top'}) }}" title="{{ 'move_to_top'|trans }}">
{{- 'icon_move_to_top'|trans -}}
</a>
{% endif %}
{% endif %}
I'm not getting any errors. But there are no buttons shown in my "Actions" column. The HTML is like this:
<td class="sonata-ba-list-field sonata-ba-list-field-text" objectid="28">
<div class="btn-group">
</div>
</td>
When I dump the variable pix_position from my twig file I get 0. When I dump the variable admin.last_position I also get 0. In my database all the position fields are 0. But how can I order them in my backend than?
UPDATE 2:
Now the buttons are shown.
But when I click on the left one he places it on top, and not one up. Same for the button on the right... . When I click on the left button he should only go one place up.
{% if admin.isGranted('EDIT', object) and admin.hasRoute('edit') %}
{% set pix_position = sortableObjectPosition(object) %}
{% if pix_position < admin.last_position %} // Won't pass
<a class="btn btn-sm btn-default" href="{{ admin.generateObjectUrl('move', object, {'position': 'bottom'}) }}" title="{{ 'move_to_bottom'|trans }}">
{{- 'icon_move_to_bottom'|trans -}}
</a>
{% endif %}
{% if pix_position < admin.last_position %} // Won't pass
<a class="btn btn-sm btn-default" href="{{ admin.generateObjectUrl('move', object, {'position': 'down'}) }}" title="{{ 'move_down'|trans }}">
{{- 'icon_move_down'|trans -}}
</a>
{% endif %}
{% if pix_position > 0 %} // Won't pass, but 1 yes
<a class="btn btn-sm btn-default" href="{{ admin.generateObjectUrl('move', object, {'position': 'up'}) }}" title="{{ 'move_up'|trans }}">
{{- 'icon_move_up'|trans -}}
</a>
{% endif %}
{% if pix_position > 0 %} // Won't pass, but 1 yes
<a class="btn btn-sm btn-default" href="{{ admin.generateObjectUrl('move', object, {'position': 'top'}) }}" title="{{ 'move_to_top'|trans }}">
{{- 'icon_move_to_top'|trans -}}
</a>
{% endif %}
{% endif %}
So, instead of init the default value to 0, just init it to 1
Update
Actually, if you move one object, it will go on top, because its value is 2 and all other are to 1.
One possibility, is instead of setting every thing to 1, is to set an incremential value by default.
Extract from this answer :
mysql_query("
UPDATE member_profile
SET points = points + 1
WHERE user_id = '".$userid."'
");

Symfony - Using twig extension with form prevents errors from showing up

I'm trying to use twig extensions as widgets to render sections of the page.
I have this class EventWidget, which is a twig extension that defines a twig function called event_widget_create that's responsible for rendering the create page of my entity.
The problem is, There's no form errors printed inside the view, even though there're errors displayed when I do var_dump($form->getErrorsAsString()) inside the controller or the widget function.
There's something that I noticed, when clicking submit, the fields data disappears and I get the feeling that the page reloads.
Here's my widget extension code:
class EventWidget extends \Twig_Extension
{
/**
* #var Twig_Environment
*/
protected $env;
/**
* #var \Tsk\FEBundle\FormHandler\EventFormHandler
*/
protected $eventFormHandler;
function __construct(EventFormHandler $eventFormHandler)
{
$this->eventFormHandler = $eventFormHandler;
}
/**
* #param Twig_Environment $environment
*/
public function initRuntime(Twig_Environment $environment)
{
$this->env = $environment;
}
public function getFunctions()
{
return [
new \Twig_SimpleFunction("event_widget_create", [$this, "getEventWidgetCreate"]),
];
}
public function getEventWidgetCreate(FormInterface $form)
{
return $this->env->render("#Default/Partial/events_widget_create.html.twig",[
"form" => $form->createView()
]);
}
/**
* #return string
*/
public function getName()
{
return "event_widget";
}
}
And here's my controller:
/**
* #Route("/")
*
* #package Tsk\FEBundle\Controller
*/
class EventController extends Controller
{
/**
* #Route("/event/create", name="tsk_fe_event_create")
* #Template("#Default/event_create.html.twig")
* #Security("has_role('ROLE_ARTIST')")
*/
public function createEventAction(Request $request)
{
$handler = $this->get("tsk_fe.event_form.handler");
$form = $handler->create();
if ($request->getMethod() == "POST") {
if ($handler->process($form)) {
return new RedirectResponse($this->generateUrl("tsk_fe_default_index"));
}
}
return ["form" => $form];
}
}
And the form:
class EventType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add("title", "text", [
"error_bubbling" => true
])
->add("description", "textarea", [
"required" => false
])
->add("start", "thrace_datetimepicker", [
"label" => "From",
"error_bubbling" => true
])
->add("end", "thrace_datetimepicker", [
"label" => "To",
"error_bubbling" => true
])
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
"data_class" => "Tsk\FEBundle\Entity\Event",
]);
}
public function getName()
{
return "event";
}
}
And lastly the view:
This's the main view:
"#Default/event_create.html.twig"
{% extends "#TskFE/layout.html.twig" %}
{% block content %}
{{ event_widget_create(form)|raw }}
{% endblock content %}
And this's the partial view that's rendered by the widget:
"#Default/Partial/events_widget_create.html.twig":
{% form_theme form with ['ThraceFormBundle:Form:fields.html.twig'] %}
{{ form_start(form, {"action": url("tsk_fe_event_create"), 'attr': {'novalidate': 'novalidate'} }) }}
<div class="form-group">
{{ form_label(form.title) }}
{{ form_widget(form.title, {"attr":{"class": "form-control"} }) }}
{{ form_errors(form.title) }}
</div>
<div class="form-group">
{{ form_label(form.description) }}
{{ form_widget(form.description, {"attr":{"class": "form-control"} }) }}
{{ form_errors(form.description) }}
</div>
<div class="form-group">
{{ form_label(form.start) }}
{{ form_widget(form.start, {"attr":{"class": "form-control"} }) }}
{{ form_errors(form.start) }}
</div>
<div class="form-group">
{{ form_label(form.end) }}
{{ form_widget(form.end, {"attr":{"class": "form-control"} }) }}
{{ form_errors(form.end) }}
</div>
<input type="submit" value="Submit" class="btn btn-info"/>
Cancel
{{ form_rest(form) }}
{{ form_end(form) }}
It seems you have bubbled your errors by using 'error_bubbling' => true. Not sure if it is what you want because you render error individually by field.
Error bubbling means all errors are attached to the parent form instead of being attach to the related field. So, if it is what you want, you must add {{ form_errors(form) }} on top of your form in your template in order to get your errors displayed otherwise, just remove the error_bubbling option.

Categories