1
votes

I am writing an Custom Symfony Service, a Mailer, to send all of my mails. Therefore I am trying to inject the mailer and the template Service inside the custom Service Class. I already tried other solutions from stackoverflow, like e.g. 10304468, but this didn't helped me.

This is my Mailer Service Class

namespace Acme\DemoBundle\Mail;

use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Swift_Message;

class Mailer {

    protected $mailer;

    protected $templating;



public function __construct(Swift_Message $mailer, EngineInterface $templating) {

            $this->mailer = $mailer;
            $this->templating = $templating;
        }



    public function NewUserMail($newuser){

        $message = new Swift_Message();
        $message->newInstance()
                ->setSubject('Demo Subject')
                ->setFrom(array('[email protected]' => 'Your Company'))
                ->setTo($newuser->getEmail())
                ->setBody($this->templating->render('AcmeDemoBundle:Mail:newuser.html.twig'), 'text/html');              
        $this->sendMail($message);
    }


    public function sendMail($message) {
        $this->mailer->send($message);
    }
}

This is my Service.yml (which gets loaded through the Dependecy Injection Extension file:

acme_demo_bundle.mailer:
    class:     Acme\DemoBundle\Mail\Mailer
    arguments: ["@mailer", "@templating"]

Now when I am calling the Mailer Service inside a Controller, I get this Error:

Catchable Fatal Error: Argument 1 passed to Acme\DemoBundle\Mail\Mailer::__construct() must be an instance of Swift_Message, none given,

How I call the Mailer Service inside the Controller:

/...
$message = new Mailer();
$message->NewUserMail($newuser);
/...

If I insert the mailer and templating service from the container, when generating the new Mailer Class, i won't get the error. But I thought, the Service.yml is insertig the services into my class, but obviously is does not.

I also tried this inside another symfony project, same problem. It looks like I am missing something here.... :(

1
You're not actually using the DI. You should call the mailer using $mailer = $this->container->get('acme_demo_bundle.mailer'). - qooplmao
ahh, I see, thanks. But is there no way to call the class the way I described and let Symfony automatically inject the mailer and the tempalting service into my Mailer Class? - Jake94
Not as far as I know. If you create an instance using new Xxx then you are creating a new instance outside of the DI so none of it's inner workings are available. - qooplmao
You have access to the container from inside the controller. Just do: $message = $this->get('acme_demo_bundle.mailer'); - Cerad
True, although $this->get() in the controller is just a shortcut to $this->container->get(). - qooplmao

1 Answers

0
votes

Symfony's DependencyInjection doesn't actually change the way php works. Hence the service container. It's just a series of components that helps you centralize your service (which is a class really) instantiation. You can think of it in very very simple terms as this:

class ServiceContainer{

  protected $definitions;
  protected $instantiated;

  /**
   * @param array $definitions the service definitions, e.g: the result of parsing the yml file
   */
  public function __construct($definitions){
    $this->definitions = $definitions;
  }

  public function get($service){
    if(isset($this->instantiated[$service])
      return $this->instantiated[$service]);

    $definition = $this->definitions[$service];
    $class = $definition['class'];
    $arguments = $definition['arguments'];
    // the resolved arguments
    $args = array();
    foreach($arguments as $a){
      // resolveArguments will return the corresponding object/value depending on the value of the arg
      // i.e: it will return an instantiated service for "@mailer"
      // or the parameter's value for "%some_parameter%"
      $args[] = $this->resolveArguments($a);
    }
    // now instantiate the object base on the resolved arguments
    $reflector = new ReflectionClass($class);
    $object = $reflector->newInstanceArgs($args);

    $this->instantiated[$service] = $object;

    return $object;
  }
}