the variable $context is not interpreted correctly in the template - ajax

I can't get out of this error: Object of class Symfony\Bridge\Twig\Mime\WrappedTemplatedEmail could not be converted to string
My setup :
php 8.2
symfony 6.2
mailer 6.2
and i use maildev
I would like to generate a mail sending with ajax.
My service :
<?php
namespace App\Service;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\MailerInterface;
class SendMailService
{
private $mailer;
public function __construct(MailerInterface $mailer)
{
$this->mailer = $mailer;
}
public function send(string $from, string $to, string $subject, string $template, array $context): void
{
$email = (new TemplatedEmail())
->from($from)
->to($to)
->subject($subject)
->htmlTemplate("emails/$template.html.twig")
->context($context);
// On envoie le mail
$this->mailer->send($email);
}
}
if I put ->context([$context]) instead of ->context($context), in my template I get this error: there is no variable 'prenom'
My controller action :
#[Route('/app_email', name: 'app_email', methods: ['POST'])]
public function sendEmail(Request $request, SendMailService $mail): Response
{
if ($request->isXmlHttpRequest()) {
$from = $this->getParameter('from_email');
$emailAdressTo = $request->request->get('email'); // To
$template = 'contact';
$subject = "Envoi à partir du formulaire de contact du site Vous assurance";
$nom = $request->request->get('nom');
$prenom = $request->request->get('prenom');
$entreprise = $request->request->get('entreprise');
$message = $request->request->get('message');
$context = array(
'nom' => $nom,
'prenom' => $prenom,
'entreprise' => $entreprise,
'message' => $message,
);
dump($from);
dump($emailAdressTo);
dump($subject);
dump($template);
dump(gettype($context));
$mail->send($from, $emailAdressTo, $subject, $template, $context);
return new Response("ok");
}
return new Response("Erreur : ceci n'est pas une requête ajax", 400);
}
Dump result :
Dumped Contents In MainController.php line 54: "xxxx#xxx.fr" In MainController.php line 55: "xxxxx#xxxxx.com" In MainController.php line 56: "Envoi à partir du formulaire de contact du site" In MainController.php line 57: "contact" In MainController.php line 58: "array"
if I comment out the $context variable, my email is sent
My ajax function :
var formNewContact = $('form[id="formContact"]');
formNewContact.on("submit", function (e) {
e.preventDefault();
var formData = new FormData($(this)[0]);
$.ajax({
method: "POST",
url: "{{ path('app_email') }}",
data: formData,
processData: false,
contentType: false,
success: function (response) {
if (response === 'ok') {
} else {
alert("Erreur");
}
}, // Fin success
error: function () {
alert("Erreur serveur");
}, // Fin error
}); // Fin ajax
}); // Fin function submit form contact
My template :
<p>Bonjour,</p>
<p><strong>De : </strong>{{ prenom }}<strong>{{ nom }}</strong>.</p>
<p><strong>Email : </strong>{{ email }}</p>
<p><strong>Entreprise : </strong>{{ entreprise }}</p>
<p><strong>Message :</strong></p>
<hr />
<p>{{message}}</p>
<hr />
</div>
dump(gettype($context)); -> array
Thanks for your help.
I changed :
In form this field :
<div class="mb-3">
<label for="emailTo" class="form-label">Mail (obligatoire)</label>
<input type="email" class="form-control" name="emailTo" id="emailTo" aria-describedby="mailHelp" pattern="[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,4}$" required>
<div class="valid-feedback feedback-pos">
Adresse email OK
</div>
<div class="invalid-feedback feedback-pos">
Cette adresse email n'est pas correcte
</div>
</div>

In your template, you are trying to render the email instance as a string with {{ email }}. That's why you get this error.
Maybe you want to print the email address instead : {{ email.to[0].address }}
See : https://symfony.com/doc/current/mailer.html#html-content
The Twig template has access to any of the parameters passed in the context() method of the TemplatedEmail class and also to a special variable called email, which is an instance of WrappedTemplatedEmail.

Related

Laravel Controller/Ajax not saving in my database

It seems like my save(); in my categories does not function as intended below. I will show the necessary codes first:
my table name is hms_bbr_category which is also connectec to my .env locally:
DB_CONNECTION=pgsql
DB_HOST=localhost
DB_PORT=5432
DB_DATABASE=jhs
DB_USERNAME=postgres
DB_PASSWORD=pa55wor0
my model: HmsBbrCategory
class HmsBbrCategory extends Model
{
protected $table = 'hms_bbr_category';
protected $fillable = [
"category_name", "category_description"
];
}
my controller: BBRCategoryConfigurationController
class BBRCategoryConfigurationController extends Controller
{
public function index(){
return view('frontend.bbr-settings.bbr-category-configuration');
}
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'category_name'=>'required|max:191',
'category_description'=>'required|max:191',
]);
if($validator->fails())
{
return response()->json([
'status'=>400,
'errors'=>$validator->messages(),
]);
}
else {
$category = new HmsBbrCategory;
$category->category_name = $request->input('category_name');
$category->category_description = $request->input('category_description');
$category->save();
return response()->json([
'status'=>200,
'message'=>'Category Added!',
]);
}
}
The ajax and modal fields
<div class="form-group">
<input type="text" class="form-control form-group w-100 category_name" placeholder="Category Name">
</div>
<div class="form-group">
<textarea class="form-control w-100 category_description" placeholder="Category Description" cols="50" rows="10"></textarea>
</div>
<script>
$(document).ready(function (){
$(document).on('click', '.add_category', function(e){
e.preventDefault();
var category_data = {
'category_name': $('.category_name').val(),
'category_description': $('.category_description').val(),
}
//token taken from laravel documentation
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
console.log(category_data);
$.ajax({
type: "POST",
url: "/clinical/bbr-category-configuration",
data: "category_data",
dataType: "json",
success: function (response){
// console.log(response);
if(response.status == 400)
{
$('#saveform_errList').html("");
$('#saveform_errList').addClass('alert alert-danger');
$.each(response.errors, function (key, err_values) {
$('#saveform_errList').append('<li>'+err_values+'</li>');
});
}
else
{
$('#saveform_errList').html("");
$('#success_message').addClass('alert alert-success');
$('#success_message').text(response.message);
$.('#createCategory').modal('hide');
$.('#createCategory').find('input').val("");
console.log(category_data);
}
}
});
});
});
</script>
my routes at web.php
Route::get('/bbr-category-configuration', [BBRCategoryConfigurationController::class,'index']);
Route::post('/bbr-category-configuration', [BBRCategoryConfigurationController::class,'store']);
Things to note:
my hunch is that my store function does not connect properly at $category = new HmsBbrCategory; However I have checked that my table name and the fields taken are the same, as seen at $category->category_name = $request->input('category_name');
I have also tested in ajax with the values by simply adding console.log(response) as seen in the screenshot, I cannot get past my validator to get to the save(). I am not sure how but There should not be an error since my text fields are filled.
I can elaborate more if needed, I am asking what can I change to fix my validation/save. thanks for any help.
As the error shows, The validation is failing (empty value i guess) and returning the code you programmed (400).
i'm guessing it is because you are using a string instead of the variable at the attribute data: "category_data",
update the code to send the variable instead
$.ajax({
type: "POST",
url: "/clinical/bbr-category-configuration",
data: category_data, //change here
dataType: "json",
success: function (response){
//...

Creating default object from empty value using laravel 6 and ajax

i have in an annonces table a multiple images, i want to update multiple images, but it gives me error:
Creating default object from empty value knowing that i tried to transform multipleimage to a given json.in the console it gives me the name of the images to select.
AnnoncesController.php
public function filesUpdate(Request $request,$id)
{
$Annonce=Annonce::find($id);
$data = array();
if($request->hasFile('images'))
{
foreach($request->file('images') as $file)
{
$path = $request->images->store('annonces');
$Annonce->images = $path;
array_push($data,$path);
}
}
$Annonce->images = json_encode($data);
$Annonce->save();
return Redirect::to("annonces")
->withSuccess('Great! file has been successfully uploaded.');
}
web.php
Route::post('annonces/filesUpdate','AnnoncesController#filesUpdate');
details.blade.php
<form method="post" action="{{url('annonces/filesUpdate')}}" enctype="multipart/form-data"
class="dropzone" id="dropzone">
<input type="hidden" name="_method" value="PUT">
{{ csrf_field() }}
</form>
<script type="text/javascript">
Dropzone.options.dropzone =
{
maxFilesize: 12,
renameFile: function(file) {
var dt = new Date();
var time = dt.getTime();
var images = time+file.name
console.log(time+file.name);
return images;
},
acceptedFiles: ".jpeg,.jpg,.png,.gif",
addRemoveLinks: true,
timeout: 50000,
success: function(file, response)
{
console.log(response);
},
error: function(file, response)
{
return false;
}
};
</script>
You are not passing the id as route parameter in the form action so the $id value received in filesUptate method in controller will be null. You have to pass the $Annonce->id as route parameter via form action
//When you send this view as response from edit method you need to pass
//either $Annonce object or at least the $Annonce->id as $AnnonceId to the view
//If you pass the entire $Annonce object then append $Annonce->id as below
//to the form action or replace it with $AnnonceId if you are passing only
//$AnnonceId from the edit method of the controller
<form
method="post"
action="{{url('annonces/filesUpdate/' . $Annonce->id)}}"
enctype="multipart/form-data"
class="dropzone" id="dropzone"
>
<input type="hidden" name="_method" value="PUT">
{{ csrf_field() }}
</form>
The error probably arises as you are trying to call store method on array.
Try the below
public function filesUpdate(Request $request,$id)
{
$Annonce=Annonce::findOrFail($id);
$data = array();
if($request->hasFile('images'))
{
foreach($request->file('images') as $file)
{
//Trying to call store on an array here
//$request->images is not an instance of UploadedFile
//$path = $request->images->store('annonces');
//$file is an instance of UploadedFile
//so you can call store method on it
$data[] = $file->store('annonces');
}
}
$Annonce->images = json_encode($data);
$Annonce->save();
return Redirect::to("annonces")
->withSuccess('Great! file has been successfully uploaded.');
}
You can also use $casts property to let Laravel handle the casting of images attribute automatically
class Annonce extends Model
{
protected $casts = [ 'images' => 'array'];
}

Symfony UserPassword validation in ajax form

I have a problem validating User Password in Symfony 2.4.
I have a form created with html code inside twig and i am not using form builder because i am submitting the form via ajax.
The form is a change password form and i have a password field which must match with the user passord.
Code:
Html.twig code of the form:
<form id="changePassword" name="changePassword">
<label id="labelPassword">Write your current password </label>
<input type="password" id="CurrentPassword" name="CurrentPassword" />
<label id="labelNewPassword">Write your new password </label>
<input type="password" id="NewPassword" name ="NewPassword" />
<label id="labelNewPassword2">Repeat your new password</label>
<input type="password" id="NewPassword2" name ="NewPassword2" />
<input type="submit" class="btn-primary btn" value="Change"/>
</form>
ajax code:
var ServerData;
$(document).ready(function() {
$("form").submit(function(e) {
e.preventDefault();
var data = $(this).serialize();
var url = $(this).attr("name");
var id = $(this).attr("id");
if(validates(url)){
$.ajax({
url: url+"/" ,
method: "post",
dataType: "json",
data: data,
success: function (ServerData){
successFunction();
},
error: function (){
errorFunction();
}
});
}
else{
novalidFunction();
}
});
});
function validate(url){
//Just length and matching new password with repeat new password validations
}
// succesFunction(), errorFunction() and novalidFunction() and all this code are
//working great
php code of the controller:
public function changePasswordAction ($request Request){
$user= $this->getUser();
$password = $user->getPassword();
$currentPassword = $request->get("CurrentPassword");
$newPassword = $request->get("NewPassword");
//here is where i need the code to compare $password with $currentPassword;
//the problem is that $password is encoded
//then i got the code to insert new values in Users table and its working;
}
Thanks in advance and sorry about my english
i have resolved the problem:
Since you cant decode the user password you have to encode the new password. Here is the code to complete my last code:
public function changePasswordAction(Request $request){
$user = $this->getUser();
$upassword = $user->getPassword();
$password = $request ->get("CurrentPassword");
$newPassword = $request ->get("NewPassword");
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$salt = $user->getSalt();
$passwordSecure = $encoder->encodePassword($password, $salt);
$em = $this->getDoctrine()->getManager();
if ($passwordSecure == $upassword){
if($newPassword == $newPasswordtwo){
$newsalt = md5(time() * rand(1, 9999));//just a random number
$user->setSalt($newsalt);
$user->setPassword($encoder->encodePassword($newPassword, $newsalt));
$em->persist($user);
$em->flush();
return new \Symfony\Component\HttpFoundation\JsonResponse(array("estado" => "success", "msg" => "Password Changed"));
}
else{
return new \Symfony\Component\HttpFoundation\JsonResponse(array("estado" => "error", "msg" => "New password doesn't match in both fields"));
}
}
else{
return new \Symfony\Component\HttpFoundation\JsonResponse(array("estado" => "error", "msg" => "User password is not correct"));
}
}
That is working great for me. I hope that could help someone. :)

How can I refresh a select list with another

I am trying hard to refresh a list after selecting an option of a second.
I have this list
<select id="ArticleShopId">
<option>Some options</option>
<option>Some options 2</option>
<option>Some options 3</option>
</select>
I have a seond
<select id="ArticleCategoryId">
<option></option>
<option></option>
<option></option>
<option></option>
</select>
When I select an option of the first, ajax should load the table Shop and update the second select
I create an action called admin_refreshCategoriesAjax
function admin_refreshCategoriesAjax($id = null){
$this->loadModel('Category');
// Le list recupere la valeur des IDs et cherche un champs qui a la valeur "name"
$categories = $this->Category->find('list',array('order'=>'name ASC','conditions'=>array('shop_id'=>$id)));
//return "toto";
return $categories;
#return json_encode($categories);
}
I wish t create a ajax code to do it. Then I try doing it
$('select#ArticleShopId').on('change',function(){
//alert($(this).val());
//alert("/articles/refreshCategoriesAjax/"+$(this).val());
$.ajax({
type: "GET",
url: "<?php echo $this->Html->url(array('controller' => 'articles', 'action' => 'refreshCategoriesAjax', 'admin' => true)); ?>",
data: "id="+$(this).val(),
success: function(msg){
console.log(msg);
}
})
})
but msg does not return my an array with the $categories values.
How can I correctely call my action admin_refreshCategoriesAjax and update my second select with the value of $categories?
many thank for your help, I spend half day on it :o(
Note:
If I enter this in my URL
http://localhost:8888/web/admin/articles/refreshCategoriesAjax/1
it return me well the array I looking for. If I changer 1 with 2, it return my other value. Then this part seams to work nice
I believe your problem is that in your function admin_refreshCategoriesAjax you are returning the array rather than doing something that will actually output it to the webpage. You could do echo json_encode($categories); to get some output you can use without explicitly creating a view for that action.
Instead of finding an id in the parameter, you will find an id in $this->request->data. To make your ajax request secure, use the following code into your view file:
$('select#ArticleShopId').on('change',function(){
//alert($(this).val());
//alert("/articles/refreshCategoriesAjax/"+$(this).val());
$.ajax({
type: "POST",
url: "<?php echo $this->Html->url(array('controller' => 'articles', 'action' => 'refreshCategoriesAjax', 'admin' => true)); ?>",
data: {id:$(this).val()},
success: function(msg){
console.log(msg);
}
});
});
And the following code into your controller:
function admin_refreshCategoriesAjax(){
$categories = array();
if($this->request->is('post'))
{
$id = $this->request->data['id'];
$this->loadModel('Category');
// Le list recupere la valeur des IDs et cherche un champs qui a la valeur "name"
$categories = $this->Category->find('list',array('order'=>'name ASC','conditions'=>array('shop_id'=>$id)));
//return "toto";
}
return $categories;
#return json_encode($categories);
}
Now to fill the data in dropdown, return json_encode($categories) from your controller. And use var result = $.parseJSON(msg); in your ajax success method.

Confirm password field not validating using 'repeated' field using form builder in symfony2 ?

This is how my code snippet looks like.
// --- this is the code in my controller ----
$registrationForm = $this->createFormBuilder()
->add('email')
->add('password', 'repeated', array('type' => 'password', 'invalid_message' => 'Passwords do not match'))
->getForm();
return $this->render('AcmeHelloBundle:Default:index.html.twig', array('form' => $registrationForm->createView()));
// --- This is the twig file code----
<form action="#" method="post" {{ form_enctype(form) }}>
{{ form_errors(form) }}
{{ form_row( form.email, { 'label': 'E-Mail:' } ) }}
{{ form_errors( form.password ) }}
{{ form_row( form.password.first, { 'label': 'Your password:' } ) }}
{{ form_row( form.password.second, { 'label': 'Repeat Password:' } ) }}
{{ form_rest( form ) }}
<input type="submit" value="Register" />
</form>
Can any one suggest why it is not working using form builder?
In Symfony 2, validation is handled by domain object. So you have to pass an Entity (domain object) to your form.
Code in controller :
public function testAction()
{
$registration = new \Acme\DemoBundle\Entity\Registration();
$registrationForm = $this->createFormBuilder($registration)
->add('email')
->add('password', 'repeated', array('type' => 'password', 'invalid_message' => 'Passwords do not match'))
->getForm();
$request = $this->get('request');
if ('POST' == $request->getMethod()) {
$registrationForm->bindRequest($request);
if ($registrationForm->isValid()) {
return new RedirectResponse($this->generateUrl('registration_thanks'));
}
}
return $this->render('AcmeDemoBundle:Demo:test.html.twig', array('form' => $registrationForm->createView()));
}
1) The form builder will map the form fields with the properties of your entity, and hydrate your form field values with your entity property values.
$registrationForm = $this->createFormBuilder($registration)...
2) The bind will hydrate your form fields values with all the data posted
$registrationForm->bindRequest($request);
3 ) To launch validation
$registrationForm->isValid()
4) if the data posted are valid, you have to redirect to an action to inform user that everything is OK, to avoid displaying an alert message from your broswer who ask if your are sure to repost data.
return new RedirectResponse($this->generateUrl('registration_thanks'));
Entity code :
<?php
namespace Acme\DemoBundle\Entity;
class Registration
{
private $email;
private $password;
public function getEmail()
{
return $this->email;
}
public function setEmail($email)
{
$this->email = $email;
}
public function getPassword()
{
return $this->password;
}
public function setPassword($password)
{
$this->password = $password;
}
}
doc for validation : http://symfony.com/doc/current/book/validation.html
NOTE : there is no need to add some validation on password entity property, the repeatedType done it for you

Resources