Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Bernard Bundle Laravel Package

bernard/bernard-bundle

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require bernard/bernard-bundle

Add to AppKernel.php:

$bundles[] = new Bernard\BernardBundle\BernardBundle();
  1. Configure Driver (e.g., config/packages/bernard.yaml):

    bernard:
        driver: file
        options:
            directory: "%kernel.project_dir%/var/bernard"
    

    Tested drivers: file, doctrine, phpamqp, phpredis, ironmq, sqs, pheanstalk.

  2. First Use Case: Create a receiver service (e.g., src/Message/Handler/SendNewsletterHandler.php):

    namespace App\Message\Handler;
    
    use Bernard\MessageHandlerInterface;
    
    class SendNewsletterHandler implements MessageHandlerInterface
    {
        public function __invoke($message)
        {
            // Handle message (e.g., send newsletter)
            return true;
        }
    }
    

    Register it in config/services.yaml:

    services:
        App\Message\Handler\SendNewsletterHandler:
            tags:
                - { name: bernard.receiver, message: SendNewsletter }
    
  3. Produce a Message:

    php bin/console bernard:produce SendNewsletter '{"to":"user@example.com"}'
    
  4. Consume Messages (in a separate terminal):

    php bin/console bernard:consume --no-debug
    

Implementation Patterns

Workflows

  1. Message Production:

    • Use bernard:produce for CLI or inject Bernard\MessageProducerInterface in controllers/services:
      use Bernard\MessageProducerInterface;
      
      class NewsletterController
      {
          public function __construct(private MessageProducerInterface $producer) {}
      
          public function send()
          {
              $this->producer->send(new SendNewsletter('user@example.com'));
          }
      }
      
  2. Message Consumption:

    • Daemonize the Consumer: Use supervisord or systemd to run bernard:consume persistently. Example systemd service (/etc/systemd/system/bernard.service):
      [Unit]
      Description=Bernard Message Consumer
      After=network.target
      
      [Service]
      ExecStart=/usr/bin/php /path/to/bin/console bernard:consume --no-debug
      User=www-data
      Restart=always
      
      [Install]
      WantedBy=multi-user.target
      
    • Batch Processing: Use middleware to batch messages (e.g., Bernard\Middleware\BatchMiddleware).
  3. Error Handling:

    • Implement Bernard\MessageHandlerInterface with exception handling:
      public function __invoke($message)
      {
          try {
              // Logic
          } catch (\Exception $e) {
              // Log or retry (e.g., throw $e or return false)
          }
      }
      
    • Use bernard:debug to inspect registered receivers and middleware.
  4. Middleware Integration:

    • Add custom middleware (e.g., logging, validation):
      # config/services.yaml
      App\Middleware\LoggingMiddleware:
          tags:
              - { name: bernard.middleware, priority: 100 }
      
      namespace App\Middleware;
      
      use Bernard\Middleware\MiddlewareInterface;
      
      class LoggingMiddleware implements MiddlewareInterface
      {
          public function handle($message, callable $next)
          {
              \Log::info('Processing message', ['message' => $message]);
              return $next($message);
          }
      }
      
  5. Testing:

    • Mock MessageProducerInterface in unit tests:
      $producer = $this->createMock(MessageProducerInterface::class);
      $producer->expects($this->once())->method('send');
      $controller = new NewsletterController($producer);
      $controller->send();
      
    • Use Bernard\Test\ConsumerTestCase for integration tests.

Gotchas and Tips

Pitfalls

  1. Debug Mode Memory Leaks:

    • Always use --no-debug for long-running consumers to avoid memory bloat from Symfony’s debug toolbar and profiler.
  2. Driver-Specific Quirks:

    • Doctrine: Ensure the connection option matches your doctrine.dbal.connections name.
    • Redis: Disable SncRedisBundle logging (logging: false) to avoid RedisException issues.
    • SQS: Set prefetch: 1 to avoid invisibility timeout errors (default is >1).
  3. Message Serialization:

    • Bernard uses Bernard\Serializer\SerializerInterface. For custom types, implement a normalizer:
      use Bernard\Serializer\Normalizer\NormalizerInterface;
      
      class CustomNormalizer implements NormalizerInterface
      {
          public function normalize($object, $format = null, array $context = [])
          {
              return ['custom' => 'data'];
          }
      
          public function denormalize($data, $class, $format = null, array $context = [])
          {
              return new $class();
          }
      }
      
      Register it in services.yaml:
      App\Serializer\CustomNormalizer:
          tags:
              - { name: bernard.normalizer }
      
  4. Receiver Registration:

    • Ensure services tagged with bernard.receiver are public (public: true in YAML or public: true in PHP config).
    • Use bernard:debug to verify receivers are registered:
      php bin/console bernard:debug
      
  5. Middleware Order:

    • Middleware priority (lower numbers run first). Example:
      tags:
          - { name: bernard.middleware, priority: 50 } # Runs after priority 100
      

Debugging

  1. Consumer Stuck?:

    • Check logs for exceptions. Use --verbose for detailed output:
      php bin/console bernard:consume --verbose
      
    • For Redis, increase connection_timeout in SncRedisBundle config.
  2. Message Not Processed?:

    • Verify the message type matches a registered receiver (case-sensitive).
    • Check middleware logs for failures.
  3. Performance Issues:

    • For high-throughput queues (e.g., SQS), adjust prefetch and monitor visibility timeouts.
    • Use Bernard\Middleware\BatchMiddleware to reduce database/Redis calls.

Extension Points

  1. Custom Drivers:

    • Extend Bernard\Driver\DriverInterface and register via bernard.driver tag in services.yaml.
  2. Dynamic Receivers:

    • Load receivers dynamically (e.g., from a database) by implementing a compiler pass:
      use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
      use Symfony\Component\DependencyInjection\ContainerBuilder;
      
      class DynamicReceiverPass implements CompilerPassInterface
      {
          public function process(ContainerBuilder $container)
          {
              $receivers = $this->fetchReceiversFromDatabase();
              foreach ($receivers as $serviceId => $message) {
                  $container->getDefinition($serviceId)
                      ->addTag('bernard.receiver', ['message' => $message]);
              }
          }
      }
      
      Register the pass in BernardBundle’s extension.
  3. Async Consumption:

    • Use Symfony’s Messenger component alongside Bernard for hybrid async/sync workflows:
      # config/packages/messenger.yaml
      framework:
          messenger:
              transports:
                  bernard: '%env(MESSENGER_TRANSPORT_DSN)%'
              routing:
                  'App\Message\SendNewsletter': bernard
      
  4. Monitoring:

    • Integrate with tools like Laravel Horizon (via php-amqplib) or Prometheus by extending Bernard’s driver metrics.
    • Example: Add metrics to Bernard\Driver\FileDriver:
      use Prometheus\CollectorRegistry;
      
      class MetricsFileDriver extends FileDriver
      {
          public function __construct(CollectorRegistry $registry)
          {
              $this->registry = $registry;
          }
      
          public function pop()
          {
              $this->registry->getOrRegisterCounter('bernard_messages_popped')->inc();
              return parent::pop();
          }
      }
      

Configuration Quirks

  1. Cache Directory:

    • Avoid %kernel.cache_dir% for file driver—it’s cleared on cache:clear. Use var/bernard instead.
  2. Symfony 3+:

    • Ensure bernard/bernard-bundle:^2.0 for Symfony 3+ compatibility (v1.x supports Symfony 2.7+).
  3. Environment Variables:

    • Use %env() for sensitive options (e.g., Redis passwords):
      bernard:
          driver
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours