How to pass app directory paths to services
In this very short article, I will show you 2 simple ways how to pass directory constants to services, it's very elementary thing that most of you know, but it never hurts to see it again.
Let's say we have CronTaskExecutor
for executing cron tasks
from database via shell_exec
function that needs path to our
application, as you can see, that service require $logger
service
from DI container and $appDir
string that we must pass from our
configuration file.
class CronTaskExecutor
{
public function __construct(
private Logger $logger,
private string $appDir,
) {}
}
services:
- CronTaskExecutor(appDir: %appDir%)
It's not necessary to add services to configuration manually, since we have
built-in
search extension for registering our classes as services automatically based
on suffixes such as Facade, Repository, Factory, Executor, Manager, Sender,
Helper and so on. And the only reason we had to edit configuration file was
because we needed to pass the %appDir%
constant.
Imagine you have pretty large project, and you often have to use directory
paths like %tempDir%
%appDir%
or
%vendorDir%
and maybe your custom directory paths for backups,
media and so on. Every time you need some directory path, you would have to add
service to your configuration.
Straightforward solution to avoid this, is to create service that will
provide all important project directories for other services and register it
only once, and when service needs some directory path, we will simply inject our
DirectoryProvider
service. This is an example service class with
added $backupDir
:
(PHP 8.1 readonly properties are used only to avoid long class with getters in this article.)
declare(strict_types=1);
namespace App\Model;
class DirectoryProvider
{
public readonly string $backupDir;
public function __construct(
public readonly string $appDir,
public readonly string $tempDir,
public readonly string $vendorDir,
) {
$this->backupDir = $this->appDir . '/../backups';
}
}
and now we have to register that service in the configuration file like this:
services:
- App\Model\DirectoryProvider(
appDir: %appDir%,
tempDir: %tempDir%,
vendorDir: %vendorDir%,
)
So with that service, we'll no longer need to add services that works with
app directories to our configuration file, because now we can inject our
DirectoryProvider
instead and use
$this->directoryProvider->appDir
.
class CronTaskExecutor
{
public function __construct(
private Logger $logger,
private DirectoryProvider $directoryProvider,
) {}
public function execute(CronTask $task): void
{
$appDir = $this->directoryProvider->appDir;
}
}
Final thoughts
The only reason I have used the new syntax from PHP 8.1 (will be released
soon) in example is only to simplify class and spare some space in article,
I still prefer syntax with getters, the reason is that you can pass some
parameters to the method, for instance
getMediaDir(MediaType::Images)
, and when you decide to do that and
you will be already using public readonly properties, it will bring a little
inconsistency.
Sign in to submit a comment