Search code examples
phpsymfonydependency-injectionsymfony4

Can’t get my Mailer Service working in Symfony 4


I can’t get my Mailer working when creating a service.

I’ve been following a few tutorials. I’ve been trying to inject my dependencies but there is no way to get my $this->container->render() working

I’m getting the following error message

ServiceNotFoundException: The service "App\Services\Mailer" has a dependency on a non-existent service "templating".

What would be a good way to inject the templating service in my Mailer service? I know this is called dependency injection but I can’t have it work properly.

I tried to follow this but no luck: RenderView in My service

My Controller:

use App\Services\Mailer;

class ScriptController extends AbstractController
{
    private function getThatNotifSent($timeframe, Mailer $mailer)
    {
        // Some code

        foreach ( $users as $user ) {
            $mailer->sendNotification($user, $cryptos, $news, $timeframe);
            $count++;
        }

        $response = new JsonResponse(array('Mails Sent' => $count));
        return $response;
    }
}

My service:

<?php
// src/Service/Mailer.php

namespace App\Services;

use Symfony\Component\DependencyInjection\ContainerInterface;


class Mailer
{
    private $mailer;
    private $templating;

    public function __construct(\Swift_Mailer $mailer ,ContainerInterface $templating)
    {
        $this->mailer = $mailer;
        $this->templating = $templating;
    }
    public function sendNotification($user, $cryptos, $news, $timeframe)
    {
        $message = (new \Swift_Message('Your Daily Digest Is Here!'))
            ->setFrom('[email protected]')
            ->setTo($user->getEmail())
            ->setBody(
                $this->templating->render(
                    'emails/notification.html.twig',
                    array(
                        'timeframe' => $timeframe,
                        'cryptos' => $cryptos,
                        'user' => $user,
                        'news' => $news,
                    )
                ),
                'text/html'
            )
            ->setCharset('utf-8');

        $this->mailer->send($message);
        return true;
    }
}

My service.yaml

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
    locale: 'en'
    images_directory: '%kernel.project_dir%/public/images/blog'

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
        public: false       # Allows optimizing the container by removing unused services; this also means
                            # fetching services directly from the container via $container->get() won't work.
                            # The best practice is to be explicit about your dependencies anyway.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/*'
        exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'

    # controllers are imported separately to make sure services can be injected
    # as action arguments even if you don't extend any base controller class
    App\Controller\:
        resource: '../src/Controller'
        tags: ['controller.service_arguments']

    # add more service definitions when explicit configuration is needed
    # please note that last definitions always *replace* previous ones
    App\EventListener\LoginListener:
        tags:
            - { name: 'kernel.event_listener', event: 'security.interactive_login' }

    App\Services\Mailer:
          arguments: ["@mailer", "@templating”]

UPDATE:

I have updated my code to follow Taylan answer. My Mailer service now looks like the following (no change to sendNotification Made)

<?php
// src/Service/Mailer.php

namespace App\Services;

use Symfony\Bundle\TwigBundle\TwigEngine;


class Mailer
{
    private $mailer;
    private $templating;

    public function __construct(\Swift_Mailer $mailer ,TwigEngine $templating)
    {
        $this->mailer = $mailer;
        $this->templating = $templating;
    }

I still had the same error message. But after doing research online, I’ve updated my framework.yaml to the following after reading on this helpful link: https://github.com/whiteoctober/BreadcrumbsBundle/issues/85

framework:
    templating: { engines: [twig] }

It worked

Thanks for your help.


Solution

  • ContainerInterface typehint gives you the container, yet you named it $templating. You're supposed to get templating from container like this $this->templating = $container->get('templating').

    But do you really need the container in the first place? You should be able to inject templating directly by typehinting like this Symfony\Bundle\TwigBundle\TwigEngine $templating instead of Symfony\Component\DependencyInjection\ContainerInterface $container.

    P.S: You can search for services via php bin/console debug:container command.