I have this code...
namespace AppBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
class NotificationCommand extends ContainerAwareCommand
{
protected function configure()
{
$this->setName('app:notif');
}
public function execute(InputInterface $input, OutputInterface $output)
{
$message = \Swift_Message::newInstance()
->setFrom([
'from#example.com' => 'Example'
])
->setTo('to#example.com')
->setSubject('Subject')
->setBody(
$this->getContainer()->renderView(
'emails/notify.html.twig', [
'foo' => 'bar',
]
),
'text/html'
);
$this->getContainer()->get('mailer')->send($message);
}
}
And I get an error in response
Attempted to call an undefined method named "renderView" of class
"ContainerV5drzta\appDevDebugProjectContainer".
How do I use Swift Mailer in my Command (Symfony 3.4)?
You can dependency inject these services that should solve the problem and it's also the way Symfony is trying to turn towards.
public function __construct(
EngineInterface $templating,
\Swift_Mailer $mailer,
) {
$this->templating = $templating;
$this->mailer = $mailer;
parent::__construct();
}
You can now in your execute() render a template like so:
$message = (new \Swift_Message('My message'))
->setFrom('foo#bar.com')
->setTo('bar#foo.com')
->setBody($this->templating->render('mytemplate.html.twig'), 'text/html');
$this->mailer->send($message);
You can read more about dependency injecting in Symfony here or a more generic article here.
Related
I'd like to make an event that is triggered on delete.
When someone deletes an article I take the user email from the article and send an email with information which article is deleted and when.
I work with the Symfony 4 framework.
I have no idea how to start?
I have in Article controller for CRUD.
My solution for this problem that works.
<?php
namespace App\EventListener;
use App\Entity\Article;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Events;
use Twig\Environment;
class ArticleDeleteListener implements EventSubscriber
{
private $mailer;
private $twig;
public function __construct(\Swift_Mailer $mailer, Environment $twig)
{
$this->twig = $twig;
$this->mailer = $mailer;
}
public function getSubscribedEvents()
{
return [
Events::preRemove,
];
}
public function preRemove(LifecycleEventArgs $args)
{
$article = $args->getEntity();
if (!$article instanceof Article) {
return;
}
$emailAddress = $article->getAuthor()->getEmail();
$email = (new \Swift_Message())
->setFrom('send#example.com')
->setTo($emailAddress)
->setBody(
$this->twig->render('layouts/article/onDeleteEmail.html.twig', [
'article' => $article,
'author' => $article->getAuthor(),]
)
);
$this->mailer->send($email);
}
}
Services.yaml
App\EventListener\ArticleDeleteListener:
tags:
- { name: 'doctrine.event_listener', event: 'preRemove' }
I'm trying to send an email with SMTP in Symfony 4 and I have the following function as per the docs.
public function send_smtp(\Swift_Mailer $mailer)
{
$message = (new \Swift_Message('Hello Email'))
->setFrom('send#example.com')
->setTo('MyEmail#gmail.com')
->setBody('test email content');
$mailer->send($message);
}
However, I want to call this function from a different one like
$this->send_smtp();
But it complains about 'No parameters are passed' and
$this->send_smtp(\Swift_Mailer);
also gives the error message
Undefined constant 'Swift_Mailer'
What can be the problem and how could it be solved?
There are a few solutions possible. You can add the parameter with typehinting in your action and then use it to call your function:
/**
* #Route("/something")
*/
public function something(\Swift_Mailer $mailer)
{
$this->send_smtp($mailer);
}
or you can retrieve the service from the container in the send_smtp function:
public function send_smtp()
{
$mailer = $this->get('mailer');
$message = (new \Swift_Message('Hello Email'))
->setFrom('send#example.com')
->setTo('MyEmail#gmail.com')
->setBody('test email content');
$mailer->send($message);
}
Create service e.g.
namespace App\Service\Mailer;
class Mailer
{
private $mailer;
public function __construct(\Swift_Mailer $mailer)
{
$this->mailer = $mailer;
}
public function send_smtp()
{
$message = (new \Swift_Message('Hello Email'))
->setFrom('send#example.com')
->setTo('MyEmail#gmail.com')
->setBody('test email content');
$this->mailer->send($message);
}
}
And now you can inject this service wherever you want (e.g. to your Controller action or in another service) via __construct:
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public function someAction()
{
$this->mailer->send_smtp()
}
Or you can inject it via method or via property. You can read more about injections here: https://symfony.com/doc/current/components/dependency_injection.html
P.S. I don't recommend you use container's method get because this method works only for public services, but in Symfony 4 services are private by default.
I’m creating a Emailer Service in my new Symfony 4 application.
I have tried a million things but no luck. I could only find a few resources on this topic for S4 at the moment. Any help is appreciated.
This what I’m trying to achieve. I understand I have to use different services inside of my Emailer service but no luck.
<?php
namespace App\Mailer;
class Emailer
{
public function sendWelcome($email): \Swift_Mailer
{
$message = (new \Swift_Message('P****** - Welcome In!'))
->setFrom('no-reply#p****n.com')
->setTo($email)
->setBody(
$this->renderView(
// templates/emails/registration.html.twig
'emails/registration.html.twig',
array('name' => $user->getUsername())
),
'text/html'
)
->setCharset('utf-8');
$mailer->send($message);
return true;
}
}
First you need to get your templating service injected into your class (constructor injection) and then you can use it to render template.
In the code you can see it that we type-hint it in constructor so Symfony Dependency injection know what we need. Then we just use it. Same will be with your $mailer service.
<?php
namespace App\Mailer;
use Symfony\Component\Templating\EngineInterface;
class Emailer
{
/**
* #var EngineInterface
*/
private $templating;
/**
* TestTwig constructor.
*/
public function __construct(EngineInterface $templating)
{
$this->templating = $templating;
}
public function sendWelcome($email): \Swift_Mailer
{
$message = (new \Swift_Message('P****** - Welcome In!'))
->setFrom('no-reply#p****n.com')
->setTo($email)
->setBody(
$this->templating->render(
// templates/emails/registration.html.twig
'emails/registration.html.twig',
array('name' => $user->getUsername())
),
'text/html'
)
->setCharset('utf-8');
$mailer->send($message);
return true;
}
}
#miles-m a use statement is not the same as injection. A use statement just makes the class accessible with the class name as an alias. Dependency Injection is a pattern that decouples your classes from each other which facilitates better testing and debugging (you can swap out your injected objects for mock objects etc).
One way to inject the Swift_Mailer would be as a constructor parameter, i.e.
class Emailer
{
/** #var \Swift_Mailer $mailer */
private $mailer;
public function __construct(
EngineInterface $templating,
\Swift_Mailer $mailer <== mailer will be injected here
) : \Swift_Mailer
{
//...
$this->mailer->send($message);
}
}
class CallingClass
{
//...
$emailer = new Emailer(
//EngineInterface instance
//\Swift_Mailer instance <== injecting
);
$emailer->sendWelcome('email#example.com');
}
Other questions
$mailer->send($message)
Where is your $mailer instance defined?
public function sendWelcome($email): \Swift_Mailer
return true;
Is true a valid instance of Swift_Mailer?
Symfony version is 3.3, PHP is 7.1
Hi, I am dealing with weird problem and I have no idea why it happens. When I run my app on localhost everything work fine, but when I run it on remote server it doesn't work even while using app_dev.php. Live version: http://task.shaelex2.ayz.pl/web/app_dev.php/
The error is:
Unable to register extension "AppBundle\Service\MailerService" as it is already registered.
services.yml
CoreService:
class: AppBundle\Service\CoreService
arguments:
- "#doctrine.orm.entity_manager"
- "#swiftmailer.mailer.default"
- "#twig"
public: true
MailSender:
class: AppBundle\Service\MailerService
arguments:
- "#swiftmailer.mailer.default"
- "#twig"
public: true
MailerService.php
<?php
namespace AppBundle\Service;
use Swift_Mailer;
use Swift_Message;
use Symfony\Bundle\TwigBundle\TwigBundle;
class MailerService extends \Twig_Extension
{
private $mailer;
public function __construct(Swift_Mailer $mailer, \Twig_Environment $twig)
{
$this->mailer = $mailer;
$this->twig = $twig;
}
public function sendMail($address, $adverts)
{
$message = new Swift_Message('Adverts');
$message->setFrom("xxx");
$message->setTo($address);
$message->setBody(
$this->twig->render(':email:email.html.twig', array('emails' => $adverts)),
'text/html');
$this->mailer->send($message);
}
}
CoreService.php
<?php
namespace AppBundle\Service;
use AppBundle\Entity\Advert;
use AppBundle\Entity\Logs;
use AppBundle\Entity\UserSettings;
use Doctrine\ORM\EntityManager;
use Swift_Mailer;
class CoreService
{
protected $em;
protected $mailer;
protected $twig;
public function __construct(EntityManager $em, Swift_Mailer $mailer, \Twig_Environment $twig) {
$this->em = $em;
$this->mailer = $mailer;
$this->twig = $twig;
}
public function fetch() {
print ("fetching\n");
$links = $this->em->getRepository(UserSettings::class)->findAll();
foreach ($links as $link) {
$driver = $link->getPortal();
print ($driver);
$site = $link->getDeepLink();
$scraper1 = new Scraper(new AdvertScrapeDriver($driver), $site);
$run = $scraper1->scrapeAdverts($this->em);
$logs = new Logs($driver, $site);
$this->em->persist($logs);
}
print("emailing\n");
$emails = $this->em
->getRepository(Advert::class)
->findBy(array('sent' => '0'));
foreach ($emails as $object) {
/* $object Advert */
$object->setSent(1);
$this->em->persist($object);
}
$logs = new Logs("email", "xxx");
$this->em->persist($logs);
$this->em->flush();
print("logs done\n");
$mails = new MailerService($this->mailer, $this->twig);
$mails->sendMail("xxx", $emails);
print("sent emails\n");
return $emails;
}
public function test(){
print("testuje");
$emails = $this->em
->getRepository(Advert::class)
->findBy(array('sent' => '0'));
$mails = new MailerService($this->mailer, $this->twig);
$mails->sendMail("xxx", $emails);
}
}
And the route which use CoreService
/**
* #Route("/debug/fetch", name="debug_fetch")
*/
public function debugFetch(\Swift_Mailer $mailer, \Twig_Environment $twig) {
$em = $this->getDoctrine()->getManager();
$sg = new CoreService($em, $mailer, $twig);
$emails = $sg->fetch();
return $this->render('email/email.html.twig', array(
'emails' => $emails,
));
}
Probably you are using default symfony configuration, and your twig extension already loaded by symfony.
Read this documentation
Next, register your class as a service and tag it with twig.extension.
If you're using the default services.yml configuration, you're done!
Symfony will automatically know about your new service and add the
tag.
I think you are using any package which already registered with "MailerService"
Try to use any other name of class.
i have created a service
services:
app.EmailAndSms:
class: AppBundle\PublicFunctions\EmailAndSms
arguments: ["%parameter1%","%parameter2%"]
and
namespace AppBundle\PublicFunctions;
use Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class EmailAndSms extends Controller{
public function __construct($parameter1,$parameter2) {
.....
....
}
public static function sendEMail() {
$Con= new Controller;
$message = \Swift_Message::newInstance()
->setSubject($maildata['sub'])
->setFrom('notification#xxxxx.com')
->setTo($maildata['To'])
->setReturnPath('notification#xxxxx.com') ->setBody($Con->renderView( 'Emails/EMailTemplate.html.twig', array('content' => $Passtemplate)), 'text/html');
}
}
got error
Error: Call to a member function has() on a non-object
"file": "/var/www/html/xxxx_rest/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php",
"line": 162,
You should start by cleaning up your code.
Remove the static modifier, static methods are to be avoided in general.
You don't need the new Controller instance since you already are extending the controller class so instead of
$Con->renderView('Emails/EMailTemplate.html.twig', array('content' => $Passtemplate)), 'text/html');
Just do
$this->renderView('Emails/EMailTemplate.html.twig', array('content' => $Passtemplate)), 'text/html');
the non-object has() is called on is the service container of your controller because as you instantiate your controller yourself the container is not injected.
In the end you don't need to exten Controller either, you should just get the twig service since this is what you need and not the whole service container.
To fix all this inject twig in your service as well as swiftmailer to send your email:
services:
app.EmailAndSms:
class: AppBundle\PublicFunctions\EmailAndSms
arguments: ["%parameter1%","%parameter2%", '#twig', #mailer]
Then in your class:
namespace AppBundle\PublicFunctions;
class EmailAndSms {
private $twig;
private $mailer;
public function __construct($parameter1,$parameter2, \Twig_environment $twig, $mailer) {
.....
....
$this->twig = $twig;
$this->mailer = $mailer;
}
public function sendEMail($maildata) {
$message = \Swift_Message::newInstance()
->setSubject($maildata['sub'])
->setFrom('notification#xxxxx.com')
->setTo($maildata['To'])
->setReturnPath('notification#xxxxx.com')
->setBody($this->twig->render('Emails/EMailTemplate.html.twig', array('content' => $Passtemplate)));
$success = $this->mailer->send($message);
return $success;
}
}
Now to use this service from a controller :
$this->get('app.EmailAndSms')->sendEmail($maildata);