I've created a User class in my Bundle based on FOS\UserBundle\Model\User\BaseUser to register my users.
Here is my User.php :
class User extends BaseUser
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
// Constructor
public function __construct()
{
parent::__construct();
// your own logic
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Here is my UserType.php :
class UserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('valider', 'submit')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'CSW78\Bundle\Entity\User'
));
}
public function getParent()
{
return 'fos_user_registration';
}
/**
* #return string
*/
public function getName()
{
return 'user';
}
}
I overrode register.html.twig, putting it in /app/resources/FOSUserBundle/views/Registration and it is called.
Here is my register.html.twig :
{% block body %}
<div id="cadre" class="arrondi">
<h1>Inscription</h1>
<br>
{% block fos_user_content %}
<form action="{{ path('fos_user_registration_register') }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register form-horizontal">
<div id="fos_user_registration_form">
<div class="form-group">
{{ form_label(form.username, 'Identifiant :', {'label_attr': {'class': 'col-xs-5 col-sm-4 col-md-3 col-lg-3 control-label'}}) }}
<div class="col-xs-7 col-sm-8 col-md-5 col-lg-5">
{{ form_widget(form.username, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{{ form_label(form.email, 'Email :', {'label_attr': {'class': 'col-xs-5 col-sm-4 col-md-3 col-lg-3 control-label'}}) }}
<div class="col-xs-7 col-sm-8 col-md-5 col-lg-5">
{{ form_widget(form.email, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{{ form_label(form.plainPassword.first, 'Mot de passe :', {'label_attr': {'class': 'col-xs-5 col-sm-4 col-md-3 col-lg-3 control-label'}}) }}
<div class="col-xs-7 col-sm-8 col-md-5 col-lg-5">
{{ form_widget(form.plainPassword.first, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{{ form_label(form.plainPassword.second, 'Mot de passe (confirmation) :', {'label_attr': {'class': 'col-xs-5 col-sm-4 col-md-3 col-lg-3 control-label'}}) }}
<div class="col-xs-7 col-sm-8 col-md-5 col-lg-5">
{{ form_widget(form.plainPassword.second, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
{{ form_widget(form._token, {'attr': {'class': 'form-control'}}) }}
{{ form_widget(form.valider, {'attr': {'class': 'btn btn-info btn-responsive btn-color'}}) }}
{{ form_end(form) }}
</div>
</form>
{% endblock %}
</div>
{% endblock %}
The problem is there is no validation made when I click on the submit button.
I thought that the validation constraints would inherit from the BaseUser validation constraints.
Is there something else to specify to call the BaseUser validation constraints on my User object ?
Another question: what if I want to customize the error messages, should I override the validation.xml file to do that ?
Thank you.
David
Related
I have a Custom-Entity that is registered as Sylius-Resource. This entity can have a list of images. For my usecase i followed instructions on the Docs.
I use a subclass of ImageType in order to provide the Upload-Image-Form:
ArtistImageType:
<?php
declare(strict_types=1);
namespace AppBundle\Form\Type;
use Sylius\Bundle\CoreBundle\Form\Type\ImageType;
class ArtistImageType extends ImageType
{
/**
* {#inheritdoc}
*/
public function getBlockPrefix(): string
{
return 'artist_image';
}
}
This is how I reuse this ArtistImageType in my FormType:
final class ArtistType extends AbstractResourceType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, [
'empty_data' => '',
])
->add('firstName', TextType::class, [
'empty_data' => '',
'required' => false,
])
->add('lastName', TextType::class, [
'empty_data' => '',
])
->add('images', CollectionType::class, [
'entry_type' => ArtistImageType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => 'app.images',
])
And the form.html.twig:
<div class="ui two column stackable grid">
{{ form_errors(form) }}
<div class="column">
<div class="ui segment">
<h4 class="ui dividing header">{{ 'sylius.ui.general_info'|trans }}</h4>
<div class="two fields">
{{ form_row(form.name) }}
</div>
{{ form_row(form.images) }}
</div>
<div class="ui segment">
{{ form_row(form.firstName) }}
{{ form_row(form.lastName) }}
</div>
</div>
I'm wondering how i could display the images that was already uploaded in an existing Entity similar to the Product-Form, where existing images are displayed next to the "choose file"-button?
This is what I want to achieve:
But it still gets rendered without any Preview. Apparently some further customization is necessary.
After reading Sylius code I can answer myself:
1. ArtistType::buildForm()
We need to add the attribute entry_options to pass the Artist-Entity to the ImageType:
->add('images', CollectionType::class, [
'entry_type' => ArtistImageType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'entry_options' => ['artist' => $options['data']],
'label' => 'app.images',
2. ArtistImageType
Then we made ArtistImageType fit to handle this attribute properly:
class ArtistImageType extends ImageType
{
public function buildView(FormView $view, FormInterface $form, array $options): void
{
parent::buildView($view, $form, $options);
$view->vars['artist'] = $options['artist'];
}
public function configureOptions(OptionsResolver $resolver): void
{
parent::configureOptions($resolver);
$resolver->setDefined('artist');
$resolver->setAllowedTypes('artist', Artist::class);
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix(): string
{
return 'artist_image';
}
}
Consider the getBlockPrefix-method.
3. Form-Theme:
Create a Form-Theme for the images-section:
{% extends '#SyliusUi/Form/imagesTheme.html.twig' %}
{% block artist_image_widget %}
{% spaceless %}
<div class="ui upload box segment">
{{ form_row(form.type) }}
<label for="{{ form.file.vars.id }}" class="ui icon labeled button"><i class="cloud upload icon"></i> {{ 'sylius.ui.choose_file'|trans }}</label>
{% if form.vars.value.path|default(null) is not null %}
<img class="ui small bordered image" src="{{ form.vars.value.path|imagine_filter('sylius_small') }}" alt="{{ form.vars.value.type }}" />
{% endif %}
<div class="ui hidden element">
{{ form_widget(form.file) }}
</div>
<div class="ui element">
{{- form_errors(form.file) -}}
</div>
</div>
{% endspaceless %}
{% endblock %}
Consider the block name artist_image_widget. It is the Link between Twig and getBlockPrefix-Function of the ImageType-implementation.
4. I've put the whole image-section stuff in a separate file:
_media.html.twig:
{% form_theme form '#AppBundle/Form/imagesTheme.html.twig' %}
<div class="ui" >
<h3 class="ui dividing header">{{ 'sylius.ui.media'|trans }}</h3>
<br>
{{ form_row(form.images, {'label': false}) }}
</div>
The final form:
<div class="column">
<div class="ui segment">
<h4 class="ui dividing header">{{ 'sylius.ui.general_info'|trans }}</h4>
<div class="two fields">
{{ form_row(form.name) }}
</div>
{% include 'AppBundle:Admin:_media.html.twig' %}
</div>
<div class="ui segment">
{{ form_row(form.firstName) }}
{{ form_row(form.lastName) }}
</div>
i guess that 3.Form-Theme posted by #itinance is really what fixes it (by copying widget content instead of form_row(form.images..) i've also manages to make it work). But sadly i couldnt make it work with extending '#SyliusUi/Form/imagesTheme.html.twig', even when getBlockPrefix return matching prefix for this prefix
I am using Symfony 3.4.7 . I work with 3 linked entites, Articles, Categories, an ArticlesCategories. ArticlesCategories is the relation table.
To manage an article and their relation articleCategories, I use the class CollectionType that I add to the FormType ArticlesType.
In my display I add and I remove a relation articlesCatégroies to an Article.
This is the code of an entity Articles :
/**
* Articles
*
* #ORM\Table(name="articles")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ArticlesRepository")
* #UniqueEntity("codeArticle", message="Déjà utilisé")
*/
class Articles
{
public function __construct()
{
$this->articlesCategories = new ArrayCollection();
}
/**
* #var string
*
* #ORM\Column(name="code_article", type="string", length=10)
* #ORM\Id
*/
private $codeArticle;
//... other variables
/**
* #var ArticlesCategories
*
* #ORM\OneToMany(targetEntity="AppBundle\Entity\ArticlesCategories", mappedBy="codeArticle", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private $articlesCategories;
// other getters and setters
/**
* Add articlesCategorie
*
* #param ArticlesCategories $articleCategorie
*
* #return Articles
*/
public function addArticlesCategorie(ArticlesCategories $articleCategorie){
$this->articlesCategories[] = $articleCategorie;
$articleCategorie->setCodeArticle($this);
return $this;
}
/**
* remove articlesCategorie
*
* #param ArticlesCategories $articlesCategorie
*/
public function removeArticlesCategorie(ArticlesCategories $articlesCategorie){
$this->articlesCategories->removeElement($articlesCategorie);
}
public function setArticlesCategories($articlesCategories){
$this->articlesCategories = $articlesCategories;
return $this;
}
/**
* Get articlesCategories
*
* #return Collection
*/
public function getArticlesCategories(){
return $this->articlesCategories;
}
}
This the code of an entity ArticlesCategories :
/**
* ArticlesCategories
*
* #ORM\Table(name="articles_categories", uniqueConstraints={#ORM\UniqueConstraint(name="unique_codeArticle_codeCategorie", columns={"code_article_id", "code_categorie_id"})})
* #ORM\Entity(repositoryClass="AppBundle\Repository\ArticlesCategoriesRepository")
* #UniqueEntity(fields={"codeArticle", "codeCategorie"}, message="Cette relation est déjà enregistré")
*/
class ArticlesCategories
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Articles", inversedBy="articlesCategories", cascade={"remove"})
* #ORM\JoinColumn(referencedColumnName="code_article", nullable=false)
*/
private $codeArticle;
/**
* #var string
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Categories", cascade={"remove"})
* #ORM\JoinColumn(referencedColumnName="reference", nullable=false)
*/
private $codeCategorie;
/**
* #var string
*
* #ORM\Column(name="critere_rech_1", type="string", length=45, nullable=true)
*/
private $critereRech1;
//... getters and setters
}
This is the code of my form ArticlesType :
class ArticlesType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('codeArticle')
//...autres attributs
->add('articlesCategories', CollectionType::class, array(
'entry_type' => ArticlesCategoriesType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'label' => 'categories',
'attr' => array('class' => 'collection-articlesCategories'),
'auto_initialize' => true,
'by_reference' => false
));
}
}
This the action who I called when I want to edit an article :
class ArticlesController extends Controller
{
/**
* Displays a form to edit an existing article entity.
*
* #Route("/edit/{codeArticle}", name="articles_edit", defaults={"codeArticle" = null} )
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Articles $article = null)
{
if($article != null){
/*$em = $this->getDoctrine()->getManager();
$article = $em->getRepository('AppBundle:Articles')->find($id_article);*/
$deleteForm = $this->createDeleteForm($article);
$editForm = $this->createForm('AppBundle\Form\ArticlesType', $article);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
// récupère tous les articles même ceux qui viennent d'être ajouter par la fonction JS add
$articlesCategories = $article->getArticlesCategories();
dump($articlesCategories);
foreach($articlesCategories as $ac){
// si l'article est null
if($ac->getCodeArticle() == null){
// on attribue à la relation articleCategorie l'article que l'on modifi
$ac->setCodeArticle($article);
}
}
$this->getDoctrine()->getManager()->flush();
}
return $this->render('articles/edit.html.twig', array(
'article' => $article,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
else{
return $this->forward('AppBundle:articles:new', [
'message' => 'Pour éditer un article il faut d\'abord l\'afficher.'
]
);
}
}
}
I display the form on the Twig view.
And I use Jquery to add and remove of the form a relation ArticlesCategories.
This is what the form of my article looks like with its collection:
My display
The probleme that I meet is, when i add a relation and I click on "Editer", I can see that the relation is create in my database. But when I remove a relation and I click on "Editer", I can see that my relation is not remove on the database.
I don't see where is my mistake.
I hope I am clear.
Thank you for help.
[EDIT]
This is my view twig :
{% extends 'articles/gerer.html.twig' %}
{% import 'articles/fields.html.twig' as formMacros %}
{% block contenu %}
{{ form_start(delete_form) }}
<input type="submit" value="Supprimer">
{{ form_end(delete_form) }}
{{ form_start(edit_form) }}
{{ form_label(edit_form.codeArticle, "Référence article") }}
{{ form_errors(edit_form.codeArticle) }}
{{ form_widget(edit_form.codeArticle, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.description, "Description") }}
{{ form_errors(edit_form.description) }}
{{ form_widget(edit_form.description, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.ecotaxe) }}
{{ form_errors(edit_form.ecotaxe) }}
{{ form_widget(edit_form.ecotaxe, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.qteMaxCde) }}
{{ form_errors(edit_form.qteMaxCde) }}
{{ form_widget(edit_form.qteMaxCde, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.publication) }}
{{ form_errors(edit_form.publication) }}
{{ form_widget(edit_form.publication, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.designation) }}
{{ form_errors(edit_form.designation) }}
{{ form_widget(edit_form.designation, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.taxonomie) }}
{{ form_errors(edit_form.taxonomie) }}
{{ form_widget(edit_form.taxonomie, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.referenceStock) }}
{{ form_errors(edit_form.referenceStock) }}
{{ form_widget(edit_form.referenceStock, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.articleRegroupement) }}
{{ form_errors(edit_form.articleRegroupement) }}
{{ form_widget(edit_form.articleRegroupement, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.articleAssocie1) }}
{{ form_errors(edit_form.articleAssocie1) }}
{{ form_widget(edit_form.articleAssocie1, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.articleAssocie2) }}
{{ form_errors(edit_form.articleAssocie2) }}
{{ form_widget(edit_form.articleAssocie2, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.articleAssocie3) }}
{{ form_errors(edit_form.articleAssocie3) }}
{{ form_widget(edit_form.articleAssocie3, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.seuilDegressif) }}
{{ form_errors(edit_form.seuilDegressif) }}
{{ form_widget(edit_form.seuilDegressif, {'attr': {'class': 'form-control'}}) }}
{{ form_label(edit_form.tauxDegressif) }}
{{ form_errors(edit_form.tauxDegressif) }}
{{ form_widget(edit_form.tauxDegressif, {'attr': {'class': 'form-control'}}) }}
<div class="row well well-sm js-collection-articles-categories-wrapper" data-prototype="{{ formMacros.printCategorieRow(edit_form.articlesCategories.vars.prototype)|e('html_attr') }}"
data-index="{{ edit_form.articlesCategories|length }}">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
Catégories
</div>
{% for ac in edit_form.articlesCategories %}
{{ formMacros.printCategorieRow(ac) }}
{% endfor %}
<a href="#" class="js-collection-articles-categories-add">
<span class="fa fa-plus-circle"> Ajouter une catégorie</span>
</a>
</div>
<input type="submit" value="Modifier" />
{{ form_end(edit_form) }}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
jQuery(document).ready(function () {
var $wrapper = $('.js-collection-articles-categories-wrapper');
$wrapper.on('click', '.js-remove-articles-categories', function (e) {
e.preventDefault();
$(this).closest('.js-collection-articles-categories-item')
.fadeOut()
.remove();
})
$wrapper.on('click', '.js-collection-articles-categories-add', function (e) {
e.preventDefault();
var prototype = $wrapper.data('prototype');
var index = $wrapper.data('index');
var newForm = prototype.replace(/__name__/g, index);
$wrapper.data('index', index + 1);
$(this).before(newForm);
})
});
</script>
{% endblock %}
I use a form_theme to display an element of my collection, this is the code :
{% import _self as formMacros %}
{% macro printCategorieRow(ac) %}
<div class="js-collection-articles-categories-item">
{{ form_errors(ac) }}
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-6">
{{ form_label(ac.codeCategorie) }}
{{ form_widget(ac.codeCategorie, {'attr': {'class': 'select_articles_categories'}}) }}
</div>
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12">
<a href="#" class="js-remove-articles-categories pull-right">
<span class="fa fa-close">Supprimer une catégorie</span>
</a>
<table class="table">
<tr>
<th>Critères</th>
<th>Valeurs</th>
</tr>
<tr id="new_article_table_critere1">
<td><div id="critere1">{{ form_label(ac.critereRech1) }}</div></td>
<td>{{ form_widget(ac.critereRech1, {'attr': {'class': 'form-control'}}) }}</td>
</tr>
<tr id="new_article_table_critere2">
<td><div id="critere2">{{ form_label(ac.critereRech2) }}</div></td>
<td>{{ form_widget(ac.critereRech2, {'attr': {'class': 'form-control'}}) }}</td>
</tr>
<tr id="new_article_table_critere3">
<td><div id="critere3">{{ form_label(ac.critereRech3) }}</div></td>
<td>{{ form_widget(ac.critereRech3, {'attr': {'class': 'form-control'}}) }}</td>
</tr>
<tr id="new_article_table_critere4">
<td><div id="critere4">{{ form_label(ac.critereRech4) }}</div></td>
<td>{{ form_widget(ac.critereRech4, {'attr': {'class': 'form-control'}}) }}</td>
</tr>
</table>
</div>
</div>
{% endmacro %}
Make the following change in your entity, 'Articles'.
Note: Don't forget to add a setter function (ex: setcodeArticle()) for 'codeArticle' in your entity, 'ArticlesCategories'
public function removeArticlesCategorie(ArticlesCategories $articlesCategorie){
$this->articlesCategories->removeElement($articlesCategorie);
$articlesCategorie->setcodeArticle(null);
}
I am looking for a solution in my controller to check before sending a form if the user already exists in the database. Here is my action on which I would like to implement this.
/**
* Creates a new invite entity.
*
* #Route("/inscription", name="invite_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$invite = new Invite();
$form = $this->createForm(InviteType::class, $invite);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($invite);
$em->flush();
$this->get('app_mailer')->sendMailInscriptionMjml($invite, $this->getParameter('client_mail_to'));
$this->get('session')->getFlashBag()->add('success', 'Votre inscription à été pris en compte.');
} else {
$this->get('session')->getFlashBag()->add('error', 'Une erreur est survenue.');
}
return $this->redirect($this->generateUrl('invite_show', array('id' => $invite->getId())));
}
return $this->render('#App/invite/new.html.twig', array(
'invite' => $invite,
'form' => $form->createView(),
));
}
Thank you for your help
You shouldn't need to do this in the controller. This is basic entity validation and Symfony comes with built in constraints to handle this sort of thing.
Assuming you are using a User Entity similar to below in your Symfony application you need only apply a unique validation constraint to the user class and specify which properties you want to test against for uniqueness. This example will validate that the user is unique by email, and throw an exception if not.
// src/AppBundle/Entity/User.php
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** #UniqueEntity(
* fields={"email"},
* errorPath="email",
* message="It appears you have already registered with this email."
*)
*/
class User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string $email
*
* #ORM\Column(name="email", type="string", length=255, unique=true)
* #Assert\Email()
*/
protected $email;
// ...
}
Pay notice to the #UniqueEntity("email") annotation on the class and the use statements. Of course you'll need to adopt this logic to your user class.
// controller action
public function newAction(Request $request)
{
$invite = new Invite();
$form = $this->createForm(InviteType::class, $invite);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($invite);
$em->flush();
$this->get('app_mailer')->sendMailInscriptionMjml(
$invite, $this->getParameter('client_mail_to')
);
$this->get('session')->getFlashBag()
->add('success', 'Votre inscription à été pris en compte.');
return $this->redirect(
$this->generateUrl(
'invite_show', array(
'id' => $invite->getId()
)
)
);
}
}
return $this->render('#App/invite/new.html.twig', array(
'invite' => $invite,
'form' => $form->createView(),
));
}
For more on this:
https://symfony.com/doc/current/reference/constraints/UniqueEntity.html
// Pass in the entity manager to your form via options
// Do this before you call $this->createForm:
// $options['entityManager'] = $this->getDoctrine()->getManager();
// then call $form = $this->createForm(InviteType::class, $invite, $options);
// Inside your form type i.e. InviteType
$em = $options['entityManager'];
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
$user = $data['user']; // this needs to be whatever you called user in your form
$userRepo = $em->getRepository('User'); // this needs to be the location of your user repository
if ($userRepo->findOneBy(['user' => $user])) { // you need to pick a field that determines how you will search for the user via the repository
$form->addError(new FormError('User already exists'));
}
}
);
<div class="container accroche">
<h5>{{ 'Inscription aux évenements'|trans }}</h5>
<p>Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l'imprimerie depuis les années 1500,
quand un peintre anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique,
sans que son contenu n'en soit modifié. Il a été popularisé dans les années 1960 grâce à la vente de feuilles Letraset contenant des passages du Lorem Ipsum, et, plus récemment,
par son inclusion dans des applications de mise en page de texte, comme Aldus PageMaker.
</p>
</div>
{{ form_start(form, {attr: {novalidate: 'novalidate','id':'formValidate'}}) }}
<div class="middle">
<div class="middle_form">
<div class="container">
<div class="stepwizard">
<div class="stepwizard-row setup-panel col-md-12 text-center">
<div class="stepwizard-step col-md-3">
1
</div>
<div class="stepwizard-step col-md-3">
2
</div>
<div class="stepwizard-step col-md-3">
3
</div>
<div class="stepwizard-step col-md-3">
4
</div>
</div>
</div>
<div class="row setup-content" id="step-1">
<div class="col-md-12">
<h3>{{ 'Informations invités'|trans }}</h3>
<div class="row">
<div class="input-field col-12">
{{ form_widget(form.name, {'attr': {'class': 'validate', 'id': 'last_name'}}) }}
{{ form_errors(form.name) }}
<label for="last_name">{{ 'Nom'|trans }} <sup>*</sup></label>
</div>
</div>
<div class="row">
<div class="input-field col-12">
{{ form_widget(form.surname, {'attr': {'class': 'validate', 'id': 'surname'}}) }}
{{ form_errors(form.surname) }}
<label for="surname">{{ 'Prénom'|trans }} <sup>*</sup></label>
</div>
</div>
<div class="row">
<div class="input-field col-12">
{{ form_widget(form.email, {'attr': {'class': 'validate', 'id': 'email'}}) }}
{{ form_errors(form.email) }}
<label for="email">{{ 'E-mail'|trans }} <sup>*</sup></label>
</div>
</div>
<div class="row">
<div class="col-12">
<label>{{ 'Présence'|trans }} <sup>*</sup></label>
{{ form_widget(form.dispo, {'attr': {'class': 'validate', 'id': 'dispo'}}) }}
{{ form_errors(form.dispo) }}
</div>
</div>
<button class="btn btn-primary nextBtn btn-lg pull-right" type="button">{{ 'SUIVANT'|trans }}</button>
</div>
</div>
<div class="row setup-content" id="step-2">
<div class="col-md-12">
<h3>{{ 'Informations participants'|trans }}</h3>
<div class="row">
<ul class="customers"
data-prototype="{{ form_widget(form.customers.vars.prototype)|e('html_attr') }}">
{% for customers in form.customers %}
<div class="row">
<div class="input-field col-12">
{{ form_row(customers.name, {'attr': {'class': 'validate', 'id': 'name'}}) }}
{{ form_errors(customers.name) }}
</div>
</div>
<div class="row">
<div class="input-field col-12">
{{ form_row(customers.surname, {'attr': {'class': 'validate', 'id': 'surname'}}) }}
{{ form_errors(customers.surname) }}
</div>
</div>
<div class="row">
<div class="input-field col-12">
{{ form_row(customers.old) }}
{{ form_errors(customers.old) }}
</div>
</div>
{% endfor %}
</ul>
</div>
<button class="btn btn-primary prevBtn btn-lg pull-left" type="button">{{ 'PRECEDENT'|trans }}</button>
<button class="btn btn-primary nextBtn btn-lg pull-right" type="button">{{ 'SUIVANT'|trans }}</button>
</div>
</div>
<div class="row setup-content" id="step-3">
<div class="col-md-12">
<h3>Logements</h3>
<div class="row">
<div class="input-field col-12">
{{ form_widget(form.housing, {'attr': {'class':'validate'}}) }}
{{ form_errors(form.housing) }}
<label>{{ 'Comment allez vous vous logez ?'|trans }} <sup>*</sup></label>
</div>
</div>
<div class="row">
<div class="input-field col-12">
{{ form_widget(form.hotel, {'attr': {'class':'validate'}}) }}
{{ form_errors(form.hotel) }}
<label>{{ 'Hôtel'|trans }} <sup>*</sup></label>
</div>
</div>
<button class="btn btn-primary prevBtn btn-lg pull-left" type="button">{{ 'PRECEDENT'|trans }}</button>
<button class="btn btn-primary nextBtn btn-lg pull-right" type="button">{{ 'SUIVANT'|trans }}</button>
</div>
</div>
<div class="row setup-content" id="step-4">
<div class="col-md-12">
<h3>{{ 'Arrivée/Départ'|trans }}</h3>
<div class="row">
<div class="col-12">
<label>{{ 'Date d\'arrivée'|trans }} <sup>*</sup></label>
{#<input class="datepicker" type="text" id="dateArrival" name="form[dateArrival]"/>#}
{{ form_widget(form.dateArrival, {'attr': {'class': 'datepicker validate'}}) }}
{{ form_errors(form.dateArrival) }}
</div>
</div>
<div class="row">
<div class="col-12">
<label>{{ 'Date de départ'|trans }} <sup>*</sup></label>
{#<input class="datepicker" type="text" id="dateDeparture" name="form[dateDeparture]"/>#}
{{ form_widget(form.dateDeparture, {'attr': {'class': 'datepicker validate'}}) }}
{{ form_errors(form.dateDeparture) }}
</div>
</div>
<div class="row">
<div class="input-field col-12">
{{ form_widget(form.transport, {'attr': {'class':'validate'}}) }}
{{ form_errors(form.transport) }}
<label>{{ 'Transport utilisé'|trans }} <sup>*</sup></label>
</div>
</div>
<div class="btn-center">
<button class="btn btn-primary prevBtn btn-lg pull-left" type="button">{{ 'PRECEDENT'|trans }}</button>
{{ form_widget(form.save, {'attr': {'class':'btn btn-success', 'id':'SaveAccount'}}) }}
</div>
</div>
</div>
</div>
</div>
</div>
{{ form_widget(form.dateArrival, {'attr': {'class': 'hidden'}}) }}
{{ form_widget(form.dateDeparture, {'attr': {'class': 'hidden'}}) }}
{{ form_end(form) }}
First, get the id $id = #YourId;. You can then select the user using SQL. SELECT * FROM [user_table] WHERE id = $id; If the result holds a user, then the user exists.
I am having a weird problem. I added an upload image field to a form. Every thing work fine when i use this code in the twig file
{{ form_start(form) }}
<button>d</button>
{{ form_end(form) }}
But when ever i want to use form_widget to costumize the look of the form this error appear when ever i try to sumit the form
FatalErrorException
Error: Call to a member function getFileName() on string.
This is the View that cause the problem
{% extends 'BridgeTravelBundle:Admin:layout.html.twig' %}
{% block body %}
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<form method="POST" id="demo-form2" data-parsley-validate class="form-horizontal form-label-left">
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Nom</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
{{ form_widget(form.name, { 'attr': {'class': 'form-control', 'placeholder': 'Prenom' } }) }}
{{ form_errors(form.name) }}
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Icon</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
{{ form_widget(form.icon, { 'attr': {'class': 'form-control', 'placeholder': 'Prenom' } }) }}
{{ form_errors(form.icon) }}
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Icon</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
{{ form_widget(form.file) }}
{{ form_errors(form.file) }}
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-md-offset-3">
<button class="btn btn-success">Valider</button>
</div>
</div>
</form>
</div>
</div>
{% endblock body %}
This is the Action that control the form.
public function addCategoryAction(Request $request){
$category=new Category();
$form=$this->createForm(CategoryType::class,$category);
$form->handleRequest($request);
if ($form->isSubmitted())
{
$image= $form['file']->getData();
$em=$this->getDoctrine()->getManager();
$req = $request->request->get('Bridge_TravelBundle_Category');
$category->setName($req['name']);
$category->setIcon($req['icon']);
$name = $req['name'];
try {
if(!is_dir("CategoriesPictures")){
mkdir("CategoriesPictures");
}
move_uploaded_file($image,"CategoriesPictures/".$image->getFileName());
rename("CategoriesPictures/".$image->getFileName() , "CategoriesPictures/".$name.".jpg");
}
catch (IOExceptionInterface $e) {
echo "Erreur Profil existant ou erreur upload image ".$e->getPath();
}
$em->persist($category);
$em->flush();
return $this->redirectToRoute('admin_categories');
}
return $this->render("BridgeTravelBundle:Admin:addcategory.html.twig",array('form' => $form->createView(),));
}
This the CategoryType.php
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CategoryType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name')
->add('icon')
->add('file',FileType::class, array(
'multiple' => false,
'attr' => array(
'accept' => 'image/*',
)
)
) ;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Bridge\TravelBundle\Entity\Category'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'Bridge_TravelBundle_Category';
}
}
This attribute enctype='multipart/form-data' is missing from your form tag.
You should just you form_start & form_end instead writing form tag by yourself.
You can also put custom attributes with form_start function like this
{{ form_start(form, { 'attr': {'class': 'foo', 'id': 'bar' } }) }}
Also, form_end is very important because it also print out form_rest and any missing field.
<form method="POST" id="demo-form2" data-parsley-validate class="form-horizontal form-label-left">
will become
{{ form_start(form, { 'attr': { 'id': 'demo-form2', 'data-parsley-validate': null, 'class': 'form-horizontal form-label-left' } }) }}
and
</form>
will become
{{ form_end(form) }}
I am doing a web application with symfony3 and I need a way to let the users to edit and update their profile. I used FosUserBundle to manage the the users access but i don't know what steps to take to solve my problem.
Does someone have some ideas or useful links to share ?
thank you
I Solved the problem. Yes it's my first question on stackoverflow and I'm learning.
here is my code:
dogController.php
/**
* #Route("/profile/edit", name= "edit_profile" )
*/
public function edit_profileAction(Request $request)
{
$user = $this->getUser();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isValid()) {
/** #var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->get('fos_user.user_manager');
$event = new FormEvent($form, $request);
$dispatcher = $this->get('event_dispatcher');
$dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
//$url = $this->generateUrl('fos_user_profile_show');
$url = $this->generateUrl('edit_profile');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
$this->get('session')->getFlashBag()->add(
'notice',
'Profile Updated!'
);
return $response;
}
return $this->render('dog/edit_profile.html.twig',array('form'=>$form->createView()));
}
UserType.php
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Vich\UploaderBundle\Form\Type\VichImageType;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Form\Extension\Core\Type\FileType;
class UserType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('username')
->add('name')
->add('surname')
->add('email')
->add('telephone')
->add('imageFile', FileType::Class );
}
public function setDefaultOptions(OptionsResolverInterface $resolver){
$resolver->setDefaults( array('data_class' => 'AppBundle\Entity\User') );
}
public function getName() {
return 'appBundle_user';
}`enter code here`
}
edit_profile.html.twig
<header>
<div class="container">
<div class="row">
<div class="col-lg-12">
<h2 class="name">Edit Profile</h2>
<div class="row" >
<div class="col-lg-12">
<div class="input_width" >
{% for flashMessage in app.session.flashbag.get('notice') %}
<div class="alert alert-success alert">
{{ flashMessage }}
</div>
{% endfor %}
{{form_start(form, {'attr': {'class': 'form-horizontal'}} )}}
{{ form_errors(form) }}
<div class="form-group">
{{ form_label(form.username) }}
{{ form_errors(form.username) }}
{{ form_widget(form.username , {'attr': {'class': 'form-control'}} ) }}
</div>
<div class="form-group">
{{ form_label(form.email) }}
{{ form_errors(form.email) }}
{{ form_widget(form.email , {'attr': {'class': 'form-control'}} ) }}
</div>
<div class="form-group">
{{ form_label(form.name) }}
{{ form_errors(form.name) }}
{{ form_widget(form.name , {'attr': {'class': 'form-control'}} ) }}
</div>
<div class="form-group">
{{ form_label(form.surname) }}
{{ form_errors(form.surname) }}
{{ form_widget(form.surname, {'attr': {'class': 'form-control'}}) }}
</div>
<div class="form-group">
{{ form_label(form.telephone) }}
{{ form_errors(form.telephone) }}
{{ form_widget(form.telephone, {'attr': {'class': 'form-control'}}) }}
</div>
<div class="form-group">
{{ form_label(form.imageFile) }}
{{ form_errors(form.imageFile) }}
{{ form_widget(form.imageFile) }}
</div>
<input type="submit" value="Submit" class="btn btn-default bluInput " />
{{form_end(form)}}
</div>
</div>
</div>
</div>
</div>
</div>
</header>
Basically I had to create a form type class linked to my entity, then, use it in my controller as long as the Fos user bundle user manager.