ChatGPT解决这个技术问题 Extra ChatGPT

How to develop and include a Composer package?

I'm looking to develop a package in PHP, but I don't want it immediately available on GitHub or somewhere. It's easy enough to include a Packagist file in my composer.json, but how do I add a local package into my composer.json? Also, should I be building the package in /vendor/foo/bar (relative to the root composer.json), or should I put it somewhere else?

Edit: I guess my question is about how everyone else writes their packages. Does every new package get added to Packagist, and then when you want to test your changes, you commit to GitHub (or wherever), and then pull that back down via Composer? That seems really inefficient.


F
Federico J. Álvarez Valero

Instead of creating a new repository, you can tell composer to use any local path:

https://getcomposer.org/doc/05-repositories.md#path

For instance, lets say that you have your PHP projects under ~/devel/projects

You may have your main project in ~/devel/projects/main_project, and your "local package" in ~/devel/projects/local_package

Define your composer configuration for the local package. In ~/devel/projects/local_package/composer.json.

{
    "name": "your_vendor_id/your_local_package",
    ...
}

Then, you can edit ~/devel/projects/main_project/composer.json and link to your local package via path repo:

"repositories": [
    {
        "type": "path",
        "url": "../local_package",
        "options": {
            "symlink": true
        }
    }
],
"require": {
    "your_vendor_id/your_local_package": "dev-master",
    ...
}

More info on this link (not written by me but has a good explanation on this subject):

https://carlosbuenosvinos.com/working-at-the-same-time-in-a-project-and-its-dependencies-composer-and-path-type-repository/


C
Community

As this question has many different components/standards to be explained, I'll try to explain as much as possible here and you can PM me or just Google it for more specific questions as they come up.

To answer your first question, "How do I add a local package into my composer.json?":

If by "add local package" you mean autoload your class/package, you can do that by either using PSR-4 or PSR-0 or Classmap options in composer.

Read more

PSR [petermoulding.com] (via archive.org)

PSR-4 autoloading support in Composer [seld.be]

Battle of the Autoloaders: PSR-0 vs. PSR-4 [Sitepoint]

Why use a PSR-0 or PSR-4 autoload in composer if classmap is actually faster? [SO]

You can Google it if you need more info on PSR-0, PSR-4 and Classmap.

Example

"autoload": {
   "psr-4": { "Core\\": "src/Core" }  ## "standard": { "namespace" : "path/to/dir"}
}

Or (edit)

If you actually want to add a local package:

Create a composer.json for the local package, like: { "name": "localPackage/core", "version": "dev-master" } You can also specify other properties and/or dependencies as required. Zip the package, with the composer.json file as the root file in the archive.zip, and place it where desired. In the other project/package where you want to include the local package, add the local package name to the required parameter, like "localPackage/core": "dev-master" Add the following under the repositories parameter: "repositories" : [ { "type": "artifact", "url": "path/to/localPackage.zip" } ]

Now if you have the local package on git, then there would be no need to archive the package (basically omit step 2) and you just need to replace the URL in the above example to the path/to/localPackage/.git.

(End of edit)

Now to answer the larger question: "How do I develop and include a Composer package?":

Decide the directory structure. Commonly it is as follows: /PackageRoot /src/PackageCore composer.json ## this is your library’s composer.json LICENSE and set up your composer.json. An example of one of mine composer.json files can be found at http://pastebin.com/tyHT01Xg. Upload it to Github and tag the version. Use Semantic versioning (make sure you exclude/ignore the vendor directory when uploading to Github). Register the package with Packagist (after logging in). If you have tagged your commit as v1.0.0 (or similar), then this will show up in your Packagist dashboard for that package.

Now, if everything is done right, you should be able to use your library as a dependency in other projects by adding it to the composer.json of that project.


But how to develop a composer package without the need to publish it? The reason is that I don't want to publish my package, because it's basically not finished yet, but I still want to define my composer.json file and it's dependencies without the need to actually commit and/or publish it already somewhere. I want to be able to tinker with my code until it's okay and when it's ready I want to publish it. Example: I have a project A and for this project I define a require dependency on my new package B, which only exists on my machine. How do I test B inside A without publishing?
Like i said composer works of of Packagist and Git. Its okie if your package ain't ready. just tag it as alpha/beta on git.
Basically you can't require a package that isn't on Packagist or on github. Even my application isn't ready but is up on github/packagist and tagged as v1.x.x-alpha, check it out if you'd like - github.com/shalomsam/Core
@shalomsam you can very well require packages that are not on Packagist nor github - see the Custom Repositories-Link the other answers have posted
@Lukx - yeah i stand corrected. But i still guess you can't use that to load local packages, or can you?
E
Emile Bergeron

It seems most answers on this thread are not "in the know". I am new to Composer myself, but these answers are misleading. The question could simply be stated as: "How can I develop a composer package".

Yes, you could use a custom repository or upload an unfinished package and update it after every change. That neither is the correct solution or the answer to the question.

It doesn't help that Composer's official documentation doesn't state this upfront, but you can see the heading on the Libraries documentation page:

Every project is a package

This is very important to understand

composer.json:

The previously mentioned page goes on to state:

In order to make that package installable you need to give it a name. You do this by adding the name property in composer.json { "name": "acme/hello-world", "require": { "monolog/monolog": "1.0.*" } }

In this example so far, we have a required package, and now a name. Note the vendor/name format.

So now to autoloading our own files, which is documented on the Basic usage page.

{ "autoload": { "psr-4": {"Acme\\": "src/"} } }

This will autoload the namespaced class files under the src/Acme directory.

On to the fun.

Install/Update

Install or update the package with the command:

composer update

or

php composer.phar update

This will download the required packages and create the autoload.php file

Our project structure should look simular to the following:

src
    Acme
        Foo.php
vendor
    monolog
        ...
composer.json

Including

Now to test.

Include autoload.php

require_once 'path/to/project/vendor/autoload.php';

Assuming Foo.php looks like the following:

<?php

namespace Acme;

class Foo {
    public static function bar(){
        return 'baz';
    }
}

?>

we can then call this from our script:

echo Acme\Foo::bar(); // baz

Please correct any misleading information I may have stated. This is what seems the be the solution to a popular question.


As the edit to the original question mentions, it's really inefficient to have to commit, push, then run update on the parent project every time you make a little change your sub-package. I'm not sure that this answer deals with that issue.
F
Finlay Beaton

Here's a recap of the solutions plus my own

publish on packagist

Since you don't want to publish yet, you're in development, this is a poor option.

upload github

You may not want to publish your library source on github, not want to pay for a private repo, or be able to use a cloud external service (due to political or network policies).

zip your library

You can use the composer repository path in your example implementation to point to a local zip file as a release. You'll have to re-zip every time you make a change to the lib, even with a batch file to do it, this is icky.

upload to local git/svn repo on your machine

This is getting close, but you'll need to do a composer update each time you change your library and want to test your example implementation. This mimics productions but is cumbersome. Personally I recommend this solution, even though it's not brainless.

Autoload the library directly (sortof does what you want)

This is a hack, but you could just add:

{    
  "require": {
  },
  "autoload": {
    "psr-4": { 
      "yourlibnamespace": "D:\\Code\\yourlib\\src\\" 
    }
  }

}

Please note that you will need to copy+paste the 'require' section from your lib to your sample implementation. Change 'yourlibnamespace' to your library namespace and "D:\Code\yourlib\src\" to your local path to your library source.

This way any changes are immediately reflected. However you will not be using or testing your library's composer.json file at all. If you change a requirement in your library .json it will not flow through at all. So it has some big disadvantages, but does do what you want, which is to test your library implementation immediately with the least commands possible.

add your example implementation directly in your library tree (recommended)

Usually you just have src\ and tests\, but many have examples\ where you can find sample implementations. As you develop your application you can contribute to these example implementations. You can do this in a local git/svn repo, and you have the advantage of getting the lib's 'require', plus the namespace automatically. It is the best of all worlds. I recommend this method.


Very misleading. The question is about developing before uploading. #5 is the correct answer, and is not a hack.
You are mistaken. The question is "how do I develop a new composer package locally before I publish on packagist" not "How do I use composer packages in my project". The answer you posted after downvoting me (and making it so I can't comment on your answer) wrongly answers the 2nd question, not the topic of this question. All 6 approaches in my answer are correct (3-6 answer op directly), they all have different downsides. I suggest #6.
f
fsw

Maybe adding a custom repository will help you?

https://github.com/composer/composer/blob/master/doc/05-repositories.md

You can set up a local git repository with your library very easily.

Of course if you use composer to manage dependencies you should build your library someplace else and download it to vendor/ via composer coz this is the whole point i guess.


So as you are developing, you have to do a composer update every time you make a tiny change to your package in order for the dev project to pull in the latest version? Is there a quicker way?
I'm in the same situation. I don't get how to develop a composer package locally without the need of uploading it somewhere or running a composer command everytime a change is made.
This tip was just for developing a composer package out of your library. Why do you want to use composer to develop the library itself? I think you can ask another question coz i am not using composer any more and this is almost 2 years old. cheers
@fsw, because your Composer package is a Composer plugin, for example.
G
George Kagan

That's my flow of creating and developing a new Composer package locally:

Create a new repository for the package on GitHub (just an example) Add it to Composer's database (packagist.org) Add it to your main project via composer require. This is where you start wondering how can you apply hotfixes quickly Clone it on your local machine somewhere, this is where you develop it Now to test your local version, add a php require() statement where you load the class files in question. The autoloader won't load the one downloaded via composer but your local one. When you're done hotfixing, delete/comment out the the require statement to revert back to using the composer version of the package. Commit all changes, tag the commit and push to GitHub; hook fires to update Composer. Run composer update on your main project, the package gets updated to your local version.

This is still not ideal, but it gets the work done for small to medium packages.


S
Simon East

To make developing more efficient I simply symlink the development repository into a directory that has already installed it.

For example, if /Code/project-1 requires a package that's in /Code/package-1, I:

Commit package-1 to GitHub (can even be private). I then tell project-1 to install it using a custom repository (see other answers for the link to repository configuration). Once it gets installed, I symlink /Code/project-1/vendor/developer/package-1 to /Code/package-1.

That way, when I make changes in /Code/package-1, it's immediately reflected in /Code/project-1.


r
roelleor

My workflow does not completely answer the OP's question but may be helpful for others.

I like to develop a reusable package / lib in a real world project and I do not want to go through git / composer locally. I also do not like to load the package differently locally compared to production (e.g. through a local require statement or local composer setting).

So what I do is simple: I add the package directly under the vendor directory, either directly or using a symlink.

drawbacks

When using composer update / install, your package may be overwritten. (so I tend to update or add dependencies one by one, during this time). When not being careful, composer install on the production environment may install a different version. So keep pushing your package and version tags!! Changing the package's dependencies and loading it in the parent project trough composer update, overwrites the package's folder