Paul
Paul

Reputation: 1400

get getEnvironment() from a service

In my notification service I have to send the notifications by mail, but in dev I want to send all the email to a specific adress:

if ( $this->container->get('kernel')->getEnvironment() == "dev" ) {

    mail( '[email protected]', $lib, $txt, $entete );

} else {

    mail( $to->getEmail(), $lib, $txt, $entete );

}

But the $this->container->get('kernel')->getEnvironment() works only in a controller.

I think I have to add an argument in my service constructor:

notification:
  class:      %project.notification.class%
  arguments: [@templating, @doctrine]

But I didn't find any information about this.

Upvotes: 37

Views: 77471

Answers (11)

Maciej Paprocki
Maciej Paprocki

Reputation: 1379

You can now use autowiring using atributes:

use Symfony\Component\DependencyInjection\Attribute\Autowire;

class Something {

    public function __construct(
        #[Autowire('%kernel.environment%')]
        private string $env,
    ) {}

}

Also, if you are using service dependent on env, it's generally nicer to swap services or decorate them. ( it's often though purist exercise )

So you would either have two services dev and non dev and inject one depending on env, or you would have decorator that is only added in one env.

If you are speaking strictly about email, though, using mailtrap or self hosted version is highly advised.

Upvotes: 0

delirehberi
delirehberi

Reputation: 522

You can get all environments in .env file with $_ENV superglobal, thanks to dotenv

$_ENV['APP_ENV']

Upvotes: 4

Artem
Artem

Reputation: 1666

If you use the Symfony Mailer component to send emails. You don't need to get the environment. Just define a new env variable that contains your specific address and put it in the EnvelopeListener

service.yaml

mailer.set_recipients:
    class: Symfony\Component\Mailer\EventListener\EnvelopeListener
    tags: ['kernel.event_subscriber']
    arguments:
        $sender: null
        $recipients: '%env(json:ALL_MAIL_RECIPIENT)%'

.env

ALL_MAIL_RECIPIENT='[]'

.env.local

ALL_MAIL_RECIPIENT='["[email protected]"]'

Upvotes: 0

Grezor
Grezor

Reputation: 251

I would like to have a return of my code.

.env.local :

API_KEY_TOTO="azerty" 

But it is possible to pass the environment variable in the service.yml file. Here is an example

config/services.yaml

App\Service\MyService:
  bind:
      $apiKeyToto: '%env(API_KEY_TOTO)%'

App\Service\MyService.php :

class MyService {

private $client;
private $apiKeyToto;

public function __construct(HttpClientInterface $client, string $apiKeyToto)
{
    $this->client = $client;
    $this->apiKeyToto= $apiKeyToto;
}

public function getAllRepository(): array
{
    return $this->getApi('/users/{username}/repos?&type=all&direction=desc&per_page=100');
}

private function getApi(string $url)
{
    $response = $this->client->request('GET', 'https://api.github.com' . $url, [
            'auth_basic' => ['username', $this->apiKeyToto],
        ]
    );

    return $response->toArray();
}

}

If you have any other suggestions.

Upvotes: 0

Andrew Zhilin
Andrew Zhilin

Reputation: 1708

In symfony you can bind default value by $variableName.

config/services.yaml

services:
    _defaults:
        bind:
            $kernelEnvironment: '%kernel.environment%'

NotificationService.php

private $env;

public function __construct($kernelEnvironment)
{
    $this->env = $kernelEnvironment;
}

Upvotes: 2

Yoan Arnaudov
Yoan Arnaudov

Reputation: 4154

Actually you should not need to get the actual environment. For example if you need to send slack notifications only on production you can configure send_slack_notification parameter and set it to true/false in the different environments.

Then in your code you can do something like:

if ($parameters->get('send_slack_notification') == true) {
    //send the notifications
}

By using this approach you can later turn on/off this setting in different environments without changing your implementation. Another benefit is that when you check your parameters file you can right away see all the options in the different environments and this will make debugging easier.

NOTE

KernelInterface $kernel->getEnvironment() can return both lowercase and uppercase results depending on how you've configured in your .env files. Another reason why you should't use it.

Upvotes: 2

Ricardo Almira
Ricardo Almira

Reputation: 89

If you are into a static class and don't have access to the container, you always can do this inside the AppKernel.php->registerBundles():

$_ENV['APP_ENV'] = $this->getEnvironment();

That way you will always have the environment inside the superglobal $_ENV.
It's kinda a hack, but works like a charm.

Upvotes: 0

CasualBen
CasualBen

Reputation: 909

For Symfony 4 you could do:

use Symfony\Component\HttpKernel\KernelInterface;

class SomeService
{
    /**
     * @var string
     */
    private $environment;

    /**
     * Your Service constructor.
     */
    public function __construct(KernelInterface $kernel)
    {
        $this->environment = $kernel->getEnvironment();
    }
}

$this->environment now holds your environment like dev, prod or test.

Upvotes: 39

Toni
Toni

Reputation: 1852

In Symfony 4 (maybe 3.x, too) you can fetch the environment in a controller like this:

$env = $this->getParameter('kernel.environment');

(No explicit controller injection via services.yaml needed)

Upvotes: 8

rokas
rokas

Reputation: 1591

There is no need to inject container. In fact, it is not a good idea to inject container because you're making your class dependent on the DI.

You should inject environment parameter:

services.yml

notification:
  class:      NotificationService
  arguments: ["%kernel.environment%"]

NotificationService.php

<?php

private $env;

public function __construct($env)
{
    $this->env = $env;
}

public function mailStuff()
{
    if ( $this->env == "dev" ) {
        mail( '[email protected]', $lib, $txt, $entete );  
    } else {
        mail( $to->getEmail(), $lib, $txt, $entete );
    }
}

Upvotes: 70

Alex L
Alex L

Reputation: 651

The reason you can get $this->container in a controller is because it is injected into the controller that you extend.

For example, you could inject in the container and set it up in your constructor.

services.yml

notification:
  class:      %project.notification.class%
  arguments: [@templating, @doctrine]

NotificationService.php

<?php

private $container;

public function __construct()
{
    $this->container = $container;
}

public function mailStuff()
{
    if ( $this->container->get('kernel')->getEnvironment() == "dev" ) {
        mail( '[email protected]', $lib, $txt, $entete );  
    } else {
        mail( $to->getEmail(), $lib, $txt, $entete );
    }
}

Have a look at dependency injection for more information.


PLEASE NOTE

Generally, injecting in the container is bad and means there is a better way to do something. In this case, Symfony already has the solution that we're trying to solve.

Enter SwiftMailer.

And specifically, the section on sending all dev emails to a set address.

Give it a go at setting up Swiftmailer and add the following to your dev config.

app/config/config_dev.yml

swiftmailer:
    delivery_address: '[email protected]'

Upvotes: 5

Related Questions