Note
The dummy data in this example is intended to speed up copy and paste for a real, buildable example package. Remember to change it with your own before release.
Metadata Files
Extensions are recommended to be published as individual, reusable Fusion
packages that other packages can depend on as needed. To initialize such
a package, create the production metadata file fusion.json with the
following content:
{
"name": "Runner",
"description": "Custom Reflex runner.",
"id": "custom/runner",
"version": "0.1.0",
"structure": {
"/dependencies": "valvoid.com/valvoid/reflex/1.0.0",
"/state": "stateful"
},
"environment": {
"php": {
"version": "8.2.0"
}
}
}
In addition, create the shareable development metadata file fusion.dev.php
with the following content:
return [
"structure" => [
"/configs/reflex.php" => ":valvoid/reflex/config"
]
];
Build the project for the next sections by running:
fusion build
Notable files in the project structure afterward:
dependencies/valvoidbox: DI container the framework uses for abstractionreflex: Reflex package
state: Generated filesfusion.dev.phpfusion.json
Interface Implementation
The downloaded Reflex package provides the interface
Valvoid\Reflex\Runners\Runner for normalized runner interactions. Create
the file CustomRunner.php in the src directory with a class that
implements this interface:
namespace Custom\Runner;
use Valvoid\Box\Box;
use Valvoid\Reflex\Runners\Runner;
class CustomRunner implements Runner
{
public function __construct(
private Box $box,
private array $config)
{
// constructor is optional
// only required if you need deps or config
}
public function execute(): bool
{
// consume runner config
echo $this->config["example"];
// all tests successful
return true;
}
}
Now generate the code prefix that Reflex uses internally for autoloading:
fusion build
Notable files in the project structure afterward:
dependencies/valvoid/reflex: Frameworkstate/prefixes.php: Prefix (Custom\Runner=>/src)
src: Exposed autoload dirCustomRunner.php: Custom runner
As mentioned in the previous section, Reflex uses the
Box dependency
injection container for abstraction across the framework. In addition to
instantiable parameters like $box itself (shared instance) or any of your
custom code, the runner $config from the next section can be consumed
as a default constructor argument, since Reflex binds this configuration to
the argument name config:
$this->box->inject(CustomRunner::class,
// inject argument if required
// when creating the runner object
config: $config)
Note
Default arguments are optional. Box passes default arguments by name only if the constructor defines such a parameter. Otherwise, the class is instantiated without them.
For interaction with custom tests, use the Valvoid\Reflex\Test\Interactor
class. It simplifies test execution by abstracting logic, similar
to how Valvoid\Reflex\Test\Wrapper abstracts logic on the test side:
$interactor = $this->box->get(Interactor::class,
// required on-demand argument
test: AnyCustomTest::class)
For code coverage, use the Valvoid\Reflex\Coverage\Coverage class:
$coverage = $this->box->get(Coverage::class,
// required on-demand arguments
// empty array if nothing to ignore
ignore: $config,
code: $config)
Note
Coverage requires absolute file paths.
Explicit Config Entry
Reflex organizes tests by runner configuration and uses the default
test runner
for all configs unless an explicit runner is set. To use the custom runner
from this example, create the file reflex.php in the configs directory
with the following content:
use Custom\Runner\CustomRunner;
return [
"extension" => [
"runner" => CustomRunner::class,
// whatever custom entries
"example" => "###"
]
];
Notable files in the project structure afterward:
configs: All configsreflex.php: Mapped custom runner config
The runner key is the only required entry. All other key-value pairs can
be set freely. If you run the configured command, you should see the
example output ###:
php dependencies/valvoid/reflex/reflex extension
Custom CLI File
To shorten the previous command, create the file reflex in your project
root with the following content:
require __DIR__ . "/dependencies/valvoid/reflex/reflex";
This allows you to interact with Reflex without referencing the dependency path directly:
php reflex extension
Separated Environments
Remember to ignore local files and exclude development files in VCS:
configs: Developmentdependencies: Localsrc: Productionstate/snapshot.json: Developmentfusion.dev.php: Developmentfusion.json: Productionreflex: Development