Modules

A Module is a collection of DI & AOP bindings that sets up your application.

BEAR.Sunday doesn’t have a global config file or a config class to set default values for components such as a database or a template engine. Instead for each peice of functionality we set up DI and AOP by injecting configuration values into a stand alone module.

AppModule (src/Module/AppModule.php) is the root module. We use an install() method in here to load each module that we would like to invoke.

You can also override existing bindings by using override().

class AppModule extends AbstractAppModule
{
    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        // ...
        // install additional modules
        $this->install(new AuraSqlModule('mysql:host=localhost;dbname=test', 'username', 'password');
        $this->install(new TwigModule));
        // install basic module
        $this->install(new PackageModule));
    }
}

DI bindings

Ray.Di is the core DI framework used in BEAR.Sunday. It binds interfaces to a class or factory to create an object graph.

// Class binding
$this->bind($interface)->to($class);
// Provider (factory) binding
$this->bind($interface)->toProvider($provider);
// Instance binding
$this->bind($interface)->toInstance($instance);
// Named binding
$this->bind($interface)->annotatedWith($annotation)->to($class);
// Singleton
$this->bind($interface)->to($class)->in(Scope::SINGLETON);
// Constructor binding
$this->bind($interface)->toConstructor($class, $named);

More info can be found at Ray.Di README

Binding Priority

See also: Ray.Di Bindings

Within a Single Module

Bindings declared first take priority. In the following example, Foo1 takes priority:

$this->bind(FooInterface::class)->to(Foo1::class);
$this->bind(FooInterface::class)->to(Foo2::class);

Module Installation Priority

Modules installed first take priority. In the following example, Foo1Module takes priority:

$this->install(new Foo1Module);
$this->install(new Foo2Module);

To give a later module priority, use override(). In the following example, Foo2Module takes priority:

$this->install(new Foo1Module);
$this->override(new Foo2Module);

Context String Priority

Context modules are processed in reverse order (right-to-left). For example, with context prod-hal-api-app:

Installation order: AppModule → ApiModule → HalModule → ProdModule

Later installed modules can override earlier bindings. This means:

  • HalModule takes priority over AppModule
  • ProdModule takes priority over HalModule

When creating a custom context module that needs to override bindings from a built-in context (like HalModule), position it to the left of that context in the context string. For example, to override HalModule’s RenderInterface binding:

// Context: "prod-mycontext-hal-api-app"
// Installation order: AppModule → ApiModule → HalModule → MycontextModule → ProdModule

AOP Bindings

We can “search” for classes and methods with a built-in Matcher, then interceptors can be bound to any found methods.

$this->bindInterceptor(
    // In any class
    $this->matcher->any(),
    // Method(s) names that start with "delete"
    $this->matcher->startWith('delete'),
    // Bind a Logger interceptor
    [LoggerInterceptor::class]
);

$this->bindInterceptor(
    // The AdminPage class or a class inherited from it.
    $this->matcher->SubclassesOf(AdminPage::class),
    // Annotated with the @Auth annotation
    $this->matcher->annotatedWith(Auth::class),
    // Bind the AdminAuthenticationInterceptor
    [AdminAuthenticationInterceptor::class]
);

Matcher has various binding methods.

Interceptor

In an interceptor a MethodInvocation object gets passed to the invoke method. We can the decorate the targetted instances so that you run computations before or after any methods on the target are invoked.

class MyInterceptor implements MethodInterceptor
{
    public function invoke(MethodInvocation $invocation)
    {
        // Before invocation
        // ...

        //  Method invocation
        $result = $invocation->proceed();

        //  After invocation
        // ...

        return $result;
    }
}

With the MethodInvocation object, you can access the target method’s invocation object, method’s and parameters.

Annotations can be obtained using the reflection API.

$method = $invocation->getMethod();
$class = $invocation->getMethod()->getDeclaringClass();
  • $method->getAnnotations()
  • $method->getAnnotation($name)
  • $class->getAnnotations()
  • $class->getAnnotation($name)

Environment Settings

BEAR.Sunday does not have any special environment mode except prod. A Module and the application itself are unaware of the current environment.

There is no way to get the current “mode”, this is intentional to keep the code clean.