phpcronslimphp-di

How would I run a cron using auto-wired classes


I'm currently building out an application that uses Slim v4 and PHP-DI for auto-wiring dependencies. This is fantastic besides the fact that I need to build a CRON that utilizes some classes that are auto-wired. Here's my example:

class NotificationService
{

    private $notification;

    public function __construct( NotificationFactory $notificationFactory )
    {
        $this->notification = $notificationFactory;
    }
}

In this case the Notification Service is auto-wired to use the Notification Factory, which is great. But I need to create a CRON that utilizes the NotificationService for sending notifications:

class TimedNotification
{

    private $notification;

    public function __construct( NotificationService $notificationService )
    {
         $this->notification = $notificationService;
    }


    public function sendNotification(): bool
    {
        $sent = $this->notification->sendMessage( 'This message is a test.' );
        return $sent;

    }

}

// Separate File
$timedNotification = new TimedNotification();
$timedNotification->sendMessage();

I'd like to be able to use a CRON to call the Timed notification file, or a separate file that has the TimedNotification instantiation like 0 23 * * * /my/dir/mycrons && php timednotifications.php

Is there a tried and true way of performing this, or would i have to build the entire app in a file to run the CRON ?


Solution

  • To autowire the dependencies, you have to use the DI container.

    Example:

    <?php
    
    use DI\ContainerBuilder;
    
    require_once __DIR__ . '/../vendor/autoload.php';
    
    class NotificationService
    {
        public function sendMessage(string $message): bool
        {
            echo $message . "\n";
    
            return true;
        }
    }
    
    class TimedNotification
    {
        private $notification;
    
        public function __construct(NotificationService $notificationService)
        {
            $this->notification = $notificationService;
        }
    
        public function sendNotification(): bool
        {
            $sent = $this->notification->sendMessage('This message is a test.');
    
            return $sent;
        }
    
    }
    
    $containerBuilder = new ContainerBuilder();
    
    // Add container definitions
    //$containerBuilder->addDefinitions(...);
    
    // Build PHP-DI Container instance
    $container = $containerBuilder->build();
    
    // Separate File
    $timedNotification = $container->get(TimedNotification::class);
    $timedNotification->sendNotification();
    

    Output:

    This message is a test.
    

    In a real world application a Symfony Console would be the "standard" way to go.

    File: bin\console.php

    <?php
    
    use Psr\Container\ContainerInterface;
    use Symfony\Component\Console\Application;
    use Symfony\Component\Console\Input\ArgvInput;
    
    require_once __DIR__ . '/../vendor/autoload.php';
    
    $env = (new ArgvInput())->getParameterOption(['--env', '-e'], 'development');
    
    if ($env) {
        $_ENV['APP_ENV'] = $env;
    }
    
    /** @var ContainerInterface $container */
    $container = (require __DIR__ . '/../config/bootstrap.php')->getContainer();
    
    $application = $container->get(Application::class);
    
    // Add custom commands
    // See: https://symfony.com/doc/current/console.html#creating-a-command
    
    $application->add($container->get(MyCustomCommand::class));
    $application->add($container->get(MySecondCommand::class));
    // ...
    
    $application->run();