Simplify PHPDoc comments in Laravel and Symfony integrations

Remove verbose documentation pattern references and redundant
explanations, keeping only essential type annotations.
This commit is contained in:
Younes ENNAJI
2026-01-15 22:22:20 +01:00
parent 8f594698c7
commit 21348f384d
35 changed files with 51 additions and 1209 deletions
+2 -46
View File
@@ -16,15 +16,7 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\Finder;
/** /**
* InstallCommand - Artisan command for installing PHPFlasher resources. * Artisan command for installing PHPFlasher resources.
*
* This command provides a CLI interface for installing PHPFlasher resources
* including assets (JS and CSS files) and configuration files. It discovers
* all registered PHPFlasher plugins and installs their resources.
*
* Design patterns:
* - Command: Implements the command pattern for Artisan CLI integration
* - Discovery: Automatically discovers and processes registered plugins
*/ */
final class InstallCommand extends Command final class InstallCommand extends Command
{ {
@@ -35,21 +27,11 @@ final class InstallCommand extends Command
*/ */
protected $description = 'Installs all <fg=blue;options=bold>PHPFlasher</> resources to the <comment>public</comment> and <comment>config</comment> directories.'; protected $description = 'Installs all <fg=blue;options=bold>PHPFlasher</> resources to the <comment>public</comment> and <comment>config</comment> directories.';
/**
* Creates a new InstallCommand instance.
*
* @param AssetManagerInterface $assetManager Manager for handling PHPFlasher assets
*/
public function __construct(private readonly AssetManagerInterface $assetManager) public function __construct(private readonly AssetManagerInterface $assetManager)
{ {
parent::__construct(); parent::__construct();
} }
/**
* Configure the command.
*
* Sets the command name, description, help text, and options.
*/
protected function configure(): void protected function configure(): void
{ {
$this $this
@@ -60,20 +42,6 @@ final class InstallCommand extends Command
->addOption('symlink', 's', InputOption::VALUE_NONE, 'Symlink <fg=blue;options=bold>PHPFlasher</> assets instead of copying them.'); ->addOption('symlink', 's', InputOption::VALUE_NONE, 'Symlink <fg=blue;options=bold>PHPFlasher</> assets instead of copying them.');
} }
/**
* Execute the command.
*
* Installs PHPFlasher resources by:
* 1. Displaying a fancy banner
* 2. Processing each registered plugin
* 3. Publishing assets and config files
* 4. Creating a manifest file
*
* @param InputInterface $input Command input
* @param OutputInterface $output Command output
*
* @return int Command exit code (0 for success, non-zero for failure)
*/
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$output->writeln(''); $output->writeln('');
@@ -162,13 +130,7 @@ final class InstallCommand extends Command
} }
/** /**
* Publish assets from a plugin to the public directory. * @return string[]
*
* @param PluginInterface $plugin The plugin to publish assets from
* @param string $publicDir The target public directory
* @param bool $useSymlinks Whether to symlink or copy assets
*
* @return string[] Array of published file paths
*/ */
private function publishAssets(PluginInterface $plugin, string $publicDir, bool $useSymlinks): array private function publishAssets(PluginInterface $plugin, string $publicDir, bool $useSymlinks): array
{ {
@@ -202,12 +164,6 @@ final class InstallCommand extends Command
return $files; return $files;
} }
/**
* Publish a plugin's configuration file.
*
* @param PluginInterface $plugin The plugin to publish configuration for
* @param string $configFile The source configuration file path
*/
private function publishConfig(PluginInterface $plugin, string $configFile): void private function publishConfig(PluginInterface $plugin, string $configFile): void
{ {
if (!file_exists($configFile)) { if (!file_exists($configFile)) {
+1 -25
View File
@@ -7,38 +7,14 @@ namespace Flasher\Laravel\Component;
use Illuminate\View\Component; use Illuminate\View\Component;
/** /**
* FlasherComponent - Blade component for rendering notifications. * Blade component for rendering PHPFlasher notifications.
*
* This class provides a Blade component interface for rendering PHPFlasher
* notifications in Laravel views. It can be used with Laravel's component syntax:
* <x-flasher :criteria="json_encode(['limit' => 5])" :context="json_encode(['foo' => 'bar'])" />
*
* Design patterns:
* - View Component: Implements Laravel's view component pattern
* - Adapter: Adapts the Flasher render method to Laravel's component interface
*/ */
final class FlasherComponent extends Component final class FlasherComponent extends Component
{ {
/**
* Creates a new FlasherComponent instance.
*
* @param string $criteria JSON-encoded filtering criteria for notifications
* @param string $context JSON-encoded rendering context
*/
public function __construct(public string $criteria = '', public string $context = '') public function __construct(public string $criteria = '', public string $context = '')
{ {
} }
/**
* Renders the component.
*
* This method decodes the JSON criteria and context, then delegates to
* the Flasher service to render the notifications as HTML.
*
* @return string Rendered HTML content
*
* @throws \JsonException If JSON decoding fails
*/
public function render(): string public function render(): string
{ {
/** @var array<string, mixed> $criteria */ /** @var array<string, mixed> $criteria */
+3 -53
View File
@@ -14,27 +14,10 @@ use Livewire\LivewireManager;
use Livewire\Mechanisms\HandleComponents\ComponentContext; use Livewire\Mechanisms\HandleComponents\ComponentContext;
/** /**
* LivewireListener - Integrates PHPFlasher with Livewire component lifecycle. * Integrates PHPFlasher with Livewire component lifecycle.
*
* This listener ensures that PHPFlasher notifications can be displayed during
* Livewire component updates without requiring a full page load. It dispatches
* notifications as Livewire events that are handled by the front-end JavaScript.
*
* Design patterns:
* - Observer: Listens to Livewire component lifecycle events
* - Adapter: Adapts PHPFlasher notifications to Livewire's event system
* - Security-aware: Ensures CSP compliance with proper nonce handling
*/ */
final readonly class LivewireListener final readonly class LivewireListener
{ {
/**
* Creates a new LivewireListener instance.
*
* @param LivewireManager $livewire The Livewire manager
* @param FlasherInterface $flasher The PHPFlasher service
* @param ContentSecurityPolicyHandlerInterface $cspHandler The CSP handler for security
* @param \Closure $request Closure to get the current request
*/
public function __construct( public function __construct(
private LivewireManager $livewire, private LivewireManager $livewire,
private FlasherInterface $flasher, private FlasherInterface $flasher,
@@ -43,15 +26,6 @@ final readonly class LivewireListener
) { ) {
} }
/**
* Handle a Livewire component dehydration event.
*
* This method is invoked during Livewire's component rendering process
* and dispatches any pending notifications as Livewire events.
*
* @param Component $component The Livewire component being rendered
* @param ComponentContext $context The Livewire component context
*/
public function __invoke(Component $component, ComponentContext $context): void public function __invoke(Component $component, ComponentContext $context): void
{ {
if ($this->shouldSkip($context)) { if ($this->shouldSkip($context)) {
@@ -67,14 +41,7 @@ final readonly class LivewireListener
} }
/** /**
* Dispatches notifications as Livewire events. * @param array{envelopes: Envelope[]} $data
*
* This method adds the notifications data to the Livewire component's
* dispatched events, which will be processed by the front-end.
*
* @param Component $component The Livewire component
* @param ComponentContext $context The Livewire component context
* @param array{envelopes: Envelope[]} $data The notification data
*/ */
private function dispatchNotifications(Component $component, ComponentContext $context, array $data): void private function dispatchNotifications(Component $component, ComponentContext $context, array $data): void
{ {
@@ -89,30 +56,13 @@ final readonly class LivewireListener
$context->addEffect('dispatches', $dispatches); $context->addEffect('dispatches', $dispatches);
} }
/**
* Determines if notification processing should be skipped.
*
* Skips processing in the following cases:
* - Not a Livewire request
* - During component mounting (initial render)
* - When a redirect is in progress
*
* @param ComponentContext $context The Livewire component context
*
* @return bool True if notification processing should be skipped
*/
private function shouldSkip(ComponentContext $context): bool private function shouldSkip(ComponentContext $context): bool
{ {
return !$this->livewire->isLivewireRequest() || $context->mounting || isset($context->effects['redirect']); return !$this->livewire->isLivewireRequest() || $context->mounting || isset($context->effects['redirect']);
} }
/** /**
* Creates the security context for rendering notifications. * @return array<string, mixed>
*
* This method generates CSP nonces to ensure scripts loaded by PHPFlasher
* comply with Content Security Policy.
*
* @return array<string, mixed> The context with CSP nonces
*/ */
private function createContext(): array private function createContext(): array
{ {
+1 -16
View File
@@ -8,25 +8,10 @@ use Flasher\Prime\EventDispatcher\EventListener\NotificationLoggerListener;
use Laravel\Octane\Events\RequestReceived; use Laravel\Octane\Events\RequestReceived;
/** /**
* OctaneListener - Resets notification logger between Octane requests. * Resets notification logger between Octane requests.
*
* This listener ensures that notifications from previous requests don't
* leak into new requests when running Laravel Octane, which keeps workers
* alive between requests.
*
* Design patterns:
* - Observer: Observes Octane request events
* - State Reset: Cleans up state between stateful worker requests
*/ */
final readonly class OctaneListener final readonly class OctaneListener
{ {
/**
* Handle the Octane RequestReceived event.
*
* Resets the notification logger to ensure clean state for the new request.
*
* @param RequestReceived $event The Octane request received event
*/
public function handle(RequestReceived $event): void public function handle(RequestReceived $event): void
{ {
/** @var NotificationLoggerListener $listener */ /** @var NotificationLoggerListener $listener */
+1 -27
View File
@@ -10,28 +10,7 @@ use Flasher\Prime\Stamp\StampInterface;
use Illuminate\Support\Facades\Facade; use Illuminate\Support\Facades\Facade;
/** /**
* Flasher - Laravel Facade for the PHPFlasher service. * Laravel facade for PHPFlasher with IDE autocompletion support.
*
* This facade provides a static interface to PHPFlasher's functionality within Laravel,
* following Laravel's facade pattern. It offers comprehensive IDE autocompletion for all
* PHPFlasher methods by providing method signatures in PHPDoc comments.
*
* Design patterns:
* - Facade: Provides a simplified, static interface to a complex subsystem
* - Proxy: Acts as a proxy to the underlying PHPFlasher service
*
* Usage examples:
* ```php
* // Simple notification
* Flasher::success('Operation completed successfully');
*
* // Chained configuration
* Flasher::type('success')
* ->title('Success')
* ->message('Record saved')
* ->option('timeout', 5000)
* ->push();
* ```
* *
* @method static NotificationBuilder title(string $message) * @method static NotificationBuilder title(string $message)
* @method static NotificationBuilder message(string $message) * @method static NotificationBuilder message(string $message)
@@ -71,11 +50,6 @@ use Illuminate\Support\Facades\Facade;
*/ */
final class Flasher extends Facade final class Flasher extends Facade
{ {
/**
* Get the registered name of the component.
*
* @return string The name of the facade's service binding ('flasher')
*/
protected static function getFacadeAccessor(): string protected static function getFacadeAccessor(): string
{ {
return 'flasher'; return 'flasher';
+1 -125
View File
@@ -43,27 +43,10 @@ use Laravel\Octane\Events\RequestReceived;
use Livewire\LivewireManager; use Livewire\LivewireManager;
/** /**
* FlasherServiceProvider - Main service provider for Laravel integration. * Main service provider for Laravel integration.
*
* This class serves as the entry point for integrating PHPFlasher with Laravel.
* It registers all necessary services, components, commands, and middleware
* to provide a seamless Laravel experience.
*
* Design patterns:
* - Service Provider: Implements Laravel's service provider pattern for registration
* - Adapter: Adapts Laravel-specific components to PHPFlasher interfaces
* - Bridge: Connects the framework-agnostic PHPFlasher core to Laravel
*/ */
final class FlasherServiceProvider extends PluginServiceProvider final class FlasherServiceProvider extends PluginServiceProvider
{ {
/**
* Register PHPFlasher services with the Laravel container.
*
* This method follows Laravel's service provider registration phase by:
* 1. Creating the core plugin
* 2. Registering configuration
* 3. Registering core services and adapters
*/
public function register(): void public function register(): void
{ {
$this->plugin = $this->createPlugin(); $this->plugin = $this->createPlugin();
@@ -80,17 +63,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
$this->registerAssetManager(); $this->registerAssetManager();
} }
/**
* Boot PHPFlasher services after all providers are registered.
*
* This method follows Laravel's service provider boot phase by:
* 1. Setting up the service container bridge
* 2. Registering commands
* 3. Loading translations
* 4. Registering middleware
* 5. Registering Blade directives and components
* 6. Setting up Livewire integration
*/
public function boot(): void public function boot(): void
{ {
FlasherContainer::from(static fn () => Container::getInstance()); FlasherContainer::from(static fn () => Container::getInstance());
@@ -102,22 +74,11 @@ final class FlasherServiceProvider extends PluginServiceProvider
$this->registerLivewire(); $this->registerLivewire();
} }
/**
* Create the PHPFlasher core plugin instance.
*
* @return FlasherPlugin The core PHPFlasher plugin
*/
public function createPlugin(): FlasherPlugin public function createPlugin(): FlasherPlugin
{ {
return new FlasherPlugin(); return new FlasherPlugin();
} }
/**
* Register the main Flasher service with Laravel's container.
*
* This service is the main entry point for all PHPFlasher functionality
* and is made available via the 'flasher' service binding.
*/
private function registerFlasher(): void private function registerFlasher(): void
{ {
$this->app->singleton('flasher', static function (Application $app) { $this->app->singleton('flasher', static function (Application $app) {
@@ -135,12 +96,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
$this->app->bind(FlasherInterface::class, 'flasher'); $this->app->bind(FlasherInterface::class, 'flasher');
} }
/**
* Register the factory locator service.
*
* The factory locator is responsible for locating and providing
* notification factory instances.
*/
private function registerFactoryLocator(): void private function registerFactoryLocator(): void
{ {
$this->app->singleton('flasher.factory_locator', static function () { $this->app->singleton('flasher.factory_locator', static function () {
@@ -148,12 +103,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
}); });
} }
/**
* Register the response manager service.
*
* The response manager is responsible for rendering notifications
* into different formats (HTML, JSON, etc.).
*/
private function registerResponseManager(): void private function registerResponseManager(): void
{ {
$this->app->singleton('flasher.response_manager', static function (Application $app) { $this->app->singleton('flasher.response_manager', static function (Application $app) {
@@ -165,11 +114,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
}); });
} }
/**
* Register the template engine adapter for Blade.
*
* This adapter allows PHPFlasher to render templates using Laravel's Blade engine.
*/
private function registerTemplateEngine(): void private function registerTemplateEngine(): void
{ {
$this->app->singleton('flasher.template_engine', static function (Application $app) { $this->app->singleton('flasher.template_engine', static function (Application $app) {
@@ -179,12 +123,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
}); });
} }
/**
* Register the resource manager service.
*
* The resource manager is responsible for managing assets (JS, CSS)
* needed by notifications.
*/
private function registerResourceManager(): void private function registerResourceManager(): void
{ {
$this->app->singleton('flasher.resource_manager', static function (Application $app) { $this->app->singleton('flasher.resource_manager', static function (Application $app) {
@@ -208,12 +146,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
}); });
} }
/**
* Register the storage manager service.
*
* The storage manager is responsible for storing and retrieving
* notifications from storage (session in Laravel's case).
*/
private function registerStorageManager(): void private function registerStorageManager(): void
{ {
$this->app->singleton('flasher.storage_manager', static function (Application $app) { $this->app->singleton('flasher.storage_manager', static function (Application $app) {
@@ -228,12 +160,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
}); });
} }
/**
* Register the event dispatcher and event listeners.
*
* The event dispatcher is responsible for dispatching events during
* the notification lifecycle.
*/
private function registerEventDispatcher(): void private function registerEventDispatcher(): void
{ {
$this->app->singleton('flasher.notification_logger_listener', fn () => new NotificationLoggerListener()); $this->app->singleton('flasher.notification_logger_listener', fn () => new NotificationLoggerListener());
@@ -259,11 +185,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
}); });
} }
/**
* Register the Artisan commands for PHPFlasher.
*
* Commands are only registered when running in console mode.
*/
private function registerCommands(): void private function registerCommands(): void
{ {
if (!$this->app->runningInConsole()) { if (!$this->app->runningInConsole()) {
@@ -281,11 +202,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
$this->commands(InstallCommand::class); $this->commands(InstallCommand::class);
} }
/**
* Register PHPFlasher information with Laravel's about command.
*
* This adds PHPFlasher information to the output of the `php artisan about` command.
*/
private function registerAboutCommand(): void private function registerAboutCommand(): void
{ {
if (!class_exists(AboutCommand::class)) { if (!class_exists(AboutCommand::class)) {
@@ -310,22 +226,12 @@ final class FlasherServiceProvider extends PluginServiceProvider
]); ]);
} }
/**
* Register PHPFlasher middleware with Laravel.
*
* Middleware includes session processing and response modification.
*/
private function registerMiddlewares(): void private function registerMiddlewares(): void
{ {
$this->registerSessionMiddleware(); $this->registerSessionMiddleware();
$this->registerFlasherMiddleware(); $this->registerFlasherMiddleware();
} }
/**
* Register the response middleware.
*
* This middleware injects notification assets into responses.
*/
private function registerFlasherMiddleware(): void private function registerFlasherMiddleware(): void
{ {
if (!$this->getConfig('inject_assets')) { if (!$this->getConfig('inject_assets')) {
@@ -345,11 +251,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
$this->pushMiddlewareToGroup(FlasherMiddleware::class); $this->pushMiddlewareToGroup(FlasherMiddleware::class);
} }
/**
* Register the session middleware.
*
* This middleware processes flash messages from the session.
*/
private function registerSessionMiddleware(): void private function registerSessionMiddleware(): void
{ {
if (!$this->getConfig('flash_bag')) { if (!$this->getConfig('flash_bag')) {
@@ -368,11 +269,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
$this->pushMiddlewareToGroup(SessionMiddleware::class); $this->pushMiddlewareToGroup(SessionMiddleware::class);
} }
/**
* Push middleware to the web middleware group.
*
* @param string $middleware The middleware class name
*/
private function pushMiddlewareToGroup(string $middleware): void private function pushMiddlewareToGroup(string $middleware): void
{ {
$this->callAfterResolving(HttpKernel::class, function (HttpKernel $kernel) use ($middleware) { $this->callAfterResolving(HttpKernel::class, function (HttpKernel $kernel) use ($middleware) {
@@ -380,11 +276,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
}); });
} }
/**
* Register the Content Security Policy handler.
*
* This service handles CSP headers when injecting assets.
*/
private function registerCspHandler(): void private function registerCspHandler(): void
{ {
$this->app->singleton('flasher.csp_handler', static function () { $this->app->singleton('flasher.csp_handler', static function () {
@@ -392,11 +283,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
}); });
} }
/**
* Register the asset manager service.
*
* The asset manager is responsible for managing asset paths and manifests.
*/
private function registerAssetManager(): void private function registerAssetManager(): void
{ {
$this->app->singleton('flasher.asset_manager', static function () { $this->app->singleton('flasher.asset_manager', static function () {
@@ -407,11 +293,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
}); });
} }
/**
* Register Blade directives and components.
*
* @param BladeCompiler $blade The Blade compiler instance
*/
private function registerBladeDirectives(BladeCompiler $blade): void private function registerBladeDirectives(BladeCompiler $blade): void
{ {
$blade->directive('flasher_render', function (string $expression = '') { $blade->directive('flasher_render', function (string $expression = '') {
@@ -425,11 +306,6 @@ final class FlasherServiceProvider extends PluginServiceProvider
$blade->component(FlasherComponent::class, 'flasher'); $blade->component(FlasherComponent::class, 'flasher');
} }
/**
* Register Livewire integration.
*
* This sets up listeners for Livewire component lifecycle events.
*/
private function registerLivewire(): void private function registerLivewire(): void
{ {
if (class_exists(LivewireManager::class) && !$this->app->bound('livewire')) { if (class_exists(LivewireManager::class) && !$this->app->bound('livewire')) {
+1 -20
View File
@@ -9,24 +9,10 @@ use Illuminate\Contracts\Session\Session;
use Illuminate\Http\Request as LaravelRequest; use Illuminate\Http\Request as LaravelRequest;
/** /**
* Request - Adapter for Laravel HTTP requests. * Adapter for Laravel HTTP requests.
*
* This adapter implements PHPFlasher's RequestInterface for Laravel HTTP requests,
* providing a consistent interface for request inspection and session interaction
* regardless of the underlying framework.
*
* Design patterns:
* - Adapter: Adapts framework-specific request objects to PHPFlasher's interface
* - Decorator: Adds PHPFlasher-specific functionality to request objects
* - Composition: Uses composition to delegate to the underlying request object
*/ */
final readonly class Request implements RequestInterface final readonly class Request implements RequestInterface
{ {
/**
* Creates a new Request adapter.
*
* @param LaravelRequest $request The underlying Laravel request object
*/
public function __construct(private LaravelRequest $request) public function __construct(private LaravelRequest $request)
{ {
} }
@@ -90,11 +76,6 @@ final readonly class Request implements RequestInterface
$session?->forget($type); $session?->forget($type);
} }
/**
* Gets the session from the request, with graceful handling of missing sessions.
*
* @return Session|null The session or null if not available
*/
private function getSession(): ?Session private function getSession(): ?Session
{ {
try { try {
+1 -21
View File
@@ -10,24 +10,10 @@ use Symfony\Component\HttpFoundation\JsonResponse as SymfonyJsonResponse;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
/** /**
* Response - Adapter for Laravel/Symfony HTTP responses. * Adapter for Laravel/Symfony HTTP responses.
*
* This adapter implements PHPFlasher's ResponseInterface for Laravel and Symfony
* HTTP responses, providing a consistent interface for response manipulation
* regardless of the underlying framework.
*
* Design patterns:
* - Adapter: Adapts framework-specific response objects to PHPFlasher's interface
* - Decorator: Adds PHPFlasher-specific functionality to response objects
* - Composition: Uses composition to delegate to the underlying response object
*/ */
final readonly class Response implements ResponseInterface final readonly class Response implements ResponseInterface
{ {
/**
* Creates a new Response adapter.
*
* @param SymfonyResponse $response The underlying Symfony/Laravel response object
*/
public function __construct(private SymfonyResponse $response) public function __construct(private SymfonyResponse $response)
{ {
} }
@@ -74,12 +60,6 @@ final readonly class Response implements ResponseInterface
return $this->response->getContent() ?: ''; return $this->response->getContent() ?: '';
} }
/**
* {@inheritdoc}
*
* This implementation preserves the original content in Laravel responses,
* ensuring compatibility with Laravel's view system and JSON responses.
*/
public function setContent(string $content): void public function setContent(string $content): void
{ {
$original = null; $original = null;
+1 -26
View File
@@ -11,39 +11,14 @@ use Illuminate\Http\Request as LaravelRequest;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
/** /**
* FlasherMiddleware - Middleware for injecting PHPFlasher assets into responses. * Middleware for injecting PHPFlasher assets into responses.
*
* This middleware processes outgoing HTTP responses to inject PHPFlasher's
* JavaScript and CSS assets when needed. It's typically added to Laravel's
* web middleware group.
*
* Design patterns:
* - Pipeline: Participates in Laravel's middleware pipeline
* - Decorator: Decorates HTTP responses with PHPFlasher assets
* - Adapter: Adapts Laravel requests/responses to PHPFlasher interfaces
*/ */
final readonly class FlasherMiddleware final readonly class FlasherMiddleware
{ {
/**
* Creates a new FlasherMiddleware instance.
*
* @param ResponseExtensionInterface $responseExtension Service for extending responses with notifications
*/
public function __construct(private ResponseExtensionInterface $responseExtension) public function __construct(private ResponseExtensionInterface $responseExtension)
{ {
} }
/**
* Handle an incoming request.
*
* Processes the response after the application has generated it,
* injecting PHPFlasher assets and notifications as needed.
*
* @param LaravelRequest $request The incoming request
* @param \Closure $next The next middleware handler
*
* @return mixed The processed response
*/
public function handle(LaravelRequest $request, \Closure $next): mixed public function handle(LaravelRequest $request, \Closure $next): mixed
{ {
$response = $next($request); $response = $next($request);
+1 -26
View File
@@ -11,39 +11,14 @@ use Illuminate\Http\Request as LaravelRequest;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
/** /**
* SessionMiddleware - Middleware for processing session flash messages. * Middleware for processing session flash messages.
*
* This middleware processes Laravel's session flash messages and converts them
* to PHPFlasher notifications, allowing seamless integration with existing code
* that uses Laravel's built-in flash messaging.
*
* Design patterns:
* - Pipeline: Participates in Laravel's middleware pipeline
* - Adapter: Adapts Laravel flash messages to PHPFlasher notifications
* - Transformer: Transforms one message format to another
*/ */
final readonly class SessionMiddleware final readonly class SessionMiddleware
{ {
/**
* Creates a new SessionMiddleware instance.
*
* @param RequestExtensionInterface $requestExtension Service for processing request flash messages
*/
public function __construct(private RequestExtensionInterface $requestExtension) public function __construct(private RequestExtensionInterface $requestExtension)
{ {
} }
/**
* Handle an incoming request.
*
* Processes the request and response to convert Laravel flash messages
* to PHPFlasher notifications.
*
* @param LaravelRequest $request The incoming request
* @param \Closure $next The next middleware handler
*
* @return mixed The processed response
*/
public function handle(LaravelRequest $request, \Closure $next): mixed public function handle(LaravelRequest $request, \Closure $next): mixed
{ {
$response = $next($request); $response = $next($request);
+1 -30
View File
@@ -9,38 +9,16 @@ use Flasher\Prime\Storage\Bag\BagInterface;
use Illuminate\Session\SessionManager; use Illuminate\Session\SessionManager;
/** /**
* SessionBag - Laravel session storage for PHPFlasher notifications. * Laravel session storage for PHPFlasher notifications.
*
* This class implements PHPFlasher's storage interface using Laravel's session
* system, providing persistence for notifications across requests.
*
* Design patterns:
* - Adapter: Adapts Laravel's session system to PHPFlasher's storage interface
* - Repository: Provides CRUD operations for notification storage
*/ */
final readonly class SessionBag implements BagInterface final readonly class SessionBag implements BagInterface
{ {
/**
* Session key for storing notification envelopes.
*/
public const ENVELOPES_NAMESPACE = 'flasher::envelopes'; public const ENVELOPES_NAMESPACE = 'flasher::envelopes';
/**
* Creates a new SessionBag instance.
*
* @param SessionManager $session Laravel's session manager
*/
public function __construct(private SessionManager $session) public function __construct(private SessionManager $session)
{ {
} }
/**
* {@inheritdoc}
*
* Retrieves all stored notification envelopes from the session.
*
* @return Envelope[] The stored notification envelopes
*/
public function get(): array public function get(): array
{ {
/** @var Envelope[] $envelopes */ /** @var Envelope[] $envelopes */
@@ -49,13 +27,6 @@ final readonly class SessionBag implements BagInterface
return $envelopes; return $envelopes;
} }
/**
* {@inheritdoc}
*
* Stores notification envelopes in the session.
*
* @param Envelope[] $envelopes The notification envelopes to store
*/
public function set(array $envelopes): void public function set(array $envelopes): void
{ {
$this->session->put(self::ENVELOPES_NAMESPACE, $envelopes); $this->session->put(self::ENVELOPES_NAMESPACE, $envelopes);
+1 -76
View File
@@ -12,18 +12,7 @@ use Illuminate\Contracts\Foundation\CachesConfiguration;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
/** /**
* PluginServiceProvider - Base service provider for PHPFlasher plugins. * Base service provider for PHPFlasher plugins in Laravel.
*
* This abstract class provides the foundation for all PHPFlasher plugin
* service providers in Laravel. It handles the registration of plugin
* configuration, factories, and services.
*
* Design patterns:
* - Template Method: Defines the skeleton of registration process with customizable steps
* - Factory: Creates plugin instances via createPlugin method
* - Service Provider: Implements Laravel's service provider pattern
*
* Plugin providers should extend this class and implement the createPlugin method.
*/ */
abstract class PluginServiceProvider extends ServiceProvider abstract class PluginServiceProvider extends ServiceProvider
{ {
@@ -32,23 +21,8 @@ abstract class PluginServiceProvider extends ServiceProvider
*/ */
protected PluginInterface $plugin; protected PluginInterface $plugin;
/**
* Create the plugin instance.
*
* Child classes must implement this method to provide their specific plugin.
*
* @return PluginInterface The plugin instance
*/
abstract public function createPlugin(): PluginInterface; abstract public function createPlugin(): PluginInterface;
/**
* Register services with the Laravel container.
*
* This method:
* 1. Creates the plugin instance
* 2. Registers plugin configuration
* 3. Calls the afterRegister hook for customization
*/
public function register(): void public function register(): void
{ {
$this->plugin = $this->createPlugin(); $this->plugin = $this->createPlugin();
@@ -57,37 +31,17 @@ abstract class PluginServiceProvider extends ServiceProvider
$this->afterRegister(); $this->afterRegister();
} }
/**
* Bootstrap services after all providers are registered.
*
* This method:
* 1. Registers the plugin factory
* 2. Calls the afterBoot hook for customization
*/
public function boot(): void public function boot(): void
{ {
$this->registerFactory(); $this->registerFactory();
$this->afterBoot(); $this->afterBoot();
} }
/**
* Get the plugin's configuration file path.
*
* @return string The absolute path to the configuration file
*/
public function getConfigurationFile(): string public function getConfigurationFile(): string
{ {
return rtrim($this->getResourcesDir(), '/').'/config.php'; return rtrim($this->getResourcesDir(), '/').'/config.php';
} }
/**
* Get a configuration value with optional default.
*
* @param string|null $key The configuration key to retrieve, or null for all config
* @param mixed $default The default value to return if the key doesn't exist
*
* @return mixed The configuration value
*/
protected function getConfig(?string $key = null, mixed $default = null): mixed protected function getConfig(?string $key = null, mixed $default = null): mixed
{ {
/** @var Repository $config */ /** @var Repository $config */
@@ -96,11 +50,6 @@ abstract class PluginServiceProvider extends ServiceProvider
return $key ? $config->get('flasher.'.$key, $default) : $config->get('flasher'); return $key ? $config->get('flasher.'.$key, $default) : $config->get('flasher');
} }
/**
* Get the plugin's resources directory path.
*
* @return string The absolute path to the resources directory
*/
protected function getResourcesDir(): string protected function getResourcesDir(): string
{ {
$r = new \ReflectionClass($this); $r = new \ReflectionClass($this);
@@ -108,12 +57,6 @@ abstract class PluginServiceProvider extends ServiceProvider
return pathinfo($r->getFileName() ?: '', \PATHINFO_DIRNAME).'/Resources/'; return pathinfo($r->getFileName() ?: '', \PATHINFO_DIRNAME).'/Resources/';
} }
/**
* Register the plugin's configuration.
*
* This method merges the plugin's default configuration with any user-defined
* configuration and registers it with Laravel's config repository.
*/
protected function registerConfiguration(): void protected function registerConfiguration(): void
{ {
if ($this->app instanceof CachesConfiguration && $this->app->configurationIsCached()) { if ($this->app instanceof CachesConfiguration && $this->app->configurationIsCached()) {
@@ -136,32 +79,14 @@ abstract class PluginServiceProvider extends ServiceProvider
$config->set($key, $this->plugin->normalizeConfig($current)); $config->set($key, $this->plugin->normalizeConfig($current));
} }
/**
* Hook method executed after registration.
*
* Child classes can override this method to add custom registration logic.
*/
protected function afterRegister(): void protected function afterRegister(): void
{ {
} }
/**
* Hook method executed after boot.
*
* Child classes can override this method to add custom boot logic.
*/
protected function afterBoot(): void protected function afterBoot(): void
{ {
} }
/**
* Register the plugin's notification factory.
*
* This method:
* 1. Registers the factory as a singleton
* 2. Registers any aliases for the factory
* 3. Adds the factory to the factory locator
*/
protected function registerFactory(): void protected function registerFactory(): void
{ {
$this->app->singleton($this->plugin->getServiceId(), function (Application $app) { $this->app->singleton($this->plugin->getServiceId(), function (Application $app) {
+1 -24
View File
@@ -8,37 +8,14 @@ use Flasher\Prime\Template\TemplateEngineInterface;
use Illuminate\View\Factory; use Illuminate\View\Factory;
/** /**
* BladeTemplateEngine - Laravel Blade adapter for PHPFlasher templates. * Laravel Blade adapter for PHPFlasher templates.
*
* This class provides an implementation of PHPFlasher's template engine interface
* using Laravel's Blade templating system. It allows PHPFlasher to render templates
* using all of Blade's features.
*
* Design patterns:
* - Adapter: Adapts Laravel's Blade engine to PHPFlasher's template interface
* - Bridge: Connects PHPFlasher's templating needs with Laravel's templating system
*/ */
final readonly class BladeTemplateEngine implements TemplateEngineInterface final readonly class BladeTemplateEngine implements TemplateEngineInterface
{ {
/**
* Creates a new BladeTemplateEngine instance.
*
* @param Factory $blade Laravel's view factory
*/
public function __construct(private Factory $blade) public function __construct(private Factory $blade)
{ {
} }
/**
* {@inheritdoc}
*
* Renders a template using Laravel's Blade engine.
*
* @param string $name The template name or path
* @param array<string, mixed> $context The template variables
*
* @return string The rendered template
*/
public function render(string $name, array $context = []): string public function render(string $name, array $context = []): string
{ {
return $this->blade->make($name, $context)->render(); return $this->blade->make($name, $context)->render();
+3 -43
View File
@@ -8,42 +8,14 @@ use Flasher\Prime\Translation\TranslatorInterface;
use Illuminate\Translation\Translator as LaravelTranslator; use Illuminate\Translation\Translator as LaravelTranslator;
/** /**
* Translator - Laravel adapter for PHPFlasher translations. * Laravel adapter for PHPFlasher translations.
*
* This class provides an implementation of PHPFlasher's translator interface
* using Laravel's translation system. It enables PHPFlasher notifications
* to be localized using Laravel's language files and translation workflow.
*
* Design patterns:
* - Adapter: Adapts Laravel's translator to PHPFlasher's interface
* - Decorator: Adds PHPFlasher-specific behavior to Laravel's translator
*/ */
final readonly class Translator implements TranslatorInterface final readonly class Translator implements TranslatorInterface
{ {
/**
* Creates a new Translator instance.
*
* @param LaravelTranslator $translator Laravel's translator service
*/
public function __construct(private LaravelTranslator $translator) public function __construct(private LaravelTranslator $translator)
{ {
} }
/**
* {@inheritdoc}
*
* Translates a message using Laravel's translation system.
* Tries multiple namespaces in this order:
* 1. flasher::messages.{id}
* 2. messages.{id}
* 3. {id} directly
*
* @param string $id The translation key
* @param array<string, mixed> $parameters The parameters for variable substitution
* @param string|null $locale The locale to use, or null for default
*
* @return string The translated string
*/
public function translate(string $id, array $parameters = [], ?string $locale = null): string public function translate(string $id, array $parameters = [], ?string $locale = null): string
{ {
$parameters = $this->formatParameters($parameters); $parameters = $this->formatParameters($parameters);
@@ -61,27 +33,15 @@ final readonly class Translator implements TranslatorInterface
return $translation; return $translation;
} }
/**
* {@inheritdoc}
*
* Gets the current locale from Laravel's translator.
*
* @return string The current locale code
*/
public function getLocale(): string public function getLocale(): string
{ {
return $this->translator->getLocale(); return $this->translator->getLocale();
} }
/** /**
* Formats the parameters by stripping the colon prefix from keys for Laravel's translator. * @param array<string, mixed> $parameters
* *
* This ensures compatibility between PHPFlasher's parameter format (:parameter) * @return array<string, mixed>
* and Laravel's parameter format (parameter).
*
* @param array<string, mixed> $parameters The parameters with potential colon prefixes
*
* @return array<string, mixed> The formatted parameters
*/ */
private function formatParameters(array $parameters): array private function formatParameters(array $parameters): array
{ {
+1 -23
View File
@@ -5,33 +5,11 @@ declare(strict_types=1);
namespace Flasher\Symfony\Attribute; namespace Flasher\Symfony\Attribute;
/** /**
* AsFlasherFactory - Attribute for tagging notification factories. * Attribute for tagging notification factories.
*
* This attribute enables auto-configuration of notification factory services in Symfony.
* When applied to a factory class, it automatically registers the class with the container
* using the specified alias, making it available to the PHPFlasher system.
*
* Design patterns:
* - Attribute-based Configuration: Uses PHP 8 attributes for declarative service configuration
* - Service Tagging: Implements Symfony's tag-based service discovery mechanism
*
* Usage:
* ```php
* #[AsFlasherFactory('toastr')]
* class ToastrFactory implements NotificationFactoryInterface
* {
* // ...
* }
* ```
*/ */
#[\Attribute(\Attribute::TARGET_CLASS)] #[\Attribute(\Attribute::TARGET_CLASS)]
final readonly class AsFlasherFactory final readonly class AsFlasherFactory
{ {
/**
* Creates a new AsFlasherFactory attribute.
*
* @param string $alias The unique alias for the notification factory (e.g., 'toastr', 'noty')
*/
public function __construct(public string $alias) public function __construct(public string $alias)
{ {
} }
+1 -24
View File
@@ -5,34 +5,11 @@ declare(strict_types=1);
namespace Flasher\Symfony\Attribute; namespace Flasher\Symfony\Attribute;
/** /**
* AsFlasherPresenter - Attribute for tagging response presenters. * Attribute for tagging response presenters.
*
* This attribute enables auto-configuration of response presenter services in Symfony.
* When applied to a presenter class, it automatically registers the class with the
* container using the specified alias, making it available to PHPFlasher's response system.
*
* Design patterns:
* - Attribute-based Configuration: Uses PHP 8 attributes for declarative service configuration
* - Service Tagging: Implements Symfony's tag-based service discovery mechanism
* - Strategy Pattern: Supports pluggable response formatting strategies
*
* Usage:
* ```php
* #[AsFlasherPresenter('html')]
* class HtmlPresenter implements PresenterInterface
* {
* // ...
* }
* ```
*/ */
#[\Attribute(\Attribute::TARGET_CLASS)] #[\Attribute(\Attribute::TARGET_CLASS)]
final readonly class AsFlasherPresenter final readonly class AsFlasherPresenter
{ {
/**
* Creates a new AsFlasherPresenter attribute.
*
* @param string $alias The unique alias for the presenter (e.g., 'html', 'json')
*/
public function __construct(public string $alias) public function __construct(public string $alias)
{ {
} }
+2 -84
View File
@@ -17,32 +17,15 @@ use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\HttpKernel\KernelInterface;
/** /**
* InstallCommand - Console command for installing PHPFlasher resources. * Console command for installing PHPFlasher resources.
*
* This command provides a CLI interface for installing PHPFlasher resources,
* including assets (JS and CSS files) and configuration files. It discovers
* all registered PHPFlasher plugins and installs their resources.
*
* Design patterns:
* - Command Pattern: Implements the command pattern for console interaction
* - Discovery Pattern: Automatically discovers and processes registered plugins
* - Template Method Pattern: Defines a structured workflow with specific steps
*/ */
final class InstallCommand extends Command final class InstallCommand extends Command
{ {
/**
* Creates a new InstallCommand instance.
*
* @param AssetManagerInterface $assetManager Manager for handling PHPFlasher assets
*/
public function __construct(private readonly AssetManagerInterface $assetManager) public function __construct(private readonly AssetManagerInterface $assetManager)
{ {
parent::__construct(); parent::__construct();
} }
/**
* Configure the command options and help text.
*/
protected function configure(): void protected function configure(): void
{ {
$this $this
@@ -53,17 +36,6 @@ final class InstallCommand extends Command
->addOption('symlink', 's', InputOption::VALUE_NONE, 'Symlink <fg=blue;options=bold>PHPFlasher</> assets instead of copying them.'); ->addOption('symlink', 's', InputOption::VALUE_NONE, 'Symlink <fg=blue;options=bold>PHPFlasher</> assets instead of copying them.');
} }
/**
* Execute the command to install PHPFlasher resources.
*
* This method processes each registered bundle that implements PluginBundleInterface,
* installing its assets and configuration files as requested.
*
* @param InputInterface $input The input interface
* @param OutputInterface $output The output interface
*
* @return int Command status code (SUCCESS or FAILURE)
*/
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
// Display PHPFlasher banner and info message // Display PHPFlasher banner and info message
@@ -166,16 +138,7 @@ final class InstallCommand extends Command
} }
/** /**
* Publishes assets from the plugin's assets directory to the public directory. * @return string[]
*
* This method copies or symlinks asset files from the plugin's assets directory
* to the public directory for web access.
*
* @param PluginInterface $plugin The plugin containing assets
* @param string $publicDir Target directory for assets
* @param bool $useSymlinks Whether to symlink files instead of copying
*
* @return string[] List of target paths for generated manifest
*/ */
private function publishAssets(PluginInterface $plugin, string $publicDir, bool $useSymlinks): array private function publishAssets(PluginInterface $plugin, string $publicDir, bool $useSymlinks): array
{ {
@@ -207,16 +170,6 @@ final class InstallCommand extends Command
return $files; return $files;
} }
/**
* Publishes configuration files to the application's config directory.
*
* This method copies plugin configuration files to the Symfony config directory,
* but only if the target file doesn't already exist (to avoid overwriting user customizations).
*
* @param PluginInterface $plugin The plugin containing configuration
* @param string|null $configDir Target config directory
* @param string $configFile Source configuration file path
*/
private function publishConfig(PluginInterface $plugin, ?string $configDir, string $configFile): void private function publishConfig(PluginInterface $plugin, ?string $configDir, string $configFile): void
{ {
if (null === $configDir || !file_exists($configFile)) { if (null === $configDir || !file_exists($configFile)) {
@@ -232,15 +185,6 @@ final class InstallCommand extends Command
$filesystem->copy($configFile, $target); $filesystem->copy($configFile, $target);
} }
/**
* Gets the path to the public directory.
*
* This method tries to locate the public directory using multiple strategies:
* 1. First, it looks for a standard 'public' directory in the project
* 2. If not found, it falls back to the composer.json configuration
*
* @return string|null Path to the public directory or null if not found
*/
private function getPublicDir(): ?string private function getPublicDir(): ?string
{ {
$projectDir = $this->getProjectDir(); $projectDir = $this->getProjectDir();
@@ -257,15 +201,6 @@ final class InstallCommand extends Command
return $this->getComposerDir('public-dir'); return $this->getComposerDir('public-dir');
} }
/**
* Gets the path to the config directory.
*
* This method tries to locate the config/packages directory using multiple strategies:
* 1. First, it looks for a standard 'config/packages' directory in the project
* 2. If not found, it falls back to the composer.json configuration
*
* @return string|null Path to the config directory or null if not found
*/
private function getConfigDir(): ?string private function getConfigDir(): ?string
{ {
$projectDir = $this->getProjectDir(); $projectDir = $this->getProjectDir();
@@ -283,11 +218,6 @@ final class InstallCommand extends Command
return $this->getComposerDir('config-dir'); return $this->getComposerDir('config-dir');
} }
/**
* Gets the project root directory from the kernel.
*
* @return string|null The project directory path or null if not available
*/
private function getProjectDir(): ?string private function getProjectDir(): ?string
{ {
$kernel = $this->getKernel(); $kernel = $this->getKernel();
@@ -303,13 +233,6 @@ final class InstallCommand extends Command
return \is_string($projectDir) ? $projectDir : null; return \is_string($projectDir) ? $projectDir : null;
} }
/**
* Gets a directory path from composer.json extra configuration.
*
* @param string $dir The directory key to look for in composer.json extra section
*
* @return string|null The directory path or null if not found
*/
private function getComposerDir(string $dir): ?string private function getComposerDir(string $dir): ?string
{ {
$projectDir = $this->getProjectDir(); $projectDir = $this->getProjectDir();
@@ -330,11 +253,6 @@ final class InstallCommand extends Command
return $composerConfig['extra'][$dir] ?? null; return $composerConfig['extra'][$dir] ?? null;
} }
/**
* Gets the kernel instance from the application.
*
* @return KernelInterface|null The Symfony kernel or null if not available
*/
private function getKernel(): ?KernelInterface private function getKernel(): ?KernelInterface
{ {
$application = $this->getApplication(); $application = $this->getApplication();
+3 -30
View File
@@ -5,42 +5,15 @@ declare(strict_types=1);
namespace Flasher\Symfony\Component; namespace Flasher\Symfony\Component;
/** /**
* FlasherComponent - Twig component for rendering notifications. * Twig component for rendering PHPFlasher notifications.
*
* This class implements a Twig component that can be used in templates to render
* PHPFlasher notifications. It supports customizing the filtering criteria,
* presenter format, and rendering context.
*
* Design patterns:
* - Component-based Architecture: Implements Twig's component pattern
* - Data Transfer Object: Holds configuration for notification rendering
*
* Usage in templates:
* ```twig
* <twig:flasher
* criteria="{{ {limit: 5} }}"
* presenter="html"
* context="{{ {foo: 'bar'} }}" />
* ```
*/ */
final class FlasherComponent final class FlasherComponent
{ {
/** /** @var array<string, mixed> */
* Filtering criteria for notifications.
*
* @var array<string, mixed>
*/
public array $criteria = []; public array $criteria = [];
/**
* Presentation format (e.g., 'html', 'json').
*/
public string $presenter = 'html'; public string $presenter = 'html';
/** /** @var array<string, mixed> */
* Additional context for rendering.
*
* @var array<string, mixed>
*/
public array $context = []; public array $context = [];
} }
@@ -9,24 +9,10 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
/** /**
* EventListenerCompilerPass - Registers event listeners with the event dispatcher. * Registers event listeners with the event dispatcher.
*
* This compiler pass finds all services tagged with 'flasher.event_listener'
* and registers them with the PHPFlasher event dispatcher. This allows for
* automatic discovery and registration of event listeners.
*
* Design patterns:
* - Compiler Pass: Modifies container definitions during compilation
* - Service Discovery: Automatically discovers tagged services
* - Observer Pattern: Helps set up the event dispatch/observer system
*/ */
final class EventListenerCompilerPass implements CompilerPassInterface final class EventListenerCompilerPass implements CompilerPassInterface
{ {
/**
* Process the container to register event listeners.
*
* @param ContainerBuilder $container The service container builder
*/
public function process(ContainerBuilder $container): void public function process(ContainerBuilder $container): void
{ {
$definition = $container->findDefinition('flasher.event_dispatcher'); $definition = $container->findDefinition('flasher.event_dispatcher');
@@ -10,24 +10,10 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
/** /**
* PresenterCompilerPass - Registers response presenters with the response manager. * Registers response presenters with the response manager.
*
* This compiler pass finds all services tagged with 'flasher.presenter'
* and registers them with the PHPFlasher response manager. This allows for
* automatic discovery and registration of response presenters.
*
* Design patterns:
* - Compiler Pass: Modifies container definitions during compilation
* - Service Discovery: Automatically discovers tagged services
* - Strategy Pattern: Helps set up pluggable response presentation strategies
*/ */
final class PresenterCompilerPass implements CompilerPassInterface final class PresenterCompilerPass implements CompilerPassInterface
{ {
/**
* Process the container to register presenters.
*
* @param ContainerBuilder $container The service container builder
*/
public function process(ContainerBuilder $container): void public function process(ContainerBuilder $container): void
{ {
$definition = $container->findDefinition('flasher.response_manager'); $definition = $container->findDefinition('flasher.response_manager');
+1 -31
View File
@@ -11,36 +11,14 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent;
/** /**
* FlasherListener - Injects PHPFlasher assets into responses. * Injects PHPFlasher assets into responses.
*
* This event subscriber listens for kernel.response events and injects
* PHPFlasher JavaScript and CSS assets into appropriate HTTP responses.
* It adapts Symfony's request and response objects to PHPFlasher's interfaces.
*
* Design patterns:
* - Observer Pattern: Observes Symfony's kernel events
* - Adapter Pattern: Adapts Symfony's request/response to PHPFlasher's interfaces
* - Event Subscriber: Subscribes to Symfony's event dispatcher system
*/ */
final readonly class FlasherListener implements EventSubscriberInterface final readonly class FlasherListener implements EventSubscriberInterface
{ {
/**
* Creates a new FlasherListener instance.
*
* @param ResponseExtensionInterface $responseExtension Service for extending responses with notifications
*/
public function __construct(private ResponseExtensionInterface $responseExtension) public function __construct(private ResponseExtensionInterface $responseExtension)
{ {
} }
/**
* Processes the response to inject PHPFlasher assets.
*
* This handler adapts Symfony's request and response objects to PHPFlasher's
* interfaces, then delegates to the response extension for asset injection.
*
* @param ResponseEvent $event The response event
*/
public function onKernelResponse(ResponseEvent $event): void public function onKernelResponse(ResponseEvent $event): void
{ {
$request = new Request($event->getRequest()); $request = new Request($event->getRequest());
@@ -49,14 +27,6 @@ final readonly class FlasherListener implements EventSubscriberInterface
$this->responseExtension->render($request, $response); $this->responseExtension->render($request, $response);
} }
/**
* {@inheritdoc}
*
* Returns events this subscriber listens to and their corresponding handlers.
* The low priority (-20) ensures this runs after most other response listeners.
*
* @return array<string, array<int, int|string>> The events and handlers
*/
public static function getSubscribedEvents(): array public static function getSubscribedEvents(): array
{ {
return [ return [
+1 -30
View File
@@ -11,36 +11,14 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent;
/** /**
* SessionListener - Processes session flash messages. * Processes session flash messages.
*
* This event subscriber listens for kernel.response events and converts
* Symfony's session flash messages to PHPFlasher notifications. This enables
* PHPFlasher to work with existing code that uses Symfony's flash messaging.
*
* Design patterns:
* - Observer Pattern: Observes Symfony's kernel events
* - Adapter Pattern: Adapts Symfony's flash messages to PHPFlasher notifications
* - Transformer Pattern: Transforms data from one format to another
*/ */
final readonly class SessionListener implements EventSubscriberInterface final readonly class SessionListener implements EventSubscriberInterface
{ {
/**
* Creates a new SessionListener instance.
*
* @param RequestExtensionInterface $requestExtension Service for processing request flash messages
*/
public function __construct(private RequestExtensionInterface $requestExtension) public function __construct(private RequestExtensionInterface $requestExtension)
{ {
} }
/**
* Processes the request to convert flash messages to notifications.
*
* This handler adapts Symfony's request and response objects to PHPFlasher's
* interfaces, then delegates to the request extension for flash processing.
*
* @param ResponseEvent $event The response event
*/
public function onKernelResponse(ResponseEvent $event): void public function onKernelResponse(ResponseEvent $event): void
{ {
$request = new Request($event->getRequest()); $request = new Request($event->getRequest());
@@ -49,13 +27,6 @@ final readonly class SessionListener implements EventSubscriberInterface
$this->requestExtension->flash($request, $response); $this->requestExtension->flash($request, $response);
} }
/**
* {@inheritdoc}
*
* Returns events this subscriber listens to and their corresponding handlers.
*
* @return array<string, array<int, int|string>> The events and handlers
*/
public static function getSubscribedEvents(): array public static function getSubscribedEvents(): array
{ {
return [ return [
@@ -8,51 +8,20 @@ use Flasher\Prime\Factory\NotificationFactoryInterface;
use Flasher\Prime\Factory\NotificationFactoryLocatorInterface; use Flasher\Prime\Factory\NotificationFactoryLocatorInterface;
use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\DependencyInjection\ServiceLocator;
/**
* NotificationFactoryLocator - Locator for notification factories using Symfony's ServiceLocator.
*
* This class adapts Symfony's ServiceLocator to PHPFlasher's NotificationFactoryLocatorInterface,
* enabling runtime discovery and lazy-loading of notification factories.
*
* Design patterns:
* - Adapter Pattern: Adapts Symfony's ServiceLocator to PHPFlasher's interface
* - Service Locator Pattern: Provides unified access to notification factory services
* - Lazy Loading: Services are only instantiated when requested
*/
final readonly class NotificationFactoryLocator implements NotificationFactoryLocatorInterface final readonly class NotificationFactoryLocator implements NotificationFactoryLocatorInterface
{ {
/** /**
* Creates a new NotificationFactoryLocator instance. * @param ServiceLocator<NotificationFactoryInterface> $serviceLocator
*
* @param ServiceLocator<NotificationFactoryInterface> $serviceLocator Symfony's service locator
*/ */
public function __construct(private ServiceLocator $serviceLocator) public function __construct(private ServiceLocator $serviceLocator)
{ {
} }
/**
* {@inheritdoc}
*
* Checks if a notification factory with the given ID exists.
*
* @param string $id The factory identifier
*
* @return bool True if the factory exists, false otherwise
*/
public function has(string $id): bool public function has(string $id): bool
{ {
return $this->serviceLocator->has($id); return $this->serviceLocator->has($id);
} }
/**
* {@inheritdoc}
*
* Gets a notification factory by ID.
*
* @param string $id The factory identifier
*
* @return NotificationFactoryInterface The notification factory
*/
public function get(string $id): NotificationFactoryInterface public function get(string $id): NotificationFactoryInterface
{ {
return $this->serviceLocator->get($id); return $this->serviceLocator->get($id);
+1 -30
View File
@@ -14,24 +14,10 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
/** /**
* FlasherSymfonyBundle - Main bundle for PHPFlasher Symfony integration. * Main bundle for PHPFlasher Symfony integration.
*
* This bundle serves as the entry point for integrating PHPFlasher with Symfony.
* It registers compiler passes, configures the container extension, and sets up
* the global container instance for PHPFlasher.
*
* Design patterns:
* - Bundle: Implements Symfony's bundle pattern for packaging functionality
* - Registry: Sets up the container registry for PHPFlasher
* - Extension: Extends the base plugin bundle with PHPFlasher-specific functionality
*/ */
final class FlasherSymfonyBundle extends Support\PluginBundle // Symfony\Component\HttpKernel\Bundle\Bundle final class FlasherSymfonyBundle extends Support\PluginBundle // Symfony\Component\HttpKernel\Bundle\Bundle
{ {
/**
* Set up the global container reference when the bundle boots.
*
* This allows PHPFlasher to access services from Symfony's container.
*/
public function boot(): void public function boot(): void
{ {
if ($this->container instanceof ContainerInterface) { if ($this->container instanceof ContainerInterface) {
@@ -39,32 +25,17 @@ final class FlasherSymfonyBundle extends Support\PluginBundle // Symfony\Compone
} }
} }
/**
* Register compiler passes with the container.
*
* @param ContainerBuilder $container The container builder
*/
public function build(ContainerBuilder $container): void public function build(ContainerBuilder $container): void
{ {
$container->addCompilerPass(new EventListenerCompilerPass()); $container->addCompilerPass(new EventListenerCompilerPass());
$container->addCompilerPass(new PresenterCompilerPass()); $container->addCompilerPass(new PresenterCompilerPass());
} }
/**
* Get the container extension for this bundle.
*
* @return ExtensionInterface The bundle extension
*/
public function getContainerExtension(): ExtensionInterface public function getContainerExtension(): ExtensionInterface
{ {
return new FlasherExtension($this->createPlugin()); return new FlasherExtension($this->createPlugin());
} }
/**
* Create the core PHPFlasher plugin.
*
* @return FlasherPlugin The core PHPFlasher plugin
*/
public function createPlugin(): FlasherPlugin public function createPlugin(): FlasherPlugin
{ {
return new FlasherPlugin(); return new FlasherPlugin();
+1 -20
View File
@@ -11,24 +11,10 @@ use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface;
/** /**
* Request - Adapter for Symfony's HTTP request. * Adapter for Symfony's HTTP request.
*
* This class implements PHPFlasher's RequestInterface for Symfony's HTTP request,
* providing a consistent interface for request inspection and session interaction
* regardless of the underlying framework.
*
* Design patterns:
* - Adapter Pattern: Adapts framework-specific request to PHPFlasher's interface
* - Decorator Pattern: Adds PHPFlasher-specific functionality to request objects
* - Null Object Pattern: Gracefully handles missing sessions
*/ */
final readonly class Request implements RequestInterface final readonly class Request implements RequestInterface
{ {
/**
* Creates a new Request adapter.
*
* @param SymfonyRequest $request The underlying Symfony request object
*/
public function __construct(private SymfonyRequest $request) public function __construct(private SymfonyRequest $request)
{ {
} }
@@ -92,11 +78,6 @@ final readonly class Request implements RequestInterface
$this->getType($type); $this->getType($type);
} }
/**
* Gets the session from the request, with graceful handling of missing sessions.
*
* @return SessionInterface|null The session or null if not available
*/
private function getSession(): ?SessionInterface private function getSession(): ?SessionInterface
{ {
try { try {
+1 -15
View File
@@ -9,24 +9,10 @@ use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
/** /**
* Response - Adapter for Symfony's HTTP response. * Adapter for Symfony's HTTP response.
*
* This class implements PHPFlasher's ResponseInterface for Symfony's HTTP response,
* providing a consistent interface for response manipulation regardless of the framework.
* It allows PHPFlasher to work with Symfony responses in a framework-agnostic way.
*
* Design patterns:
* - Adapter Pattern: Adapts framework-specific response to PHPFlasher's interface
* - Decorator Pattern: Adds PHPFlasher-specific functionality to response objects
* - Composition: Uses composition to delegate to the underlying response object
*/ */
final readonly class Response implements ResponseInterface final readonly class Response implements ResponseInterface
{ {
/**
* Creates a new Response adapter.
*
* @param SymfonyResponse $response The underlying Symfony response object
*/
public function __construct(private SymfonyResponse $response) public function __construct(private SymfonyResponse $response)
{ {
} }
+5 -56
View File
@@ -15,16 +15,7 @@ use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\Data;
/** /**
* FlasherDataCollector - Collects PHPFlasher data for the Symfony profiler. * Collects PHPFlasher data for the Symfony profiler.
*
* This data collector captures information about PHPFlasher notifications,
* both dispatched and displayed, for the Symfony web profiler. It also collects
* configuration and version information.
*
* Design patterns:
* - Data Collector: Implements Symfony's data collector pattern for profiling
* - Late Collection: Collects data after a request is completed
* - Type Safety: Uses PHPDoc annotations for complex type declarations
* *
* @phpstan-type NotificationShape array{ * @phpstan-type NotificationShape array{
* title: string, * title: string,
@@ -62,11 +53,6 @@ use Symfony\Component\VarDumper\Cloner\Data;
final class FlasherDataCollector extends AbstractDataCollector implements LateDataCollectorInterface final class FlasherDataCollector extends AbstractDataCollector implements LateDataCollectorInterface
{ {
/** /**
* Creates a new FlasherDataCollector instance.
*
* @param NotificationLoggerListener $logger The notification logger for accessing dispatched notifications
* @param array<string, mixed> $config The PHPFlasher configuration
*
* @phpstan-param ConfigShare $config * @phpstan-param ConfigShare $config
*/ */
public function __construct( public function __construct(
@@ -75,25 +61,11 @@ final class FlasherDataCollector extends AbstractDataCollector implements LateDa
) { ) {
} }
/**
* Initial data collection - called during request processing.
*
* This implementation doesn't collect data here, deferring to lateCollect.
*
* @param Request $request The request object
* @param Response $response The response object
* @param \Throwable|null $exception Any exception that occurred
*/
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{ {
// No action needed here since we're collecting data in lateCollect // No action needed here since we're collecting data in lateCollect
} }
/**
* Late data collection - called after response is sent.
*
* Collects information about notifications, configuration, and versions.
*/
public function lateCollect(): void public function lateCollect(): void
{ {
$this->data = [ $this->data = [
@@ -111,28 +83,18 @@ final class FlasherDataCollector extends AbstractDataCollector implements LateDa
} }
/** /**
* Gets the collector data. * @return array<string, mixed>|Data
*
* @return DataShape|Data<DataShape>
*/ */
public function getData(): array|Data public function getData(): array|Data
{ {
return $this->data; return $this->data;
} }
/**
* Gets the collector name for the profiler panel.
*
* @return string The collector name
*/
public function getName(): string public function getName(): string
{ {
return 'flasher'; return 'flasher';
} }
/**
* Resets the collector between requests when using kernel.reset.
*/
public function reset(): void public function reset(): void
{ {
$this->logger->reset(); $this->logger->reset();
@@ -140,9 +102,7 @@ final class FlasherDataCollector extends AbstractDataCollector implements LateDa
} }
/** /**
* Gets the displayed notification envelopes. * @return array<NotificationShape>|Data
*
* @return NotificationShape[]|Data<NotificationShape>
*/ */
public function getDisplayedEnvelopes(): array|Data public function getDisplayedEnvelopes(): array|Data
{ {
@@ -150,9 +110,7 @@ final class FlasherDataCollector extends AbstractDataCollector implements LateDa
} }
/** /**
* Gets the dispatched notification envelopes. * @return array<NotificationShape>|Data
*
* @return NotificationShape[]|Data<NotificationShape>
*/ */
public function getDispatchedEnvelopes(): array|Data public function getDispatchedEnvelopes(): array|Data
{ {
@@ -160,8 +118,6 @@ final class FlasherDataCollector extends AbstractDataCollector implements LateDa
} }
/** /**
* Gets the PHPFlasher configuration.
*
* @phpstan-return ConfigShare|Data * @phpstan-return ConfigShare|Data
*/ */
public function getConfig(): array|Data public function getConfig(): array|Data
@@ -170,20 +126,13 @@ final class FlasherDataCollector extends AbstractDataCollector implements LateDa
} }
/** /**
* Gets version information. * @return array<string, string>|Data
*
* @return array{php_flasher: string, php: string, symfony: string}|Data
*/ */
public function getVersions(): array|Data public function getVersions(): array|Data
{ {
return $this->data['versions'] ?? []; return $this->data['versions'] ?? [];
} }
/**
* Gets the template path for the profiler panel.
*
* @return string The template path
*/
public static function getTemplate(): string public static function getTemplate(): string
{ {
return '@FlasherSymfony/profiler/flasher.html.twig'; return '@FlasherSymfony/profiler/flasher.html.twig';
+2 -15
View File
@@ -5,24 +5,11 @@ declare(strict_types=1);
namespace Flasher\Symfony\Storage; namespace Flasher\Symfony\Storage;
/** /**
* FallbackSession - In-memory session storage fallback. * In-memory session storage fallback.
*
* This class provides a simple in-memory storage mechanism that can be used
* when the regular Symfony session is not available. It stores values in a
* static array, making them available for the duration of the request.
*
* Design patterns:
* - Null Object Pattern: Provides a non-failing alternative to a missing session
* - In-Memory Repository: Stores data in memory as a simple alternative to persistence
* - Singleton-like Pattern: Uses a static storage array shared across instances
*/ */
final class FallbackSession implements FallbackSessionInterface final class FallbackSession implements FallbackSessionInterface
{ {
/** /** @var array<string, mixed> */
* In-memory storage for session data.
*
* @var array<string, mixed>
*/
private static array $storage = []; private static array $storage = [];
public function get(string $name, mixed $default = null): mixed public function get(string $name, mixed $default = null): mixed
@@ -5,34 +5,11 @@ declare(strict_types=1);
namespace Flasher\Symfony\Storage; namespace Flasher\Symfony\Storage;
/** /**
* FallbackSessionInterface - Contract for alternative session storage. * Contract for alternative session storage.
*
* This interface defines methods for a fallback storage mechanism when the
* regular Symfony session is not available. This is particularly useful in
* stateless contexts or when the session hasn't been started.
*
* Design patterns:
* - Interface Segregation: Defines a minimal interface for session-like storage
* - Strategy Pattern: Allows different storage implementations to be used
* - Fallback Strategy: Provides an alternative when primary storage is unavailable
*/ */
interface FallbackSessionInterface interface FallbackSessionInterface
{ {
/**
* Retrieves a value from the fallback session storage.
*
* @param string $name the name of the value
* @param mixed $default the default value to return if the name is not found
*
* @return mixed the value from storage or default
*/
public function get(string $name, mixed $default = null): mixed; public function get(string $name, mixed $default = null): mixed;
/**
* Stores a value in the fallback session storage.
*
* @param string $name the name of the value to store
* @param mixed $value the value to store
*/
public function set(string $name, mixed $value): void; public function set(string $name, mixed $value): void;
} }
+1 -45
View File
@@ -11,48 +11,19 @@ use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface;
/** /**
* SessionBag - Symfony session storage for PHPFlasher notifications. * Symfony session storage for PHPFlasher notifications.
*
* This class implements PHPFlasher's storage interface using Symfony's session
* system, providing persistence for notifications across requests. It includes
* fallback behavior for stateless contexts.
*
* Design patterns:
* - Adapter Pattern: Adapts Symfony's session to PHPFlasher's storage interface
* - Strategy Pattern: Uses different storage strategies based on context
* - Fallback Strategy: Falls back to in-memory storage when session unavailable
* - Repository Pattern: Provides CRUD operations for notification storage
*/ */
final readonly class SessionBag implements BagInterface final readonly class SessionBag implements BagInterface
{ {
/**
* Session key for storing notification envelopes.
*/
public const ENVELOPES_NAMESPACE = 'flasher::envelopes'; public const ENVELOPES_NAMESPACE = 'flasher::envelopes';
/**
* Fallback storage for contexts where session is unavailable.
*/
private FallbackSessionInterface $fallbackSession; private FallbackSessionInterface $fallbackSession;
/**
* Creates a new SessionBag instance.
*
* @param RequestStack $requestStack Symfony's request stack for accessing session
* @param FallbackSessionInterface|null $fallbackSession Optional custom fallback storage
*/
public function __construct(private RequestStack $requestStack, ?FallbackSessionInterface $fallbackSession = null) public function __construct(private RequestStack $requestStack, ?FallbackSessionInterface $fallbackSession = null)
{ {
$this->fallbackSession = $fallbackSession ?: new FallbackSession(); $this->fallbackSession = $fallbackSession ?: new FallbackSession();
} }
/**
* {@inheritdoc}
*
* Gets all notification envelopes from storage.
*
* @return Envelope[] The stored notification envelopes
*/
public function get(): array public function get(): array
{ {
$session = $this->getSession(); $session = $this->getSession();
@@ -63,13 +34,6 @@ final readonly class SessionBag implements BagInterface
return $envelopes; return $envelopes;
} }
/**
* {@inheritdoc}
*
* Stores notification envelopes in storage.
*
* @param array<Envelope> $envelopes The notification envelopes to store
*/
public function set(array $envelopes): void public function set(array $envelopes): void
{ {
$session = $this->getSession(); $session = $this->getSession();
@@ -77,14 +41,6 @@ final readonly class SessionBag implements BagInterface
$session->set(self::ENVELOPES_NAMESPACE, $envelopes); $session->set(self::ENVELOPES_NAMESPACE, $envelopes);
} }
/**
* Gets the appropriate session storage implementation.
*
* Uses Symfony session if available and request is not stateless,
* otherwise falls back to the fallback session implementation.
*
* @return SessionInterface|FallbackSessionInterface The storage implementation
*/
private function getSession(): SessionInterface|FallbackSessionInterface private function getSession(): SessionInterface|FallbackSessionInterface
{ {
try { try {
+2 -53
View File
@@ -11,40 +11,14 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
use Symfony\Component\HttpKernel\Bundle\AbstractBundle; use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
/** /**
* PluginBundle - Base class for PHPFlasher plugin bundles. * Base class for PHPFlasher plugin bundles.
*
* This abstract class provides common functionality for all PHPFlasher plugin bundles.
* It extends Symfony's AbstractBundle to integrate with the kernel bundle system,
* while implementing PluginBundleInterface to provide PHPFlasher-specific functionality.
*
* Design patterns:
* - Template Method: Defines skeleton of common bundle operations
* - Factory Method: Creates plugin instances
* - Bridge: Connects Symfony bundle system with PHPFlasher plugin system
* - Extension: Extends AbstractBundle with PHPFlasher-specific functionality
*/ */
abstract class PluginBundle extends AbstractBundle implements PluginBundleInterface abstract class PluginBundle extends AbstractBundle implements PluginBundleInterface
{ {
/**
* Creates an instance of the plugin.
*
* This factory method must be implemented by child classes to instantiate
* the specific plugin that the bundle integrates.
*
* @return PluginInterface The plugin instance
*/
abstract public function createPlugin(): PluginInterface; abstract public function createPlugin(): PluginInterface;
/** /**
* Loads bundle configuration into the Symfony container. * @param array<string, mixed> $config
*
* This method registers the plugin's factory service in the container and
* configures it appropriately. The core FlasherSymfonyBundle is exempt from
* this process since it has special handling.
*
* @param array<string, mixed> $config The processed bundle configuration
* @param ContainerConfigurator $container The container configurator
* @param ContainerBuilder $builder The container builder
*/ */
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
{ {
@@ -67,15 +41,6 @@ abstract class PluginBundle extends AbstractBundle implements PluginBundleInterf
} }
} }
/**
* Prepends default plugin configuration for Flasher.
*
* This method adds the plugin's scripts, styles, and options to the Flasher
* configuration before the container is compiled.
*
* @param ContainerConfigurator $container The container configurator
* @param ContainerBuilder $builder The container builder
*/
public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void
{ {
if ($this instanceof FlasherSymfonyBundle) { if ($this instanceof FlasherSymfonyBundle) {
@@ -95,27 +60,11 @@ abstract class PluginBundle extends AbstractBundle implements PluginBundleInterf
]); ]);
} }
/**
* Gets the path to the plugin's configuration file.
*
* Returns the absolute path to the plugin's configuration file
* based on the bundle's path.
*
* @return string Absolute path to the configuration file
*/
public function getConfigurationFile(): string public function getConfigurationFile(): string
{ {
return rtrim($this->getPath(), '/').'/Resources/config/config.yaml'; return rtrim($this->getPath(), '/').'/Resources/config/config.yaml';
} }
/**
* Gets the bundle's directory path.
*
* Uses reflection to determine the location of the bundle class file,
* then returns its directory.
*
* @return string The bundle directory path
*/
public function getPath(): string public function getPath(): string
{ {
if (!isset($this->path)) { if (!isset($this->path)) {
+1 -22
View File
@@ -7,32 +7,11 @@ namespace Flasher\Symfony\Support;
use Flasher\Prime\Plugin\PluginInterface; use Flasher\Prime\Plugin\PluginInterface;
/** /**
* PluginBundleInterface - Contract for PHPFlasher plugin bundles. * Contract for PHPFlasher plugin bundles.
*
* This interface defines the basic requirements for a Symfony bundle that
* integrates a PHPFlasher plugin. It focuses on plugin creation and configuration.
*
* Design patterns:
* - Factory Method: Defines interface for creating plugin instances
* - Plugin Architecture: Supports extensible plugin system
* - Bridge: Connects Symfony bundle system with PHPFlasher plugin system
*/ */
interface PluginBundleInterface interface PluginBundleInterface
{ {
/**
* Creates an instance of the plugin.
*
* This factory method is responsible for instantiating the plugin that
* this bundle integrates with Symfony.
*
* @return PluginInterface The plugin instance
*/
public function createPlugin(): PluginInterface; public function createPlugin(): PluginInterface;
/**
* Gets the path to the plugin's configuration file.
*
* @return string Absolute path to the configuration file
*/
public function getConfigurationFile(): string; public function getConfigurationFile(): string;
} }
+1 -24
View File
@@ -8,37 +8,14 @@ use Flasher\Prime\Template\TemplateEngineInterface;
use Twig\Environment; use Twig\Environment;
/** /**
* TwigTemplateEngine - Adapter for Symfony's Twig template engine. * Adapter for Symfony's Twig template engine.
*
* This class adapts Symfony's Twig environment to PHPFlasher's template engine
* interface, enabling notification templates to be rendered using Twig.
*
* Design patterns:
* - Adapter Pattern: Adapts Twig to PHPFlasher's template interface
* - Null Object Pattern: Gracefully handles a missing Twig dependency
* - Bridge Pattern: Bridges PHPFlasher's templating needs with Symfony's templating system
*/ */
final readonly class TwigTemplateEngine implements TemplateEngineInterface final readonly class TwigTemplateEngine implements TemplateEngineInterface
{ {
/**
* Creates a new TwigTemplateEngine instance.
*
* @param Environment|null $twig The Twig environment or null if Twig is not available
*/
public function __construct(private ?Environment $twig = null) public function __construct(private ?Environment $twig = null)
{ {
} }
/**
* Renders a template using Twig.
*
* @param string $name The template name or path
* @param array<string, mixed> $context The template variables
*
* @return string The rendered template
*
* @throws \LogicException If Twig is not available
*/
public function render(string $name, array $context = []): string public function render(string $name, array $context = []): string
{ {
if (null === $this->twig) { if (null === $this->twig) {
+1 -36
View File
@@ -9,42 +9,14 @@ use Symfony\Component\Translation\TranslatorBagInterface;
use Symfony\Contracts\Translation\TranslatorInterface as SymfonyTranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface as SymfonyTranslatorInterface;
/** /**
* Translator - Adapter for Symfony's translation service. * Adapter for Symfony's translation service.
*
* This class adapts Symfony's translation system to PHPFlasher's TranslatorInterface,
* enabling notification messages to be translated using Symfony's translation capabilities.
* It searches for messages in multiple domains with cascading fallbacks.
*
* Design patterns:
* - Adapter Pattern: Adapts Symfony's translator interface to PHPFlasher's interface
* - Facade Pattern: Simplifies the translation process with a unified interface
* - Chain of Responsibility: Tries multiple translation domains in sequence
*/ */
final readonly class Translator implements TranslatorInterface final readonly class Translator implements TranslatorInterface
{ {
/**
* Creates a new Translator instance.
*
* @param SymfonyTranslatorInterface $translator The Symfony translator service
*/
public function __construct(private SymfonyTranslatorInterface $translator) public function __construct(private SymfonyTranslatorInterface $translator)
{ {
} }
/**
* Translates a message using Symfony's translation system.
*
* This method attempts to translate the message in the following order:
* 1. In the 'flasher' domain (flasher-specific translations)
* 2. In the 'messages' domain (application-wide translations)
* 3. Returns the original ID if no translation is found
*
* @param string $id The message ID or key
* @param array<string, mixed> $parameters The translation parameters
* @param string|null $locale The locale or null to use the default
*
* @return string The translated string
*/
public function translate(string $id, array $parameters = [], ?string $locale = null): string public function translate(string $id, array $parameters = [], ?string $locale = null): string
{ {
if (!$this->translator instanceof TranslatorBagInterface) { if (!$this->translator instanceof TranslatorBagInterface) {
@@ -62,13 +34,6 @@ final readonly class Translator implements TranslatorInterface
return $id; return $id;
} }
/**
* Gets the current locale from Symfony's translator.
*
* Falls back to system default locale if translator doesn't provide one.
*
* @return string The current locale code
*/
public function getLocale(): string public function getLocale(): string
{ {
if (method_exists($this->translator, 'getLocale')) { // @phpstan-ignore-line if (method_exists($this->translator, 'getLocale')) { // @phpstan-ignore-line
+3 -27
View File
@@ -9,33 +9,14 @@ use Twig\Extension\AbstractExtension;
use Twig\TwigFunction; use Twig\TwigFunction;
/** /**
* FlasherTwigExtension - Twig extension for rendering notifications. * Twig extension for rendering PHPFlasher notifications.
*
* This class provides Twig functions that allow notification rendering
* directly from Twig templates. It exposes PHPFlasher's rendering
* capabilities to template files.
*
* Design patterns:
* - Extension Pattern: Extends Twig's functionality
* - Adapter Pattern: Adapts PHPFlasher's API for Twig templates
* - Delegation: Delegates actual rendering to the Flasher service
*/ */
final class FlasherTwigExtension extends AbstractExtension final class FlasherTwigExtension extends AbstractExtension
{ {
/**
* Creates a new FlasherTwigExtension instance.
*
* @param FlasherInterface $flasher The PHPFlasher service
*/
public function __construct(private readonly FlasherInterface $flasher) public function __construct(private readonly FlasherInterface $flasher)
{ {
} }
/**
* Returns the Twig functions provided by this extension.
*
* @return TwigFunction[] Array of Twig functions
*/
public function getFunctions(): array public function getFunctions(): array
{ {
return [ return [
@@ -44,13 +25,8 @@ final class FlasherTwigExtension extends AbstractExtension
} }
/** /**
* Renders the flash notifications based on the specified criteria, presenter, and context. * @param array<string, mixed> $criteria
* * @param array<string, mixed> $context
* @param array<string, mixed> $criteria the criteria to filter the notifications
* @param "html"|"json"|string $presenter The presenter format for rendering the notifications (e.g., 'html', 'json').
* @param array<string, mixed> $context additional context or options for rendering
*
* @return mixed The rendered output (HTML string, JSON string, etc.)
*/ */
public function render(array $criteria = [], string $presenter = 'html', array $context = []): mixed public function render(array $criteria = [], string $presenter = 'html', array $context = []): mixed
{ {