For some reason the calendar in our symfony project doesn't show up. We're using Bootstrap script and we don't see what are we doing wrong.
We have been trying to follow up the steps from this page but it didn't work:
https://ourcodeworld.co/articulos/leer/224/crear-un-calendario-de-eventos-planificador-con-dhtmlxscheduler-en-symfony-3
If someone is able to help us we'll be very thankfull. We'll also leave a list of the files of our project.
This is the template that I want that appear the calendar:
{% block stylesheets %}
<!-- Incluir el estilo plano del planificador -->
<link rel='stylesheet' type='text/css' href='{{ asset("libraries/dhtmlx/codebase/dhtmlxscheduler_flat.css") }}' charset="utf-8"/>
<!-- Si no usa el modo de pantalla completa, ignore el siguiente estilo -->
<style type="text/css" media="screen">
html, body{
margin:0px;
padding:0px;
height:100%;
overflow:hidden;
}
</style>
{% endblock %}
{% block body %}
<div id="scheduler_element" class="dhx_cal_container" style='width:100%; height:100%;'>
<div class="dhx_cal_navline">
<div class="dhx_cal_prev_button"> </div>
<div class="dhx_cal_next_button"> </div>
<div class="dhx_cal_today_button"></div>
<div class="dhx_cal_date"></div>
<div class="dhx_cal_tab" name="day_tab" style="right:204px;"></div>
<div class="dhx_cal_tab" name="week_tab" style="right:140px;"></div>
<div class="dhx_cal_tab" name="month_tab" style="right:76px;"></div>
</div>
<div class="dhx_cal_header"></div>
<div class="dhx_cal_data"></div>
</div>
{% endblock %}
{% block javascripts %}
<script src='{{ asset("libraries/dhtmlx/codebase/dhtmlxscheduler.js") }}' type='text/javascript' charset="utf-8"></script>
<!-- Incluya jQuery para manejar solicitudes AJAX-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- Incluye Momentjs para jugar con las fechas -->
<script src="{{ asset("libraries/momentjs/moment.js") }}"></script>
<script>
// Exponer las citas globalmente imprimiendo la cadena JSON con twig y el filtro sin procesar
// para que puedan ser accesibles por el programador Scripts.js el controlador
window.GLOBAL_APPOINTMENTS = {{ citas|raw }};
// Como los scripts del planificador estarán en otros archivos, las rutas generadas por twig
// también debe estar expuesto en la ventana
window.GLOBAL_SCHEDULER_ROUTES = {
create: '{{ path("crear") }}',
update: '{{ path("update") }}',
delete: '{{ path("delete") }}'
};
</script>
<script src='{{ asset("libraries/schedulerScripts.js") }}' type='text/javascript' charset="utf-8"></script>
<script type="text/javascript" src="https://raw.githubusercontent.com/flouthoc/minAjax.js/master/index.js"></script>
{% endblock %}
----------------------------------------
This is the controller that we are using:
<?php
namespace App\Controller;
use App\Entity\Cita;
use App\Repository\CitaRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class CitaController extends AbstractController
{
#[Route('/prueba', name:'prueba')]
public function indexAction(ManagerRegistry $doctrine)
{
$citasRepository = new CitaRepository($doctrine);
$citas = $citasRepository->findAll();
$formatedCitas = $this->formatCitaToJson($citas);
return $this->render("prueba/prueba.html.twig", [
'citas' => $formatedCitas
]);
}
#[Route('/prueba/create', name:'crear')]
public function createAction(ManagerRegistry $doctrine,Request $request){
$citasRepository = new CitaRepository($doctrine);
// Use el mismo formato que usa Moment.js en la vista
$format = "d-m-Y H:i:s";
$cita = new Cita();
$cita->setTitulo($request->request->get("title"));
$cita->setDescripcion($request->request->get("description"));
$cita->setFechaDeInicio(
\DateTime::createFromFormat($format, $request->request->get("start_date"))
);
$cita->setFechaDeFin(
\DateTime::createFromFormat($format, $request->request->get("end_date"))
);
$em = $doctrine->getManager();
$em->persist($cita);
$em->flush();
return new JsonResponse(array(
"status" => "success"
));
}
#[Route('/prueba/update/{id}', name:'update')]
public function updateAction(ManagerRegistry $doctrine,Request $request,$id){
$citasRepository = new CitaRepository($doctrine);
$cita = $citasRepository->findOneBy(['id'=>$id]);
if(!$cita){
return new JsonResponse(array(
"status" => "error",
"message" => "The appointment to update $id doesn't exist."
));
}
// Use el mismo formato que usa Moment.js en la vista
$format = "d-m-Y H:i:s";
// Actualizar campos de la cita
$cita->setTitulo($request->request->get("title"));
$cita->setDescripcion($request->request->get("description"));
$cita->setFechaDeInicio(
\DateTime::createFromFormat($format, $request->request->get("start_date"))
);
$cita->setFechaDeFin(
\DateTime::createFromFormat($format, $request->request->get("end_date"))
);
// Actualizar cita
$em = $doctrine->getManager();
$em->persist($cita);
$em->flush();
return new JsonResponse(array(
"status" => "success"
));
}
#[Route('/prueba/delete/{id}', name:'delete')]
public function deleteAction(ManagerRegistry $doctrine,Request $request,$id){
$em = $doctrine->getManager();
$citasRepository = new CitaRepository($doctrine);
$cita = $citasRepository->findOneBy(['id'=>$id]);
if(!$cita){
return new JsonResponse(array(
"status" => "error",
"message" => "The given appointment $id doesn't exist."
));
}
// ¡Eliminar cita de la base de datos!
$em->remove($cita);
$em->flush();
return new JsonResponse(array(
"status" => "success"
));
}
private function formatCitaToJson($citas){
$formatedCitas = [];
foreach($citas as $cita){
array_push($formatedCitas, array(
"id" => $cita->getId(),
"description" => $cita->getDescripcion(),
// Es importante mantener start_date, end_date y text con la misma clave
// para el área de JavaScript
// aunque el getter podría ser diferente, por ejemplo:
// "start_date" => $appointment->getBeginDate();
"text" => $cita->getTitulo(),
"start_date" => $cita->getFechaDeInicio()->format("Y-m-d H:i"),
"end_date" => $cita-> getFechaDeFin()->format("Y-m-d H:i")
));
}
return json_encode($formatedCitas);
}
}
-----------------------------------
This is the Entity we are using:
<?php
namespace App\Entity;
use App\Repository\CitaRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: CitaRepository::class)]
class Cita
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\Column(type: 'date')]
private $fecha;
#[ORM\Column(type: 'time')]
private $hora;
#[ORM\OneToOne(mappedBy: 'cita', targetEntity: Reserva::class)]
private $reserva;
#[ORM\ManyToOne(inversedBy: 'citas')]
private ?Servicios $Servicio = null;
#[ORM\Column(length: 255)]
private ?string $Titulo = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $Descripcion = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $fecha_de_inicio = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $fecha_de_fin = null;
public function getId(): ?int
{
return $this->id;
}
public function getFecha(): ?\DateTimeInterface
{
return $this->fecha;
}
public function setFecha(\DateTimeInterface $fecha): self
{
$this->fecha = $fecha;
return $this;
}
public function getHora(): ?\DateTimeInterface
{
return $this->hora;
}
public function setHora(\DateTimeInterface $hora): self
{
$this->hora = $hora;
return $this;
}
public function getReserva(): ?Reserva
{
return $this->reserva;
}
public function setReserva(?Reserva $reserva): self
{
$this->reserva = $reserva;
return $this;
}
public function getServicio(): ?Servicios
{
return $this->Servicio;
}
public function setServicio(?Servicios $Servicio): self
{
$this->Servicio = $Servicio;
return $this;
}
public function getTitulo(): ?string
{
return $this->Titulo;
}
public function setTitulo(string $Titulo): self
{
$this->Titulo = $Titulo;
return $this;
}
public function getDescripcion(): ?string
{
return $this->Descripcion;
}
public function setDescripcion(?string $Descripcion): self
{
$this->Descripcion = $Descripcion;
return $this;
}
public function getFechaDeInicio(): ?\DateTimeInterface
{
return $this->fecha_de_inicio;
}
public function setFechaDeInicio(?\DateTimeInterface $fecha_de_inicio): self
{
$this->fecha_de_inicio = $fecha_de_inicio;
return $this;
}
public function getFechaDeFin(): ?\DateTimeInterface
{
return $this->fecha_de_fin;
}
public function setFechaDeFin(?\DateTimeInterface $fecha_de_fin): self
{
$this->fecha_de_fin = $fecha_de_fin;
return $this;
}
}
Related
I'm using Laminas framework for a project I'm developing. I installed Node.js to use maildev as SMTP server for sending mail e-mails with PHPMailer and everything is working well.
The next step is to create scripts with Laminas framework laminas-cli and this one also works fine. The problem is that at the end on the execution of my script, I would like to send e-mail to the user and I'm getting this error :
Additional params: -fnanguisamuel#gmail.com 2022-01-19 19:44:06
Result: false 2022-01-19 19:44:06 Could not instantiate mail
function. 2022-01-19 19:44:06 Sending with mail() 2022-01-19
19:44:06 Sendmail path: 2022-01-19 19:44:06 Envelope sender:
nanguisamuel#gmail.com 2022-01-19 19:44:06 To:
nanguisamuel#gmail.com 2022-01-19 19:44:06 Subject: TEST LAMINAS
2022-01-19 19:44:06 Headers: Date: Wed, 19 Jan 2022 19:44:06 +0000
From: nanguisamuel#gmail.com
Reply-To: nanguisamuel#gmail.com
Message-ID: <bYYlElEH6jBVhViNmZY2Mpqd6EteZ1DLZKbNDK1O4#DESKTOP-D4AB8IN>
X-Mailer: PHPMailer 6.5.3 (https://github.com/PHPMailer/PHPMailer)
MIME-Version: 1.0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: base64 2022-01-19 19:44:06 Additional params:
-fnanguisamuel#gmail.com
I have to say that when I call my custom class function with from my controllers, I get the e-mail in my localhost page for maildev but from the console I do not get anything.
Here are my code snippets :
My ConsoleGenerationRelances command :
<?php
declare(strict_types=1);
namespace Commun\Scripts;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
class ConsoleGenerationRelances extends Command
{
/** #var string */
private $mapper;
private $cronEnv;
private $MAIL;
protected static $defaultName = 'console-generation-relances';
public function __construct($mapper=[],$cronEnv=[],$MAIL=NULL){
$this->mapper = $mapper;
$this->cronEnv = $cronEnv;
$this->MAIL = $MAIL;
parent::__construct();
}
protected function configure() : void
{
$this->setName(self::$defaultName);
//$this->addOption('name', null, InputOption::VALUE_REQUIRED, 'Module name');
}
protected function execute(InputInterface $input, OutputInterface $output) : int
{
$mapperAbonnementPrestation = $this->mapper['mapperAbonnementPrestation'];
$relances = $mapperAbonnementPrestation->getDataRelancesForConsole();
$output->writeln('Démarrage du script des relances |~> : '.date('Y-m-d H:i:s'));
$nbreJourAvantRelance = $this->cronEnv['cron'];
//$output->writeln(json_encode($this->MAIL));
foreach ($relances as $relance){
if(empty($nbreJourAvantRelance) || empty($relance['dateLimitePaiement']) ){ // Si parametre de relance non defini alors on saute l'execution
continue;
}
$now = strtotime(date('Y-m-d H:i:s')); // or your date as well
$dateLimitePaiement = strtotime($relance['dateLimitePaiement']);
$datediff = $now-$dateLimitePaiement;
$nombreJour = abs(round($datediff / 86400));
if($nombreJour<=$nbreJourAvantRelance){ // On envoie le mail
//sleep(10); //$this->MAIL->envoiMailCreationCompte(['emailTo' => ['nanguisamuel#gmail.com'],'nomPrenoms' => 'Samuel NANGUI','motDePasse' => 'test']); //On envoie un mail au user avec ses parametres
$this->MAIL->test(['nanguisamuel#gmail.com']);
}
}
$output->writeln('Fin du script des relances |~> : '.date('Y-m-d H:i:s'));
return 0;
}
}
Factory of my ConsoleGenerationRelances
<?php
declare(strict_types=1);
namespace Commun\Scripts\Factory;
use Commun\Scripts\ConsoleGenerationRelances;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Commun\Controller\Plugin\NslabsMail;
use Commun\Scripts\Mail\CronMail;
class ConsoleGenerationRelancesFactory implements FactoryInterface
{
/**
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
* #return $requestedName Entity
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$mappers = ['mapperAbonnementPrestation' => $container->get('TABONNEMENTPRESTATION')];
$mailConfig = $container->get('config')['sendMailParameters'];
$host = $mailConfig['host'];
$smtpSecure = $mailConfig['smtpSecure'];
$port = $mailConfig['port'];
$debug = $mailConfig['debug'];
$smtpAuth = $mailConfig['smtpAuth'];
$username = $mailConfig['username'];
$password = $mailConfig['password'];
$useSMTP = $mailConfig['useSMTP'];
return new ConsoleGenerationRelances($mappers,
$container->get('config'),
new CronMail(new NslabsMail($host,$smtpSecure,$port,$debug,$smtpAuth,$username,$password,$useSMTP))
);
}
}
My Custom CronMail class below :
<?php
/**
* #module Commun
* #subpackage Scripts/Mail
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2022 Nslabs
*/
namespace Commun\Scripts\Mail;
use Commun\Controller\Plugin\NslabsMail;
class CronMail
{
protected $classMail;
function __construct(NslabsMail $_classMail)
{
$this->classMail = $_classMail;
}
public function test($to){
$this->classMail->ajouterDestinataire($to);
$this->classMail->ajouterReplyTo('nanguisamuel#gmail.com');
$this->classMail->ajouterExpediteur('nanguisamuel#gmail.com');
$message = $this->classMail->enteteEmail()
.'Cher/Chère SAM,<br/><br/>'
."Ca marche avec PHP MAILER.<br/><br/>"
."<br/><br/>"
.$this->classMail->ajoutSignature();
try{
$this->classMail->setMessage('TEST LAMINAS', $message);
$this->classMail->send();
} catch (\Exception $e){
//var_dump($e->getMessage());
//die();
}
$this->classMail->clearAllAddressesAndAttachments();
}
public function envoiMailCreationCompte($params){
$this->classMail->ajouterDestinataire($params['emailTo']);
$this->classMail->ajouterReplyTo('nanguisamuel#gmail.com');
$this->classMail->ajouterExpediteur(EXPEDITEUR_MAIL_GENERAL);
$this->classMail->ajouterDestinaireCopieCarbone(['nanguisamuel#gmail.com']);
$message = $this->classMail->enteteEmail()
.'Cher/Chère ' . $params['nomPrenoms'] . ',<br/><br/>'
."Nous avons le plaisir de vous informer de la création de votre compte utilisateur avec le mot de passe suivant : ".$params['motDePasse']." <br/><br/>"
."Nous vous recommandons de le changer dès votre première connexion a la platefome.<br/>"
."<br/><br/>"
.$this->classMail->ajoutSignature();
try{
$this->classMail->setMessage('['.PORTAIL.'] Confirmation de création de compte utilisateur', $message);
$this->classMail->send();
} catch (\Exception $e){
//var_dump($e->getMessage());
//die();
}
$this->classMail->clearAllAddressesAndAttachments();
}
}
And finally my NslabsMail Class :
<?php
/**
* #module Commun
* #subpackage Controller/Plugin
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2020 Nslabs
*/
namespace Commun\Controller\Plugin;
Use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;
require APPLICATION_PATH.'/vendor/autoload.php';
class NslabsMail extends PHPMailer
{
/*private $host;
private $smtpAuth;
private $username;
private $password;
private $smtpSecure;
private $port;
private $debug;*/
public function __construct($host='localhost',$smtpSecure=PHPMailer::ENCRYPTION_SMTPS,$port=25,$debug=SMTP::DEBUG_SERVER,$smtpAuth=FALSE,$username=NULL,$password=NULL,$useSMTP=FALSE,$exceptions=null) {
parent::__construct($exceptions);
$this->Host = $host;
$this->SMTPAuth = $smtpAuth;
if($smtpAuth){
$this->Username = $username;
$this->Password = $password;
}
$this->SMTPSecure = $smtpSecure;
$this->Port = $port;
$this->SMTPDebug = $debug;
$this->CharSet = 'UTF-8';
$this->Encoding = 'base64';
if($useSMTP){
$this->isSMTP();
}else{
$this->isMail();
}
}
public function clearAllAddressesAndAttachments(){
$this->clearAddresses();
$this->clearAllRecipients();
$this->clearAttachments();
$this->clearBCCs();
$this->clearReplyTos();
$this->clearCCs();
}
public function ajouterExpediteur($email,$username=''){
$this->setFrom($email, $username);
}
public function ajouterDestinataire($adressesDestinataire=[]){
if(empty($adressesDestinataire)){
throw new Exception("Aucun destinaire précise");
}
foreach ($adressesDestinataire as $adresse){
$this->addAddress($adresse, !empty($adresse['username']) ? $adresse['username'] : '');
}
}
public function ajouterDestinataireCopie($adressesCC=[]){
if(!empty($adressesCC)){
foreach ($adressesCC as $adresse){
$this->addCC($adresse, !empty($adresse['username']) ? $adresse['username'] : '');
}
}
}
public function ajouterReplyTo($email){
$this->addReplyTo($email);
}
public function ajouterDestinaireCopieCarbone($adressesBCC=[]){
if(!empty($adressesBCC)){
foreach ($adressesBCC as $adresse){
$this->addBCC($adresse, !empty($adresse['username']) ? $adresse['username'] : '');
}
}
}
public function ajouterPiecesJointes($attachments=[]){
if(!empty($attachments)){
foreach ($attachments as $file){
$this->addAttachment($file);
}
}
}
public function setMessage($subject='',$message='',$isHTML=TRUE){
$this->Subject = $subject;
$this->Body = $message;
$this->isHTML($isHTML);
}
public function enteteEmail() {
$str =
'<div style="width:600px;">'.
'<div style="font-family:Arial;font-size:11px;">'.
//'<img style="margin-bottom:5px" src="'.$racine_site.'/'.$baseUrl->baseUrl('/img/logo/logo-dgi-email.png').'"><br />'.
'<span style="color:#fdd116;font-size:18px;font-weight:bold">'.PORTAIL.'</span>
<p style="color:#009177;">
Ceci est un email envoyé automatiquement par '.PORTAIL.'.<br/>
</p>
<hr style="color:#009177;">
<br/>
</div>'
.'<div style="font-family:Arial;">'
;
return $str;
}
public function ajoutSignature() {
$str =
'</div>'. // ouvert dans l'entete
'<br/>'.
'<br/>'.
'<div style="font-family:Arial;font-size:11px;">'.
'<span style="font-size:16px;font-weight:bold;margin-bottom:5px;">'.NSLabs.'</span><br/>'.
'<span style="font-size:14px;font-weight:bold;color:#d03630;">'.PORTAIL.'</span>'.
'<p style="margin-top:10px;color:grey;">Pour nous contacter :<br/>'.
'<span style="font-weight:bold;color:grey;">Tél : '.SIGNATURE_MAIL_TELEPHONE .'</span><br/>'.
'<span style="font-weight:bold;color:grey;">Email : '.SIGNATURE_MAIL_EMAIL_CONTACT.'</span><br/>'.
'<br/>'.
SIGNATURE_MAIL_ADRESSE1.'<br/>'.
'</p>'.
$this->warningNoRetour().
'</div>'.
'</div>'
;
return $str;
}
public function warningNoRetour() {
$str =
'<hr>'.
'<span style="font-size:14px;font-weight:bold;color:red">Attention aux emails frauduleux ! </span><br/>'.
'<p style="color:red;">
Pour votre sécurité, ne répondez jamais à un e-mail vous demandant vos identifiants de connexion et/ou vos comptes de paiement, <br/>
et/ou vous informant d’un changement vos identifiants de connexion.'.
'</p>'
;
return $str;
}
}
Any help will be very appreciated
I'm trying to create a new tempate in my project in symfony to put a climbing converter. But it doesn't work. I have the error:
App\Entity\Site object not found by the #ParamConverter annotation
I put the function in the entity "site" as following :
/**
* #Route("/site")
*/
class SiteController extends AbstractController
{
public function upload( KernelInterface $kernel): Response
{
$imagesDir = $kernel->getProjectDir().'/public/uploads'; // équivalent à $this->getParameter('images_directory')
dump($imagesDir) ;
return $this->render('site/show.html.twig');
}
/**
* #Route("/", name="site_index", methods={"GET"})
*/
public function index(SiteRepository $siteRepository): Response
{
return $this->render('site/index.html.twig', [
'sites' => $siteRepository->findAll(),
]);
}
/**
* #Route("/new", name="site_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$site = new Site();
$form = $this->createForm(SiteType::class, $site);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
//on recupère les medias transmises
$media = $form->get('site')->getData();
//on boucle sur les medias
foreach($media as $medi){
//on génère un nouveau nom de fichier
$fichier = md5(uniqid()) . '.' . $medi->guessExtension();
//on copie le fichier dans le dossier img
$medi->move(
$this->getParameter('images_directory'),
$fichier
);
//on stocke l'image dans la bdd
$img = new Media();
$img->setNom($fichier);
$site->addMedium($img);
}
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($site);
$entityManager->flush();
return $this->redirectToRoute('site_index');
}
return $this->render('site/new.html.twig', [
'site' => $site,
'form' => $form->createView(),
]);
}
/**
* #Route("/{id}", name="site_show", methods={"GET"})
*/
public function show(Site $site, MediaRepository $mediarepository, $id): Response
{
$media = $mediarepository->findBy(
['site'=>$id]
);
return $this->render('site/show.html.twig', [
'site' => $site,
'media' => $media,
]);
}
/**
* #Route("/{id}/edit", name="site_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Site $site): Response
{
$form = $this->createForm(SiteType::class, $site);//j'appelle le form
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
//on recupère les medias transmises
$media = $form->get('site')->getData();
//on boucle sur les medias
foreach($media as $medi){
//on génère un nouveau nom de fichier
$fichier = md5(uniqid()) . '.' . $medi->guessExtension();
//on copie le fichier dans le dossier img
$medi->move(
$this->getParameter('images_directory'),
$fichier
);
//on stocke l'image dans la bdd
$img = new Media();
$img->setNom($fichier);
$site->addMedium($img);
}
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('site_index');
}
return $this->render('site/edit.html.twig', [
'site' => $site,
'form' => $form->createView(),
]);
}
/**
* #Route("/{id}", name="site_delete", methods={"POST"})
*/
public function delete(Request $request, Site $site): Response
{
if ($this->isCsrfTokenValid('delete'.$site->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($site);
$entityManager->flush();
}
return $this->redirectToRoute('site_index');
}
/**
* #Route("/conv", name="site_converter")
*/
public function converter():Response
{
return $this->render('site/converter.html.twig');
}
}
I checked others answers about this problem, but I still can't find out the solution. Do you have any ideas?
I put some more code so that it would be easier to understand. I hope this would be usefull. It's the route for converter that makes me problem. Thanks
This happens because you have a route called /conv, you should declare it before declaring /{id} route, instead Symfony searches for a Site object with id: conv which is not found.
Move converter route and method declaration before your show route and method declaration.
I'm having an error using the paginator bundle inside a twig loop , I think missions is waiting for a sliddingpagination and not a persistentcollection , I think it's in the controller in the FindAllVisibleQuery, like waiting for an array but IDK..
This is the error I'm receiving:
Argument 2 passed to
Knp\Bundle\PaginatorBundle\Twig\Extension\PaginationExtension::render()
must be an instance of
Knp\Bundle\PaginatorBundle\Pagination\SlidingPaginationInterface,
array given, called in
/Applications/MAMP/htdocs/MySUPER/var/cache/dev/twig/12/12cef122792496c7b8dbcf0cc1f03b575f10f859de41093d7a8fd223b1623d7d.php
on line 176
MissionController.php
<?php
namespace App\Controller;
use App\Entity\Mission;
use App\Entity\MissionSearch;
use App\Form\MissionSearchType;
use App\Repository\MissionRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class MissionController extends AbstractController {
/**
* #var MissionRepository
*/
private $repository;
/**
* #var EntityManagerInterface
*/
private $em;
public function __construct(MissionRepository $repository, EntityManagerInterface $em)
{
$this->repository = $repository;
$this->em = $em;
}
/**
* #return Response
* #throws \Twig\Error\LoaderError
* #throws \Twig\Error\RuntimeError
* #throws \Twig\Error\SyntaxError
* #Route ("/missions" , name="Missions")
*/
public function index(PaginatorInterface $paginator, Request $request): Response
{
$search = new MissionSearch();
$form = $this->createForm(MissionSearchType::class, $search);
$form->handleRequest($request);
$missions = $paginator->paginate(
$this->repository->findAllVisibleQuery($search),
$request->query->getInt('page', 1),
18
);
return $this->render('lesmissions/index.html.twig', [
'current_menu' => 'missions',
'missions' => $missions,
'form' => $form->createView()
]);
}
/**
* #Route("/missions/{slug}-{id}", name="mission.show", requirements={"slug": "[a-z0-9\-]*"})
* #param Mission $mission
* #return Response
*/
public function show(Mission $mission, string $slug): Response
{
if ($mission->getSlug() !== $slug) {
return $this->redirectToRoute('mission.show', [
'id' => $mission->getId(),
'slug' => $mission->getSlug()
], 301);
}
return $this->render('lesmissions/show.html.twig', [
'mission' => $mission,
'current_menu' => 'missions'
]);
}
}
?>
Twig snippet
{% extends 'base.html.twig' %}
{% block title 'Missions' %}
{% block body %}
<div class="jumbotron text-center">
<h1>Trouvez une mission qui vous correspond</h1>
<p>My super est encore en developpement , vous pouvez apporter vos idées via le formulaire de contact</p>
</div>
<div class="jumbotron">
<div class="container">
{% if form is defined %}
{{ form_start(form) }}
<div class="form-row align-items-end">
<div class="col">
{{ form_row(form.maxGain) }}
</div>
<div class="col">
{{ form_row(form.deltaVille) }}
</div>
<div class="col">
{{ form_row(form.options) }}
</div>
<div class="col">
<div class="form-group">
<button class="btn btn-primary">Rechercher</button>
</div>
</div>
</div>
{{ form_end(form) }}
{% endif %}
</div>
</div>
<div class="container">
<h2>Les dernieres missions</h2>
<div class="row flex">
{% for mission in missions %}
<div class="col-3">
<div class="card mb-4">
<div class="card-body">
<h5 class="card-title">
{{ mission.titre }}
</h5>
<p class="card-text">{{ mission.adresse }} {{ mission.ville }}</p>
<div class="text-primary" style="font-weight: bold;font-size: 2rem;">{{ mission.gain }} €</div>
</div>
</div>
</div>
<div class="pagination">
{{ knp_pagination_render(missions) }}
</div>
{% endfor %}
</div>
</div>
{% endblock %}
MissionRepository.php
<?php
namespace App\Repository;
use App\Entity\Mission;
use App\Entity\MissionSearch;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\Query;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\ORM\QueryBuilder;
/**
* #method Mission|null find($id, $lockMode = null, $lockVersion = null)
* #method Mission|null findOneBy(array $criteria, array $orderBy = null)
* #method Mission[] findAll()
* #method Mission[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class MissionRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Mission::class);
}
/**
* #return Query
*/
public function findAllVisibleQuery(MissionSearch $search): Query
{
$query = $this->findVisibleQuery();
if ($search->getMaxGain()) {
$query = $query
->andWhere('p.price <= :maxgain')
->setParameter('maxgain', $search->getMaxGain());
}
if ($search->getDeltaVille()) {
$query = $query
->andWhere('m.ville = :deltaville')
->setParameter('deltaville', $search->getDeltaVille());
}
if ($search->getOptions()->count() > 0) {
$k = 0;
foreach($search->getOptions() as $option) {
$k++;
$query = $query
->andWhere(":option$k MEMBER OF m.options")
->setParameter("option$k", $option);
}
}
return $query->getQuery();
}
/**
* #return Mission[]
*/
public function findLatest(): array
{
return $this->findVisibleQuery()
->setMaxResults(30)
->getQuery()
->getResult();
}
private function findVisibleQuery(): QueryBuilder
{
return $this->createQueryBuilder('m')
->where('m.Accepted = false');
}
// /**
// * #return Mission[] Returns an array of Mission objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('m')
->andWhere('m.exampleField = :val')
->setParameter('val', $value)
->orderBy('m.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Mission
{
return $this->createQueryBuilder('m')
->andWhere('m.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
you need to edit your repository class to return the QueryBuilder instead of the Query itself.
Your function must be something lke that:
public function findAllVisibleQuery(MissionSearch $search): Query
{
$query = $this->findVisibleQuery();
if ($search->getMaxGain()) {
$query = $query
->andWhere('p.price <= :maxgain')
->setParameter('maxgain', $search->getMaxGain());
}
if ($search->getDeltaVille()) {
$query = $query
->andWhere('m.ville = :deltaville')
->setParameter('deltaville', $search->getDeltaVille());
}
if ($search->getOptions()->count() > 0) {
$k = 0;
foreach($search->getOptions() as $option) {
$k++;
$query = $query
->andWhere(":option$k MEMBER OF m.options")
->setParameter("option$k", $option);
}
}
return $query;
}
I have a problem with the typical form to change the password in which I first put you to put your current password.
The theory is very simple and is explained in the symfony doc but it gives me an error like the current password is incorrect
My Model:
namespace BackendBundle\Form\Model;
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;
class ChangePassword
{
/**
* #SecurityAssert\UserPassword(
* message = "Error al poner la contraseña actual"
* )
*/
protected $oldPassword;
/**
* #Assert\Length(
* min = 6,
* minMessage = "El password tiene que tener al menos 6 caracteres"
* )
*/
protected $password;
/////
public function getOldPassword() {
return $this->oldPassword;
}
public function setOldPassword($oldPassword) {
$this->oldPassword = $oldPassword;
}
/////
public function getPassword() {
return $this->oldPassword;
}
public function setPassword($oldPassword) {
$this->oldPassword = $oldPassword;
}
}
The fomType:
->add('oldPassword', PasswordType::class, array(
'label' => 'Ponga su password actual',
'mapped' => false,
))
->add('password', RepeatedType::class, array(
"required" => "required",
'type' => PasswordType::class,
'invalid_message' => 'Los dos password deben coincidir',
'first_options' => array('label' => 'Password nuevo', "attr"
=> array("class" => "form-password form-control")),
'second_options' => array('label' => 'Repita el Password nuevo', "attr" => array("class" => "form-password form-control"))
)
)
And little else must be done (I think) in addition to the controler create the view with the form and then collect the data of the new password, etc, but as I say, I sent error of not valid field that checks the password and I do not know if it's because the password I keep it encrypted
My security.yml I have it as
encoders:
BackendBundle\Entity\Users:
algorithm: bcrypt
cost: 6
My action Controller:
public function passAction(Request $request) {
$changePasswordModel = new ChangePassword();
$form = $this->createForm(ChangePasswordType::class, $changePasswordModel);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$user = $this->getUser(); //metemos como id la del usuario sacado de su sesion
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
$password = $encoder->encodePassword($changePasswordModel->getPassword(), $user->getSalt());
$user->setPassword($password);
$em->persist($user);
$flush = $em->flush();
if ($flush === null) {
$this->session->getFlashBag()->add('success', 'El usuario se ha editado correctamente');
return $this->redirectToRoute("others_show"); //redirigimos la pagina si se incluido correctamete
} else {
$this->session->getFlashBag()->add('warning', 'Error al editar el password');
}
} else {
dump($form->getErrors());
$this->session->getFlashBag()->add('warning', 'El password no se ha editado por un error en el formulario !');
}
}
return $this->render('BackendBundle:Others:editPass.html.twig', array(
'form' => $form->createView(),
));
}
It tells me that the form is not correct because the old password is incorrect. What could be wrong?
You don't need to check the validity of the old password yourself. Symfony does this for you, when you call form->isValid(). So you can drop this:
$currentPassword = $form->get("oldPassword")->getData();
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
$isValid = $encoder->isPasswordValid($user->getPassword(), $currentPassword, $user->getSalt());
$encoderService = $this->container->get('security.password_encoder');
$match = $encoderService->isPasswordValid($user, $currentPassword);
dump($match);
Instead, start your Controller like this:
public function passAction(Request $request) {
$changePasswordModel = new PasswordChange();
$form = $this->createForm(PasswordChangeType::class, $changePasswordModel);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { // will check if old password was valid
$user = $this->getUser(); //metemos como id la del usuario sacado de su sesion
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
$password = $encoder->encodePassword($changePasswordModel->getPassword(), $user->getSalt());
$user->setPassword($password);
// go on with saving $user to database
Thank you very much #Spunc for your help, I've finally gotten it to work correctly ;-)
I put the correct complete code in case there are other users with problems. Thanks again
passControler
namespace BackendBundle\Controller;
use BackendBundle\Entity\Users;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
class PassController extends Controller {
public function passAction(Request $request) {
$changePasswordModel = new ChangePassword();
$form = $this->createForm(ChangePasswordType::class, $changePasswordModel);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$user = $this->getUser(); //metemos como id la del usuario sacado de su sesion
$encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
$password = $encoder->encodePassword($changePasswordModel->getPassword(), $user->getSalt());
$user->setPassword($password);
$em->persist($user);
$flush = $em->flush();
if ($flush === null) {
$this->session->getFlashBag()->add('success', 'El usuario se ha editado correctamente');
return $this->redirectToRoute("others_show"); //redirigimos la pagina si se incluido correctamete
} else {
$this->session->getFlashBag()->add('warning', 'Error al editar el password');
}
} else {
// dump($form->getErrors());
$this->session->getFlashBag()->add('warning', 'El password no se ha editado por un error en el formulario !');
}
}
return $this->render('BackendBundle:Others:editPass.html.twig', array(
'form' => $form->createView(),
));
}
}
model ChangePassword
namespace BackendBundle\Form\Model;
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;
class ChangePassword {
/**
* #SecurityAssert\UserPassword(
* message = "Error al poner la contraseña actual"
* )
*/
protected $oldPassword;
/**
* #Assert\Length(
* min = 6,
* minMessage = "El password tiene que tener al menos 6 caracteres"
* )
*/
protected $password;
public function getOldPassword() {
return $this->oldPassword;
}
public function setOldPassword($oldPassword) {
$this->oldPassword = $oldPassword;
return $this;
}
public function getPassword() {
return $this->password;
}
public function setPassword($password) {
$this->password = $password;
return $this;
}
}
ChangePasswordType
namespace BackendBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
class ChangePasswordType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('oldPassword', PasswordType::class, array(
'label' => 'Ponga su password actual',
))
->add('password', RepeatedType::class, array(
"required" => "required",
'type' => PasswordType::class,
'invalid_message' => 'Los dos password deben coincidir',
'first_options' => array('label' => 'Password nuevo', "attr" => array("class" => "form-password form-control")),
'second_options' => array('label' => 'Repita el Password nuevo', "attr" => array("class" => "form-password form-control"))
)
)
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\UserBundle\Form\Model\ChangePassword',
));
}
public function getName()
{
return 'change_passwd';
}
}
I had the same problem with the "#SecurityAssert\UserPassword" assertion. I startet in my form with
"mapped" => false
That fixed my issue. Thank's a lot. Just one remark for the future visitors of the problem. The signiture of for the password encoder has changed.
In Symfony 4.4 a setup like this will encode the new password correctly
$user->setPassword(
$passwordEncoder->encodePassword( $user,
$changePasswordModel->getPassword()
) );
I am new to symfony 3 and I would like to understand how to get a value from a table according to the result found.
Let me explain :
According to the bass diagram below, each "produit" has a "poids"(nom) and a "valeur"(valeur)
view bdd:
I would like in my basket view to display the total value of the weight according to the quantity of course.
For example, I have a product at 2kg and another at 0.300kg, it would have to result in the value of 2.3kg which is in the weight table.
I can not perform this "function".
Here is my PanierController.
class PanierController extends Controller
{
public function supprimerAction(SessionInterface $session, $id)
{
$panier = $session->get('panier');
if (array_key_exists($id, $panier))
{
unset($panier[$id]);
$session->set('panier', $panier);
$this->addFlash('success', 'Article supprimé avec succès !');
}
return $this->redirect($this->generateUrl('panier'));
}
public function ajouterAction(SessionInterface $session, Request $request, $id)
{
if (!$session->has('panier')) {
$session->set('panier', array());
}
$panier = $session->get('panier');
if (array_key_exists($id, $panier)) {
if ($request->query->get('qte') != null) {
$panier[$id] = $request->query->get('qte');
}
$this->addFlash('success', 'Quantité modifié avec succès !');
} else {
if ($request->query->get('qte') != null) {
$panier[$id] = $request->query->get('qte');
} else {
$panier[$id] = 1;
}
$this->addFlash('success', 'Article ajouté avec succès !');
}
$session->set('panier', $panier);
return $this->redirect($this->generateUrl('panier'));
}
public function panierAction(SessionInterface $session)
{
if (!$session->has('panier')) {
$session->set('panier', array());
}
$em = $this->getDoctrine()->getManager();
$produits = $em->getRepository('EcommerceBundle:Produits')->findArray(array_keys($session->get('panier')));
return $this->render('EcommerceBundle:Default:panier/layout/panier.html.twig', array('produits' => $produits, 'panier' => $session->get('panier')));
}
public function livraisonAction()
{
// servira pour l'adresse de livraison
return $this->render('EcommerceBundle:Default:panier/layout/livraison.html.twig');
}
public function validationAction()
{
return $this->render('EcommerceBundle:Default:panier/layout/validation.html.twig');
}
}
If you need more information, please let me know.
#JasonRoman,
That is to say ?
For example to display the products in the Shopping Cart view, I use the ProductsRepository in the Shopping CartController:
public function panierAction(SessionInterface $session)
{
if (!$session->has('panier')) {
$session->set('panier', array());
}
$em = $this->getDoctrine()->getManager();
$produits = $em->getRepository('EcommerceBundle:Produits')->findArray(array_keys($session->get('panier')));
return $this->render('EcommerceBundle:Default:panier/layout/panier.html.twig', array('produits' => $produits, 'panier' => $session->get('panier')));
}
ProductsRepository:
class ProduitsRepository extends EntityRepository
{
public function findArray($array)
{
$qb = $this->createQueryBuilder('u')
->select('u')
->where('u.id IN (:array)')
->setParameter('array', $array);
return $qb->getQuery()->getResult();
}
}
The result is correct in the Cart view.
In the basket view, if I ask him to show me the total weight in the basket, I do:
{% Extends "::layout/layout.html.twig"%}
{% Set totalHT = 0%}
{% Set livraisonHT = 0%}
{% Block body%}
{% Set livraisonHT = livraisonHT + (panier[produit.id] * produit.poids.nom)%}
livraisonHT gives me the total weight
On the other hand, I do not know what function to write so that it shows me the corresponding value.
Currently I have in my basket:
One product at 2kg and another product at 0.3kg
{% Set livraisonHT = livraisonHT + (panier[produit.id] * product.poids.non)%}
I think I have put my finger on something,
In my basket view, if I do a dump (produits) i get, that:
array:1 [▼
0 => Produits {#546 ▼
-id: 5
-image: Media {#445 ▶}
-gamme: Gamme {#396 ▶}
-marque: Marque {#467 ▶}
-tva: Tva {#563 ▼
+__isInitialized__: true
-id: 11
-multiplicate: 0.83333333333334
-nom: "TVA 20 %"
-valeur: 20.0
…2
}
-poids: Poids {#670 ▼
+__isInitialized__: false
-id: 209
-nom: null
-valeur: null
…2
}
-categorie: Categories {#684 ▶}
-nom: "Phantom 4 Standard"
-resume: "le résumé"
-description: "La description longue"
-details: "details à voir"
-prix: 1000.0
-disponible: true
}
]
In "weight" the name and value are zero?