Using Laminas in a cron job

Sooner or later, every bigger project needs cron jobs for background operations, maintenance or some periodical reports etc. If you are beginning with Laminas framework, it maight not be straight obvious how to use Laminas in a cron file, so you can access services and configured view renderer and other properties.

For example ... let’s have cron file daily-report.php that should select some data from database, create e-mail body and send e-mail. This could be useful for daily e-mail reports.

Directory structure on server could look like this, with Document root pointing to /public folder.

├── CRON.1h
├── CRON.day
│   └── daily-report.php
├── CRON.week
├── domain.com
│   └── data
│       └── log
│   └── public
│       └── index.php

In Laminas MVC skeleton index.php small update is needed where Application::init() is placed. Constant IS_CLI will be defined in a cron file.

File index.php

// Run the application!
if (! defined('IS_CLI') || IS_CLI == false) {
    Application::init($appConfig)->run();
}        

In the cron file we request model service and view renderer from our application, create e-mail body and pass it to Laminas mailer. Note, it is a good habit to log the process, so we have control that cron script runs regularly.

Cron file daily-report.php

<?php
use Laminas\Mvc\Application;

define('IS_CLI', true);
define('APP_ENV', 'development');

$webRoot = __DIR__ . '/../domain.com';
require $webRoot . '/public/index.php';

$application = Application::init($appConfig);

$writer = new Laminas\Log\Writer\Stream($webRoot . '/data/log/cron_daily_report.log');
$logger = new Laminas\Log\Logger();
$logger->addWriter($writer);

try {
    $dateTime = new DateTime();
    $modelUsersActions = $application->getServiceManager()->get(User\Model\UsersActionsLogTable::class);
    $viewRenderer = $application->getServiceManager()->get('ViewRenderer');

    $htmlBody = $viewRenderer->render('application/cron/messageUserReport',
        array(
            'report' => $modelUsersActions->dailyUserAction($dateTime->format('Y-m-d'))
        ));

    if(empty($htmlBody)) {
        throw new Exception('E-mail body is empty.');
    }

    $partHtml = new Laminas\Mime\Part($htmlBody);
    $partHtml->type = Laminas\Mime\Mime::TYPE_HTML;
    $partHtml->charset = 'UTF-8';

    $mimeMessage = new Laminas\Mime\Message();
    $mimeMessage->setParts(array(
        $partHtml
    ));

    $message = new Laminas\Mail\Message();
    $message->addFrom('...');
    $message->addTo('...');
    $message->setSubject('Daily report ' . $dateTime->format('d. m.'));
    $message->setEncoding('UTF-8');
    $message->setBody($mimeMessage);

    if (false === $message->isValid()) {
        throw new \UnexpectedValueException('E-mail message is not valid. Mail failed.');
    }

    $transport = new Laminas\Mail\Transport\Sendmail();
    $transport->send($message);

    $logger->info($htmlBody);
    $logger->info('Report send.');

} catch (\Exception $e) {
    $logger->crit($e->getMessage() . ' -> ' . $e->getTraceAsString());
}