Support Module
The Support module provides essential utilities, decorators, and helper functions that underpin Orchestr's dependency injection system, routing capabilities, and overall framework functionality.
Overview
The Support module (src/Support/) contains foundational utilities that enable core Orchestr features:
@Injectable() Decorator
Enables automatic dependency injection via TypeScript reflection
Helper Functions
Laravel-style global utilities for path resolution and route loading
Facade System
Static proxy pattern for elegant service access
These utilities work together to provide a familiar Laravel developer experience while leveraging TypeScript's type system and decorator metadata capabilities.
@Injectable() Decorator
The @Injectable() decorator is the cornerstone of Orchestr's dependency injection system. It marks classes for automatic constructor-based dependency injection.
TypeScript Decorators
Basic Usage
import { Injectable } from '@orchestr-sh/orchestr';
@Injectable()
export class UserService {
constructor(
private database: DatabaseService,
private logger: Logger,
private cache: CacheService
) {
// Dependencies automatically injected
}
async createUser(userData: CreateUserDto) {
this.logger.info('Creating user', userData);
const user = await this.database.insert('users', userData);
await this.cache.set(`user:${user.id}`, user);
return user;
}
}Dependency Resolution
When the container resolves an @Injectable() class, it automatically:
- Inspects the constructor parameters using TypeScript metadata
- Resolves each dependency from the container
- Creates the class instance with all dependencies injected
- Caches the instance for singleton services
Configuration Options
// Basic injectable
@Injectable()
export class BasicService {}
// Injectable with specific binding name
@Injectable('user.service')
export class NamedService {}
// Injectable as singleton
@Injectable({ singleton: true })
export class SingletonService {}
// Injectable with factory function
@Injectable({ factory: true })
export class FactoryService {
constructor(database: DatabaseService) {
this.database = database;
}
static create(container: Container) {
const database = container.make<DatabaseService>('database');
return new FactoryService(database);
}
}Helper Functions
The Support module includes Laravel-style helper functions that make common operations easier:
Path Helpers
import { path, base_path, public_path, storage_path } from '@orchestr-sh/orchestr';
// Application root directory
const appPath = path(); // '/var/www/app'
// Application directory paths
const basePath = base_path(); // '/var/www/app/app'
const publicPath = public_path(); // '/var/www/app/public'
const storagePath = storage_path(); // '/var/www/app/storage'
// Relative path resolution
const configPath = path('config/app.json'); // '/var/www/app/config/app.json'
const viewsPath = base_path('views'); // '/var/www/app/app/views'
// Path joining and normalization
const fullPath = path.join(basePath(), 'storage', 'logs', 'app.log');String Helpers
import { str } from '@orchestr-sh/orchestr';
// String manipulation
const slug = str.slug('Hello World!'); // 'hello-world'
const camel = str.camel('hello_world'); // 'helloWorld'
const snake = str.snake('HelloWorld'); // 'hello_world'
const studly = str.studly('hello_world'); // 'HelloWorld'
// String testing
const isEmail = str.isEmail('user@example.com'); // true
const isUrl = str.isUrl('https://example.com'); // true
const isUuid = str.isUuid('123e4567-e89b-12d3-a456-426614174000'); // true
// String generation
const random = str.random(32); // 'a1b2c3d4...'
const uuid = str.uuid(); // '550e8400-e29b-41d4...'
const limited = str.limit('Very long string', 10); // 'Very long...'Array Helpers
import { arr } from '@orchestr-sh/orchestr';
// Array manipulation
const users = arr.add(users, newUser); // Add element
const unique = arr.unique(duplicateArray); // Remove duplicates
const shuffled = arr.shuffle(items); // Random shuffle
const first = arr.first(items); // First element
const last = arr.last(items); // Last element
// Array querying
const adults = arr.where(users, ['age', '>=', 18]);
const admins = arr.where(users, ['role', 'admin']);
const activeUsers = arr.where(users, ['status', 'active']);
// Array transformation
const names = arr.pluck(users, 'name'); // ['John', 'Jane', ...]
const grouped = arr.groupBy(users, 'department'); // Group by key
const sorted = arr.sortBy(users, 'name'); // Sort by keyFacade System
The Support module provides the foundation for the Facade pattern used throughout Orchestr:
Base Facade Class
export abstract class Facade {
private static app: Application;
private static resolvedInstances: Map<string, any> = new Map();
static setFacadeApplication(app: Application): void {
Facade.app = app;
}
protected static getFacadeAccessor(): string {
throw new Error('Facade does not implement getFacadeAccessor method.');
}
protected static resolveFacadeInstance(name: string): any {
if (Facade.resolvedInstances.has(name)) {
return Facade.resolvedInstances.get(name);
}
if (Facade.app) {
const instance = Facade.app.make(name);
Facade.resolvedInstances.set(name, instance);
return instance;
}
throw new Error('A facade root has not been set.');
}
protected static getFacadeRoot(): any {
return Facade.resolveFacadeInstance(this.getFacadeAccessor());
}
}Creating Custom Facades
// 1. Create your service
export class CacheService {
private cache: Map<string, any> = new Map();
get(key: string): any {
return this.cache.get(key);
}
set(key: string, value: any): void {
this.cache.set(key, value);
}
}
// 2. Create the facade
export class CacheFacade extends Facade {
protected static getFacadeAccessor(): string {
return 'cache';
}
}
// 3. Create the proxy export
export const Cache = new Proxy(CacheFacade, {
get(target, prop) {
const instance = (target as any).getFacadeRoot();
if (instance && typeof instance[prop] === 'function') {
return (...args: any[]) => instance[prop](...args);
}
return instance[prop];
}
}) as any;Facade Benefits
Configuration
Configure reflection and decorator support in your TypeScript project:
// tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"target": "ES2017",
"module": "commonjs",
"lib": ["ES2017", "dom"],
"strict": true
},
"include": ["src/**/*"]
}
// package.json
{
"dependencies": {
"reflect-metadata": "^0.1.13",
"@orchestr-sh/orchestr": "^1.0.0"
}
}Decorator Support
Best Practices
Dependency Injection
Use constructor injection over manual service resolution
Type Safety
Leverage TypeScript types for all injected dependencies
Singleton Services
Mark long-lived services as singletons for performance
Factory Patterns
Use factory functions for complex initialization logic
Testing
Mock dependencies in tests using container instances
Configuration
Enable decorators and metadata in TypeScript configuration