Symfony2 send email from service - symfony

I created the next class:
//src/AppBundle/Services/RegisterMail.php
namespace AppBundle\Services;
class RegisterMail{
protected $mailer;
public function __construct($mailer)
{
$this->mailer = $mailer;
}
public function sendPassword(){
$message = \Swift_Message::newInstance()
->setSubject('Otro correo')
->setFrom('fromEmail#fromEmail.com')
->setTo('toEmail#toEmail.com')
->setBody('hola desde el servicio')
;
$envia = $this->mailer->send($message);
}
}
And I declare it as a service in my services.yml
services:
registermail:
class: AppBundle\Services\RegisterMail
arguments: [#mailer]
In my controller call the service:
//src/AppBundle/Controller/DefaultController
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class DefaultController extends Controller
{
/**
* #Route("/")
*/
public function indexAction()
{
//EnvĂ­o el email con el password
$mailer = $this->get('registermail');
$mailer->sendPassword();
return $this->render(':Default:index.html.twig');
}
}
The email are sent, but the page still loading 30 seconds, and I have an alert from developer toolbar: "An error occurred while loading the web debug toolbar (404: not found). Do you want to open the profiler?
If Accept the message symfony profiler don't show any error.
If Cancel the message developer toolbar don't appears.
What am I doing wrong?
Thank you!

#RL83 you are probably sending the message synchronously by not using any kind of spool in swiftmailer and your smtp provider is working slowly.
You should try using an async spool queue, I'd recommend using https://github.com/radutopala/TSSAutomailerBundle, which provides you with a database queue. So basically, you'll not only have a spool queue but also a history of the sent emails, stored in the database layer.

Try to replace your code with this:
//src/AppBundle/Services/RegisterMail.php
namespace AppBundle\Services;
class RegisterMail{
protected $mailer;
protected $transport; // <- Add transport to your service
public function __construct($mailer, $transport)
{
$this->mailer = $mailer;
$this->transport = $transport;
}
public function sendPassword() // <- change the method like this
{
$email = $mailer->createMessage()
->setSubject('Otro correo')
->setFrom('fromEmail#fromEmail.com')
->setTo('toEmail#toEmail.com')
->setCharset("UTF-8")
->setContentType('text/html')
->setBody('hola desde el servicio')
;
$send = $mailer->send($email);
$spool->flushQueue($transport);
}
}
Register your service and add the new dependency - the transport service "#swiftmailer.transport.real"
services:
registermail:
class: AppBundle\Services\RegisterMail
arguments: ["#mailer", "#swiftmailer.transport.real" ]
And your trouble will be resolved

Thank for your answers and sorry for the delay.
#lyberteam when i put your code, i get this error message:
Notice: Undefined variable: mailer
500 Internal Server Error - ContextErrorException
Here: $email = $mailer->createMessage()
Any suggestion?
Thank you

Related

Symfony: redirecting to homepage after encountering an error

I've recently started learning Symfony, and I've been trying to make an app that will redirect user to the homepage after encountering an error (For the sake of the question, it can be error 404) However, I had problems with finding a way to do so.
Before, I used TwigErrorRenderer as described in Symfony documentation to handle my errors, but it only explains how to redirect to new error pages created by myself. Could somebody help me with this issue?
It is generally not a good idea to do this, because you want to tell the user that their request was not processed due to an error, or that they accessed non-existing page.
But if you really want to, you can achieve it with this Event Listener.
// src/EventListener/ExceptionListener.php
<?php
declare(strict_types=1);
namespace App\EventListener;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\Routing\RouterInterface;
final class ExceptionListener
{
private RouterInterface $router;
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
public function onKernelException(ExceptionEvent $event): void
{
// You should log the exception via Logger
// You can access exception object via $event->getThrowable();
$homepageRoute = $this->router->generate('homepage', [], RouterInterface::ABSOLUTE_URL);
$response = new RedirectResponse($homepageRoute);
$event->setResponse($response);
}
}
You also need to register the Event Listener in your services.yaml.
services:
App\EventListener\ExceptionListener:
tags:
- { name: kernel.event_listener, event: kernel.exception }
Please note the following:
The Event Listener assumes that your Homepage route is called homepage;
you really should log the exception or you will lose logs about all of them;
as stated at the top of this answer, this is not a good approach to deal with exceptions.

How can I use the a cache manager in Symfony?

I my contoller I try to clear the cache when updating a page
protected function mapDataToEntity(array $data, Project $entity): void{
$entity->setName($data['name']);
$cacheManager = $this->get('sulu_http_cache.cache_manager');
$cacheManager->invalidatePath($path, $headers);
}
I get the error message:
Attempted to call an undefined method named "get" of class
"App\Controller\Admin\ProjectController". Did you mean to call e.g.
"cgetAction", "getAction", "getLocale" or "getSecurityContext"?
You should autowire your cache manager instead of trying to access it from the container.
private CacheManager $cacheManager;
public function __construct(CacheManager $cacheManager)
{
$this->cacheManager = $cacheManager;
}
And use it in your method:
$this->cacheManager->invalidatePath($path, $headers);

Symfony 3 : How to access my database inside my provider? (with doctrine)

I would like to access my database that contains all my user inside my provider with doctrine. I followed a tutorial (http://symfony.com/doc/current/security/custom_provider.html) to build my provider for my user, so I have an loadUserByUsername function :
public function loadUserByUsername($username)
{
// make a call to your webservice here
$player = new Player();
$player = $this->getDoctrine()
->getRepository('AppBundle:Player')
->findOneByPseudo($username);
// pretend it returns an array on success, false if there is no user
if ($player) {
return $player;
}
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
But of course my getDoctrine() function is undefined. So there is something I don't understand with the provider, I am trying to use it to be authenticated when I login so I need a provider, but why I can't search inside my database? How should I write this function? Thank for your help
EDIT :
When I add doctrine by service.yml (and after writting my constructor inside my provider), I have this error :
FatalThrowableError in PlayerProvider.php line 13:
Type error: Argument 1 passed to AppBundle\Security\PlayerProvider::__construct() must be an instance of Doctrine\Bundle\DoctrineBundle\Registry, instance of Doctrine\ORM\EntityManager given, called in /home/jean/PW6/SkA/SkeletonsOnlineV2/skeleton-online/var/cache/dev/appDevDebugProjectContainer.php on line 327
EDIT 2 : When I just put arguments: ['#doctrine'] inside my service.yml, I get an error that says that doctrine is undefined
EDIT 3 : It works now, I just made a dumb mistake
If you read further, it says the following (emphasis mine):
The real implementation of the user provider will probably have some dependencies or configuration options or other services. Add these as arguments in the service definition.
So in your case it would be something like
# app/config/services.yml
services:
app.webservice_user_provider:
class: AppBundle\Security\User\WebserviceUserProvider
arguments: ['#doctrine']
And your class needs a constructor
class WebserviceUserProvider implements UserProviderInterface
{
protected $doctrine;
public function __construct (\Doctrine\Bundle\DoctrineBundle\Registry $doctrine)
{
$this->doctrine = $doctrine;
}
// ...
}
Then in your method replace $this->getDoctrine() with just $this->doctine

Get twilio instance in FOSUserBundle event

I am trying to send SMS to users who register in my website through Twilio, I got the vresh/twilio-bundle and it works fine.
I am trying to pass twilio instance to the event but I think I am missing something, here is what I am doing:
In config.yml i set the servide like this:
services:
registration.completed.listener:
class: Jaguar\AloBundle\EventListener\RegistrationEventListener
arguments:
entityManager: ["#doctrine.orm.voipswitch_entity_manager", "vresh_twilio"]
tags:
- { name: kernel.event_subscriber, event: performOnRegistrationCompleted }
I have declared the twilio config:
vresh_twilio:
sid: 'xxx'
authToken: 'xxx'
version: '2010-04-01'
retryAttempts: 3
Then, in my method I try to get the instance:
public function performOnRegistrationCompleted(UserEvent $event)
{
$twilio = $event->get('vresh_twilio');
}
But it fails...
Any help on this, please?
Thanks a lot!
There are a few issues with your service setup.
You are not actually passing the Twilio instance as you have no # sign preceding the service name. #vresh_twilio is a service, vresh_twilio is just a string.
You are passing in an associative array with a key of entityManager and a value that is also an array with the values of the service #doctrine.orm.voipswitch_entity_manager and the string vresh_twilio.
You're not passing the Twilio instance in your event you are building a listener with the Twilio instance in the constructor.
Your service should actually look like...
services:
registration.completed.listener:
class: Jaguar\AloBundle\EventListener\RegistrationEventListener
arguments:
entityManager: "#doctrine.orm.voipswitch_entity_manager"
twilio: "#vresh_twilio"
// Or
// - #doctrine.orm.voipswitch_entity_manager
// - #vresh_twilio
// Or
// [#doctrine.orm.voipswitch_entity_manager, #vresh_twilio]
//
// As they all mean the same thing and the keys aren't
// used in your actual service __construct
tags:
- { name: kernel.event_subscriber, event: performOnRegistrationCompleted }
This would mean your listener would then have a constructor to receive those services like..
protected $entityManager;
protected $twilio;
public function __conctruct(ObjectManager $entityManager, TwilioWrapper $twilio)
{
$this->entityManager = $entityManager;
$this->twilio = $twilio;
}
Meaning that you could then call it in your class using $this->twilio.
Also, from looking at the services that the Vresh\TwilioBundle creates it looks like the service that you would want to be injecting would be #twilio.api rather than #vresh_twilio as it doesn't seem to exist but I may be wrong there (I haven't used the bundle myself).

Symfony2: Problems using logger in a service (passed as as parameter)

I'm developing a project using Symfony 2.1.
I have created a service that is being called from a controller, and it's working ok.
Now I need that the service generates log, and I'm trying to pass logger this way:
soap.client:
class: MyFirm\MyAppBundle\Service\SOAPClient
arguments:
logger: "#logger"
My service is defined this way:
namespace MyFirm\MyAppBundle\Service;
use \SoapClient as SoapClient;
use Monolog\Logger;
class SOAPClient
{
private $logger;
function __construct (Logger $logger)
{
$this->logger = $logger;
}
function sendMessage ($message, $wsdl_url)
{
$webServResult = "ERROR";
try{
$client = new SoapClient($wsdl_url, array("trace"=>true,
"exceptions"=>true));
$webServResult=$client->sendMessage($data);
}
catch(\Exception $ex){
$webServResult="ERROR";
$message=$ex->getMessage();
$log_text = print_r($ex, true)."\n".
$client->__getLastRequest()."\n".
$client->__getLastResponse();
$this->logger->err("ERROR: ".$log_text);
}
return $webServResult;
}
}
However, when I use the logger (if the wsdl doesn't exist, for example), the application hangs.
Am I doing anything wrong? Thanks a lot.
This is not a problzm from logger but from SoapClient that doesn't throw any Exception in case of unreachable WSDL... It waits until a Fatal error is thrown...
You have to check if WSDl exists before calling SoapClient ;)
Sorry, the problem wasn't at logger, but in the lines:
$log_text = print_r($ex, true)."\n".
$client->__getLastRequest()."\n".
$client->__getLastResponse();
If I remove these lines and log only the Exception message all goes right.
SoapClient does generate an Exception if the WSDL is not found:
SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://localhost/unknown.wsdl' :
failed to load external entity "http://localhost/unknown.wsdl"
Solved and fixed. Sorry for the spam.

Resources