- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
335 lines
9.2 KiB
PHP
335 lines
9.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* DefaultImplementation Attribute - Real-World Usage Examples
|
|
*
|
|
* This file demonstrates practical usage of the #[DefaultImplementation] attribute
|
|
* in a typical application structure.
|
|
*/
|
|
|
|
namespace App\Examples\DefaultImplementation;
|
|
|
|
use App\Framework\DI\Attributes\DefaultImplementation;
|
|
|
|
// =============================================================================
|
|
// Example 1: Repository Pattern
|
|
// =============================================================================
|
|
|
|
interface UserRepository
|
|
{
|
|
public function findById(string $id): ?User;
|
|
public function findAll(): array;
|
|
public function save(User $user): void;
|
|
}
|
|
|
|
/**
|
|
* Database implementation of UserRepository
|
|
* Automatically registered as default implementation
|
|
*/
|
|
#[DefaultImplementation(UserRepository::class)]
|
|
final readonly class DatabaseUserRepository implements UserRepository
|
|
{
|
|
public function __construct(
|
|
private DatabaseConnection $db
|
|
) {}
|
|
|
|
public function findById(string $id): ?User
|
|
{
|
|
// Database query implementation
|
|
return null; // Simplified
|
|
}
|
|
|
|
public function findAll(): array
|
|
{
|
|
return []; // Simplified
|
|
}
|
|
|
|
public function save(User $user): void
|
|
{
|
|
// Database insert/update implementation
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Example 2: Service Layer
|
|
// =============================================================================
|
|
|
|
interface NotificationService
|
|
{
|
|
public function send(string $recipient, string $message): void;
|
|
}
|
|
|
|
/**
|
|
* Email-based notification service
|
|
* Auto-detects NotificationService interface
|
|
*/
|
|
#[DefaultImplementation] // No explicit interface - auto-detect
|
|
final readonly class EmailNotificationService implements NotificationService
|
|
{
|
|
public function __construct(
|
|
private MailerService $mailer
|
|
) {}
|
|
|
|
public function send(string $recipient, string $message): void
|
|
{
|
|
$this->mailer->sendMail($recipient, 'Notification', $message);
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Example 3: Infrastructure Adapters
|
|
// =============================================================================
|
|
|
|
interface CacheAdapter
|
|
{
|
|
public function get(string $key): mixed;
|
|
public function set(string $key, mixed $value, int $ttl = 3600): void;
|
|
public function delete(string $key): void;
|
|
}
|
|
|
|
/**
|
|
* Redis cache adapter
|
|
* Automatically becomes the default cache implementation
|
|
*/
|
|
#[DefaultImplementation(CacheAdapter::class)]
|
|
final readonly class RedisCacheAdapter implements CacheAdapter
|
|
{
|
|
public function __construct(
|
|
private RedisConnection $redis
|
|
) {}
|
|
|
|
public function get(string $key): mixed
|
|
{
|
|
return $this->redis->get($key);
|
|
}
|
|
|
|
public function set(string $key, mixed $value, int $ttl = 3600): void
|
|
{
|
|
$this->redis->setex($key, $ttl, $value);
|
|
}
|
|
|
|
public function delete(string $key): void
|
|
{
|
|
$this->redis->del($key);
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Example 4: HTTP Client Abstraction
|
|
// =============================================================================
|
|
|
|
interface HttpClient
|
|
{
|
|
public function get(string $url, array $headers = []): HttpResponse;
|
|
public function post(string $url, array $data, array $headers = []): HttpResponse;
|
|
}
|
|
|
|
/**
|
|
* Guzzle-based HTTP client
|
|
* Auto-detects HttpClient interface
|
|
*/
|
|
#[DefaultImplementation]
|
|
final readonly class GuzzleHttpClient implements HttpClient
|
|
{
|
|
public function __construct(
|
|
private \GuzzleHttp\Client $guzzle
|
|
) {}
|
|
|
|
public function get(string $url, array $headers = []): HttpResponse
|
|
{
|
|
$response = $this->guzzle->get($url, ['headers' => $headers]);
|
|
return new HttpResponse($response->getStatusCode(), (string) $response->getBody());
|
|
}
|
|
|
|
public function post(string $url, array $data, array $headers = []): HttpResponse
|
|
{
|
|
$response = $this->guzzle->post($url, [
|
|
'headers' => $headers,
|
|
'json' => $data
|
|
]);
|
|
return new HttpResponse($response->getStatusCode(), (string) $response->getBody());
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Example 5: Multiple Interfaces (Auto-detect First)
|
|
// =============================================================================
|
|
|
|
interface EventLogger
|
|
{
|
|
public function logEvent(string $event, array $context): void;
|
|
}
|
|
|
|
interface Flushable
|
|
{
|
|
public function flush(): void;
|
|
}
|
|
|
|
/**
|
|
* File-based event logger with flush capability
|
|
* Auto-detects EventLogger (first interface)
|
|
*/
|
|
#[DefaultImplementation] // Binds to EventLogger, not Flushable
|
|
final readonly class FileEventLogger implements EventLogger, Flushable
|
|
{
|
|
public function __construct(
|
|
private string $logFilePath
|
|
) {}
|
|
|
|
public function logEvent(string $event, array $context): void
|
|
{
|
|
file_put_contents(
|
|
$this->logFilePath,
|
|
json_encode(['event' => $event, 'context' => $context]) . "\n",
|
|
FILE_APPEND
|
|
);
|
|
}
|
|
|
|
public function flush(): void
|
|
{
|
|
file_put_contents($this->logFilePath, '');
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Example 6: Using Default Implementations
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Service that depends on default implementations
|
|
*/
|
|
final readonly class UserService
|
|
{
|
|
public function __construct(
|
|
private UserRepository $userRepository, // DatabaseUserRepository injected
|
|
private NotificationService $notifications, // EmailNotificationService injected
|
|
private CacheAdapter $cache // RedisCacheAdapter injected
|
|
) {}
|
|
|
|
public function registerUser(string $email, string $name): void
|
|
{
|
|
// Check cache first
|
|
$cachedUser = $this->cache->get("user:$email");
|
|
if ($cachedUser !== null) {
|
|
return; // User already registered
|
|
}
|
|
|
|
// Create and save user
|
|
$user = new User($email, $name);
|
|
$this->userRepository->save($user);
|
|
|
|
// Cache the user
|
|
$this->cache->set("user:$email", $user, 3600);
|
|
|
|
// Send notification
|
|
$this->notifications->send($email, "Welcome to our platform, $name!");
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Example 7: Advanced - Combining with Initializers
|
|
// =============================================================================
|
|
|
|
interface PaymentGateway
|
|
{
|
|
public function charge(int $amountInCents, string $token): PaymentResult;
|
|
}
|
|
|
|
/**
|
|
* Stripe payment gateway
|
|
* Requires complex initialization via Initializer
|
|
*/
|
|
#[DefaultImplementation(PaymentGateway::class)]
|
|
final readonly class StripePaymentGateway implements PaymentGateway
|
|
{
|
|
public function __construct(
|
|
private StripeApiClient $stripeClient
|
|
) {}
|
|
|
|
public function charge(int $amountInCents, string $token): PaymentResult
|
|
{
|
|
return $this->stripeClient->createCharge($amountInCents, $token);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initializer for StripeApiClient
|
|
* Runs after DefaultImplementation registration
|
|
*/
|
|
final readonly class StripeInitializer
|
|
{
|
|
#[\App\Framework\DI\Initializer]
|
|
public function initializeStripeClient(): StripeApiClient
|
|
{
|
|
$apiKey = $_ENV['STRIPE_SECRET_KEY'] ?? throw new \RuntimeException('Missing Stripe API key');
|
|
|
|
return new StripeApiClient($apiKey, [
|
|
'api_version' => '2023-10-16',
|
|
'timeout' => 30
|
|
]);
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Usage in Application
|
|
// =============================================================================
|
|
|
|
/**
|
|
* The container automatically resolves all dependencies:
|
|
*
|
|
* $container->get(UserService::class)
|
|
* -> UserRepository (DatabaseUserRepository)
|
|
* -> NotificationService (EmailNotificationService)
|
|
* -> CacheAdapter (RedisCacheAdapter)
|
|
*
|
|
* All instances are singletons - same instance returned on subsequent calls
|
|
*/
|
|
|
|
// =============================================================================
|
|
// Stub Classes (for example completeness)
|
|
// =============================================================================
|
|
|
|
class User
|
|
{
|
|
public function __construct(
|
|
public string $email,
|
|
public string $name
|
|
) {}
|
|
}
|
|
|
|
class DatabaseConnection {}
|
|
class MailerService
|
|
{
|
|
public function sendMail(string $to, string $subject, string $body): void {}
|
|
}
|
|
class RedisConnection
|
|
{
|
|
public function get(string $key): mixed { return null; }
|
|
public function setex(string $key, int $ttl, mixed $value): void {}
|
|
public function del(string $key): void {}
|
|
}
|
|
class HttpResponse
|
|
{
|
|
public function __construct(
|
|
public int $statusCode,
|
|
public string $body
|
|
) {}
|
|
}
|
|
class StripeApiClient
|
|
{
|
|
public function __construct(string $apiKey, array $options) {}
|
|
public function createCharge(int $amount, string $token): PaymentResult
|
|
{
|
|
return new PaymentResult(true, 'ch_123');
|
|
}
|
|
}
|
|
class PaymentResult
|
|
{
|
|
public function __construct(
|
|
public bool $success,
|
|
public string $transactionId
|
|
) {}
|
|
}
|