Hi @odan,
many thanks for this tip around translations and middleware. I have added a new middleware that does the trick for me.
Now, from the action controller I’m able to get translations I want with a single line, i.e:
var_dump($request->getAttribute('i18n'));
what is just awesome.
For others, as they may be interested in similiar solution:
Container:
...
Translations::class => function (ContainerInterface $container) {
$app = $container->get(App::class);
$settings = $container->get('settings')['translations'];
return new Translations($settings['default_locale']);
},
TranslationMiddleware::class => function (ContainerInterface $container) {
return TranslationMiddleware::create(
$container->get(App::class),
Translations::class
);
},
A single line to a Middleware.php stack was added:
$app->add(TranslationMiddleware::class);
MiddlewareTranslation.php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Interfaces\RouteParserInterface;
use Slim\Routing\RouteContext;
use RuntimeException;
use App\Factory\Translations;
use Slim\App;
class TranslationMiddleware implements MiddlewareInterface {
protected $i18n;
public static function create(App $app, string $containerKey = 'i18n'): self
{
$container = $app->getContainer();
if ($container === null) {
throw new RuntimeException('The app does not have a container.');
}
if (!$container->has($containerKey)) {
throw new RuntimeException(
"The specified container key does not exist: $containerKey"
);
}
$tr = $container->get($containerKey);
if (!($tr instanceof Translations)) {
throw new RuntimeException(
"Translations instance could not be resolved via container key: " . $containerKey
);
}
return new self(
$tr
);
}
public function __construct(Translations $tr) {
$this->i18n = $tr;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$routeContext = RouteContext::fromRequest($request);
$route = $routeContext->getRoute();
$phrases = $this->i18n->getTranslations($route->getName(), $this->i18n->get_locale());
$request = $request->withAttribute('i18n', $phrases);
return $handler->handle($request);
}
}
However, I think I need to better describe my need with the logger in order to get a further piece of an advice from you. The objective I have against the logger is simple: write all important information about the application state throughout its entire lifecycle. So I would like to use info(), warning() and other functions in many different places, logging contextaul details as well as the same information regardless where logger is used: (request method, http code, route etc.).
Would you still also create a middleware for the logger and create an instance of the logger in the process()
method, where you also define filehandler and push processors? So something similar to this:
public function __construct(LoggerFactory $l) {
$this->factory = $l;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$routeContext = RouteContext::fromRequest($request);
$route = $routeContext->getRoute();
$this->logger = $this->factory
->addExtras($route) // to extract all pieces I want and then use pushProcessor()
->addFileHandler('application.log')
->createLogger();
$request = $request->withAttribute('log', $this->logger);
return $handler->handle($request);
}
Is this the way forward? Your 5 cents are more than welcome