In newer versions of Symfony, the structure of bundles has changed. In my opinion, it is not clearly described in the documentation how to create such a bundle.

For example, we will create a godrar/core bundle.

Each bundle should have a composer configuration file.

composer.json

{
    "name": "godrar/core",
    "type": "symfony-bundle",
    "description": "Wspólna biblioteka dla projektów Symfony",
    "autoload": {
        "psr-4": {
            "Godrar\\CoreBundle\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Godrar\\CoreBundle\\Tests\\": "tests/"
        }
    },
    "minimum-stability": "dev"
}

We add the bundle configuration file.

src/GodrarCoreBundle.php

<?php

namespace Godrar\CoreBundle;

use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

class GodrarCoreBundle extends AbstractBundle
{
}

The directory structure is described on the Symfony website:

https://symfony.com/doc/current/bundles/best_practices.html#services

TypeDirectory
Commandssrc/Command/
Controllerssrc/Controller/
Service Container Extensionssrc/DependencyInjection/
Doctrine ORM entitiessrc/Entity/
Doctrine ODM documentssrc/Document/
Event Listenerssrc/EventListener/
Configuration (routes, services, etc.)config/
Web Assets (compiled CSS and JS, images)public/
Web Asset sources (.scss, .ts, Stimulus)assets/
Translation filestranslations/
Validation (when not using attributes)config/validation/
Serialization (when not using attributes)config/serialization/
Templatestemplates/
Unit and Functional Teststests/

You no longer need to add configuration, translation, or template files to the src/Resources directory, as was previously required.


Configuration files within bundles are not automatically processed.


If a bundle contains a service, you can manually add it to the project’s services.yaml to make it visible.

config/services.yaml

services:
    Godrar\CoreBundle\EventListener\TimestampableListener: ~

We can also create a configuration file within the bundle and import it into services.yaml.
Below, autowiring and autoconfiguration are set up for our bundle.

config/services.yaml (in bundle)

parameters:

services:
    Godrar\CoreBundle\:
        autowire: true
        autoconfigure: true

        resource: '../src/*'

Import in the project configuration file.

config/services.yaml

imports:
    - { resource: '@GodrarCoreBundle/config/services.yaml' }

We can also set up automatic configuration loading so that nothing needs to be imported manually (this is the most convenient approach).

src/GodrarCoreBundle.php

<?php

namespace Godrar\CoreBundle;

use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

class GodrarCoreBundle extends AbstractBundle
{
    public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
    {
        $container->import('../config/services.yaml');
    }
}

Installing our bundle via Composer:

composer require godrar/core

Installing our bundle via Composer:

composer require godrar/core:dev-main-sf7

When installing via Composer, the bundle will be automatically registered in the file:

config/bundles.php

return [
    …
    Godrar\CoreBundle\GodrarCoreBundle::class => ['all' => true],
]