Configuration

Canvas follows convention-over-configuration. It works immediately with zero setup - create config files only when you need to override defaults.

Simple Configuration

Canvas works out of the box. Add config files only for custom settings:

// config/database.php
return [
    'driver'   => 'mysql',
    'host'     => 'localhost',
    'database' => 'canvas',
    'username' => 'root',
    'password' => '',
];

Automatic Service Discovery

Register configuration through Composer metadata - Canvas discovers and loads it automatically:

// composer.json
{
  "extra": {
    "discover": {
      "canvas": {
        "providers": [
          {
            "class": "Quellabs\\Canvas\\Discover\\DatabaseServiceProvider",
            "config": "config/database.php"
          }
        ]
      }
    }
  }
}

Package Auto-Discovery

Install packages - Canvas detects and configures them automatically:

composer require quellabs/canvas-twig      # Auto-configures Twig
composer require quellabs/canvas-blade     # Auto-configures Blade
composer require quellabs/canvas-redis     # Auto-configures Redis

Contextual Configuration

Use different implementations of the same interface in different contexts. The `for()` method creates isolated configuration scopes:

// Same interface, different implementations
$twig = $this->container->for('twig')->get(TemplateEngineInterface::class);
$blade = $this->container->for('blade')->get(TemplateEngineInterface::class);

// Same interface, different storage backends
$redis = $this->container->for('redis')->get(CacheInterface::class);
$file = $this->container->for('file')->get(CacheInterface::class);

Aspect Configuration

Configure aspects through annotation parameters:

/**
 * @InterceptWith(CacheAspect::class, ttl=3600, tags={"reports", "admin"})
 * @InterceptWith(RateLimitAspect::class, limit=10, window=60)
 */
public function heavyOperation() {
    // Cached for 1 hour with tags, rate limited to 10/minute
}

Custom Service Providers

Create discoverable service providers for custom configuration. Access config through the injected config parameter:

class PaymentServiceProvider extends ServiceProvider {

    public function supports(string $className, array $context = []): bool {
        return
            $className === PaymentInterface::class &&
            ($context['provider'] ?? null) === 'stripe';
    }

    public function createInstance(string $className, array $dependencies, array $config): object {
        return new StripePaymentService($config['api_key']);
    }
}

Zero Configuration Example

This works immediately without any setup:

class HomeController extends BaseController {

    /**
     * @Route("/")
     */
    public function index() {
        return $this->render('home.tpl');
    }
}