Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Publishing to Packagist

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

Our bundle is ready to be shared with the world! So let's take care of a few last details, and publish our bundle to Packagist!

Choosing a License

But, before we publish this anywhere, we need do some boring, but very important legal work. Go to choosealicense.com and find the license that works best for you. Symfony is licensed MIT, and that's definitely the best practice. Whatever you choose, copy the license, find your bundle code, and at the root, create the LICENSE file.

MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Pushing to GitHub

Legal stuff, done! Next, find your terminal: there are a bunch of uncommitted changes. Oh, before we add them, I made a mistake!

I have an extra tests/Controller/cache directory! Open IpsumApiControllerTest and find the getCacheDir() method. I meant to change this to use the same cache directory as FunctionalTest, which is already set to be ignored by git. Add a ../ to the path. Then, delete the extra cache/ dir. There's also an extra logs directory, but it's empty, so just ignore it.

... lines 1 - 26
class KnpULoremIpsumControllerKernel extends Kernel
{
... lines 29 - 55
public function getCacheDir()
{
return __DIR__.'/../cache/'.spl_object_hash($this);
}
}

Now move back to your terminal, add everything to git, give it an inspiring message, and commit!

With everything committed, let's push this to GitHub! Well, you can host it anywhere, but GitHub is the most common place. I'll click "New Repository", choose the KnpUniversity organization, and name it lorem-ipsum-bundle.

It's not required, but it's usually nice to name the repository the same as the package name in composer.json. Give it a clever description, make sure it's public, and create repository!

Copy the code to push to an existing repository, go find your terminal, quick! Paste, hit enter, wait impatiently... then... say hello to our new repository!

Registering on Packagist

With that done, we can now put our bundle up on Packagist! Go to packagist.org and make sure you're logged in. Then, it's super easy: click "Submit", copy the GitHub URL, paste, and click "Check".

This does some sanity checks in the background, like parsing your composer.json file and waiting for Jordi to search for any similar packages on Packagist, to help avoid duplication.

Looks ok! Moment of truth: Submit!

Boom! We are a package!

Auto-updating with the GitHub Service Hook

Oh, but notice this message:

The package is not auto-updated. Please setup the Github Service Hook

This is actually important. When we create a new tag in GitHub, we want Packagist to automatically see it.

Go back to GitHub, click Settings, Integration & services, "Add service" and find Packagist. You'll need to enter your username and a token you can find on your Packagist profile page. Then, add service!

Requiring the new Package

And, for now, we're done! We have a real package! Next, open our application's composer.json file. We're still using this path repository option. Let's finally install our package properly. Remove the repositories section.

Then, go to the terminal for your app, and, first, remove the current package:

composer remove knpuniversity/lorem-ipsum-bundle

Gone! And thanks to the Flex recipe, it also removed the bundle from bundles.php. Cool!

Now, lets re-install it:

composer require knpuniversity/lorem-ipsum-bundle

This downloads dev-master, so the master branch, because there's no tag yet. And! Flex re-added the bundle to bundles.php.

Writing a Decent README

Cool! But, go back to the GitHub page for our bundle. See anything missing? Yea, no README! That's not ok! If you go back to the "Symfony bundle best practices" page, this has an example README you can use to get started.

Head back to our code, I'll close a few files, then create a new README.md file. And, bam! I just wrote us a README file!

# Hello LoremIpsumBundle!
LoremIpsumBundle is a way for you to generate "fake text" into
your Symfony application, but with *just* a little bit more joy
than your normal lorem ipsum.
Install the package with:
```console
composer require knpuniversity/lorem-ipsum-bundle --dev
```
And... that's it! If you're *not* using Symfony Flex, you'll also
need to enable the `KnpU\LoremIpsumBundle\KnpULoremIpsumBundle`
in your `AppKernel.php` file.
## Usage
This bundle provides a single service for generating fake text, which
you can autowire by using the `KnpUIpsum` type-hint:
... lines 21 - 94

Don't worry, I'm not going to lecture you on how to write README files. Well, actually, can I take just one minute to point out the most important parts that I think people sometimes forget?

To start, make sure your bundle has these four parts. One, at the top, say what the bundle does in plain language! Two, show the composer require installation command. Three, give a simple usage example, before talking about any other technical jargon. And four, show the configuration.

After that, you can talk about whatever complex or theoretical stuff you want, like how to create a word provider.

Also, when you create code examples, there are two common mistakes. First, make sure you include the file path as a comment: people don't always know where a file should live. Second, don't create the code blocks here. Believe me, you'll make a mistake. Code them in a real app, paste them here, then tweak.

Oh, and for the configuration section, remember, you can run:

php bin/console config:dump knpu_lorem_ipsum

to get a full config tree to paste here. Oh, and, if the user needs to create a file - like knpu_lorem_ipsum.yaml, say that explicitly: sometimes people think they're doing something wrong if a file doesn't already exist.

A Recipe?

The last thing I would recommend is, if it makes sense, create a recipe for your bundle. Do this at github.com/symfony/recipes-contrib. We're not going to do this, but if your bundle needs a config file or any other setup, this is a huge way to make it easier to use.

If you don't create a recipe, Flex will at least enable the bundle automatically. And in a lot of cases - like for this bundle - that's enough.

Ok, just one topic left, and it's fun! Let's setup continuous integration on Travis CI so that we can be sure our tests are always passing.

Leave a comment!

20
Login or Register to join the conversation
Benoit D. Avatar
Benoit D. Avatar Benoit D. | posted 1 year ago

It is my first time to post on Packagist. If I take the code from the tutorial and try to post it and I get "A package with the name knpuniversity/lorem-ipsum-bundle already exists." which I guess was to be expected. If I want to finish section 19 and 20, what should I do?

1 Reply

Hey Benoit,

Good question! Well, you just need to make the package name unique, i.e. rename that "knpuniversity/lorem-ipsum-bundle" into something like "%your github username here%/lorem-ipsum-bundle". It should be unique enough this way.

Cheers!

Reply
Damien millet Avatar
Damien millet Avatar Damien millet | posted 3 years ago

Hi, again me,
when i install my bundle with, composer req my/package i get an error :

!! DependencyInjection/config/packages/synology.yaml
!! In SynologyExtension.php line 23:
!!
!! Notice: Undefined index: dsm_app_id

cause he don't found the file /config/packages/synology.yaml in the symfony root project

######

Edit :

Ok found ! must add default value in the dependency configuration file

1 Reply
Boolean T. Avatar
Boolean T. Avatar Boolean T. | posted 2 years ago | edited

Hello, I have a question about the recipe.
I've decided to write my own recipe for this nice bundle ( https://github.com/BooleanType/symfony-recipes/tree/master/boolean-type ). My version of bundle is here: https://packagist.org/packages/boolean-type/lorem-ipsum-bundle .

Why have I decided to write it? First of all is, for sure, getting experience in it :) Secondly, when I remove bundle via composer remove, I see an error in console: There is no extension able to load the configuration for "knpu_lorem_ipsum", which is quite understandable, since the configuration file is not removed along with the bundle. The same is true when creating a bundle: I would like the configuration file to be created automatically, as happens when installing the official Symfony bundles.

So, my recipe is very easy:
1) registers bundle in <i>bundles.php</i>;
2) copies <i>knpu_lorem_ipsum.yaml</i> in app's <i>/config/packages</i> dir;
3) creates 2 vars in <i>.env</i>: KNPU_LOREM_IPSUM_FOO and KNPU_LOREM_IPSUM_BAR;
4) shows some custom text after bundle installation.
All I want is to see, if it works correctly. But unfortunately I can't test it :(

As I know, that private recipes (as mine is) are not allowed for pushing to contrib. I've tried to use "Server for Symfony Flex" ( https://server-for-symfony-flex.readthedocs.io/en/latest/ ), but no success. I run php bin/console system:status and see my recipe:


Configuration
 ----------------------------------- ----------
  Proxy for official endpoint         enabled
  Caching for official endpoint       enabled
  Local mirror for official recipes   enabled
  Local mirror for contrib recipes    disabled
 ----------------------------------- ----------

Repo status
 ---------- ------------------------------------------------ ----------------- ------------ ---------------------
  Repo       Url                                              Remote readable   Downloaded   Last Update
 ---------- ------------------------------------------------ ----------------- ------------ ---------------------
  private    https://github.com/BooleanType/symfony-recipes   Yes               Yes          2021-02-17 21:38:48
  official   https://github.com/symfony/recipes               Yes               Yes          2021-02-17 21:38:52
  contrib    https://github.com/symfony/recipes-contrib       Yes               No
 ---------- ------------------------------------------------ ----------------- ------------ ---------------------

But when I run composer recipes boolean-type/lorem-ipsum-bundle, I see only auto-generated recipe, which just adds my bundle in <i>bundles.php</i>:


name             : boolean-type/lorem-ipsum-bundle
version          : v1.0.0
status           : auto-generated recipe

Of course, I expect to see my <i>private</i> recipe, but something is wrong. And I even can't say, or am <i>I</i> wrong, when using this server, either this server just doesn't work for some reason.

So, is there a possibility to test my recipe? Can you advice me some lib / tech for this? Maybe, it is still possible to test via pushing to contrib?

Thanks in advance.

Reply

Hey @Boolean_Type!

Nice job on the recipe!

And yes, it is possible to test your recipe. As you mentioned, there is no support for private recipes. The process to test looks like this:

A) Create a pull request to for your recipe. You will want to make it against the https://github.com/symfony/... repository
B) Once the pull request is open, at the bottom, you should see the message "This branch was successfully deployed" with a "Show environments" link. You can see an example on this open PR: https://github.com/symfony/...
C) If you click on that link, it will give you instructions on how to test your recipe. Basically, when you create a pull request, it deploys your recipe to the Symfony Flex server. Then, you can set an environment variable to tell your local Flex to use that deployment. This allows you to (after setting the env var) go into a project and "composer require" your bundle and see how the new recipe behaves :).

Let me know if this helps!

Cheers!

Reply
Boolean T. Avatar
Boolean T. Avatar Boolean T. | weaverryan | posted 2 years ago | edited

Thank you, weaverryan , for the answer very much. The recipe works like a charm! :)

Reply
Boolean T. Avatar
Boolean T. Avatar Boolean T. | weaverryan | posted 2 years ago | edited

Hello again! :)
I've done all your instructions, my recipe is now in pull request ( https://github.com/symfony/recipes-contrib/pull/1099 ).

Also I've got instructions, when clicked "View deployment" button generated by symfony-flex-server bot ( https://flex.symfony.com/r/github.com/symfony/recipes-contrib/1099 ):


Step 0. Allow installing "contrib" recipes in your application:
composer config extra.symfony.allow-contrib true

Step 1. Define the SYMFONY_ENDPOINT environment variable:
# On *nix and Mac
export SYMFONY_ENDPOINT=https://flex.symfony.com/r/github.com/symfony/recipes-contrib/1099
# On Windows
SET SYMFONY_ENDPOINT=https://flex.symfony.com/r/github.com/symfony/recipes-contrib/1099

# ... and so on ...

So, I've set env var, removed and installed back my bundle. Next I run:
composer recipes boolean-type/lorem-ipsum-bundle

Result is:


Using "https://flex.symfony.com/r/github.com/symfony/recipes-contrib/1099" as the Symfony endpoint
name             : boolean-type/lorem-ipsum-bundle
version          : v1.0.0
status           : auto-generated recipe

I've noticed this <i>"Using ... as the Symfony endpoint"</i>. But when I run composer recipes:install boolean-type/lorem-ipsum-bundle --force -v, still auto-generated recipe is applied. What am I missing? Thanks.

Reply

Hey there,

That's odd, in theory it should work. Is it related to this comment? https://github.com/symfony/...

Reply
Boolean T. Avatar

But you see, I just tried to install the bundle on another project - it worked! :) Maybe, I have wrong setting on my home test project or I had to wait a bit until it worked (I guess waiting, because the installation instructions ( https://flex.symfony.com/r/... ) did not appear immediately, but only a few hours after the recipe was successfully validated by bot).
I'll try at at home project tonight too and I will know for sure.

Reply

Interesting... perhaps it was Composer's cache who caused that odd behavior. If you face to this problem again try clearing out composer's cache and see if that works :)

Cheers!

Reply
Boolean T. Avatar

I've cleared my cache and repeated the whole bundle and recipe installations process - everything works as expected! Thanks!

1 Reply
Boolean T. Avatar

Hej, I'm not sure, that this comment is actual, 'cause I've re-pushed my files after that ( https://github.com/symfony/... ) and all checks passed for this commit...

Reply
Вячеслав Л. Avatar
Вячеслав Л. Avatar Вячеслав Л. | posted 3 years ago

Helloy.
Can you help?
In my case symfony flex doesn't enable bundle in bundles.php.
I can't understand why? Maybe you can suggest me a reason.
I use symfony 4.4

Reply

Hey Вячеслав Л.

Can you tell me what bundle is not being registered? Also, could you double check that Symfony Flex is installed in your project?
When you install a bundle that comes with a recipe, you should see a message coming from Composer that a recipe was found

Cheers!

Reply
Вячеслав Л. Avatar
Вячеслав Л. Avatar Вячеслав Л. | MolloKhan | posted 3 years ago

I try install my bundle, from private bitbucket repository, In my project Flex installed, because other bundles registred, after composer required

Reply

Ohh, it's your own bundle. It may be missing the "type" key on your composer.json. Check at this piece of documentation: https://symfony.com/doc/4.4...

Cheers!

Reply
Вячеслав Л. Avatar
Вячеслав Л. Avatar Вячеслав Л. | MolloKhan | posted 3 years ago | edited

`{

"name": "company/name",
"description": "some test",
"type": "symfony-bundle",
"license": "proprietary",
"require": {
    "php": "^7.1.2",
    "ext-ctype": "*",
    "ext-iconv": "*",
    "symfony/config": "4.4.*",
    "symfony/dependency-injection": "4.4.*",
    "symfony/http-kernel": "4.4.*",
    "symfony/yaml": "4.4.*",
    "symfony/serializer": "4.4.*",
    "symfony/form": "4.4.*"
},
"autoload": {
    "psr-4": {
        "Mokryinos\\ServiceResponseBundle\\": "src/"
    }
},
"conflict": {
    "symfony/symfony": "*"
}

}
`
my composer.json in bundle

Reply

Hey Вячеслав Л.!

Well, the type key looks perfect :). Here is the logic in Symfony Flex that automatically updates bundles.php when it's installing a "symfony-bundle" type: https://github.com/symfony/flex/blob/c497c0c77cb9018cccd9c092832ebf9826612f92/src/Flex.php#L760-L775

For this to work, you need a few things:
A) The symfony-bundle type
B) Flex needs to be able to locate your bundle class

My guess is that (B) is not working. Flex looks in some "common" places for your "bundle" file and follows some conventions to find it. The logic is here: https://github.com/symfony/flex/blob/e4f5a2653ca503782a31486198bd1dd1c9a47f83/src/SymfonyBundle.php#L33-L63

This looks at your psr-4 path (so, src/ in your case) then uses your namespace to try to find the correct bundle class there. I'm not actually sure all the things it "tries" - the logic is in the extractClassNames() method that it calls. I would add some var_dump inside that method and install your bundle to see what class names it's looking for. It's possible that your bundle class (or file path) is not what Flex is expecting, so it can't "guess" it and install it.

Let me know what you find out!

Cheers!

Reply
Default user avatar
Default user avatar Sela Yair | posted 3 years ago

How do you keep updating the bundle once it's in Packagist? I mean the code now is in /vendor how do I manage to have the GIT?

Reply

Hey Sela,

As an author of the bundle, you have access to its Git repository, right? So, just push your changes to that repo. If you would like to do some changes in the bundle in a real project - you can install the bundle from the local Git repository with Composer. Then it will be symlinked, so when you will change code in your bundle's local repository - you will see the changes in your project. See Composer docs for more information on it: https://getcomposer.org/doc... .

As an alternative solution, Composer allow you to install packages from source, use "composer install --prefer-source" and Composer, instead downloading just files, will pull down the entire Git repositories, but the previous solutions might be better I think :) And actually exactly this solution we show in this course, see https://symfonycasts.com/sc... . Have you seen that chapter? :)

I hope this helps!

Cheers!

1 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