Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Proper Bundle composer.json File

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $8.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

We put the bundle into our app temporarily because it made it really easy to hack on the bundle, test in the app and repeat.

But now that it's getting kinda stable, it's time to move the bundle into its own directory with its own repository. It's like watching your kid grow up, and finally move into their own apartment.

Find your terminal, and kick that lazy bundle out of your house and into a new directory next door:

mv lib/LoremIpsumBundle ../LoremIpsumBundle

In PhpStorm, let's open that second directory inside a new window, and re-decorate things a little bit. Ok, a lot to keep track of: application code, bundle code and terminal. To confuse things more, open a third terminal tab and move it into the bundle, which, sadly, does not have a git repository yet!

Let's add one!

git init git status

Add everything and commit!

git add .
git commit -m "Unicorns"

Bootstrapping composer.json

To make this a shareable package, it needs its very-own composer.json file. To create it, run:

composer init

Let's call it knpuniversity/lorem-ipsum-bundle, give it a description, make sure the author is correct, leave minimum-stability alone and, for "Package Type" - this is important! - use symfony-bundle. That's needed so that Flex will automatically enable the bundle when it's installed. For License, I'll use MIT - but more on that later. And finally, let's not add any dependencies yet. And, generate! Let's definitely ignore the vendor/ directory.

{
"name": "knpuniversity/lorem-ipsum-bundle",
"description": "Happy lorem ipsum",
"type": "symfony-bundle",
"license": "MIT",
"authors": [
{
"name": "Ryan Weaver",
"email": "ryan@knpuniversity.com"
}
],
"require": {}
}

Hello .gitignore file and hello composer.json! This file has a few purposes. First, of course, it's where we will eventually require any packages the bundle needs. We'll do that later. But I am going to start at least by saying that we require php 7.1.3. That's the version that Symfony 4.0 requires.

... lines 1 - 11
"require": {
"php": "^7.1.3"
}
... lines 15 - 16

Autoloading Rules

Second, the composer.json file is where we define our autoloading rules: Composer needs to know what namespace our bundle uses and where those classes live.

Up until now, we put those autoload rules inside the main project. Let's steal that section and remove the line for our bundle. Paste that into the bundle and remove the App line. The KnpU\\LoremIpsumBundle\\ namespace lives in just, src/.

... lines 1 - 14
"autoload": {
"psr-4": {
"KnpU\\LoremIpsumBundle\\": "src/"
}
}
... lines 20 - 21

Using a "path" Repository

So... yay! We have a standalone bundle with its own repository! But, I'm not quite ready to push this to Packagist yet... and I kinda want to keep testing it inside my app. But, how? We can't composer require it until it lives on Packagist, right?

Well, there is one trick. Google for "composer path package".

Click on the "Repositories" documentation and... all the way at the bottom... there's a path option! This allows us to point to any directory on our computer that contains a composer.json file. Then, suddenly, that library becomes available to composer require.

Copy the repositories section, find our application's composer.json and, at the bottom, paste this. The library lives at ../LoremIpsumBundle.

Tip

The course code contains LoremIpsumBundle project inside itself, hence you won't see ../ on the repository URL in the code blocks.

83 lines composer.json
... lines 1 - 75
"repositories": [
{
"type": "path",
"url": "LoremIpsumBundle"
}
]
... lines 82 - 83

Thanks to that, our application now knows that there is a package called knpuniversity/lorem-ipsum-bundle available. Back at the terminal, find the tab for our application and composer require knpuniversity/lorem-ipsum-bundle, with a :*@dev at the end.

composer require "knpuniversity/lorem-ipsum-bundle:*@dev"

A path package isn't quite as smart as a normal package: you don't have versions or anything like that: it just uses whatever code is in that directory. This tells Composer to require that package, but not worry about the version.

And, cool! On my system, it installed with a symlink, which means we can keep hacking on the bundle and testing it live in the app.

Oh, and since Symfony flex noticed that our package has a symfony-bundle type, it actually tried to configure a recipe, which would normally enable the bundle for us in bundles.php. It didn't this time, only because we already have that code.

Now that everything is reconnected, it should work! Refresh the page. Yes! That bundle is properly living on its own.

Next, we actually already have some tests for our bundle... but they still live in the app. Let's move these into the bundle and start talking about properly adding the dependencies that it needs.

Leave a comment!

49
Login or Register to join the conversation
Zinger Avatar

Note that if you're using docker, the local repo path method will not work. The symlink inside your docker container will fail. A workaround is to place your project files one folder deeper before initializing docker, and placing your bundle in that parent folder so that the bundle files get added into your docker container.

1 Reply

Hey S.A.

Thank you for this tip about Docker!

Cheers!

Reply
Cameron Avatar
Cameron Avatar Cameron | posted 2 years ago

Hmm, would it be better to use got submodule and add the bundle to gitignore?

for instance, are there issues when you clone the project to a new computer and it's not clear where the bundle comes from? Or is this taken care of? 🤔

Reply

Hey Cameron,

It should be clear enough - Composer should fail with a clear message, so yes, you would need to do something to fix it but it should be understandable what to do, depends on your file structure.

About git submodules - not sure, it might be easier, I agree... but fairly speaking I have never used them, so not sure about any pitfalls you might find with them.

Cheers!

Reply
Jérémie Avatar
Jérémie Avatar Jérémie | posted 3 years ago

It seems that I have the same problem as Frank J, but I cannot solve my problem.
I tried to rename several times the name of the bundle class and the directory ... I followed the naming conventions of the documentation and the directory structure but it didn't work. Finally, I did as in the course but it still doesn't work ... My bundle works well but flex still doesn't want to add the bundle in bundles.php. If someone wants to take a look here is the link to the repository: https://github.com/sheeptiz...

Reply
Jérémie Avatar

It's ok now, I don't know why the recipe still does not work in the original project from which it was extracted BUT the installation of the bundle and the recipe works with all my other Symfony projects. Weird but I give up the idea of understanding, too bad!

Reply

Hey Jérémie!

Hmm, that is super weird! Just thinking... it could be that the bundle was already "marked" as being installed in the symfony.lock file in your original project. So when you set things up so that bundles.php would be updated, it didn't happen because Flex said "Hey! I see that this recipe (well, there was no recipe at the time really) was already installed! So I'll do nothing".

Or... maybe something else weird happened ;). Anyways, glad it's working for you now.

Cheers!

Reply
Jérémie Avatar
Jérémie Avatar Jérémie | weaverryan | posted 3 years ago

Hello, I tried and it corrected the problem! Thank you so much for the info.

Reply
Jérémie Avatar
Jérémie Avatar Jérémie | posted 3 years ago

Hello, great lesson. I was wondering about the yaml file (in the course the knpu_lorem_ipsum.yaml file) if it was normal that it is not created when installing the Bundle. I think yes I noticed that many recipes have these files described on the server (for example config / package / mybundle.yaml). The presence of these files in the deposit folder guarantees their creation when downloading the Bundle? Is this the same principle if I need to fill a resource to an internal routing file in the bundle, by creating config / routes / my_route_info.yaml?

Reply

Hey Jeremie,

It's fine that the config file is not created automatically when you require the bundle with Composer. Technically, Flex only add your bundle to the bundles.php to include and activate it in your project, and that's it. Well, you can teach Flex to create a config file as well if you really need this. Like if you know that your bundle should always have a config file where users will always tweak some values. But if your bundles have good defaults values - probably you don't need to force creating that config file at all - the less config files the better, as it's easier for your to focus on other config files. If *some* devs who use your bundle need that config - they will create it themselves.

But if you really think that every installation of your bundle should contain that config file because every user want to set a specific unique config for their project - you can teach Flex, i.e. create a recipe for your bundle in https://github.com/symfony/... . Symfony has 2 repositories for recipes: https://github.com/symfony/... that contain official recipes and https://github.com/symfony/... that contain third-party recipes.

Here's an example of how to create such recipes: https://github.com/symfony/...

I hope this helps!

Cheers!

1 Reply
Jérémie Avatar
Jérémie Avatar Jérémie | Victor | posted 3 years ago

Hi Victor, thank you for your reply. It is very clear and thank you again for this explanation and the links.

Reply

Thanks for this great insight on Symfony bundles! Really enjoying the course so far.
I have a question. I tried to install the local bundle via composer and it works but... flex doesn't seem to enable the bundle at all in bundles.php. I tried removing everything, cleared caches, and still it doesn't seem to work. Is this an expected behavior since ':*@dev' or is there any configuration I'm missing? Thanks.

Reply

Hey FranksPress

If I understood correctly, your custom bundle is not being automatically installed by Symfony Flex. If that's the case, then you just need to mark your bundle as a Symfony bundle. Check the related docs here: https://symfony.com/doc/mas...

Cheers!

Reply

Hi again, yes it was configured as symfony-bundle and it still wasn't being installed by Symfony Flex. The trouble was that I decided to call my bundle 'test/testbundle' and for some reason it was ignored by Symfony Flex. Now it works. Thanks

Reply

Ha! That's weird, Symfony Flex may ignore bundles by default if it thinks that they live in the tests namespace

Reply
Jesús L. Avatar
Jesús L. Avatar Jesús L. | posted 3 years ago

Hi, thanks for the tutorial, I have a small problem importing the bundle and I don't know if they could help me.
The bundle works correctly, while it resides within lib.
When you create the bundle and import it, you import it correctly and it appears in the vendors directory, but unfortunately, you cannot load the extension or configuration classes.
I have tried to take the package into the src directory and even remove everything from the src directory, leaving it as follows but without success, when debugging: container. My services are not registered. Just as the record is not created in bundles.php or the configuration yaml in packages.

myBundle / src / DependencyInjection ...
myBundle / composer.json

The autoload would look like this:
"autoload": {
"psr-4": {
"Idv \\ MyBundle \\": ""
}
}
or
"autoload": {
"psr-4": {
"Idv \\ MyBundle \\": "src /"
}
}

What could be happening?
Thank you

P.D i use symfony 4.2 and 4.3

Reply
Jesús L. Avatar

Sorry the package name in composer.json was incorrect, fixed! Thank you

Reply

Hey Jesus,

Glad you figured the problem yourself! And thank you for sharing your solution with others.

Cheers!

Reply
Default user avatar
Default user avatar Victor Toulouse | posted 4 years ago

Hi! Not sure if it's the right place to ask, but here it goes:
How do you determine the version constraints on your dependencies?

Reply

Hey Victor Toulouse

That's a good question. We usually set our dependencies to only update on minor updates by using the carrot constraint "^", e.g. "symfony/monolog-bundle": "^3.0.2", but it may depend on the library, if you know that the library's owner won't introduce a BC break on any minor update, then that's a safe choice, but if you don't trust it too much, then you may want to only update on patch updates or don't update at all.

If you want to know the details about constraints, then I recommend you to read this guide: https://madewithlove.be/tilde-and-caret-constraints/

Cheers!

1 Reply
Default user avatar
Default user avatar Victor Toulouse | MolloKhan | posted 4 years ago

Thank for the reply!
But, I was rather thinking about the process of choosing version constraints more than how to enforce them.
I'm sorry, that wasn't very clear.
For example: let's say I need a class from a symfony component which is currently in version 4.
But of course I'd like my version constraints to be as flexible as possible. I don't want to force all the projects using my bundle to use version 4 of that component if version 2 and 3 also work, right?

Is there any way of finding the compatible versions of the component other than manually installing them one by one and checking that all required files are present and everything still works?
Maybe running automated tests with a range of different dependency versions?

Reply

Oh I get it, then you could setup your dependencies using the pipe "|" operator, e.g. "symfony/console": "3 | 4", of course, your bundle has to be flexible enough for working correctly on both versions. About automated tests for checking different versions, you could use TravisCI for that task. I'm not an expert about Travis but I've seen many projects using it, like this one: https://github.com/symfony/monolog-bundle/blob/master/.travis.yml

I hope this help you :). Cheers!

1 Reply
Default user avatar
Default user avatar Victor Toulouse | MolloKhan | posted 4 years ago

Oh, right! Travis can do that :)
Found it in the doc:
https://docs.travis-ci.com/...
And also another specific example there:
https://dyrynda.com.au/blog...

Thanks a lot!

Reply

Excellent! Thanks for sharing those links :)

Reply
Bertin Avatar
Bertin Avatar Bertin | posted 5 years ago | edited

I've moved my bundle in its own directory but getting the following error:

"(1/1) ClassNotFoundException
Attempted to load class "BhamMenuBundle" from namespace "Bham\MenuBundle".
Did you forget a "use" statement for another namespace?"

There is something wrong with the namespace but i've followed the same steps.
I've added the composer path


# config/bundles.php
    "repositories": [
        {
            "type": "path",
            "url": "../MenuBundle/"
        }
    ]

These are my files;

<b>Application</b>


# config/bundles.php
return [
    ...
    Bham\MenuBundle\BhamMenuBundle::class => ['all' => true],
];

# vendor/bham/menu-bundle/src/
/**
 * BhamMenuBundle
 */

namespace Bham\MenuBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
 * Class BhamMenuBundle
 * @package Bham\MenuBundle
 */
class BhamMenuBundle extends Bundle {

}

<b>Bundle</b>


#MenuBundle/composer.json
{
    "name": "bham/menu-bundle",
    "description": "Generate a menu with BhamMenuBundle",
    "type": "symfony-bundle",
    "license": "MIT",
    "authors": [
        {
            "name": "Bertin van den Ham",
            "email": "bertinvandenham@gmail.com"
        }
    ],
    "require": {
        "php": "^7.1.3"
    },
    "autoload": {
        "psr-4": {
            "Bham\\MenuBundle\\" : "src/"
        }
    }
}

Also run the command composer dumpautoload.
Also removed the cached directory and removed the composer.lock file
but now i'am getting this error:

composer require bham/menu-bundle:*@dev

" [InvalidArgumentException]
Could not find a matching version of package bham/menu-bundle. Check the package spelling, your version constraint and that the package is available in a stability which matc
hes your minimum-stability (stable)."

Does i miss some configs?

Reply

Hey Bertin!

Hmm. Ok, let's try one thing quickly. Change your composer require to this:


composer require bham/menu-bundle:@dev

We had a report from one other user that the was causing problems. This might fix your second* problem, which could be related to the first problem :). I don't see any issues with your autoloading config. So, let's try the above to make sure we get the bundle in correctly. If you ARE still having this error, let me know - we'll look closely into the autoload stuff.

P.S. Nice job with the formatted code-blocks - you're a KnpU pro ;)

Cheers!

Reply
Bertin Avatar
Bertin Avatar Bertin | weaverryan | posted 5 years ago | edited

Hey weaverryan ,

I've found the problem. I'm working on a vagrant machine (Homestead) and the local bundle directory is not know in the vagrant structure. To solve this problem I've created a private Github repo and pushed my bundle to it.
Then I've created a version v1.0.0 and added the following to my composer.json


# composer.json from application
{
    "type": "project",
    "license": "proprietary",
    "require": {
        "php": "^7.1.3",
        "bham/menu-bundle": "^1.0",
        ...
    },
    "repositories": [
        {
          "type": "vcs",
          "url":  "git@github.com:username/name-to-bundle.git"
        }
    ]
}

When running the command: <b>composer require bham/menu-bundle</b>
composer asks for an token to authorize my to use the git repo.

Now everything works find.
And for developing i could work directly from my vendor bundle directory because it has its on Github Repo.

But i will try to make it work localy with vagrant because its easer to develop when the bundle is localy.

Reply
Bertin Avatar
Bertin Avatar Bertin | Bertin | posted 5 years ago | edited

I've find a solution for Vagrant Homestead.
First add the seperated folder to your Homestead.yaml


#Homestead.yaml
folders:
    ...
   # added new line where my local bundles are
    - map: ~/Documents/Development/bundles/
      to: /home/vagrant/documents/development/bundles/

And then in my composer.json file


#composer.json
    "repositories": [
        {
            "type": "path",
            "url": "/home/vagrant/documents/development/bundles/MenuBundle"
        }
    ]

And finally the commend: composer require bham/menu-bundle:*@dev works.

1 Reply

Awesome! I'm glad that you could fix it by yourself :)
Thanks for sharing your solution with us

Cheers!

Reply
Jennifer K. Avatar
Jennifer K. Avatar Jennifer K. | posted 5 years ago

When I try to install the bundle (in the "start" directory) I get the following error:

Executing script cache:clear [KO]
[KO]
Script cache:clear returned with error code 1
!!
!! In ArrayNode.php line 319:
!!
!! Unrecognized option "word_provider" under "knpu_lorem_ipsum"
!!

What am I doing wrong? Where can I start debugging? I compared the services.xml of the newly created bundle and that in finish, and they are the same.

--
update: I was able to fix this by removing the "word_provider" entry from config/packages/knpu_lorem_ipsum.yaml in the start directory.

Reply

Hey Jennifer K.!

Ah man! Ok, we *really* work hard to make sure the code *actually* works :). So, let's figure this out! When I download the course code from this page, I actually do NOT have *any* config/packages/knpu_lorem_ipsum.yaml file. There IS one in the finish directory, but not the start. Are you seeing something different?

Cheers!

Reply
Jennifer K. Avatar
Jennifer K. Avatar Jennifer K. | posted 5 years ago

Just a note: the "respositories" section of composer.json belongs in the "start" directory's composer.json... not in the LoremIpsumBundle composer.json

Reply

Yep, for sure - good not! This is a particularly confusing tutorial as we flip around between 2 different code bases (the bundle & the project). The "repositories" section lives in your "app" code at this point, not in the composer.json of LoremIpsumBundle :).

Reply

Hey there

I have a little issue, when I did composer require knpuniversity/lorem-ipsum-bundle:*@dev, I have this message
fish: No matches for wildcard 'knpuniversity/lorem-ipsum-bundle:*@dev'. See `help expand`.

So I removed the *@dev but after that the error is

In ArrayNode.php line 311:
!!
!! Unrecognized option "word_provider" under "knpu_lorem_ipsum"
If I removed the "word_provider" like there, I have a invalid service

Invalid service "App\Service\CustomWordProvider": class "App\Service\Custom
!! WordProvider" does not exist.

What's wrong ?
thanks

Reply

Hey Gregory!

Ok, so let's look at each part!

I have a little issue, when I did composer require knpuniversity/lorem-ipsum-bundle:@dev, I have this message fish: No matches for wildcard 'knpuniversity/lorem-ipsum-bundle:@dev'.

This makes me think that your "path" package isn't setup correctly. Here are some things to check :)

A) Make sure you have the "repositories" section setup correctly that we added: https://knpuniversity.com/screencast/symfony-bundle/extracting-bundle#using-a-path-repository

B) Double-check the name of your library in your new composer.json that lives in the bundle. Is it exactly knpuniversity/lorem-ipsum-bundle?

So I removed the *@dev but after that the error is

This is probably just because, due to some issue with the path repository, you are actually downloading the real knpuniversity/lorem-ipsum-bundle. And so, you are getting basically the "final" version of the bundle, which actually does not include the word_provider option (we remove this in one of the last chapters).

Check into the first issue - I think the both problems come from there somehow!

Cheers!

Reply

Hey weaverryan

this is my repositories setting:


"repositories": [
        {
            "type": "path",
            "url": "../LoremIpsumBundle"
        }
    ]

my 2 folders are at the same level. for the naming this is exactly knpuniversity/lorem-ipsum-bundle

I'm gonna keep looking ;)

Thanks for your answer.

Cheers!

Reply

Hey Gregory

I was able to reproduce it. So, there must be something with one (or both) of your composer.json file.
The "repositories" key should be defined in the composer.json inside your application, and the "url" field is a relative path to the "Bundle" folder.
Then, it is important to put back the "*@dev" or you will be fetching the real "knpuniversity/lorem-ipsum-bundle"

I hope it helps ;)

Reply

Hey MolloKhan

I know that the problem is from the url of the repositories but my composer.json is in my project and the url is the relative path.

I made 3 screenshots to show you my hierarchy folder but I don't know how to share it.

But I can explain:
I have a big folder inside of it I have my folder for my App and my folder for the "Bundle".
So inside my App I have my composer.json at the same level of symfony.lock. In this composer I have my key "repositories" like above. And in my Bundle folder at the same level of the folder src I have my other composer.json with the name "knpuniversity/lorem-ipsum-bundle"

So in the url the relative is well "../LoremIpsumBundle".
And I understand totally the necessity of "*@dev" .

But thanks for you help ;)

Reply

You can upload them to imgur (or any other platform) and share the url.

The composer.json file of your "Bundle" project lives inside the "src" folder? It has to live at the root of the project
That may be the problem

Reply

Thanks for imgur I forgot the name ;)

No my composer.json file of the Bundle is not in "src" folder.
You can see it on the screen Screenshot

Reply

Hmm, everything looks fine. Probably is something with the cache. Try clearing your composer's cache

composer clearcache```

Reply

wow... Ok, remove your "composer.lock" and try again but add "-vvv" to command, so we can get more debugging information

Reply

the same error

fish: No matches for wildcard 'knpuniversity/lorem-ipsum-bundle:*@dev'. See `help expand`.
composer require knpuniversity/lorem-ipsum-bundle:*@dev -vvv

Reply

Uhmm, my belt is running out of tricks...
Which composer version (try updating it) and OS are you using?

Reply

Composer version 1.6.4 2018-04-13 12:04:24 and I'm using macOS High Sierra 10.13.4

Ok it's work if I remove the *
I just need to do


composer require knpuniversity/lorem-ipsum-bundle:@dev

I hope it helps other people.

Thanks guys for your time.

Cheers!

Reply

Hey Gregory!

Hmm, interesting! Thanks for sharing your fix! We're going to check into it, but me may very well add a note about this - I'm not sure why the * worked for me, but not you! But, happy it's working now :).

Cheers!

Reply

Hey weaverryan

I don't know why too. I made this tutorial with another computer same OS, same version of composer and I had the same problem. This tip worked again so it is a good thing to know ;)

And thanks to you and all your team for the great works.

I'm totally addict at KnpUniversity ;)

Cheers!

1 Reply

The note is not necessary, the same thing happened to me, look at this comment and solve it.

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial is built using Symfony 4, but most of the concepts apply fine to Symfony 5!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "doctrine/annotations": "^1.8", // v1.8.0
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
        "knpuniversity/lorem-ipsum-bundle": "*@dev", // dev-master
        "nexylan/slack-bundle": "^2.0,<2.2", // v2.0.1
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.1.6
        "symfony/asset": "^4.0", // v4.0.6
        "symfony/console": "^4.0", // v4.0.6
        "symfony/flex": "^1.0", // v1.18.7
        "symfony/framework-bundle": "^4.0", // v4.0.6
        "symfony/lts": "^4@dev", // dev-master
        "symfony/twig-bundle": "^4.0", // v4.0.6
        "symfony/web-server-bundle": "^4.0", // v4.0.6
        "symfony/yaml": "^4.0", // v4.0.6
        "weaverryan_test/lorem-ipsum-bundle": "^1.0" // v1.0.0
    },
    "require-dev": {
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.4
        "sensiolabs/security-checker": "^4.1", // v4.1.8
        "symfony/debug-bundle": "^3.3|^4.0", // v4.0.6
        "symfony/dotenv": "^4.0", // v4.0.6
        "symfony/maker-bundle": "^1.0", // v1.1.1
        "symfony/monolog-bundle": "^3.0", // v3.2.0
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.3.3
        "symfony/stopwatch": "^3.3|^4.0", // v4.0.6
        "symfony/var-dumper": "^3.3|^4.0", // v4.0.6
        "symfony/web-profiler-bundle": "^3.3|^4.0" // v4.0.6
    }
}
userVoice