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
Related
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;
}
}
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've got a command tryng to access a repository method. But I can't succeed.
services.yml
app.command.app_checkOfferDemand:
class: AppRefactoredBundle\Command\CheckOfferAndDemand
arguments: ['#doctrine.orm.entity_manager']
tags:
- { name: console.command }
app_OfferRepository
class app_OfferRepository extends \Doctrine\ORM\EntityRepository
{
private function checkAndUpdate(){
$em = $this->getContainer()->get('doctrine')->getManager();
$qb = $em->createQueryBuilder();
$q = $qb->update('app_Offer', 'o')
->set('o.status_id', 2)
->where('o.createdAt < DATE_SUB(NOW(), INTERVAL 2 HOUR)')
->getQuery();
return $q->execute();
}
}
CheckOfferAndDemand
class CheckOfferAndDemand extends Command{
private $em;
public function __construct(EntityManager $em)
{
parent::__construct();
$this->em=$em;
}
protected function configure()
{
// On set le nom de la commande
$this->setName('app:check_OfferDemand');
// On set la description
$this->setDescription("Permet de controler le timeout des offres et demandes");
// On set l'aide
$this->setHelp("Cette commande ne prend pas d'argument et travailler sur toutes les offres et demandes");
}
public function execute(InputInterface $input, OutputInterface $output){
$output->writeln("update des offres");
$this->em->getRepository('AppRefactoredBundle:app_Offer')->checkAndUpdate();
$output->writeln("update des demandes");
$this->em->getRepository('AppRefactoredBundle:app_Demand')->checkAndUpdate();
$this->em->flush();
$output->writeln("DONE");
}
}
The command by itself is working (the first update print is made).
But then the error is triggered
Undefined method 'checkAndUpdate'. The method name must start with either findBy, findOneBy or countBy!
The entities seems to be well declared too
/**
* app_Offer
*
* #ORM\Table(name="app__offer")
* #ORM\Entity(repositoryClass="AppRefactoredBundle\Repository\app_OfferRepository")
*/
class app_Offer
Thanks for your help.
Your Repository method cannot be accessed because it's denoted as private.
Change
private function checkAndUpdate() {
to
public function checkAndUpdate() {
I have a problem on symfony 3.
I'm trying to manage my roles from a page I created.
The role system I use is the same as the one used by FOSUserBundle.
/**
* #ORM\Column(type="array")
*/
protected $roles = [];
/**
* Constructor
*/
public function __construct()
{
$this->setIsActif(true);
$this->roles = array();
}
/**
* {#inheritdoc}
*/
public function addRole($role)
{
$role = strtoupper($role);
if ($role === ['ROLE_USER']) {
return $this;
}
if (!in_array($role, $this->roles, true)) {
$this->roles[] = $role;
}
return $this;
}
/**
* {#inheritdoc}
* #return array
*/
public function getRoles()
{
return array_unique(array_merge(['ROLE_USER'], $this->roles));
}
/**
* Vérifie si l'utilisateur possède le rôle passé en paramètre
* {#inheritdoc}
*
* #param string
* #return bool
*/
public function hasRole($role)
{
return in_array(strtoupper($role), $this->getRoles(), true);
}
/**
* Supprimer un rôle
* {#inheritdoc}
*
* #return UserCas
*/
public function removeRole($role)
{
if (false !== $key = array_search(strtoupper($role), $this->roles, true)) {
unset($this->roles[$key]);
$this->roles = array_values($this->roles);
}
return $this;
}
/**
* Set roles
* {#inheritdoc}
*
* #return UserCas
*/
public function setRoles(array $roles)
{
$this->roles = array();
foreach ($roles as $role) {
$this->addRole($role);
}
return $this;
}
/**
* Réinitialise les rôles de l'utilisateur
*/
public function resetRoles()
{
$this->roles = [];
}
When I was in a "PREPROD" environment, everything was working, my roles were changing well. But since I switched to "PROD", when my user does not have a role (so it is automatically ROLE_USER), well 9 times out of 10, I can not assign any other role. But if he has a role other than ROLE_USER, then I can assign him any role. Why does not it work in preprod? I do not know...
On twig, I have my list of users with a list option where I choose the new role. Then it updates the page. My request retrieves the label of the new role and is assigned
Twig:
<form action="{{path('user_role_change', {'username': unUser.username })}}" method="POST">
<select id="role" name="role" onChange="this.form.submit();">
{% for unRole in listeRoles %}
<option value="{{unRole}}" {% if unRole == 'User' %} selected {% endif %}>{{unRole}}</option>
{% endfor %}
</select>
</form>
Controller:
/**
* Change le rôle d'un utilisateur lorsque l'on change l'option dans l'option list des rôles d'un utilisateur
*
* #Route("/changeRole/{username}", name="user_role_change")
* #Method("GET")
*/
public function changeRoleAction(Request $request, $username)
{
$em = $this->getDoctrine()->getManager();
$idRole=$request->get('role');
$user = $em->getRepository('PagesBundle:UserCas')->findOneByUsername($username); // On cherche si c'est un UserCas (user académique)
if($user == null)
{
$user = $em->getRepository('PagesBundle:User')->findOneByUsername($username); // On cherche si c'est un User externe
$nouveauRole = $this->getNouveauRole($idRole);
$user->setRoles($nouveauRole);
$em->persist($user);
$em->flush();
return $this->redirectToRoute('roles_index'); //redirection vers la page de gestion des Informations
}
/**
* Méthode inverse de $this->switchRole()
* Elle renvoi le rôle en type array de sorte à ce qu'elle soit injectable dans l'attribut roles de l'utilisateur ( ex: "Admin" => "ROLE_ADMIN")
*
* #param int $nomRole
* #return array
*/
public function getNouveauRole($nomRole)
{
switch($nomRole)
{
case "Admin":
$role = ['ROLE_ADMIN'];
break;
case "Packages":
$role = ['ROLE_PACKAGES'];
break;
case "Infos":
$role = ['ROLE_INFOS'];
break;
default:
$role = [];
break;
}
return $role;
}
Can someone help me please ?
Try to fix your addRole() method like the following:
/**
* {#inheritdoc}
*/
public function addRole($role)
{
$role = strtoupper($role);
if ($role === 'ROLE_USER') {
return $this;
}
if (!in_array($role, $this->roles, true)) {
$this->roles[] = $role;
}
return $this;
}
I'm using Symfony workflow on my project. I can pass the first transition and see that the next transitions are enabled with $workflow->getEnabledTransitions($entity);. When passing to another route which introduce the next transition (part of the enabled transitions) it seems that the workflow has initialized back itself when checking the enabled transitions.
Here is my workflow.yaml configuration file :
framework:
workflows:
produit_selection:
type: 'workflow' # or 'state_machine'
audit_trail:
enabled: true
marking_store:
type: 'single_state'
arguments:
- 'currentPlace'
supports:
- App\Entity\Produit
initial_place: initiale
places:
- initiale
- commande
- selectionne
- invalide_selection
transitions:
commander:
from: initiale
to: commande
selectionner:
from: commande
to: selectionne
invalider_selection:
from: commande
to: invalide_selection
Here is my commandeProduit controller action :
/**
* #Route("/produit/commande/{id<\d+>}", name="produit_commande")
* #param Request $request
* #param $id
* #param ProduitRequestCommandeUpdateHandler $updateHandler
* #return \Symfony\Component\HttpFoundation\Response
* #Security("has_role('ROLE_MARKETING')")
*/
public function commandeProduit(
Request $request,
$id,
ProduitRequestCommandeUpdateHandler $updateHandler,
Registry $workflows
) {
$repository = $this->getDoctrine()->getRepository(Produit::class);
/** #var Produit $produit */
$produit = $repository->find($id);
$produitRequest = ProduitRequest::createFromProduit($produit);
$form = $this->createForm(ProduitCommandeType::class, $produitRequest)->handleRequest($request);
$box = $produit->getBox();
if ($form->isSubmitted() AND $form->isValid()) {
$produit = $updateHandler->handle($produitRequest, $produit, $box);
if (null === $produit) {
$this->addFlash(
'error',
"La commande a été annulée car elle dépasse le budget."
);
} elseif ($produit->getCommande()) {
$workflow = $workflows->get($produit, 'produit_selection');
//$workflow->getMarking($produit);
if ($workflow->can($produit, 'commander')) {
try {
$workflow->apply($produit, 'commander');
} catch (TransitionException $exception) {
// ... if the transition is not allowed
}
}
$transitions = $workflow->getEnabledTransitions($produit);
/** #var Transition $transition */
foreach($transitions as $transition) {
$this->addFlash(
'error',
$transition->getName()
);
}
$this->addFlash(
'notice',
"La commande du produit a bien été prise en compte avec la quantité " . $produit->getQuantite() . "."
);
} else {
$this->addFlash(
'warning',
"Le produit n'est pas disponible."
);
}
return $this->redirectToRoute("produits_commande");
}
$fournisseur = $produit->getFournisseur();
return $this->render('produits/commande_produit.html.twig', [
'box' => $box,
'fournisseur' => $fournisseur,
'form' => $form->createView()
]);
}
And here is my selectionProduit controller action :
/**
* #Route("/produit/selection/{id<\d+>}", name="produit_selection")
* #param Request $request
* #param $id
* #param ProduitRequestUpdateHandler $updateHandler
* #param Registry $workflows
* #return \Symfony\Component\HttpFoundation\Response
* #Security("has_role('ROLE_MARKETING')")
*/
public function selectionProduit(
Request $request,
$id,
ProduitRequestUpdateHandler $updateHandler,
Registry $workflows
) {
$repository = $this->getDoctrine()->getRepository(Produit::class);
/** #var Produit $produit */
$produit = $repository->find($id);
$produitRequest = ProduitRequest::createFromProduit($produit);
$form = $this->createForm(ProduitSelectionType::class, $produitRequest)->handleRequest($request);
if($form->isSubmitted() AND $form->isValid()) {
$produit = $updateHandler->handle($produitRequest, $produit);
if ($produit->getSelectionne()) {
$workflow = $workflows->get($produit, 'produit_selection');
//$workflow->getMarking($produit);
$workflow->can($produit, 'selectionner');
try {
$workflow->apply($produit, 'selectionner');
} catch (TransitionException $exception) {
// ... if the transition is not allowed
}
$transitions = $workflow->getEnabledTransitions($produit);
/** #var Transition $transition */
foreach($transitions as $transition) {
$this->addFlash(
'error',
$transition->getName()
);
}
$this->addFlash(
'notice',
"Le produit a bien été sélectionné avec la quantité " . $produit->getQuantite() . ".");
} else {
$workflow = $workflows->get($produit, 'produit_selection');
//$workflow->getMarking($produit);
if ($workflow->can($produit, 'invalider_selection')) {
try {
$workflow->apply($produit, 'invalider_selection');
} catch (TransitionException $exception) {
// ... if the transition is not allowed
}
}
$transitions = $workflow->getEnabledTransitions($produit);
$this->addFlash(
'warning',
"Le produit n'a pas été sélectionné.");
}
return $this->redirectToRoute("produits_selection");
}
$box = $produit->getBox();
$fournisseur = $produit->getFournisseur();
return $this->render('produits/selection_produit.html.twig', [
'box' => $box,
'fournisseur' => $fournisseur,
'form' => $form->createView()
]);
}
Why the workflow doesn't transit to the next place after changing route ? How to fix that ? Thanks for help.
I found it. We have to flush the entity to store the current place :
$workflow->apply($produit, 'selectionner');
$this->getDoctrine()->getManager()->flush();
And in the entity we have a field defined like this :
/**
* #ORM\Column(type="string", length=100)
*/
public $currentPlace;