I've been having a problem trying to upload a single file with Symfony2.3. When I try to upload the file I get the following error:
FatalErrorException: Error: Call to a member function move() on a non-object in
I have checked $csvFileForm['csvFile']->getData(); and its a string (the name of the file), also $file = $this->getRequest()->files; has size zero.
Here is the show action:
/**
* Finds and displays a Project entity.
*
* #Route("/{id}", name="console_project_show")
* #Method("GET")
* #Template()
*/
public function showAction($id)
{
$csvFileForm = $this->createFormBuilder()
->add('csvFile', 'file')
->getForm();
return array(
'csvFileForm' => $csvFileForm->createView()
);
}
and the form in the template looks like this:
<form method="POST" action="{{ path('console_project_upload_urls', { 'id': entity.id }) }}" >
{{ form_row(csvFileForm.csvFile) }}
{{ form_row(csvFileForm._token) }}
<input type="submit" name="submit" class="submit"/>
</form>
The upload action is this:
/**
* Lists all Project entities.
*
* #Route("/{id}/upload-urls", name="console_project_upload_urls")
* #Method("POST")
*/
public function uploadUrlsAction(Request $request, $id)
{
$csvFileForm = $this->createFormBuilder()
->add('csvFile', 'file')
->getForm();
$request = $this->getRequest();
$csvFileForm->handleRequest($request);
$data = $csvFileForm['csvFile']->getData();
$data->move(".", "something.csv"); // This is where the exception occurs
$file = $this->getRequest()->files; // I have used this to check the size of the array
return $this->redirect(...);
}
Thanks for any help.
You have to add the enctype to your form tag.
<form method="POST" action="{{ path('console_project_upload_urls', { 'id': entity.id }) }}" {{ form_enctype(form) }}>
...
</form>
Note: This is deprecated as of Symfony2.3 and will be removed in Symfony3. You should use the new form_start() twig helper.
{{ form_start(form, {'method': 'POST', 'action': path('console_project_upload_urls', { 'id': entity.id })}) }}
...
{{ form_end(form) }}
Related
A form I have created includes an upload field to upload a file with. This file can be any format. The form itself is created inside a FormType, and a controller handles the submission of the form successfully. However, every time I submit the form to this controller and I do a print_r or var_dump(), the upload field isn't included as part of the params of the POST request. When I use $file = $request->files->get('estimateUpload'); and var_dump() that it will only ever return NULL.
Here is the formType that I am using:
<?php
namespace App\Form;
use App\Entity\IhcVehicleDamageMatrix;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\File;
class IhcVehicleDamageEntryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id')
->add('incidentId')
->add('vehicleDamageId')
->add('damageType')
->add('description')
->add('wheelTyreDamage')
->add('tyreAge')
->add('tyreDotCode')
->add('treadDepth')
->add('renumerationCost')
->add('itemAge')
->add('created')
->add('modified')
->add('estimateUpload', FileType::class, [
'required' => false
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => IhcVehicleDamageMatrix::class,
]);
}
}
In the view file this is how I am using the upload field:
{{ form_start(damageForm, {'action': path('forms_ihc_damage_details_submitform'), 'method': 'POST', 'attr': {'id': 'ihcFormDamageDetails', 'enctype': 'multipart/form-data'}}) }}
{{ form_row(damageForm._token) }}
<tr>
<th>Upload Estimate</th>
<td>
{{ form_widget(damageForm.estimateUpload) }}
<small>{{ form_help(damageForm.estimateUpload) }}</small>
<div class="form-error">
{{ form_errors(damageForm.estimateUpload) }}
</div>
</td>
</tr>
{{ form_errors(damageForm) }}
{{ form_end(damageForm, {'render_rest': false}) }}
And in the controller, this is how I am getting the form data:
public function vehicleDamageForm(Request $request)
{
// Get Form Details
$formdet = $request->get('ihc_vehicle_damage_entry');
$em = $this->getDoctrine()->getManager();
$file = $request->files->get('estimateUpload');
var_dump($file);
}
The better way is to get estimateUpload directly from IhcVehicleDamageMatrix. Try something like this inside controller:
$ihcVehicleDamageMatrix = new IhcVehicleDamageMatrix();
$form = $this->createForm(IhcVehicleDamageEntryType::class, $ihcVehicleDamageMatrix);
if ($form->isSubmitted() && $form->isValid()) {
$file = $ihcVehicleDamageMatrix->estimateUpload();
dump($file);
}
I followed the symfony 4.2 documentation, but it seems the form is not submitted...
I spent my whole sunday, but it seems a secret how does it works, in the logs I do not see any errors.
So start it. the config contains these settings:
framework:
validation:
email_validation_mode: 'html5'
enable_annotations: true
Here the entity:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass="App\Repository\FeedbackRepository")
*/
class Feedback extends BaseEntity
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
* #Assert\Type("string")
* #Assert\NotBlank
*/
private $name;
/**
* #ORM\Column(type="string", length=255)
* #Assert\Type("string")
* #Assert\Email()
* #Assert\NotBlank
*/
private $email;
AS you can see I use the Assert annotations for the validations.
So here the formtype:
class FeedbackType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class)
->add('email', EmailType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Feedback::class,
// enable/disable CSRF protection for this form
'csrf_protection' => true,
// the name of the hidden HTML field that stores the token
'csrf_field_name' => '_token',
]);
}
}
Maybe the problem with the token, but I do not know exactly.
Now let see the view:
<form action="{{ path('feedback') }}" type="POST">
<div class="input-field">
<i class="material-icons prefix">account_circle</i>
{{ form_label(feedback.name) }}
{{ form_widget(feedback.name) }}
</div>
<div class="input-field">
<i class="material-icons prefix">email</i>
{{ form_label(feedback.email) }}
{{ form_widget(feedback.email) }}
</div>
{{ form_widget(feedback._token) }}
Next, here the controller which get the request.
/**
* #Route("/feedback", name="feedback", methods="GET|POST")
*/
public function feedbackFormAction(Request $request, EntityManagerInterface $entityManager): JsonResponse
{
$feedbackForm = new Feedback();
$form = $this->createForm(FeedbackType::class, $feedbackForm);
$form->handleRequest($request);
dump($request);
dump($feedbackForm);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($feedbackForm);
$entityManager->flush();
} else {
$errors = $this->getErrorsFromForm($form);
dump($form);die;
return new JsonResponse(['data' => ['result' => 'failed', 'errors' => $errors]]);
}
return new JsonResponse(['data' => ['result' => 'success']]);
}
The errors give me an empty array in Json format.
If I check the dump($feedbackForm) I see that the submitted property is false. and the modeldata, viewdata and normdata values are null... But how is this possible?
Dumping request:
query: ParameterBag {#16 ▼
#parameters: array:1 [▼
"feedback" => array:11 [▼
"name" => "a"
"email" => "a#a.a"
"_token" => "NJHBv7NpwYlugFcU-sE0qoBEQkS38yhxOjbklkHu8j0"
]
]
}
I think, this is correct.
You have not loaded the form data into the entity and trying to persist an empty new Feedback.
if ($form->isSubmitted() && $form->isValid()) {
// add line below
$feedbackForm = $form->getData();
$entityManager->persist($feedbackForm);
$entityManager->flush();
} else { ...
Read carefully https://symfony.com/doc/current/forms.html#handling-form-submissions
Did you create your FeedbackType, Controller action and the form view manually?
Remove all and use
php bin/console make:crud Feedback
This will generate operational files :-)
I think that using form_row is apropriate that using form_widget
Your Controller
/**
* #Route("/feedback", name="feedback", methods="GET|POST")
*/
public function feedbackFormAction(Request $request, EntityManagerInterface $entityManager): JsonResponse
{
$feedback = new Feedback();
$form = $this->createForm(FeedbackType::class, $feedback);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$entityManager->persist($feedbackForm);
$entityManager->flush();
return new JsonResponse(['data' => ['result' => 'success']]);
}
else {
$errors = $this->getErrorsFromForm($form);
return new JsonResponse(['data' => ['result' => 'failed', 'errors' => $errors]]);
}
}
return $this->render('path_to_your_feed_back.html.twig', [
'feedback' => $feedback,
'form' => $form->createView(),
]);
}
Your form.html.twig
{{ form_start(form, {'method': 'POST', 'attr' : {'class' : 'formFeedback'}}) }}
<div class="input-field">
<i class="material-icons prefix">account_circle</i>
{{ form_row(form.name) }}
</div>
<div class="input-field">
<i class="material-icons prefix">email</i>
{{ form_row(form.email) }}
</div>
{{ form_end(form) }}
My motivation is to edit values displayed in this edit form. But when I press edit button it throws out this error. I can't figure it out. Can anyone help what is missing in my code?
An exception has been thrown during the rendering of a template ("Some
mandatory parameters are missing ("user") to generate a URL for route
"sokosimu_editor_edit_editoruser".") in
SokosimuEditorBundle:User:editUser.html.twig at line 7. 500 Internal
Server Error - Twig_Error_Runtime
Router
sokosimu_editor_edit_editoruser:
path: /edit/editoruser/{user}
defaults: {_controller:SokosimuEditorBundle:Editor:editEditorUser}
requirements:
_method: GET|POST
Controller
public function editEditorUserAction(User $user,Request $request){
$form = $this->createForm(new EditUserType(),$user);
//2. handle the submit (will happen on POST)
$form->handleRequest($request);
if($form ->isValid() && $form->isSubmitted()){
}
$em = $this->get('doctrine')->getManager();
$editUser = $user ->getEditoruser();
return $this->render('SokosimuEditorBundle:User:editUser.html.twig', array(
'form' => $form->createView()
));
}
View
{% block title %}Edit User{% endblock%}
{% block body %}
<form action="{{ path('sokosimu_editor_edit_editoruser') }}" method="post" {{ form_enctype(form) }} class="formedit">
{{ form_errors(form) }}
{{ form_row(form.alias)}}
{{ form_row(form.email) }}
{#{{ form_row(form.password) }}#}
{{ form_row(form.mobile) }}
{{ form_row(form.submit) }}
{{ form_rest(form) }}
</form>
{% endblock %}
Form
<?php
namespace Sokosimu\EditorBundle\Form\Type;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class EditUserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('alias','text',array('required'=>false));
$builder->add('email', 'email',array('required'=>true));
// $builder->add('password','password',array('required'=>true));
$builder->add('mobile','text',array('required'=>false));
$builder->add('submit', 'submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Sokosimu\UserBundle\Entity\User'
// 'data_class' => NULL
));
}
public function getName()
{
return 'editUser';
}
}
You need to pass user in the path:
<form action="{{ path('sokosimu_editor_edit_editoruser', {'user': user}) }}" method="post" {{ form_enctype(form) }} class="formedit">
And in controller render the twig with user:
return $this->render('SokosimuEditorBundle:User:editUser.html.twig', array(
'form' => $form->createView(),
'user' => $user
));
Fix route to
sokosimu_editor_edit_editoruser:
path: /edit/editoruser/{userId}
defaults: {_controller:SokosimuEditorBundle:Editor:editEditorUser}
requirements:
_method: GET|POST
Fix controller to
public function editEditorUserAction(Request $request, $userId)
{
$user = $this->getDoctrine()->getRepository('SokosimuEditorBundle:User')->find($userId);
$form = $this->createForm(new EditUserType(), $user);
//2. handle the submit (will happen on POST)
$form->handleRequest($request);
if ($form->isValid() && $form->isSubmitted()) {
$em = $this->get('doctrine')->getManager();
$editUser = $user->getEditoruser();
}
return $this->render('SokosimuEditorBundle:User:editUser.html.twig', array(
'form' => $form->createView()
));
}
With the help from #panche14, I have modified the code a bit.Answer from #panche14 returned object but the form #param expected to be string or integer.
return $this->render('SokosimuEditorBundle:User:editUser.html.twig',
array('form' => $form->createView(),
'user' => $user ->getId();
));
Also add this in twig file:
{'user': user}
as specified by #panche14
Now, the edit button works fine as desired.
I would like to create a function to search for a movie through the query builder
I have a table Movie:
1. Id
2. Titre
3. Content
And i have class MovieRepository :
class MovieRepository extends EntityRepository
{
public function myFindAll()
{
return $this->createQueryBuilder('a')
->getQuery()
->getResult();
}
public function getSearchMovies($movie){
$qb = $this->createQueryBuilder('m')
->where('m.title LIKE :title')
->setParameter('title', '%' . $movie->getTitle() . '%')
->orderBy('m.title', 'DESC')
->getQuery();
}
}
Also i have MovieController :
public function indexAction()
{
$movie = new Movie;
$form = $this->createForm(new SearchMovieType(), $movie);
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$form->bind($request);
$movies = $this->getDoctrine()
->getManager()
->getRepository('AreaDownloadBundle:Movie')
->getSearchUsers($movie);
return $this->render('AreaDownloadBundle:Download:index.html.twig', array('form' => $form->createView(),array('movies' => $movies)));
} else {
$movies = $this->getDoctrine()
->getManager()
->getRepository('AreaDownloadBundle:Movie')
->myFindAll();
return $this->render('AreaDownloadBundle:Download:index.html.twig',array('form' => $form->createView(), 'movies' => $movies));
}
}
SearchMovieType :
class SearchMovieType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title','text', array('required' => false, ))
;
}
And i have index.hml.twig, which can display movies with a search bar :
{% extends "::template.html.twig" %}
{% block body %}
<form action="{{ path('area_download_index') }}" method="post">
<div id="bar">
{{ form_widget(form.title) }}
<input type="submit" value="Chercher">
{{ form_rest(form) }}
</div>
</form>
{% for movie in movies %}
{{ movie.title }}
{{ movie.content }}
{% endfor %}
{% endblock %}
when I seized a title of a movie he sends me this error
Variable "movies" does not exist in AreaDownloadBundle:Download:index.html.twig at line 12
Instead of posting it as a comment, it should have been posted as an answer in the correct formatting; like so:
return $this->render(
'AreaDownloadBundle:Download:index.html.twig',
array(
'form' => $form->createView(),
'movies' => $movies
)
);
This definitely should fix the problem!
I am currently developping using symfony2 and using FOSUserBundle for user management.
I built a menus.yml config file to separate html from menu structure. Basicaly I import menus.yml in my config.yml file and it's added to twig's global vars. Here's a look at my menus.yml (Abridged version)
twig:
globals:
menus:
loggedin:
topleft:
-
path: ~
caption: Réseau
icon: glyphicon-comment
submenu:
-
path: nouvelles
caption: Fil de nouvelles
icon: glyphicon-globe
topright:
-
path: ~
caption: "{{ app.user.prenom }} {{ app.user.nom }}"
icon: glyphicon-user
Then, in my template html file, I render the menu using this
{% for m in menus.loggedin.topleft %}
<li class="dropdown">
{{ m.caption }}
<ul class="dropdown-menu">
{% for item in m.submenu %}
<li>{{item.caption}}</li>
{% if item.seperator is defined and item.seperator == true %}
<li class="divider"></li>
{% endif %}
{% endfor %}
</ul>
</li>
{% endfor %}
But I am unable to display the user's first name and last name as the textual value gets printed as is into the html page. I tried hooking the app.user into caption like this
caption: %app.user.prenom% %app.user.nom%
But it doesn't work, saying the value doesn't exist (yet?)
Anybody has a clue how I can work this around?
I looked for an equivalent of the eval() PHP or Javascript function in Twig and found this SO question: Twig variables in twig variable.
Here is the code from an answer by Berry Langerak which define a Twig filter:
<?php
/**
* A twig extension that will add an "evaluate" filter, for dynamic evaluation.
*/
class EvaluateExtension extends \Twig_Extension {
/**
* Attaches the innervars filter to the Twig Environment.
*
* #return array
*/
public function getFilters( ) {
return array(
'evaluate' => new \Twig_Filter_Method( $this, 'evaluate', array(
'needs_environment' => true,
'needs_context' => true,
'is_safe' => array(
'evaluate' => true
)
))
);
}
/**
* This function will evaluate $string through the $environment, and return its results.
*
* #param array $context
* #param string $string
*/
public function evaluate( \Twig_Environment $environment, $context, $string ) {
$loader = $environment->getLoader( );
$parsed = $this->parseString( $environment, $context, $string );
$environment->setLoader( $loader );
return $parsed;
}
/**
* Sets the parser for the environment to Twig_Loader_String, and parsed the string $string.
*
* #param \Twig_Environment $environment
* #param array $context
* #param string $string
* #return string
*/
protected function parseString( \Twig_Environment $environment, $context, $string ) {
$environment->setLoader( new \Twig_Loader_String( ) );
return $environment->render( $string, $context );
}
/**
* Returns the name of this extension.
*
* #return string
*/
public function getName( ) {
return 'evaluate';
}
}
Example usage:
$twig_environment->addExtension( new EvaluateExtension( ) );
Use it in the template:
{% set var = 'inner variable' %}
{{'this is a string with an {{var}}'|evaluate}}