there has been a lot of time questions on how to use logger (Monolit) in the router.php file, that comes out the box when running slim from Docker, under shinsenter/slim:latest image.
The answers on the web are sometimes confusing and sometimes pointing to different versions. After reading and doing some trial and error, here is my fast and dirty solution to this problem.
<?php
declare(strict_types=1);
use App\Application\Actions\DB\DB;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;
use Slim\Interfaces\RouteCollectorProxyInterface as Group;
use Psr\Log\LoggerInterface;
return function (App $app) {
$container = $app->getContainer();
$logger = $container->get(LoggerInterface::class);
$app->get('/', function (Request $request, Response $response) use ($logger) {
$response->getBody()->write('Hello world!');
$logger->info("/ GET was called.");
return $response;
});
when using RouteCollectorProxyInterface as $group, you can use this:
<?php
declare(strict_types=1);
use App\Application\Actions\DB\DB;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;
use Slim\Interfaces\RouteCollectorProxyInterface as Group;
use Psr\Log\LoggerInterface;
return function (App $app) {
$app->group('/api', function (Group $group) use ($app) {
$container = $app->getContainer();
$logger = $container->get(LoggerInterface::class);
$group->options('/{routes:.*}', function (Request $request, Response $response) {
// CORS Pre-Flight OPTIONS Request Handler
return $response;
});
$group->get('/', function (Request $request, Response $response) use ($logger) {
$response->getBody()->write('Hello world!');
$logger->info("/api/ GET was called");
return $response;
});
I just hope it helps someone, as it took me some time to figure this out.
Hi,
sorry to coming to this after some months, but is there a way to call loggerInterface from a PHPMailer Support Class, like presented in this post: PHPMailer Example?
I tried your initial injection, and it didnât work. I must say, that this injections stuff is not very intuitive to me.
I tried your initial injection, and it didnât work.
Sorry to hear that. Could you share more details?
I must say, that this injections stuff is not very intuitive to me.
The concept of dependency injection is to declare all required classes and interfaces within the class constructor. The DI container will then create and inject these objects. Itâs a straightforward and efficient way to manage object dependencies.
Using functions (closures) as routing handlers means that you cannot benefit from the concept of DI. The non-class based approach (closures as routing handler) can become unmaintainable in the long run as you have to manually create, wire, and pass everything together.
<?php
namespace App\Application\Actions\Support;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
use Psr\Log\LoggerInterface;
use Slim\App;
class Mailer
{
private $host;
private $username;
private $password;
private $port;
private $from_email;
private $from_name;
private $mail;
private $logger;
public function __construct()
{
$this->mail = new PHPMailer(true);
$this->logger = new LoggerInterface();
$this->logger->info("mail was initialiazed");
}
The error here is: âCannot instantiate interface Psr\Log\LoggerInterfaceâ, which makes sense, I guess.
I also tried this:
[...]
public function __construct()
{
$this->mail = new PHPMailer(true);
$this->logger = $this->get(LoggerInterface::class);
$this->logger->info("/ GET was called.");
}
Here the msg is: Call to undefined method App\Application\Actions\Support\Mailer::get(), which also makes sense.
The DI container will then create and inject these objects.
When you say inject, do you mean initialize it in the background and make them available? Are they then treated as static classes overall? and who is the âparentâ that manages the DI, is it Slim\App? If you have other sources or code that I can look at, you can also point me to that.
The DI container itself also acts as a âfactoryâ that can create these objects either automatically (autowiring) or manually using factoring definitions (plain functions).
In your case I would recommend to create a DI container definition for Psr\Log\LoggerInterface::class and PHPMailer::class.
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
return [
LoggerInterface:class => function (ContainerInterface $container) {
return new Logger(...);
},
PHPMailer::class => function (ContainerInterface $container) {
$mailer = new PHPMailer(...);
// ...
return $mailer;
}),
];
Note that the PHPMailer is now âsharedâ. So when you need to send multiple mails at once, I would recommend to implement a custom MailerFactory instead.
Then just declare these dependencies within a Service class when needed:
final class MyService
{
private LoggerInterface $logger;
private PHPMailer $mailer;
public function __construct(PHPMailer $mailer, LoggerInterface $logger)
{
$this->mailer = $mailer;
$this->logger = $logger;
}
// your business logic
}