0

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 ?

DLzer
  • 159
  • 11

1 Answers1

1

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();
odan
  • 4,757
  • 5
  • 20
  • 49
  • 1
    You're the man odan! Love your Slim blogs. I understand now that you have to pull in bootstrap to invoke the container to use the class. Curious question, why would Smyfony Console be the 'real' way to go? Both seem privy to utilizing the container in the same manner. Thanks again. – DLzer May 10 '21 at 11:57
  • 1
    Thanks for your feedback :-) You ask for a "a tried and true way of performing this". I really like your minimal console approach. What I see in my daily business is that Symfony console is the post popular and used so far. If you don't need it, then don't use it. – odan May 10 '21 at 18:06