5
votes

I have a number of private, custom bundles that I use in my Symfony projects. Under Symfony 3, they lived in a sub-directory of src:

src/
    DSL/
      DSLLibraryBundle/
      DSLTelnetBundle/
      ...
    SiteBundle/      # (or AppBundle)

Under Symfony 4, the application-specific bundle is gone and it's unclear to me where my custom bundles should live.

The documentation on bundles (https://symfony.com/doc/current/bundles/best_practices.html#bundles-naming-conventions) provide no specific recommendations for placing custom bundles.

I have tried placing my DSL directory directly under the project directory and under src/. I end up with undefined class errors either way.

I currently have:

src/
    DSL/
        LibraryBundle/
            DSLLibraryBundle.php

The bundle file:

// src/DSL/DSLLibrary/DSLLibraryBundle.php:

namespace DSL\LibraryBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class DSLLibraryBundle extends Bundle
{

}

The entry in bundles.php:

DSL\LibraryBundle\DSLLibraryBundle::class => ['all' => true],

Current error when running a console command:

PHP Fatal error: Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "DSLLibraryBundle" from namespace "DSL\LibraryBundle".

A couple of notes:
- My custom bundles are not installed via Composer
- The actual DSL/ directory will be a symlink once I get this working

4

4 Answers

3
votes

Update April 12, 2019: In the end, I took a completely different approach than my initial attempts.
In a nutshell, I now use composer to include my custom bundles.

My custom bundles live in their own directory tree.
Each bundle must have a valid composer.json file defining the bundle. For example:

{
  "name": "dsl/base-bundle",
  "description": "Base bundle required by all other DSL bundles",
  "type": "symfony-bundle",
  "version": "2.1.0",
  "license": "proprietary",
  "authors": [{"name": "David M. Patterson", "email": "[email protected]"}],
  "minimum-stability": "stable",
  "require": {
  },
  "require-dev": {
  },
  "autoload": {
    "psr-4":  {
      "Dsl\\BaseBundle\\": "src/"
    }
  }
}

Then define a custom repository in the project's composer.json file:

"repositories":[
  {
    "type": "path",
    "url":  "/full/path/to/DslBaseBundle"
  },
 ], ...

Then do a composer require dsl/base-bundle
Composer will create a symlink in vendor/ to the bundle and everything works as expected from there on.

My personal library is a regular Symfony project with a lib sub-directory that contains my bundles, each in its own sub-directory below lib/.

The Symfony application provides me with a convenient test bed. Note that the custom bundles must be included in it the same as for any other Symfony project.

@Stnaire, hope that helps.

1
votes

Update 30-Jan-2017:

Okay. As far as I can tell, Symfony 4 is, effectively, private bundle hostile.

Additional work just kept turning up more and more problems (like getting unit testing to work for a private bundle).

I am currently pursuing other options that won't result in too much additional daily work.

Please ignore my original answer below.

--

My original answer:

After some more digging I realized that the classes in my custom bundle directory tree were not being picked up by composer during dump-autoload.

I think this is because Symfony 4 is not expecting any bundles except in vendor/.

The solution was to add my library directory to composer.json.

So My project tree now contains a directory for my private, custom bundles.

<projectName>/
    assets/
    ...
    DSL/
        DSLLibraryBundle/
        DSLTelnetBundle/
        ...
    public/
    src/
    ...

My composer.json autoload.psr-4 entry now looks like this:

"autoload": {
    "psr-4": {
        "App\\": "src/",
        "DSL\\": "DSL/"
    }
},
1
votes

It's actually not as bad as it's painted in other comments - you can still have your private bundles inside src/, you just have to explicitly exclude them from autowiring, so they don't get accidentally loaded with an incorrect namespace.

Lets say you have a PrivateBundle in src/PrivateBundle.

You set up it's autoloading in composer.json like so:

"autoload": {
  "psr-4": {
    "App\\": "src/",
    "SomeNamespace\\PrivateBundle\\": "src/PrivateBundle/"
  }
}

and in your services configuration (I usually use config/services.yaml) do this:

# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
    resource: '../src/*'
    exclude: '../src/PrivateBundle'

If you don't add this exclude, your SomeNamespace\PrivateBundle\* classes get automatically loaded by Symfony as App\PrivateBundle\*, but contain namespace SomeNamespace\PrivateBundle;, so when PHP detects a usage of SomeNamespace\PrivateBundle it autoloads them again through Composer, resulting in Cannot declare class *, because the name is already in use errors.

0
votes

Symfony4 no longer uses bundles inside the src/ . Bundles are only used within vendor/ as dependencies.