I'm trying to make a form that users can easily change their password. I hope my logic is correct, however I'm getting an error as follows;
Expected argument of type "string", "AppBundle\Form\ChangePasswordType" given
Here is my controller;
public function changePasswdAction(Request $request)
{
$changePasswordModel = new ChangePassword();
$form = $this->createForm(new ChangePasswordType(), $changePasswordModel);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// perform some action,
// such as encoding with MessageDigestPasswordEncoder and persist
return $this->redirect($this->generateUrl('homepage'));
}
return $this->render(':security:changepassword.html.twig', array(
'form' => $form->createView(),
));
}
Here is my model;
class ChangePassword
{
/**
* #SecurityAssert\UserPassword(
* message = "Wrong value for your current password"
* )
*/
protected $oldPassword;
/**
* #Assert\Length(
* min = 6,
* minMessage = "Password should by at least 6 chars long"
* )
*/
protected $newPassword;
/**
* #return mixed
*/
public function getOldPassword()
{
return $this->oldPassword;
}
/**
* #param mixed $oldPassword
*/
public function setOldPassword($oldPassword)
{
$this->oldPassword = $oldPassword;
}
/**
* #return mixed
*/
public function getNewPassword()
{
return $this->newPassword;
}
/**
* #param mixed $newPassword
*/
public function setNewPassword($newPassword)
{
$this->newPassword = $newPassword;
}
}
Here is my change password type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ChangePasswordType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('oldPassword', 'password');
$builder->add('newPassword', 'repeated', array(
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'required' => true,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
));
}
}
Here is my viewer;
{{ form_widget(form.current_password) }}
{{ form_widget(form.plainPassword.first) }}
{{ form_widget(form.plainPassword.second) }}
The solution mentioned by #dragoste worked well for me.
I changed the following line
$form = $this->createForm(new ChangePasswordType(), $changePasswordModel);
with this line;
$form = $this->createForm(ChangePasswordType::class, $changePasswordModel);
In recent Symfony releases you can pass only class name in createForm
Change
$form = $this->createForm(new ChangePasswordType(), $changePasswordModel);
to
$form = $this->createForm(ChangePasswordType::class, $changePasswordModel);
Read more about building forms at
http://symfony.com/doc/current/best_practices/forms.html#building-forms
Related
want to add optional DateType class in symfony form. It kinda works because I can submit form without setting the date but it auto sets todays date.
TodoType.php
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name')
->add('Deadline', DateType::class, [
'widget' => 'single_text',
'required' => false,
'empty_data' => ''
])
->add('Submit', SubmitType::class)
;
}
deadline entities
/**
* #ORM\Column(type="date", nullable=true)
*/
private $deadline;
...
public function getDeadline(): ?\DateTimeInterface
{
return $this->deadline;
}
public function setDeadline(\DateTimeInterface $deadline = null): self
{
$this->deadline = $deadline;
return $this;
}
TodoController.php
/**
* #Route("/todos", methods={"GET", "POST"}, name="todos")
*
*/
public function todos(EntityManagerInterface $entityManager, Request $request): Response
{
// Rendering todos
$todos = $entityManager->getRepository(Todo::class)
->findBy(
['owner' => $this->getUser()]
);
// Creating new TODO
$todo = new Todo();
$todo
->setOwner($this->getUser())
->setCreationDate(new \DateTime());
$form = $this->createForm(TodoType::class, $todo);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$entityManager->persist($todo);
$entityManager->flush();
return $this->redirectToRoute('todos');
}
return $this->render('todo/todos.html.twig', [
'todos' => $todos,
'form' => $form->createView(),
]);
}
To render in .twig I used just {{ form(form) }} haven't customized it yet.
Edit: code missing
Every thing looks good.
I tried on my side and it worked fine (in database, i got null):
Form:
$builder->add(
'dateTime', DateType::class, [
'required' => false,
'widget' => 'single_text',
'empty_data' => ''
]
);
Entity
public function __construct() {
// empty
}
/**
* #var DateTime|null
* #ORM\Column(name="date_time", type="datetime", nullable=true)
*/
private ?DateTime $dateTime;
/**
* #return DateTime|null
*/
public function getDateTime(): ?DateTime
{
return $this->dateTime;
}
/**
* #param DateTime|null $dateTime
*
* #return SupportTimeSlot
*/
public function setDateTime(?DateTime $dateTime): SupportTimeSlot
{
$this->dateTime = $dateTime;
return $this;
}
Controller
/**
* #Route("/time-slot-detail/{id}", name="time_slot_detail", methods={"GET", "POST"})
* #param SupportTimeSlot $supportTimeSlot
* #param Request $request
* #param SupportTimeSlotManager $supportTimeSlotManager
*
* #return Response
*/
public function timeSlotDetail(
SupportTimeSlot $supportTimeSlot,
Request $request,
SupportTimeSlotManager $supportTimeSlotManager
): Response
{
$form = $this->createForm(TimeSlotEditType::class, $supportTimeSlot);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$supportTimeSlotManager->save($supportTimeSlot);
return $this->redirectToRoute('boa_support_time_slot_detail', ['id' => $supportTimeSlot->getId()]);
}
return $this->render(
'boa/support/detail.twig', [
'timeSlot' => $supportTimeSlot,
'form' => $form->createView(),
]
);
}
Twig
<div class="row">
<div class="col-12">
{{ form_start(form) }}
{{ form_row(form.dateTime) }}
<button type="submit" class="btn btn-block btn-outline-info">
{% trans %}Save{% endtrans %}
</button>
{{ form_end(form) }}
</div>
</div>
My project contain some datepicker and datetimepicker js, maybe try to instanciate js to check if it come from this.
Otherwise try to debug your $request in your controller. If it provide some date for your deadline attribute, your problem come from twig/js
If $request is null but your entity is populated with data for deadline, your problem come from your construct
If you save your entity with enpty deadline but you gotr one in database, your problem come from your database
I'm writing an API. And I need to validate the form. Other forms validate correctly, but this one does not validate at all.
This is my form type class:
public function buildForm(FormBUilderInterface $builder, array $options){
$builder
->add('passwordConfirmation', RepeatedType::class, [
'required' => true,
'invalid_message' => 'Passwords must match!',
'type' => PasswordType::class
]);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOption(OptionsResolver $resolver){
$resolver->setDefaults(array(
'data_class' => RepeatPassword::class,
'csrf_protection' => false
))
}
public function getName() {
return 'repeatPassword';
}
My entity:
class RepeatedPassword{
/**
* #var string
* #Assert\Length(
* min = 8,
* minMessage = "Your password must be at least {{ limit }} characters long")
* )
* #Assert\NotBlank()
*/
private $passwordConfirmation;
/**
* #return mixed
*/
public function getPasswordConfirmation() {
return $this->passwordConfirmation;
}
/**
* #param mixed $passwordConfirmation
*/
public function setPasswordConfirmation($passwordConfirmation): void{
$this->passwordConfirmation = $passwordConfirmation;
}
}
Method where I try validate:
public function resetPassword(Request $request): View{
$form = $this->createForm(RepeatPasswordType::class);
$form->handleRequest($request);
if ($form->isValid()) {
$this->userService->setPassword($this->getUser(), $form->getData()->getPasswordConfirmation());
return View::create([], Response::HTTP_OK);
}
return View::create($form->getErrors(), Response::HTTP_BAD_REQUEST);
}
My config.yml file:
validation: { enabled: true, enable_annotations: true }
serializer: { enable_annotations: true }
Data I send and server response with status 400:
I've seen an issue before where $form->handleRequest was behaving differently to $form->submit. I was able to debug more effectively by manually calling submit.
$form = $this->createForm(RepeatPasswordType::class);
if ($request->getMethod() === 'post') {
$form->submit($request->request->get($form->getName()));
if (!$form->isValid()) {
// etc
}
}
Maybe it helps:
add following to your form
'constraints' => [
new NotNull(),
new NotBlank(),
],
All I can see for now is that you have an extra "," at the end of your minMessage Assert. Have you tried removing it ?
I'm following this tutorial http://symfony.com/doc/current/controller/upload_file.html but the $file isn't being converted to an UploadedFile, it stays as a string:
var_dump($file);
/home/owner/Desktop/Workspace/Documentary/src/DW/DocumentaryBundle/Controller/Admin/DocumentaryController.php:103:string '/tmp/phpmmv1LP' (length=14)
Type error: Argument 1 passed to DW\DocumentaryBundle\Uploader\PosterUploader::upload() must be an instance of Symfony\Component\HttpFoundation\File\UploadedFile, string given, called in /home/owner/Desktop/Workspace/DocumentaryWIRE/src/DW/DocumentaryBundle/Controller/Admin/DocumentaryController.php on line 106
Create Action:
/**
* #param Request $request
* #return Response
*/
public function createAction(Request $request)
{
$documentary = new Documentary();
$form = $this->createForm(DocumentaryType::class, $documentary);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$file = $documentary->getPoster();
$posterUploader = $this->getPosterUploader();
$fileName = $posterUploader->upload($file);
$documentary->setPoster($fileName);
$documentaryService = $this->getDocumentaryService();
$documentaryService->save($documentary);
}
return $this->render('DocumentaryBundle:Admin:create.html.twig', array(
'form' => $form->createView(),
));
}
View
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
Form:
<?php
namespace DW\DocumentaryBundle\Form;
use DW\DocumentaryBundle\Entity\Documentary;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DocumentaryType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class)
->add('storyline', TextareaType::class)
->add('summary', TextareaType::class)
->add('year', IntegerType::class)
->add('length', IntegerType::class)
->add('status', TextType::class)
->add('views', IntegerType::class)
->add('shortUrl', TextType::class)
->add('videoId', TextType::class)
->add('videoSource', TextType::class)
->add('poster', FileType::class, [
'label' => 'Poster'])
->add('category', EntityType::class, [
'class' => 'CategoryBundle:Category',
'choice_label' => 'name',
])
->add('submit', SubmitType::class);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Documentary::class,
));
}
/**
* #return string
*/
public function getName()
{
return "documentary";
}
}
Controller:
<?php
namespace DW\DocumentaryBundle\Uploader;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class PosterUploader
{
/**
* #var string
*/
private $targetDir;
/**
* #param string $targetDir
*/
public function __construct(string $targetDir)
{
$this->targetDir = $targetDir;
}
/**
* #param UploadedFile $file
* #return string
*/
public function upload(UploadedFile $file)
{
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move($this->targetDir, $fileName);
return $fileName;
}
}
The documentation is NOT wrong! They don't use type hinting in their example:
// src/AppBundle/Entity/Product.php
public function setBrochure($brochure)
{
$this->brochure = $brochure;
return $this;
}
When you use string type hinting then UploadedFile::__toString() will be invoked!
So check your entity. It should be something like this:
public function setPoster($poster)
{
// ...
}
To get a file from request, in Symfony, you need to get $request->files. For example $request->files->get('file_name');.
The documentation is wrong, it should be: $file = $form->get('poster')->getData();
/**
* #param Request $request
* #return Response
*/
public function createAction(Request $request)
{
$documentary = new Documentary();
$form = $this->createForm(DocumentaryType::class, $documentary);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$file = $form->get('poster')->getData();
$posterUploader = $this->getPosterUploader();
$fileName = $posterUploader->upload($file);
$documentary->setPoster($fileName);
$documentaryService = $this->getDocumentaryService();
$documentaryService->save($documentary);
}
return $this->render('DocumentaryBundle:Admin:create.html.twig', [
'form' => $form->createView(),
]);
}
I am trying to create a form using Symfony and Doctrine.
I created a Job class, and a table in mysql which relates to it, using Doctrine. It also made the JobType and JobController, and Routing facility.
I can access the index page, where the jobs are listed, but can't access the new entry page.
Here are the files used for creating the forms.
JobController.php
<?php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use AppBundle\Entity\Job;
use AppBundle\Form\JobType;
/**
* Job controller.
*
* #Route("/job")
*/
class JobController extends Controller
{
/**
* Lists all Job entities.
*
* #Route("/", name="job_index")
* #Method("GET")
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$jobs = $em->getRepository('AppBundle:Job')->findAll();
return $this->render('job/index.html.twig', array(
'jobs' => $jobs,
));
}
/**
* Creates a new Job entity.
*
* #Route("/new", name="job_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$job = new Job();
$jobType = new JobType();
$form = $this->createForm($jobType, $job);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($job);
$em->flush();
return $this->redirectToRoute('job_show', array('id' => $job->getId()));
}
return $this->render('job/new.html.twig', array(
'job' => $job,
'form' => $form->createView(),
));
}
/**
* Finds and displays a Job entity.
*
* #Route("/{id}", name="job_show")
* #Method("GET")
*/
public function showAction(Job $job)
{
$deleteForm = $this->createDeleteForm($job);
return $this->render('job/show.html.twig', array(
'job' => $job,
'delete_form' => $deleteForm->createView(),
));
}
/**
* Displays a form to edit an existing Job entity.
*
* #Route("/{id}/edit", name="job_edit")
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Job $job)
{
$deleteForm = $this->createDeleteForm($job);
$editForm = $this->createForm(new JobType(), $job);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($job);
$em->flush();
return $this->redirectToRoute('job_edit', array('id' => $job->getId()));
}
return $this->render('job/edit.html.twig', array(
'job' => $job,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Deletes a Job entity.
*
* #Route("/{id}", name="job_delete")
* #Method("DELETE")
*/
public function deleteAction(Request $request, Job $job)
{
$form = $this->createDeleteForm($job);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->remove($job);
$em->flush();
}
return $this->redirectToRoute('job_index');
}
/**
* Creates a form to delete a Job entity.
*
* #param Job $job The Job entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm(Job $job)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('job_delete', array('id' => $job->getId())))
->setMethod('DELETE')
->getForm()
;
}
}
JobType.php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class JobType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('category', 'string')
->add('type', 'string')
->add('company', 'string')
->add('logo', 'string')
->add('url', 'string')
->add('position', 'string')
->add('location', 'string')
->add('desciption', 'text')
->add('how_to_apply', 'text')
->add('token', 'string')
->add('is_public', 'boolean')
->add('is_activated', 'boolean')
->add('email', 'string')
->add('expires_at', 'datetime')
->add('created_at', 'datetime')
->add('updated_at', 'datetime')
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Job'
));
}
/**
* Mandatory in Symfony2
* Gets the unique name of this form.
* #return string
*/
public function getName()
{
return 'add_job';
}
}
This is the error I receive
Thanks!
EDIT:
The content of app/config/services.yml
parameters:
# parameter_name: value
services:
# service_name:
# class: AppBundle\Directory\ClassName
# arguments: ["#another_service_name", "plain_value", "%parameter_name%"]
$editForm = $this->createForm(new JobType(), $job);
This is no longer possible in Symfony 3. In Symfony 3, you always have to pass the fully-qualified class name for form types:
$editForm = $this->createForm(JobType::class, $job);
Also, in your form type you're passing the type name instead of the FQCN of the type classes.
Symfony 3 has just released its first BETA, which means it's very bleeding edge. Also, there are almost zero tutorials for Symfony 3 yet (as it's so extremely bleeding edge). You're reading a Symfony 2 tutorial, so I recommend you to install Symfony 2 instead of 3.
So I have this simple form in symfony where I only have 3 fields. All ids working to here one entity that is not on form but it's in the DB is column df_date and it's type DATE in DB.
Here is that entity:
/**
* #ORM\Column(type="date")
* #ORM\Id
*/
protected $df_date;
/**
* Set df_date
*
* #param \DateTime $dfDate
* #return WeatherSpecials
*/
public function setDfDate($dfDate)
{
$this->df_date = $dfDate;
return $this;
}
/**
* Get df_date
*
* #return \DateTime
*/
public function getDfDate()
{
return $this->df_date;
}
Controller:
public function ajax_weather_specialsAction(Request $request, $main_id)
{
$params = array();
if (!$main_id) {
/*
$repository = $this->getDoctrine()
->getRepository('AppBundle:WeatherSpecials');
$weather_specials = $repository->find($main_id);
*/
} else {
$weather_specials = new WeatherSpecials;
}
$form = $this->createFormBuilder($weather_specials)
->add('df_weather', 'choice', array(
'choices' => array(
null, 'SU', 'PC', 'CL', 'RN'
),
'label' => false, 'required' => true,
))
->add('df_temptur', 'number', array('label' => false, 'required' => true))
->add('df_specday', 'text', array('label' => false, 'required' => false))
->add('save', 'submit', array('attr' => array('class' => 'btn btn-primary')))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($weather_specials);
// How to set df_date here???
$em->flush();
}
}
$data['status'] = 'success';
$data['html'] = $this->render('sales_tabs/weather_specials.twig', array('form' => $form->createView()))->getContent();
return new JsonResponse($data);
}
And the question is, how to set the df_date before I persist that form to the DB?
Assuming that WeatherSpecials is the entity that you want to set df_date on either set it before you persist;
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$weather_specials->setDfDate(new \DateTime());
$em->persist($weather_specials);
$em->flush();
}
or use the doctrine HasLifecycleCallbacks;
/**
* WeatherSpecials
*
* #ORM\Table(name="weather_specials")
* #ORM\Entity(repositoryClass="AppBundle\Entity\WeatherSpecialsRepository")
* #ORM\HasLifecycleCallbacks
*/
class WeatherSpecials
{
// other stuff
/**
* #ORM\PrePersist
*/
public function prePersist(\Doctrine\ORM\Event\LifecycleEventArgs $event)
{
$this->df_date = new DateTime();
}
/**
* #ORM\PreUpdate
*/
public function preUpdate(\Doctrine\ORM\Event\LifecycleEventArgs $event)
{
$this->df_date = new DateTime();
}
}
You can set the date manually before persisting the entity.
Consider the following piece of code
if ($form->isSubmitted()) {
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$weather_specials->setDfDate(new \DateTime());
$em->persist($weather_specials);
$em->flush();
}
}
This will set the date to the current date and time. You can change the datetime values according to your needs.
You can even use Doctrine's preUpdate or prePersist callbacks.
UPDATE Your entity definition is incorrect. You should define $df_date as a \Datetime parameter. Change this in your code
/**
* #var \datetime
* #ORM\Column(type="date")
* #ORM\Id
*/
protected $df_date;
//the rest of your stuff
I found the issue, and Doctrine can kiss my ... with it's recommendations. It took me 3 days to figure this one out, it wold take me 5 minutes to figure that in PHP alone. enter link description here