search hotlink icon profile hotlink icon
Re Public | 1.1.x - 1.x.x

On This Page

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/valvoid
    • box: DI container the framework uses for abstraction
    • reflex: Reflex package
  • state: Generated files
  • fusion.dev.php
  • fusion.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: Framework
    • state/prefixes.php: Prefix (Custom\Runner => /src)
  • src: Exposed autoload dir
    • CustomRunner.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 configs
    • reflex.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: Development
  • dependencies: Local
  • src: Production
  • state/snapshot.json: Development
  • fusion.dev.php: Development
  • fusion.json: Production
  • reflex: Development