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

Bundle Helpers Laravel Package

21torr/bundle-helpers

Helpers for Symfony bundles to streamline implementation. Provides shared utilities and conveniences for other bundles, reducing boilerplate and keeping bundle setup consistent and easier to maintain. Docs available online.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require 21torr/bundle-helpers
    

    Ensure your project meets the requirements: Symfony 7+ (or 8) and PHP 8.3+.

  2. First Use Case: Create a basic bundle extension with autogenerated aliases and configuration support:

    use TwoOneTorr\BundleHelpers\Bundle\Extension\BundleExtension;
    
    class MyBundleExtension extends BundleExtension
    {
        public function load(array $configs, ContainerBuilder $container): void
        {
            $configuration = new Configuration();
            $config = $this->processConfiguration($configuration, $configs);
    
            // Register services or configurations here
        }
    }
    
    • The BundleExtension base class handles:
      • Automatic alias generation (@my_bundle.service).
      • Proper getConfiguration() setup (no manual overrides needed).
      • Type-safe configuration processing.
  3. Where to Look First:

    • Official Docs for API reference.
    • src/Extension/BundleExtension.php for core functionality.
    • tests/ for real-world usage examples (e.g., dependency injection, configuration merging).

Implementation Patterns

Core Workflows

1. Configuration-Driven Services

Use BundleExtension to define services dynamically based on user config:

public function load(array $configs, ContainerBuilder $container): void
{
    $config = $this->processConfiguration(new Configuration(), $configs);

    foreach ($config['services'] as $id => $serviceConfig) {
        $container->register($id, $serviceConfig['class'])
            ->setArguments($serviceConfig['arguments'] ?? []);
    }
}
  • Pro Tip: Leverage Configuration class for validation:
    class Configuration implements ConfigurationInterface
    {
        public function getConfigTreeBuilder(): TreeBuilder
        {
            $treeBuilder = new TreeBuilder('my_bundle');
            $treeBuilder->getRootNode()
                ->children()
                    ->arrayNode('services')
                        ->useAttributeAsKey('id')
                        ->arrayPrototype()
                            ->children()
                                ->scalarNode('class')->isRequired()->end()
                                ->arrayNode('arguments')->useAttributeAsKey('name')->end()
                            ->end()
                        ->end()
                    ->end();
            return $treeBuilder;
        }
    }
    

2. Alias Autogeneration

Avoid manual alias definitions:

// In MyBundleExtension.php
protected function getAliases(): array
{
    return [
        'my_bundle.service' => static::class . '::getServiceAlias',
    ];
}

public static function getServiceAlias(ContainerBuilder $container, string $id): string
{
    return 'my_bundle.' . $id; // e.g., "my_bundle.user_repository"
}
  • Use Case: Dynamically generate service aliases for plugins or modular components.

3. Dependency Injection Simplification

Use BundleExtension to inject dependencies into services:

$container->register('my_bundle.logger', LoggerInterface::class)
    ->setPublic(true)
    ->setArgument('$logger', new Reference('logger'));

4. Event Subscribers

Attach subscribers without manual service registration:

public function load(array $configs, ContainerBuilder $container): void
{
    $container->register('my_bundle.event_subscriber', EventSubscriber::class)
        ->addTag('kernel.event_subscriber', ['event' => 'my_event']);
}

Integration Tips

  • Symfony Flex: Works seamlessly with config/packages/my_bundle.yaml.
  • Monorepos: Use autoload-dev for local testing:
    {
        "autoload-dev": {
            "psr-4": {
                "TwoOneTorr\\BundleHelpers\\": "vendor/21torr/bundle-helpers/src/"
            }
        }
    }
    
  • Testing: Mock BundleExtension in PHPUnit:
    $extension = $this->createMock(BundleExtension::class);
    $extension->method('processConfiguration')->willReturn(['enabled' => true]);
    

Gotchas and Tips

Pitfalls

  1. Namespace Mismatch:

    • Error: Class 'TwoOneTorr\BundleHelpers\...' not found.
    • Fix: Ensure your composer.json autoloads the package correctly. For local dev:
      composer dump-autoload
      
  2. Configuration Overrides:

    • Gotcha: processConfiguration() may silently ignore invalid configs if ConfigurationInterface isn’t implemented.
    • Fix: Always extend Configuration and define a TreeBuilder:
      class Configuration extends ContainerConfiguration
      {
          // ...
      }
      
  3. Symfony Version Conflicts:

    • Error: Method "load()" must be of type void (Symfony 7+).
    • Fix: Ensure your BundleExtension extends TwoOneTorr\BundleHelpers\Bundle\Extension\BundleExtension (not Symfony’s base class).
  4. Alias Collisions:

    • Gotcha: Custom aliases (e.g., @my_bundle.service) may conflict with Symfony’s built-in aliases.
    • Fix: Prefix aliases with your bundle name (e.g., @my_bundle.my_service).

Debugging

  • Dumping Configs: Use var_dump($this->processConfiguration(...)) to inspect merged configs.
  • Service Dump:
    php bin/console debug:container --parameters | grep my_bundle
    
  • Extension Logs: Enable debug mode to trace extension loading:
    php bin/console debug:configurator my_bundle
    

Extension Points

  1. Custom Configuration: Extend Configuration to add validation:

    $treeBuilder->getRootNode()
        ->children()
            ->booleanNode('debug')
                ->defaultFalse()
                ->info('Enable debug mode')
            ->end();
    
  2. Dynamic Service Loading: Use ContainerBuilder::register() with closures for lazy-loading:

    $container->register('my_bundle.dynamic_service', function (ContainerInterface $container) {
        return new DynamicService($container->get('some.dependency'));
    });
    
  3. Environment-Specific Configs: Override load() to conditionally load services:

    if ($container->getParameter('kernel.environment') === 'dev') {
        $container->loadFromExtension('my_bundle', ['debug' => true]);
    }
    

Pro Tips

  • Type Safety: Use PHP 8.3’s array_key_first() with Configuration to enforce required keys:
    $config = $this->processConfiguration(new Configuration(), $configs);
    if (!array_key_first($config['services'])) {
        throw new \InvalidArgumentException('At least one service must be defined.');
    }
    
  • Performance: Cache compiled configs in var/cache/dev/ for faster dev cycles.
  • Documentation: Annotate your Configuration with PHPDoc for IDE hints:
    /**
     * @property array<string, mixed> $services
     */
    class Configuration implements ConfigurationInterface { ... }
    
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor