This tutorial outlines the integration of custom tests within the Site Health dashboard introduced in Concrete CMS version 9.2.0. Extending the existing Site Health functionalities allows developers to introduce bespoke tests tailored to specific needs, thereby enhancing the operational efficiency and monitoring capabilities of websites.In this tutorial, we will create a custom Site Health report in a package.
A full working example can be found as an installable package on GitHub: https://github.com/concretecms/site_health_report_example
Background
Site Health Dashboard introduced in version 9.2 includes three default reports: JavaScript scanner to check content for custom JavaScript, Production Mode readiness to asses whether any settings should be changed to safely run a production site (such as turning off debug mode), and Caching Mode readiness to assess how performant a site is going to be. The outcome of the checks depends on whether the site is set to production, staging, or development mode. Likewise, when a site is switched to production mode, running the Site Health checks will be an available option.
Afte the checks run, a report will be generated and kept for future reference. Any suboptimal findings can be corrected from the report by selecting the links for each finding.
This dashboard is designed to be extended with custom checks or tests to meet a site's specific needs. Each test is a Task behind the scenes, so understanding how they work is important.
Package Controller
Setup Package Controller (controller.php
):
- Creating a new package, or modifying an existing one, by declaring the namespace, dependencies, and package propertie in controller.php
- In the on_start()
method, register the custom health report with the task manager.
namespace Concrete\Package\SiteHealthReportExample;
use Concrete\Core\Package\Package;
use Concrete\Core\Command\Task\Manager as TaskManager;
use Concrete\Example\SiteHealthReport\Command\Task\Controller\SiteHealthReportExampleController;
class Controller extends Package {
protected $pkgHandle = 'site_health_report_example';
protected $appVersionRequired = '9';
protected $pkgVersion = '0.1';
protected $pkgAutoloaderRegistries = ['src' => '\Concrete\Example\SiteHealthReport'];
public function on_start() {
$manager = $this->app->make(TaskManager::class);
$manager->extend('custom_site_health_report_example', function() {
return new SiteHealthReportExampleController($this->getEntityManager());
});
}
public function install()
{
parent::install();
$this->installContentFile('install' . DIRECTORY_SEPARATOR . 'tasks.xml');
}
}
Task Controller
Implement the Report Controller (src/Command/Task/Controller/SiteHealthReportExampleController.php
):
- Define the controller class that implements the Site Health report. This class should specify the name, description, command name, test suite, and grader.
namespace Concrete\Example\SiteHealthReport\Command\Task\Controller;
use Concrete\Core\Health\Report\ReportController;
use Concrete\Core\Health\Report\Test\SuiteInterface;
use Concrete\Example\SiteHealthReport\Health\Report\Test\Suite\ExampleSuite;
class SiteHealthReportExampleController extends ReportController
{
public function getName(): string
{
return t('Custom Site Health Report Example');
}
public function getConsoleCommandName(): string
{
return 'health:custom-report-example';
}
public function getDescription(): string
{
return t('Demonstrates how to add a custom Site Health report to a package.');
}
public function getTestSuite(): SuiteInterface
{
return new ExampleSuite();
}
public function getResultGrader(): ?GraderInterface
{
return new ProductionGrader();
}
}
Define the Tests
Create Tests (src/Health/Report/Test/Test/CheckDayOfWeekTest.php
):
Each test should implement TestInterface
and define its behavior within the run
method. This example test is not useful; it just randomly selects a day of the week and compares it with the actual day of the week, however it shows how the test can return success or a warning.
namespace Concrete\Example\SiteHealthReport\Health\Report\Test\Test;
use Concrete\Core\Config\Repository\Repository;
use Concrete\Core\Health\Report\Runner;
use Concrete\Core\Health\Report\Test\TestInterface;
use Concrete\Example\SiteHealthReport\Health\Report\Finding\Control\Location\DashboardWelcomeLocation;
use DateTime;
class CheckDayOfWeekTest implements TestInterface
{
protected $config;
public function __construct(Repository $config)
{
$this->config = $config;
}
public function run(Runner $report): void
{
$results = [
1 => 'Monday',
2 => 'Tuesday',
3 => 'Wednesday',
4 => 'Thursday',
5 => 'Friday',
6 => 'Saturday',
7 => 'Sunday'
];
$result = (string) rand(1, count($results));
$dow = (new DateTime())->format('N');
if ($result === $dow) {
$report->success(
"Random day ({$results[$result]}) is the same as today ({$results[$dow]}).",
$report->button(new DashboardWelcomeLocation())
);
}
else {
$report->warning(
"Random day ({$results[$result]}) is not the same as today ({$results[$dow]}).",
$report->button(new DashboardWelcomeLocation())
);
}
}
}
Define links to resolve test issues
In the above example, a link is provided to the Dashboard Welcome page to further investgate or resolve the issue. This is accomplished by extending DashboardPageLocation
:
namespace Concrete\Example\SiteHealthReport\Health\Report\Finding\Control\Location;
use Concrete\Core\Health\Report\Finding\Control\DashboardPageLocation;
class DashboardWelcomeLocation extends DashboardPageLocation
{
public function getPagePath(): string
{
return '/dashboard/welcome';
}
public function getName(): string
{
return 'Dashboard Welcome';
}
}
Define the Test Suite
Create Test Suites (src/Health/Report/Test/Suite/ExampleSuite.php
):
A test suite aggregates multiple tests. Like the example test in the previous section, these tests are just silly examples to show how they can be collected into a suite of tests.
namespace Concrete\Example\SiteHealthReport\Health\Report\Test\Suite;
use Concrete\Core\Health\Report\Test\Suite;
use Concrete\Example\SiteHealthReport\Health\Report\Test\Test\CheckRandomTest;
use Concrete\Example\SiteHealthReport\Health\Report\Test\Test\CheckTimeTest;
use Concrete\Example\SiteHealthReport\Health\Report\Test\Test\CheckDayOfWeekTest;
class ExampleSuite extends Suite
{
public function __construct()
{
$tests = [
CheckDayOfWeekTest::class,
CheckRandomTest::class,
CheckTimeTest::class,
];
foreach ($tests as $test) {
$this->add($test);
}
}
}
Register Tasks and Task Sets
XML Configuration (install/tasks.xml
):
- This XML file will be used during the installation or upgrade of the package to register new tasks and task sets within the system.
<concrete5-cif version="1.0">
<tasks>
<task handle="custom_site_health_report_example" package="site_health_report_example"/>
</tasks>
<tasksets>
<taskset handle="site_health">
<task handle="custom_site_health_report_example"/>
</taskset>
</tasksets>
</concrete5-cif>
Final Steps:
- Install or Upgrade the Package: install or upgrade the package through the dashboard to register the new tasks.
- Testing: After installation, test your Site Health report by navigating to the Dashboard's health section or using the CLI command
concrete/bin/concrete5 c5:health:custom-report-example
to run the test suite.