Symfony 3.2 CollectionType - forms

Here's my problem. In my project, I have a one-to-many relationship between class FactureAchat and LigneFactureAchat, when I add a Facture the products are added in the Table ligne_facture_achat without having adding the foreign key of my Facture and an error is produced "Could not determine access type for property "LinesInvoicesPurchases". " the same problem with the display of a facture with its products. "An exception has been thrown during the rendering of a template (" Notice: Undefined index: factureachat ")."
FactureAchat Entity
/*----- added from facture---*/
/**
* #ORM\OneToMany(targetEntity="LigneFactureAchat", mappedBy="factureachat",cascade={"all"})
* #Assert\Valid()
*/
protected $lignesFacturesAchats;
public function __construct() {
$this->lignesFacturesAchats = new ArrayCollection();
$this->dateCreation = new \DateTime();
$this->dateEcheance = new \DateTime();
}
/**
* Get lignesFacturesAchats
*
* #return \AppBundle\Entity\LigneFactureAchat
*/
public function getLignesFacturesAchats() {
return $this->lignesFacturesAchats;
}
public function addLignesFactureAchat(LigneFactureAchat $l) {
$l->setFactureAchat($this);
$this->lignesFacturesAchats->add($l);
}
public function removeLignesFactureAchat(LigneFactureAchat $l) {
$this->lignesFacturesAchats->removeElement($l);
}
LigneFactureAchat Entity
/**
* #var \FactureAchat
*
* #ORM\ManyToOne(targetEntity="FactureAchat",inversedBy="lignesFacturesAchats",cascade={"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="facture_achat_id", referencedColumnName="id")
* })
*/
private $factureAchat;
/**
* Set factureAchat.
*
* #param \AppBundle\Entity\FactureAchat|null $factureAchat
*
* #return LigneFactureAchat
*/
public function setFactureAchat(\AppBundle\Entity\FactureAchat $factureAchat = null)
{
$this->factureAchat = $factureAchat;
return $this;
}
/**
* Get factureAchat.
*
* #return \AppBundle\Entity\FactureAchat|null
*/
public function getFactureAchat()
{
return $this->factureAchat;
}
FactureAchat Form
$builder->add('lignesFacturesAchats', CollectionType::class, array(
'entry_type' => LigneFactureAchatType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'mapped' => true,
'by_reference' => false
));
FactureAchatController
/**
* Creates a new factureachat entity.
*
* #Route("/new", name="factureachat_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request) {
$em = $this->getDoctrine()->getManager();
$retenus = $em->getRepository('AppBundle:Retenu')->findAll();
$factureachat = new FactureAchat();
$form = $this->createForm('AppBundle\Form\FactureAchatType', $factureachat);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($factureachat);
$em->flush($factureachat);
// var_dump($factureachat->getLignesFacturesAchats());die;
if ($form->get('saveAndPrint')->isClicked()) {
return $this->redirectToRoute('factureachat_print', array('id' => $factureachat->getId()));
}
// return $this->redirectToRoute('factureachat_show', array('id' => $factureachat->getId()));
}
return $this->render('factureachat/new.html.twig', array(
'factureachat' => $factureachat,
'form' => $form->createView(),
'retenus' => $retenus
));
}
/**
* #Route("/{id}/show",name="factureachat_show")
* #Method({"GET","POST"})
*/
public function showAction(Request $request, FactureAchat $factureachat) {
$form_regler = $this->createFormBuilder($factureachat)
->add('termine', \Symfony\Component\Form\Extension\Core\Type\HiddenType::class, array(
'data' => true
))
->add('terminerAndRegler', \Symfony\Component\Form\Extension\Core\Type\SubmitType::class, array('label' => 'Terminer la facture et régler', 'attr' => ['class' => 'btn-success']))
->getForm();
$form_imprimer = $this->createFormBuilder($factureachat)
->add('termine', \Symfony\Component\Form\Extension\Core\Type\HiddenType::class, array(
'data' => true
))
->add('terminerAndImprimer', \Symfony\Component\Form\Extension\Core\Type\SubmitType::class, array('label' => 'Terminer la facture et imprimer', 'attr' => ['class' => 'btn-success']))
->getForm();
$form_regler->handleRequest($request);
$form_imprimer->handleRequest($request);
if ($form_regler->isSubmitted() && $form_regler->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirectToRoute('factureachat_reglements', array('id' => $factureachat->getId()));
}
if ($form_imprimer->isSubmitted() && $form_imprimer->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirectToRoute('factureachat_print', array('id' => $factureachat->getId()));
}
return $this->render('factureachat/show.html.twig', array(
'factureachat' => $factureachat,
'form_regler' => $form_regler->createView(),
'form_imprimer' => $form_imprimer->createView(),
'lignesFacturesAchats' => $factureachat->getLignesFacturesAchats()
));
}
show.html.twig View
<div id="collapseTwo" class="panel-collapse collapse in">
<div class="panel-body">
<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Réf</th>
<th>Désignation</th>
<th>Unité</th>
<th>PU HT</th>
<th>Remise</th>
<th>TVA</th>
<th>PU TTC</th>
<th>Qte</th>
<th>Total TTC</th>
</tr>
</thead>
<tbody>
{% set i=0 %}
{% for ligne in factureachat.lignesFacturesAchats %}
<tr class="item">
<td class="left">{{ligne.article.code}}</td>
<td class="left">{{ligne.designation}}</td>
<td class="left">{{ligne.article.unite}}</td>
<td class="center" id="prixUnitaire_{{i}}">{{ligne.prixUnitaire}}</td>
<td class="center" id="remise_{{i}}">{{ligne.remise}} %</td>
<td class="center" id="tva_{{i}}">{{ligne.tva }} %</td>
{% set puTTC=ligne.ttc/ligne.qte %}
<td class="center" id="ttc_{{i}}">{{ puTTC|number_format(3, '.', '') }}</td>
<td class="center" id="qte_{{i}}">{{ligne.qte}}</td>
<td class="center" id="total_{{i}}">{{ligne.ttc }}</td>
</tr>
{% set i=i+1 %}
{% endfor %}
<div id="lignesFacturesLength" style="visibility: hidden">{{i}}</div>
</tbody>
</table>
</div>
</div>
</div>
the error "An exception has been thrown during the rendering of a template (" Notice: Undefined index: factureachat ")." occurred on line
{% for ligne in factureachat.lignesFacturesAchats %}
Any help please

Related

Still unable with Symfony to validate collection form

I'm using SYMFONY 5 and have setup a collection form where the user is enabled to create a service and add numerous sub-services to the service. This is working fine and the user can add/edit/show/delete services and also sub-services.
Now I want to validate if a new sub-service is added and the form is submitted, the language of the sub-service item must be the one of the service item. If not, the database will not be updatet and the user will get an error message (see screen-shot). This is also working fine with one exception:
I cannot achieve to stick the error-message to the failed sub-service! It appears on every sub-service.
Here the definition of my entity service:
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\ServicesRepository")
*/
class Services
{
/**
* #ORM\Id()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=3)
*/
private $sprache;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $transid;
/**
* #ORM\Column(type="string", length=200)
*/
private $header;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $body;
/**
* #ORM\OneToMany(targetEntity="App\Entity\SubServices", mappedBy="services",cascade={"persist"})
* #Assert\Valid()
*/
private $subServices;
public function __construct()
{
$this->subServices = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function setId(int $id): self
{
$this->id = $id;
return $this;
}
public function getTransId(): ?int
{
return $this->transid;
}
public function setTransId(int $transid): self
{
$this->transid = $transid;
return $this;
}
public function getSprache(): ?string
{
return $this->sprache;
}
public function setSprache(string $sprache): self
{
$this->sprache = $sprache;
return $this;
}
public function getHeader(): ?string
{
return $this->header;
}
public function setHeader(string $header): self
{
$this->header = $header;
return $this;
}
public function getBody(): ?string
{
return $this->body;
}
public function setBody(?string $body): self
{
$this->body = $body;
return $this;
}
/**
* #return Collection|SubServices[]
*/
public function getSubServices(): Collection
{
return $this->subServices;
}
public function addSubService(SubServices $subService): self
{
if (!$this->subServices->contains($subService)) {
$this->subServices[] = $subService;
$subService->setServices($this);
}
return $this;
}
public function removeSubService(SubServices $subService): self
{
if ($this->subServices->contains($subService)) {
$this->subServices->removeElement($subService);
// set the owning side to null (unless already changed)
if ($subService->getServices() === $this) {
$subService->setServices(null);
}
}
return $this;
}
}
As you can see, in the service entity I have put #Assert\Valid() for the subservices.
Here the definition of the sub-service entity:
<?php
namespace App\Entity;
use App\Validator\SubServiceSprache;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\SubServicesRepository")
* #SubServiceSprache()
*/
class SubServices
{
/**
* #ORM\Id()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $transsubid;
/**
* #ORM\Column(type="string", length=3)
*/
private $sprache;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Services", inversedBy="subServices")
*/
private $services;
/**
* #ORM\Column(type="string", length=200)
*/
private $header;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $body;
public function getId(): ?int
{
return $this->id;
}
public function setId(int $id)
{
$this->id = $id;
}
public function getTransSubId(): ?int
{
return $this->transsubid;
}
public function setTransSubId(int $transsubid): self
{
$this->transsubid = $transsubid;
return $this;
}
public function getsprache(): ?string
{
return $this->sprache;
}
public function setsprache(string $sprache): self
{
$this->sprache = $sprache;
return $this;
}
public function getServices(): ?Services
{
return $this->services;
}
public function setServices(?Services $services): self
{
$this->services = $services;
return $this;
}
public function getHeader(): ?string
{
return $this->header;
}
public function setHeader(string $header): self
{
$this->header = $header;
return $this;
}
public function getBody(): ?string
{
return $this->body;
}
public function setBody(?string $body): self
{
$this->body = $body;
return $this;
}
}
As you can see, for the whole class subservices I have put the validation #SubServiceSprache().
Here is the definition of the validator SubServiceSprache:
<?php
namespace App\Validator;
use Symfony\Component\Validator\Constraint;
/**
* #Annotation
*/
class SubServiceSprache extends Constraint
{
public function validatedBy()
{
return \get_class($this).'Validator';
}
public function getTargets()
{
//PROPERTY_CONSTRAINT wenn zB. EMAIL geprüft werden soll
//CLASS_CONSTRAINT wenn ganze Entity geprüft werden soll
// jeweils das Objekt (EMAIL od. ganzes Klassenobjekt wird übergeben
return self::CLASS_CONSTRAINT;
}
}
And here the validation logic in SubServiceSpracheValidator:
<?php
namespace App\Validator;
use App\Entity\Services;
use App\Entity\SubServices;
use Symfony\Component\Validator\ConstraintValidator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Contracts\Translation\TranslatorInterface;
class SubServiceSpracheValidator extends ConstraintValidator
{
private $em;
private $subservice;
private $translator;
public function __construct(EntityManagerInterface $em, TranslatorInterface $translator)
{
$this->em = $em;
$this->translator = $translator;
$this->subservice = new SubServices();
}
public function validate($object, Constraint $constraint)
{
// Ist die Sprache des SubService die des Service?
if ($object instanceof SubServices) {
if($object->getServices()->getSprache() != $object->getsprache()){
// Message Translation
$message = $this->translator->trans('subservice_sprachcheck',
['subsprache' => object->getsprache(),'servsprache' => $object->getServices()->getsprache()]
);
// Assign message
$this->context->buildViolation($message)
->atPath('sprache')
->addViolation();
}
}
}
}
Here is a snippet of the form class for service:
->add('subservices', CollectionType::class,
array('entry_type' => SubservicesFormType::class,
'label' => false,
'entry_options' => array('label' => false),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'error_bubbling' => false,
))
->add('save', SubmitType::class,
array('label' => 'Sichern',
'attr' => array('class' => 'buttonsave')
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Services::class,
'error_bubbling' => false,
//'newid' => false,
]);
}
and here the one for the subservices:
class SubservicesFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('sprache', LanguageType::class,
array('label' => 'Sprache',
'disabled' => false,
'attr' => array('class' => 'form-control'),
'choice_loader' => NULL,
'choices' => ['DEUTSCH' => 'de', 'ENGLISCH' => 'en'],
'choice_translation_domain' => true,
))
->add('header', TextType::class,
array('label' => 'Überschrift',
'attr' => array('class' => 'form-control')))
->add('body', TextareaType::class,
array('label' => 'Beschreibung',
'attr' => array('class' => 'form-control')))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => SubServices::class,
'validation_groups' => ['Default'],
]);
}
}
and at last my twig-file:
{% extends 'base.html.twig' %}
{% import _self as formMacros %}
{% block title %}UB Mollekopf{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" href="{{ absolute_url('/css/ub_styles.css') }}" type="text/css" media="all">
<link rel="stylesheet" href="{{ absolute_url('css/font-awesome.css') }}">
{% endblock %}
{% macro printSubserviceRow(SubservicesFormType) %}
<td class="subserviceformsprache">{{ form_widget(SubservicesFormType.sprache) }}</td>
<td class="subserviceformheader">{{ form_widget(SubservicesFormType.header) }}</td>
<td class="subserviceformbody">{{ form_widget(SubservicesFormType.body) }}</td>
<td class="subserviceformaction"></td>
{% endmacro %}
{% block body %}
<div class="tableserviceedit">
{{ form_start(form) }}
<div class="tableheadereditservice">
<table id="editserviceheader">
<tr style="white-space: nowrap">
<th style="width: 100%; padding-left: 0.5em">{% trans %}Ändern Service{% endtrans %} {{ form_widget(form.id) }}</th>
</tr>
</table>
</div>
<div class="tablebodyeditservice">
<table id="editservicesingleheader">
<tr>
<th style="width: 3.5em;">{% trans %}Sprache{% endtrans %}</th>
<th style="width: 12em">{% trans %}Überschrift{% endtrans %}</th>
<th style="width: 15em">{% trans %}Beschreibung{% endtrans %}</th>
</tr>
<tr class="editserviceheader">
<td class="serviceformsprache">
{{ form_errors(form.sprache) }}
{{ form_widget(form.sprache) }}
</td>
<td class="serviceformheader">
{{ form_errors(form.header) }}
{{ form_widget(form.header) }}
</td>
<td class="serviceformbody">
{{ form_errors(form.body) }}
{{ form_widget(form.body) }}
</td>
</tr>
</table>
<div class="tablebodysubservices">
<table id="subservices">
<thead>
<tr>
<th style="width: 6em;">{% trans %}Sprache{% endtrans %}</th>
<th style="width: 22.2em">{% trans %}Überschrift{% endtrans %}</th>
<th style="width: 15em">{% trans %}Beschreibung{% endtrans %}</th>
</tr>
</thead>
<tbody id="collector" data-prototype="{{ formMacros.printSubserviceRow(form.subservices.vars.prototype)|e('html_attr') }}">
{% for subservice in form.subservices %}
<tr>
<td colspan="4">
<span style="color:red" > {{ form_errors(form) }}</span>
</td>
</tr>
<tr>
<td class="subserviceformsprache">
{{ form_widget(subservice.sprache) }}
</td>
<td class="subserviceformheader">
{{ form_widget(subservice.header) }}
</td>
<td class="subserviceformbody">
{{ form_widget(subservice.body) }}
</td>
<td class="subserviceformaction"></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="tablefooter" id="fussbereichnewservice">
<div class="btnfooter">{{ form_widget(form.save) }} <button type="" class="buttonabort">{% trans %}Abbruch{% endtrans %}</button></div>
</div>
{{ form_end(form) }}
{#</div>#}
{{ include('inc/navbar_bottom.html.twig') }}
{% endblock %}
{% block javascripts %}
<script src="{{ absolute_url('/js/main.js') }}"></script>
{% if locale == 'en' %}
<script src="{{ absolute_url('/js/subservicesen.js') }}"></script>
{% else %}
<script src="{{ absolute_url('/js/subservices.js') }}"></script>
{% endif %}
{% endblock %}
In the twig-template file I have tried serveral posibilities:
if I code {{ form_errors(form) }} the error-message will appear on every sub-service, if I code {{ form_errors(form.sprache) }} no error message will appear at all.
Does anybody have an idea to solve this?
and what happens if you try
{% for subservice in form.subservices %}
{{ form_errors(subservice ) }}
...
%}

How can i get form->field() value?

In short, I have the following code:
<?= $form->field( $isntmodel, 'id')->textInput() ?>
<?= Html::a('<i class="mdi-action-done"></i>', ['add-item', 'id' => ???], [
'class' => 'btn-btn-add pull-right',
]) ?>
This code is wrong.
So. I need get value which will input by user. And set it instead ???
$form->field() must have $model, $attribute, $options = []. How can I write field not using $model and $attribute? It is not table column, I need just get value and set it instead ???
I try that
public function actionAddItem($id) {
$model = $this->$model;
$product = Product::findOne($id);
$orderItem = new OrderItem();
$orderItem->order_id = $model->id;
$orderItem->title = $product->title;
$orderItem->price = $product->getPrice();
$orderItem->product_id = $product->id;
$orderItem->save();
return $this->redirect(['index']);
}
But it throws an exception. At row with $model = $this->$model , and I don't know how from field submit id to link
Adding item is work if i put this in browser http://yii2-shop/backend/web/order/add-item?modelid=13&id=1&quantity=4
UPD
Now my form looks like
<?php $form = ActiveForm::begin([]); ?>
<tr>
<td><?= $n ?></td>
<td><?= $form->field( $model, 'newOrderItemId')->textInput()->label(false) ?></td>
<td></td>
<td></td>
<td class="text-center"><?= $form->field( $model, 'newOrderItemQuantity')->textInput()->label(false) ?></td>
<td>
<?= Html::a('<i class="mdi-action-done"></i>', [
'/order/add-item',
'modelid' => $model->id,
'id' => $model->newOrderItemId,
'quantity' => $model->newOrderItemQuantity,
], [
'class' => 'btn btn-add pull-right',
'data-toggle'=>'tooltip' ,
'data-placement'=>'bottom',
'title'=>'Добавить товар',
]) ?>
</td>
</tr>
<?php ActiveForm::end(); ?>
And add-item looks like
public function actionAddItem($modelid, $id, $quantity) {
$model = $this->findModel($modelid);
$product = Product::findOne($id);
$orderItem = new OrderItem();
$orderItem->order_id = $model->id;
$orderItem->title = $product->title;
$orderItem->price = $product->getPrice();
$orderItem->product_id = $product->id;
$orderItem->quantity = $quantity;
$orderItem->save();
return $this->redirect(['index']);
}
newOrderItemId and newOrderItemQuantity are just public variables which I mark at Order model. I can't get form field value for submit it to add-item
So. I solved the problem.
I created AddOrderItem model for announce variables
<?php namespace backend\models;
use yii\base\Model;
class AddOrderItem extends Model {
public $modelid;
public $id;
public $quantity;
public function rules() {
return [
[['modelid','id','quantity'], 'integer'],
];
}
}
And I edited actionUpdate() now it's looks like
public function actionUpdate($id) {
$model = $this->findModel($id);
$addOrderModel = new AddOrderItem();
if ($addOrderModel->load(Yii::$app->request->post())) {
$product = Product::findOne($addOrderModel->id);
$orderItem = new OrderItem();
$orderItem->order_id = $model->id;
$orderItem->title = $product->title;
$orderItem->price = $product->getPrice();
$orderItem->product_id = $product->id;
$orderItem->quantity = $addOrderModel->quantity;
$orderItem->save();
return $this->redirect(['view', 'id' => $model->id]);
}
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
'addOrderModel' => $addOrderModel
]);
}
}
At views/order/update i added following row
<?= $this->render('_addItemForm', ['model' => $addOrderModel]); ?>
And _addItemForm now contains this:
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(); ?>
<td><?= $form->field( $model , 'id')->textInput()->label(false) ?></td>
<td></td>
<td></td>
<td class="text-center"><?= $form->field( $model , 'quantity')->textInput()->label(false) ?></td>
<td>
<?= Html::submitButton('<i class="mdi-action-done"></i>',[
'class' => 'btn btn-add pull-right',
'data-toggle'=>'tooltip' ,
'data-placement'=>'bottom',
'title'=>'Добавить товар',
]) ?>
</td>
<?php ActiveForm::end(); ?>
I can't believe what I done it by myself. And I'm glad that I had no one to help, because now I know more.

Error on form submission: The CSRF token is invalid. Please try to resubmit the form [duplicate]

This question already has answers here:
The CSRF token is invalid. Please try to resubmit the form
(15 answers)
Closed 7 years ago.
I've been trying to submit a form which adds a Question object into the db.
But everytime I do, the error "The CSRF token is invalid. Please try to resubmit the form" shows up.
On my form's content field, I've attached this plugin which is an editor same as Stack Overflow's.
In my form's tag field, I've attached this one for tag autocompletion.
Here's my controller code:
/**
* Creates a new Question entity.
*
* #Route("/ask", name="question_create")
* #Method("POST")
* #Template("VerySoftAskMeBundle:Question:ask.html.twig")
*/
public function createAction(Request $request) {
$entity = new Question();
$form = $this->createCreateForm($entity);
$tags = $this->getDoctrine()->getRepository('VerySoftAskMeBundle:Tag')->findAll();
date_default_timezone_set('Asia/Manila');
$entity->setDateOfPost(new \DateTime());
$entity->setOwner($this->getUser());
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('question_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
'tags' => $tags
);
}
/**
* Creates a form to create a Question entity.
*
* #param Question $entity The entity
*
* #return Form The form
*/
private function createCreateForm(Question $entity) {
$form = $this->createForm(new QuestionType(), $entity, array(
'action' => $this->generateUrl('question_create'),
'method' => 'POST',
'em' => $this->getDoctrine()->getEntityManager()
));
$form->add('submit', 'submit', array('label' => 'Ask'));
return $form;
}
/**
*
* #Route("/ask", name="ask")
* #Security( "has_role( 'ROLE_USER' )" )
* #Method("GET")
* #Template
*/
public function askAction() {
$tags = $this->getDoctrine()->getRepository('VerySoftAskMeBundle:Tag')->findAll();
$entity = new Question();
$form = $this->createCreateForm($entity);
return array(
'entity' => $entity,
'form' => $form->createView(),
'tags' => $tags
);
}
I've made a Data Transformer for my tag field which turns the input tags into tag objects.
class TagTransFormer implements DataTransformerInterface {
/**
* #var ObjectManager
*/
private $om;
/**
* #param ObjectManager $om
*/
public function __construct(ObjectManager $om) {
$this->om = $om;
}
/**
* Transforms an object (issue) to a string (number).
*
* #return ArrayCollection
*/
public function transform($tags) {
return $tags;
}
/**
* Transforms a string (number) to an object (issue).
*
* #param string $number
*
* #return ArrayCollection
*
* #throws TransformationFailedException if object (issue) is not found.
*/
public function reverseTransform($ids) {
$tags = array();
if (!$ids) {
return null;
}
$repo = $this->om
->getRepository('VerySoftAskMeBundle:Tag');
$idsArray = explode(",", $ids);
foreach ($idsArray as $id) {
$tags[] = $repo->findOneByName($id);
}
return $tags;
}
}
Here's my form class:
class QuestionType extends AbstractType {
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$entityManager = $options['em'];
$transformer = new TagTransFormer($entityManager);
$builder
->add('title', 'text')
->add('content', 'textarea')
->add($builder->create('tags', 'text')
->addModelTransformer($transformer)
);
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'VerySoft\AskMeBundle\Entity\Question'
))
->setRequired(array(
'em',
))
->setAllowedTypes(array(
'em' => 'Doctrine\Common\Persistence\ObjectManager',
));
}
/**
* #return string
*/
public function getName() {
return 'verysoft_askmebundle_question';
}
}
My Twig Template:
<div id="askDiv" style="padding-bottom: 90px;">
{{ form_start(form, { 'attr' : { 'novalidate' : 'novalidate', 'class' : 'col-md-offset-3 form-control-static col-md-7' } }) }}
<div class="col-lg-12" style="padding: 0px; margin-bottom: 30px;">
<span class="askLabels col-lg-1 text-left">{{ form_label(form.title) }}</span>
{{form_widget(form.title, { 'attr' : { 'class' : 'form-control col-lg-11' } })}}
</div>
{{ form_widget(form.content, { 'attr' : { 'class' : 'col-lg-12' } }) }}
<div class="col-lg-12" style="padding: 0px; margin-top: 20px;">
<label class="col-lg-1 text-left askLabels" for="tagField">Tags</label>
<div class="col-lg-8">
{{ form_widget(form.tags) }}
</div>
{% if app.user.reputation >= 100 %}
<a id="addTag" title="Add New Tag" data-toggle="tooltip modal" data-placement="left" class="col-lg-3" href="#"><i class="fa fa-plus-circle"></i></a>
<div id="mymodal" class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Add New Tag</h4>
</div>
<div class="modal-body">
<label for="tagName">Tag Name: </label>
<input id="tagName" class="form-control" type="text"/>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Add Tag</button>
</div>
</div>
</div>
</div>
{% endif %}
</div>
<div style="margin-top: 20px; ">
{{ form_widget(form.submit, { 'attr' : { 'class' : 'col-md-offset-4 col-md-4 btn btn-primary' } }) }}
</div>
<p>
title error{{ form_errors(form.title) }}
</p>
<p>
content error{{ form_errors(form.content) }}
</p>
<p>
tag error{{ form_errors(form.tags) }}
</p>
<p>
form error{{ form_errors(form) }}
</p>
Scripts:
$(document).ready(function(){
$("textarea").pagedownBootstrap();
var zeTags = ["{{ tags|join('", "')|raw }}"];
$('#verysoft_askmebundle_question_tags').tagit({
availableTags: zeTags,
tagLimit: 5,
beforeTagAdded: function(event, ui) {
if ($.inArray(ui.tagLabel, zeTags) == -1)
return false;
}
});
});
You missed
{{ form_rest(form) }}
Symfony2 has a mechanism that helps to prevent cross-site scripting: they generate a CSRF token that have to be used for form validation. Here, in your example, you're not displaying (so not submitting) it with form_rest(form). Basically form_rest(form) will "render" every field that you didn't render before but that is contained into the form object that you've passed to your view. CSRF token is one of those values.
For newer versions of Symonfy, e.g. 2.4+ you would use the newer form_end(form), which automatically renders all fields not rendered as well as the CSRF token.
Per the documentation:
form_end() - Renders the end tag of the form and any fields that have not yet been rendered. This is useful for rendering hidden fields and taking advantage of the automatic CSRF Protection.

How to get all form errors symfony2

Constrains:
/**
* #ORM\Column(type="string", length=15)
* #Assert\Regex(pattern = "/[0-9a-z]+/", message = "[regexp] ERROR")
* #Assert\NotBlank(message = "[notblank] ERROR")
* #Assert\NotNull(message = "[notnull] ERROR")
* #Assert\Length
* (
* min = "2",
* max = "4",
* minMessage = "[minlength] ERROR",
* maxMessage = "[maxlength] ERROR"
* )
*/
private $type_name;
/**
* #ORM\Column(type="string", length=50)
* #Assert\Regex(pattern = "/[0-9a-zA-Z\.\:\s]+/", message = "[regexp] ERROR")
* #Assert\NotBlank(message = "[notblank] ERROR")
* #Assert\NotNull(message = "[notnull] ERROR")
* #Assert\Length
* (
* min = "4",
* max = "50",
* minMessage = "[minlength] ERROR",
* maxMessage = "[maxlength] ERROR"
* )
*/
private $description;
/**
* #ORM\Column(type="string", length=60)
* #Assert\Regex(pattern = "/[0-9a-zA-Z\.\/]+/", message = "[regexp] ERROR")
* #Assert\NotBlank(message = "[notblank] ERROR")
* #Assert\NotNull(message = "[notnull] ERROR")
* #Assert\Length
* (
* min = "4",
* max = "60",
* minMessage = "[minlength] ERROR",
* maxMessage = "[maxlength] ERROR"
* )
*/
private $starterPath;
Controller (typesAction and typesAddAction):
public function typesAction()
{
$em = $this->getDoctrine()->getManager();
$types = $em->getRepository('CsmBundle:Type')->findAll();
$newType = new Type();
$form = $this->createFormBuilder($newType)
->add('typeName', 'text')
->add('description', 'text')
->add('starterPath', 'text')
->getForm();
return $this->render('CsmBundle:Root:types.html.twig', array(
'types' => $types,
'form' => $form->createView()
));
}
public function typesAddAction(Request $request)
{
$newType = new Type();
$form = $this->createFormBuilder($newType)
->add('typeName', 'text')
->add('description', 'text')
->add('starterPath', 'text')
->getForm();
if ($request->getMethod() == 'POST')
{
$form->bind($request);
if ($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($newType);
$em->flush();
return $this->redirect($this->generateUrl('root_types'));
}
else
{
$em = $this->getDoctrine()->getManager();
$types = $em->getRepository('CsmBundle:Type')->findAll();
return $this->render('CsmBundle:Root:types.html.twig', array(
'types' => $types,
'form' => $form->createView()
));
}
}
}
types.html.twig:
...
<form class="well" action="{{ path('root_types_add') }}" method="post" {{ form_enctype(form) }}>
<fieldset>
<legend>Adding New Type</legend>
<table border="0">
<tr>
<td width="100" align="left"><strong>Type name:</strong></td><td>{{ form_widget(form.typeName, { 'attr': {'class': 'txt'} }) }}</td>
</tr>
<tr>
<td align="left"><strong>Description:</strong></td><td>{{ form_widget(form.description, { 'attr': {'class': 'txt'} }) }}</td>
</tr>
<tr>
<td align="left"><strong>Starter:</strong></td><td>{{ form_widget(form.starterPath, { 'attr': {'class': 'txt'} }) }}</td>
</tr>
<tr>
<td colspan="2">{{ form_errors(form) }}</td>
</tr>
<tr>
<td colspan="2">{{ form_rest(form) }}</td>
</tr>
<tr>
<td colspan="2" align="right"><button style="" class="btn btn-large btn-success" value="add" name="add">Add!</button></td>
</tr>
</table>
</fieldset>
</form>
...
Problem there: got error only for first field (typeName).
If i input incorrect data to all fields from HTML form, i got only(!) one error for first field (typeName).
If i input incorrect data to second (description) and third (starterPath) fields - i have no error.
Please use {{ form_row(form.name) }} instead of {{ form_widget(form.name) inside your templates to resolve the issue....
form_widget only renders the field's html while form_row renders the combination of form_label, form_widget and form_errors.
Have a look at the documentation here.
If your form bubbles up the errors as global errors try setting error_bubbling to false ( defaults to true ) inside your form's default options like this:
$this->createFormBuilder($entity, array(
'error_bubbling' => false,
'data_class' => 'Vendor\MyBundle\Entity\Name',
// ... more options
)
)

what is the difference between form and chtml in yii

confusion between form and chtml
i used to form to write form ans submit to database working fine, but for some particular places, according to google search used CHTML instead of form. but when i submitted that form to database
CHTML textfield value is not submitting to database
here goes my code
_Form.php
<script language="javascript">
function firstlang(flang,slang,tlang,math,scien,soci)
{
var sflang=parseInt(flang)+parseInt(slang)+parseInt(tlang)+parseInt(math)+parseInt(scien)+parseInt(soci);
document.getElementById('totalmarks').value=sflang;
if(sflang>=300 && sflang<400)
{
var flang='C';
document.getElementById('grade').value=flang;
}
else if(sflang>=400 && sflang<500)
{
var flang='B';
document.getElementById('grade').value=flang;
}
else if(sflang>=550 && sflang<=600)
{
var flang='A';
document.getElementById('grade').value=flang;
}
}
</script>
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'marks-form',
'enableAjaxValidation'=>true,
'enableClientValidation'=>true,
'focus'=>array($model,'class'),
)); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<?php echo $form->errorSummary($model); ?>
<table width="200" border="1">
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'class'); ?></span></td>
<td><span class="row">
<?php echo CHtml::dropDownList('class','',CHtml::listData(class1::model()->findAll(),'class','class'),array('empty'=>'Choose one',
'ajax' => array(
'type'=>'POST', //request type
'url'=>CController::createUrl('Marks/dynamicstates'), //url to call.
//Style: CController::createUrl('currentController/methodToCall')
'update'=>'#studentid', //selector to update
//'data'=>'js:javascript statement'
//leave out the data key to pass all form values through
)));
//empty since it will be filled by the other dropdown
?></span></td>
<td><span class="row"><?php echo $form->error($model,'class'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'studentid'); ?></span></td>
<td><span class="row"><?php echo CHtml::dropdownlist('studentid','',array()); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'studentid'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'examtype'); ?></span></td>
<td><span class="row"><?php echo $form->textField($model,'examtype',array('size'=>30,'maxlength'=>30)); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'examtype'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'firsttlanguage'); ?></span></td>
<td><span class="row"><?php echo $form->textField($model,'firsttlanguage',array('id'=>'firsttlanguage','value'=>'0','onkeyup'=>'firstlang(this.value,secondlanguage.value,thirdlanguage.value,mathematics.value,science.value,social.value)')); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'firsttlanguage'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'secondlanguage'); ?></span></td>
<td><span class="row"><?php echo $form->textField($model,'secondlanguage',array('id'=>'secondlanguage','value'=>'0','onkeyup'=>'firstlang(this.value,firsttlanguage.value,thirdlanguage.value,mathematics.value,science.value,social.value)')); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'secondlanguage'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'thirdlanguage'); ?></span></td>
<td><span class="row"><?php echo $form->textField($model,'thirdlanguage',array('id'=>'thirdlanguage','value'=>'0','onkeyup'=>'firstlang(this.value,firsttlanguage.value,secondlanguage.value,mathematics.value,science.value,social.value)')); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'thirdlanguage'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'mathematics'); ?></span></td>
<td><span class="row"><?php echo $form->textField($model,'mathematics',array('id'=>'mathematics','value'=>'0','onkeyup'=>'firstlang(this.value,firsttlanguage.value,secondlanguage.value,thirdlanguage.value,science.value,social.value)')); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'mathematics'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'science'); ?></span></td>
<td><span class="row"><?php echo $form->textField($model,'science',array('id'=>'science','value'=>'0','onkeyup'=>'firstlang(this.value,firsttlanguage.value,secondlanguage.value,thirdlanguage.value,mathematics.value,social.value)')); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'science'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'social'); ?></span></td>
<td><span class="row"><?php echo $form->textField($model,'social',array('id'=>'social','value'=>'0','onkeyup'=>'firstlang(this.value,firsttlanguage.value,secondlanguage.value,thirdlanguage.value,mathematics.value,science.value)')); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'social'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'totalmarks'); ?></span></td>
<td><span class="row"><?php echo $form->textField($model,'totalmarks',array('id'=>'totalmarks','size'=>5,'maxlength'=>5)); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'totalmarks'); ?></span></td>
</tr>
<tr>
<td><span class="row"><?php echo $form->labelEx($model,'grade'); ?></span></td>
<td><span class="row"><?php echo $form->textField($model,'grade',array('id'=>'grade','size'=>5,'maxlength'=>5)); ?></span></td>
<td><span class="row"><?php echo $form->error($model,'grade'); ?></span></td>
</tr>
<tr>
<td> </td>
<td><span class="row buttons"><?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?></span></td>
<td> </td>
</tr>
</table>
<?php $this->endWidget(); ?>
</div><!-- form -->
MarksController.php
<?php
class MarksController extends Controller
{
/**
* #var string the default layout for the views. Defaults to '//layouts/column2', meaning
* using two-column layout. See 'protected/views/layouts/column2.php'.
*/
public $layout='//layouts/column2';
/**
* #return array action filters
*/
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
);
}
/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* #return array access control rules
*/
public function accessRules()
{
return array(
array('allow', // allow all users to perform 'index' and 'view' actions
'actions'=>array('index','view'),
'users'=>array('*'),
),
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array('create','update'),
'users'=>array('#'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete'),
'users'=>array('admin'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','dynamicstates'),
'users'=>array('admin'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
/**
* Displays a particular model.
* #param integer $id the ID of the model to be displayed
*/
public function actionView($id)
{
$this->render('view',array(
'model'=>$this->loadModel($id),
));
}
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$model=new Marks;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Marks']))
{
$model->attributes=$_POST['Marks'];
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
$this->render('create',array(
'model'=>$model,
));
}
/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
* #param integer $id the ID of the model to be updated
*/
public function actionUpdate($id)
{
$model=$this->loadModel($id);
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Marks']))
{
$model->attributes=$_POST['Marks'];
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
$this->render('update',array(
'model'=>$model,
));
}
/**
* Deletes a particular model.
* If deletion is successful, the browser will be redirected to the 'admin' page.
* #param integer $id the ID of the model to be deleted
*/
public function actionDelete($id)
{
if(Yii::app()->request->isPostRequest)
{
// we only allow deletion via POST request
$this->loadModel($id)->delete();
// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
if(!isset($_GET['ajax']))
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
}
else
throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
}
/**
* Lists all models.
*/
public function actionIndex()
{
$dataProvider=new CActiveDataProvider('Marks');
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
/**
* Manages all models.
*/
public function actionAdmin()
{
$model=new Marks('search');
$model->unsetAttributes(); // clear any default values
if(isset($_GET['Marks']))
$model->attributes=$_GET['Marks'];
$this->render('admin',array(
'model'=>$model,
));
}
/**
* Returns the data model based on the primary key given in the GET variable.
* If the data model is not found, an HTTP exception will be raised.
* #param integer the ID of the model to be loaded
*/
public function loadModel($id)
{
$model=Marks::model()->findByPk($id);
if($model===null)
throw new CHttpException(404,'The requested page does not exist.');
return $model;
}
/**
* Performs the AJAX validation.
* #param CModel the model to be validated
*/
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='marks-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
public function actiondynamicstates()
{
// $model1=new Examresults;
/*$exam_type=(int)$_POST['exam_type'];
if ($exam_type==0)
$data=array(0=>'States:');
else if ($exam_type==1)
$data=array(1=>'Alaska', 2=>'California');
else if ($exam_type==2)
$data=array(1=>'Orleans', 2=>'Bordeaux');
else if ($exam_type==3)
$data=array(1=>'Hokkaido', 2=>'Okinawa');*/
//$schoolfee = feesettings::model()->find("feetype='schoolfee' and class='".$_REQUEST['class']."'");
$data=admission::model()->findAll('class=:class',
array(':class'=>$_POST['class']));
$data=CHtml::listData($data,'studentid','studentfname');
foreach($data as $value=>$name)
echo CHtml::tag('option', array('value'=>$value), CHtml::encode($name), true);
}
}
Marks.php
<?php
/**
* This is the model class for table "marks".
*
* The followings are the available columns in table 'marks':
* #property integer $id
* #property string $class
* #property string $studentid
* #property string $examtype
* #property integer $firsttlanguage
* #property integer $secondlanguage
* #property integer $thirdlanguage
* #property integer $mathematics
* #property integer $science
* #property integer $social
* #property integer $totalmarks
* #property string $grade
*/
class Marks extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return Marks the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'marks';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('class, studentid', 'required'),
array('firsttlanguage, secondlanguage, thirdlanguage, mathematics, science, social, totalmarks', 'numerical', 'integerOnly'=>true),
array('class, studentid, examtype', 'length', 'max'=>30),
array('grade', 'length', 'max'=>5),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, class, studentid, examtype, firsttlanguage, secondlanguage, thirdlanguage, mathematics, science, social, totalmarks, grade', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'class' => 'Class',
'studentid' => 'Studentid',
'examtype' => 'Examtype',
'firsttlanguage' => 'Firsttlanguage',
'secondlanguage' => 'Secondlanguage',
'thirdlanguage' => 'Thirdlanguage',
'mathematics' => 'Mathematics',
'science' => 'Science',
'social' => 'Social',
'totalmarks' => 'Totalmarks',
'grade' => 'Grade',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('class',$this->class,true);
$criteria->compare('studentid',$this->studentid,true);
$criteria->compare('examtype',$this->examtype,true);
$criteria->compare('firsttlanguage',$this->firsttlanguage);
$criteria->compare('secondlanguage',$this->secondlanguage);
$criteria->compare('thirdlanguage',$this->thirdlanguage);
$criteria->compare('mathematics',$this->mathematics);
$criteria->compare('science',$this->science);
$criteria->compare('social',$this->social);
$criteria->compare('totalmarks',$this->totalmarks);
$criteria->compare('grade',$this->grade,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
Have a look here Creating Form. Since Yii 1.1.1 there is a widget called CActiveForm
so when you use this widget you create the form inputs with $form->textField($model,'username')instead of using CHtml::activeTextField($model,'username')but both work in the same way.
So if that field is not being saved in the database it's probably because you haven't added it to the rules of your model.
public function rules() {
return array(
array('username', 'safe'),
);
)