Symfony2 accessing mailer service - php

I am working with Symfony2 and am trying to access mailer service but constantly get this error message:
{"errors":{"code":500,"message":"Error: Call to a member function get() on a non-object"}}
my code:
<?php
namespace TestBundle\UserBundle\Utilities;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class EmailServiceClass extends Controller
{
public function sendEmail($subject, $to, $body)
{
$msg = \Swift_Message::newInstance();
$msg->setSubject($subject);
$msg->setTo($to);
$msg->setBody($body);
$msg->setContentType('text/html');
$msg->setCharset('utf-8');
$msg->setFrom('test#gmail.com');
$this->get('mailer')->send($msg);
}
}
The error comes from this line: $this->get('mailer')->send($msg);
From what I understand when I extend Controller calls I should be able to access this service without having to specifically create a service.

You should do it another way.
It's the best when your services are POPO (Plain Old PHP Object). Also dependencies should be passed via constructor, so let's refactor your service a little bit:
class EmailServiceClass //no need to extend anything
{
private $mailerService; //dependency as private property
//we're passing dependencies via constructor
public function __construct(\Swift_Mailer $mailerService)
{
$this->mailerService = $mailerService;
}
public function sendEmail($subject, $to, $body)
{
$msg = \Swift_Message::newInstance();
$msg->setSubject($subject);
$msg->setTo($to);
$msg->setBody($body);
$msg->setContentType('text/html');
$msg->setCharset('utf-8');
$msg->setFrom('test#gmail.com');
//now you can access mailer service like that
$this->mailerService->send($msg);
}
}
Now of course you need to modify the way you configure this service in Service Container.
You probably have something like this now:
services:
your_mailer:
class: TestBundle\UserBundle\Utilities\EmailServiceClass
Now you need to add arguments line in order to pass dependencies:
services:
your_mailer:
class: TestBundle\UserBundle\Utilities\EmailServiceClass
arguments: ['#mailer']
The last line defines arguments that will be passed to your service's constructor. mailer is the name of Swift_Mailer service.
More details about how to manage service dependencies can be found in Symfony's Book

Please don't extend the Controller class with a service class. You should inject the dependencies that you require using the services.yml. Please implement your service to be something along the lines of:
MyController.php:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MyController extends Controller
{
public function sendEmailAction()
{
$subject = //..
$to = //..
$body = //..
$this->get('email_service.class')->sendEmail($subject, $to, $body);
// Return a template, or redirect here..
return new Response();
}
}
EmailServiceClass.php
class EmailServiceClass
{
private $mailer;
public function __construct(\Swift_Mailer $mailer)
{
$this->mailer = $mailer;
}
public function sendEmail($subject, $to, $body)
{
$msg = \Swift_Message::newInstance();
$msg->setSubject($subject);
$msg->setTo($to);
$msg->setBody($body);
$msg->setContentType('text/html');
$msg->setCharset('utf-8');
$msg->setFrom('test#gmail.com');
$this->mailer->send($msg);
}
}
app/config/services.yml
email_service.class:
class: TestBundle\UserBundle\Utilities\EmailServiceClass
arguments: ['#mailer']

Related

Symfony 3 - Some difficulties to use templating service to send mail

I have a Mail.php file that contains a sendMail function that will be used by several of my controllers.
I got to have to use the "templating" service. But I have problems putting it in place.
My Services.yml:
email_management:
class: Site\PagesBundle\Utils\Mails
arguments: ['#templating']
public: true
My Mail.php:
<?php
namespace Site\PagesBundle\Utils;
use Site\PagesBundle\Entity\User;
use Site\PagesBundle\Entity\UserCas;
class Mails
{
private $templating;
public function __construct(EngineInterface $templating)
{
$this->templating = $templating;
}
public function sendMail($user,$raisonMail)
{
$transport = \Swift_SmtpTransport::newInstance();
$mailer = new \Swift_Mailer($transport);
// EntĂȘte
$message = \Swift_Message::newInstance()
->setFrom(array('############' => '############'))
//->setTo($user->getEmail());
->setTo("############")
->setCharset('utf-8')
->setContentType('text/html');
switch($raisonMail)
{
case 'formulaireInscription':
dump($user);
// (1) Confirmation de demande d'inscription
$message->setSubject("subject")
->setBody($this->templating->render("#Pages/swiftmail/CreationCompte/DemandeCreationCompte.html.twig",array(
'prenom'=>$user->getPrenom(),
'nom'=>$user->getNom(),
)));
break;
//... other cases
In my controller :
$templating = new EngineInterface;
$mail = new Mail($templating);
$mail->get('email_management')->sendEmail($user,$motif);
But now I've this error :
You must set a loader first.
Can someone help me please ? Thanks !
Assuming that the intention is to go for the service based option. Please note in general that the service class is intended to be moved into different folder in the project (to be under PagesBundle/Service folder).
services.yml (please note the changed path)
email_management:
class: Site\PagesBundle\Service\EmailManagementService
arguments: ['#templating']
public: true
EmailManagementService.php (please note the changed location & namespace)
<?php
namespace Site\PagesBundle\Service;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Site\PagesBundle\Entity\User;
use Site\PagesBundle\Entity\UserCas;
class Mails
{
private $templating;
public function __construct(EngineInterface $templating)
{
$this->templating = $templating;
}
...
}
Usage in controller:
$this->get('email_management')->sendMail($user,'formulaireInscription');

Call to a member function has() on a non-object on send mail in swifmailer

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);

Create an email service in Symfony

I try to make a service in my Symfony Sonata bundle to send an email to a specific person as soon as an order is created. The person to whom the email is send is the person the user select to approve the order.
I try to follow the service container documentation on Symfony's website, but it feels too incomplete for me. I want to see a complete example and not just a few snippets.
This is my email service class so far;
<?php
namespace Qi\Bss\BaseBundle\Lib\PurchaseModule;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Doctrine\ORM\EntityManager;
/**
*
*/
class Notifier
{
/**
* Service container
* #var type
*/
private $serviceContainer;
public function notifier($subject, $from, $to, $body) {
$message = \Swift_Message::newInstance()
->setSubject($subject)
->setFrom($from)
->setTo($to)
->setBody($body)
;
$this->serviceContainer->get('mailer')->send($message);
}
/**
* Sets the sales order exporter object
* #param type $serviceContainer
*/
public function setServiceContainer($serviceContainer)
{
$this->serviceContainer = $serviceContainer;
}
}
My service inside my services.yml file looks like this;
bss.pmod.order_notifier:
class: Qi\Bss\BaseBundle\Lib\PurchaseModule\Notifier
arguments: ["#mailer"]
And when I call the service in a controller action I use this line;
$this->get('bss.pmod.order_notifier')->notifier();
The error I'm getting state;
Notice: Undefined property:
Qi\Bss\FrontendBundle\Controller\PmodOrderController::$serviceContainer
Like I said before, I've looked at the service container documentation but I can't understand it.
Can someone please help me with a nice full example explaining everything?
You don't need setServiceContainer method in your service class, instead of it you should have __construct accepting mailer as first argument:
class Notifier
{
protected $mailer;
public function __construct($mailer)
{
$this->mailer = $mailer;
}
public function notifier() {
$message = \Swift_Message::newInstance()
->setSubject('Simon Koning')
->setFrom('noreply#solcon.nl')
->setTo('simon#simonkoning.co.za')
->setBody('The quick brown fox jumps over the lazy dog.')
;
$this->mailer->send($message);
}
}

Use custom Service inside Custom Event

I'm learning Symfony and I'm trying to create: a new service and Event
My service send emails
config.yml
parameters:
MyService.class: Acme\UserBundle\Services\sendEmail
MyService.transport: sendmail
service.yml
services:
MyService:
class: %MyService.class%
arguments: [#mailer]
sendEmail.php
class sendEmail {
private $mail;
public function __construct ($mail) {
$this->mail = $mail;
}
public function sendMail () {
$msg = \Swift_Message::newInstance()
->setSubject('Hi')
->setFrom('xxx#example.com')
->setTo('cc#gmail.com')
->setBody('ok');
$this->mail->send($msg);
}
}
My Event
I have created these class
UserEvent.php
<?php
namespace Acme\UserBundle\Event;
final class UserEvents {
const NEW_USER='new.user';
}
newUserEvent.php
<?php
/**
* EVENT DISPATCHER
*/
namespace Acme\UserBundle\Event;
use Acme\UserBundle\Entity\User;
use Symfony\Component\EventDispatcher\Event;
class NewUserEvent extends Event {
protected $user;
public function __construct (User $user) {
$this->user = $user;
}
public function getUser () {
return $this->user;
}
}
newUserListener.php
<?php
namespace Acme\UserBundle\Event;
use Acme\UserBundle\Services\sendEmail;
class NewUserListener {
public function sendEmailToUsers(NewUserEvent $event,sendEmail $service)
{
// ... send email to users
}
}
in my controller
$em = $this->getEm();
$dispatcher = new EventDispatcher();
// attach listener
$listner = new NewUserListener();
$dispatcher->addListener(UserEvents::NEW_USER,array($listner,'sendEmailToUsers'));
$user = $em->getRepository('AcmeUserBundle:User')->findOneBy(array('username' => 'alex')); //mock
$event = new NewUserEvent($user,$this->get('MyService'));
$dispatcher->dispatch(UserEvents::NEW_USER,$event);
return new Response('hi');
I'd like to use my service inside my event by I have this error
ContextErrorException: Catchable Fatal Error: Argument 2 passed to
Acme\UserBundle\Event\NewUserListener::sendEmailToUsers() must be an
instance of Acme\UserBundle\Services\sendEmail, none given in
Acme/UserBundle/Event/NewUserListener.php
There are many points here :
You create a new event dispatcher in your controller, but the event dispatcher service is already available in a standard Symfony app, you should use it and register your listener with the kernel.event_listener tag for your service :
http://symfony.com/doc/current/cookbook/service_container/event_listener.html
$disptacher = $this->container->get('event_dispatcher');
Secondly, nowhere you inject your service in your listener ?

Error: Call to a member function get() on a non-object

I am trying to send mail with Swift_Message however when I go to send the data it will not send and I get an error of
FatalErrorException: Error: Call to a member function get() on a
non-object in
/vagrant/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php
line 252
Here is the Email Controller that I am using.
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\DependencyInjection\ContainerInterface;
class EmailController extends Controller{
public function createMessage($subject, $from, $from_name, $to, $to_name, $body){
// Create the message
$message = \Swift_Message::newInstance()
// Give the message a subject
->setSubject($subject)
// Set the From address with an associative array
->setFrom(array($from => $from_name))
// Set the To addresses with an associative array
->setTo(array($to => $to_name))
// Give it a body
->setBody($body, 'text/html');
return $message;
}
public function sendEmail($message, $urlAlias){
$this->get('mailer')->send($message);
return $this->redirect($this->generateUrl($urlAlias));
}
}
I understand that its unable to access the object which I think is part of the container class but I can seem to get it to pull up. I have tried using $this->container->get(...
but that also does not work. What am I missing. This seems like it should be really straight forward.
I am calling this function from a different bundle using an action to call the current controller. I don't know if that makes a difference.
Ok so when looking in /vagrant/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php
The line it errors on is
/**
* Gets a service by id.
*
* #param string $id The service id
*
* #return object The service
*/
public function get($id)
{
return $this->container->get($id);
}
}
Which makes me feel like 'mailer; is not a good $id but it is used in Symfony's examples and in a lot of other private examples.
Don't know if this helps or not but figured it was worth mentioning.
Could this be because of the swiftmailer: setting inside of my config.yml file?
routing.yml file
fuel_form_homepage:
pattern: /hello/{name}
defaults: { _controller: FuelFormBundle:Default:index }
referral_form:
pattern: /form/referral/{hash}
defaults: { _controller: FuelFormBundle:Form:referralForm }
referral_result:
pattern: /form/referral/result
defaults: { _controller: FuelFormBundle:Form:referralResult }
user_form:
pattern: /form/user
defaults: { _controller: FuelFormBundle:Form:userForm }
home:
pattern: /
defaults: { _controller: FuelFormBundle:Default:home}
This is the function that calls
public function userFormAction(request $request){
$user = new User();
$form = $this->createForm('user', $user);
$form->handleRequest($request);
if($form->isValid()){
$user->setTimeCreated();
$user->setTimeUpdated();
$date = $user->getTimeCreated();
$timestamp = $date->format("U");
$hash = $user->getFirstName() . $user->getLastName() . $timestamp ;
$user->setUserHash(md5($hash));
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
print_r($user);
//TODO: #Email: #Body: make sure to replace with correct information.
//Calls a service named email_bundle_controller
$emailController = $this->get('email_bundle_controller');
$fullName = $user->getFirstName() . $user->getLastName();
$body = "please visit the following url to start referring! <a href='http://localhost:8080/app_dev.php/form/referral/" . $user->getUserHash() . "'>Your URL</a>";
$message = $emailController->createMessage('Welcome to Fuel PRM References', 'bsaverino#gmail.com', 'Brad Saverino', $user->getEmail(), $fullName, $body);
$emailController->sendEmail($message, 'user_form');
}
return $this->render('FuelFormBundle:Default:mainForm.html.twig', array('form' => $form->createView(),));
}
This is the service that allows me to call on the other bundle.
services:
fuel_form.form.type.referral:
class: Fuel\FormBundle\Form\Type\ReferralType
tags:
- { name: form.type, alias: referral}
fuel_form.form.type.user:
class: Fuel\FormBundle\Form\Type\UserType
tags:
- { name: form.type, alias: user}
email_bundle_controller:
class: Fuel\EmailBundle\Controller\EmailController
This is the FuelEmailBundle.php
namespace Fuel\EmailBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use \Symfony\Component\DependencyInjection\ContainerInterface;
class FuelEmailBundle extends Bundle
{
private static $containerInstance = null;
public function setContainer(ContainerInterface $container = null)
{
parent::setContainer($container);
self::$containerInstance = $container;
}
public static function getContainer()
{
return self::$containerInstance;
}
}
These are the changes that were made to the sendEmail function
public function sendEmail($message, $urlAlias){
$container = FuelEmailBundle::getContainer();
$mailer = $container->get('mailer');
$mailer->send($message);
return $this->redirect($this->generateUrl($urlAlias));
}
As Cerad had mentioned above, you are getting the error as container is not set. One way of fixing this issue would be to pass a container instance to your bundle so that you can call the container from anywhere in your project.
Edit the class corresponding to your bundle(BundleName.php) to include two methods setContainer and getContainer. See the example below.
namespace Venom\CoreBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use \Symfony\Component\DependencyInjection\ContainerInterface;
class VenomCoreBundle extends Bundle
{
private static $containerInstance = null;
public function setContainer(ContainerInterface $container = null)
{
parent::setContainer($container);
self::$containerInstance = $container;
}
public static function getContainer()
{
return self::$containerInstance;
}
}
Use the appropriate namespaces.
Then, use the namespace for the bundle in classes where you need the container.
You may call the container by
$container = VenomCoreBundle::getContainer();
Then, call the mailer
$mailer = $container->get('mailer');

Categories