i was working in my application and i'm using some packages, but i have the necessity to change or add some logic in it. I read that we must don't change code of the packages when they are on the vendor directory, but i didn't find how i can do instead. any ideas?
This differs from package to package.
The one-size-fits-all solution is to fork the package, essentially copying it and modifying code in the replicated version.
Often, packages may offer methods to extend or build on their work. This will be very dependent on the package, and I'd suggest you refer to it's documentation for more help down that front.
If you take the first route, you must be aware of some things:
The second you fork a package, you will be responsible for maintaining it.
If you fork the package, you will end up with a package that cannot be maintained by it's original author because you have changed it. If you keep it in composer and edit the original package, it will get overwritten the next time you run composer update. Additionally, if you're versioning your work, your package modifications will not be carried across. but if you fork it properly, it will have no ties to the original package. This means that your package may become outdated unless you spend effort maintaining it's updates.
If you're using composer, this will most likely involve forking the original package repo and modifying code in that repo instead. (Do NOT do this to just your local package files). This is probably the best solution, because it means if the original repo has made changes to it's package, you can perform merges with your repo to bring their updates into your code (whilst not affecting your changes unless the update does directly interact with the code you're modfying). From there, add your new forked repo into your composer.json file and work with that.
Related
We have a project that uses composer for dependency management; its composer.json is externally changed by a versioning tool of our own concoction, which does not keep a history of when and what was require'd to be able to roll back using composer remove. But it does roll back the composer.json file entirely.
When we update the composer.json file, we'd like to purge the now-unused packages from the project. We couldn't find a command that does just this. We have a few ideas but each with its shortcomings:
Delete vendor/, composer.lock and run composer install. Problems: very slow; only works without plugins (otherwise more than vendor for destination and composer.lock for state might be involved); versions will be reset
Use a combination of composer show and composer why to determine unused packages and run compose remove on them. This is what I expected to find implemented in an internal command since it's so obvious. Implementing externally presents a few challenges though: only text output of composer show, no --format=json or something, difficult to parse especially since it's also plagued with warning messages if any, that can't be suppressed (-q turns off output completely, even for commands that list things, very useless and weird IMHO).
Note: we are also using wikimedia/composer-merge-plugin to merge a bunch of json configs so we can't easily diff the old and new composer.json files to get a list of packages to be remove'd, we need to operate on the merged package list which only composer knows and will mercifully let us glimpse at via show.
Which is the path of least pain to achieve this?
About using update: we can't use it, because it would make for the following workcycle: someone removes a dependency in a module, the module gets tested against trunk and passed QA (about 3 days), then they publish their changes; then, in order to remove their dead overhead, I have to run update on everything, which updates everything to whatever random version composer may decide, and in turn means triggering testing and QA for everything (about 1 week). This workflow is completely unacceptable.
I just want to remove dead code. Removing dead code should not mean restarting the whole testing cycle.
I would just run composer update.
If a package is no longer declared in your composer.json (or one of its dependencies), it will get removed when you execute update
Yes, it does have the side-effect of updating your dependencies to the most recent version available according to your constraints; but if your constraints are tight enough (and you can tighten them more if this kind of thing it's concern for your project) it shouldn't be problematic.
Seems less hassle than building a specific tool/work-flow for this use-case, IMO.
The main problem seems to be that your team is removing dependencies form the project and not keeping track of those removals. Any other solution after the fact obviates that, which is the real problem.
By keeping track of the changes you could have a task that removed (composer remove) these files without any side-effects or additional work.
So, just supposing you want to keep the existing structure (which, in my opinion, might solve your requirements well, but also brings problems), you could try to implement a Composer plugin on your own. Using the event Composer\Installer\POST_DEPENDENCIES_SOLVING, you might be able to access both the resolved list of dependencies and the list of packages in composer.lock.
Defining it could be as simple as writing such a class:
<?php
class ComposerDependencyHelper
{
public static function postDependencies(\Composer\Installer\InstallerEvent $event)
{
$composer = $event->getComposer();
}
}
And it is called in your root composer.json throught the script section:
"post-dependencies-solving": [
"ComposerDependencyHelper::postDependencies"
]
I don't have the time to check this further, but through that $composer object, you should have access to a lot of information (see https://getcomposer.org/apidoc/1.6.2/Composer/Composer.html for the current documentation):
getPackage returns your current package (as defined in composer.json), while getPackage()->getRequires() lists the dependencies
getLockedRepository might return the list of packages currently present in composer.lock
Through a simple marking process (build a list of "valid" installed packages, diff this list against the package list in the repository), you could identify those dependencies that are no longer required.
To keep this whole thing more clean in the future, you should stop removing packages from composer.json without running composer remove $package.
I've already spent a few hours searching for an answer to my question but still haven't found a suitable answer.
Basically, I've taken over a PHP project which uses composer to pull in third party libraries/dependencies. However, a lot of the dependencies are no longer managed and is possible that the author might remove them completely from github anytime.
I'm currently thinking that I should check in the whole vendor folder so even if the libraries are no longer available through composer, I will still have them with me.
Alternatively, I could fork those libraries repo and have composer to pull from my account instead. Is this acceptable?
I would really hope to get some advice on the best method to deal with this.
Thanks in advance!
Should i check in the whole vendor folder in, so even if the libraries are no longer available through composer, I will still have them with me?
My suggestion is to create a backup branch containing your application with all it's vendors. Just do a git checkout -b {VERSION}-backup, followed by composer install (which gets you the composer.lock and all dependencies into the defined vendor folder) and then a git push origin {VERSION}-backup.
This allows to rely on dynamic package management as long as the packages are available via Packagist and downloadable from their source (Github, etc.).
Now, in case, a dependency gets deleted and becomes un-available, you remove it from your composer.json and merge the code from the last {VERSION}-backup branch into the master branch. = You replaced a dynamic dependency with a static one from you backup.
By the way: ever thought about getting a security audit for your code?
This will not work, with dynamically pulled dependencies. Security audits are done for specific versions - for a static set of dependencies. Given this context, pushing in a complete app with all it's dependencies is common and a best-practice. But what do we have: Composer in the backend to install new themes and composer install --no-dev --optimize-autoload on the production box to "install" software. Modern times ;)
Could I fork those libraries repo and have composer to pull from my account instead. Is this acceptable?
Yes! And you might also ask the guys over at Packagist to remove no-longer maintained packs or get them replaced or aliased to a new personal fork.
It really depends on whether your project needs to be optimized for portability or not.
Although, it's better safe with a best-practice violation, than sorry with an unavailable dependency you have to spend time replacing and refactoring for ...
From her packagist - theoretically it is possible but unlikely.
From the practice the main problem with packages directly connected to CVS. But if it is live project you allays can find another copy of code to recover functional.
Our current development setup uses a single Subversion repository containing multiple projects, each with branches, tags, and trunk. We then use a "sparse checkout" to select the projects, and branches of those projects, to work with.
The result is that the directory structure of a working copy matches that of the repository, including branch information, and we never use svn switch. (This style of working will probably be familiar to anyone who uses SVN, but may be surprising to those who don't.)
We are thinking of using Composer to manage both external and internal dependencies, but I'm not sure how this can work with the sparse checkout style of working.
I would like some way of using a directory within the existing checkout to satisfy a dependency, rather than each "root project" needing a separate copy.
For example:
sites/Foo/trunk
depends on lib Aaa, so references lib/Aaa/trunk
depends on lib Bbb 1.5.*, so references lib/Bbb/branches/release-1.5
sites/Bar/trunk
depends on lib Aaa 1.0.*, so references lib/Aaa/branches/release-1.0
depends on lib Bbb 1.5.*, so references lib/Bbb/branches/release-1.5
At present, if I edit the code in lib/Bbb/branches/release-1.5, I can test those changes on both sites, without needing to commit one and update the other.
Is there any way of using Composer to manage these dependencies?
(PS: Please don't answer with "give up on SVN, use Git, it is teh awesomez"; that is an answer to a different question.)
No - I do not believe that you can do this with Composer as standard: it expects to copy the files from whichever source (Packagist/VCS/Zips) to the local vendor folder, which is not what you want.
That said, I believe there are two potential ways you could get this working (at least in part):
Autoloader
You could try using the autoload field in the composer.json file to include the correct files into the project. You would still need to manage the checkouts of the relevant branches/versions manually (like I assume you do now), but you would be able to manage the inclusion of the internal libraries through Composer. This will probably require that your libraries are properly namespaced. The paths to the files for each namespace are relative to the root of the project, but can go below the root (via the /../ path) if required.
To be honest though, if you already have an autoloader for these files, there may not be much advantage to this solution. Relevant Docs
Composer Plugin
You could also write a composer plugin/"custom installer" that could probably manage this. This would have the advantage that you could have it manage checking out the correct parts of the sparse repository to have the correct version available, as well as doing correct wildstar version checking, but would be a much more difficult and riskier venture.
The basic process would be that you would define a new package type (e.g. 'internal-svn-package'). You would create the plugin as an external library that gets installed normally via Composer, which declares (via it's composer.json) that it handles this new type of package. Your custom logic would then be used for any packages that are listed with this custom type. I'm not sure how much of the internal composer logic for SVN checkouts you would be able to reuse however. Relevant Docs
We're starting a new project, and we're managing dependencies with Composer. We'll probably build our app on top of Laravel 4. But we'll also create our own library, which we will use for all our next projects, not just this one.
So, we have this terrible doubt: what's the best way to develop a library using composer?
If we list that new library as a dependency, every time we modify it we will have to commit the change to the repository and then call composer update.
That seems terrible!
Is there a better way to do that?
I think there are two ways to handle this, which I use depending on the case:
The library is a pure library, which is standalone, fully tested, and develop it using TDD to ensure that it all works. That way it can be used with the "commit, update" cycle you described just fine I think.
You are developing a plugin or something that must be integrated in something else (application/framework) and testing it standalone is more difficult, or you are developing it very tightly with your application. In this case require the dev-master version of the library so Composer installs it with a git clone (if it was already installed as a tag you will have to rm -rf vendor/your/library to force a reinstall as opposed to an update). You can also force this for tagged releases using the --prefer-source flag. Then once you have a clone in the vendor dir you can very easily work directly in there. If you do work in a team though you will still need to do this commit and then update to make sure the others get the latest version.
The third alternative is to just develop the code in the src/ directory of your application until it is mostly stabilized and then you can extract it as a new package and add it back as a dependency, then fall back on the first two ways I described because it will then be a lot more viable.
If you set the dependency to the repository master branch instead of a packaged distribution file, Composer will check out a working copy into the vendors folder. You can modify this working copy right in the vendors folder, as if it's part of the main project, but then commit it into its own repository. You'll indeed have to make sure to composer update after that to keep the composer.lock file in sync with the development of that library though.
It's still the more convenient way to develop a project in tandem with a dependency.
If you aim to develop a truly awesome library, then you should try to develop it independently of any other software you create.
It should fulfill one exact task only. And this probably is done after some commits, so the initial creation of the library should take only a week or two to come to a stable first version. And this version can be tagged and then used elsewhere.
When tagging, strictly try to follow semantic versioning - that way you can use the library with a version restriction like "~1.0", meaning at least version 1.0, but anything up to 1.9999 is acceptable, as long as it is not 2.0 (which would mean incompatible changes).
And then you really do not need to update any other software when you release a new version of the library. You only need to update if you want to include fixed bugs. Without bugfixes, you can update, but there is no need to do so immediately after the library's new version release.
Composer will take care of all the dependencies you need. The most important thing if you start a new library is to include the composer.json right from the start into the repository.
What if you really want to always include the newest release of the library in every other software you write? I'm not sure you realize the implications this has. It means that you are strictly binding your other software to the most recent library version. Break that version, or introduce a nasty bug, and all your software breaks. So being able to update or not actually is a feature. You will find that all foreign libraries you might use will follow the same release mechanism: They tag a new version if an important bug was fixed, or if a reasonable amount of new features was implemented. They do not wait for you to approve a new version - you have to approve THEIR new version in your software by explicitly updating to the most recent one. And the same should apply to an internal library.
Try to avoid fiddling with "dev-master" solutions mentioned here. They might work, but Composer works best if used with tagged versions. If you have a reasonably stable state of your library, tag it with "0.0.0" and include that version everywhere else instead of "dev-master". And then tag according to semantic version rules.
I am using the Composer package Omnipay in my project and I want to add a new class to the package (in my case it is support for a new payment gateway). The naming does not conflict with anything and it follows the same naming and structure conventions as sibling folders. However, when I run composer update it deletes my whole folder of changes even though it didn't need to. Is there a way I can tell composer not to delete that directory?
Leave everything under /vendor alone, don't change any files there. You should treat libraries as external dependencies - don't check them into source control or change them in any way. Just reference them in your own code.
If you need to customize a composer library, you can either work around it in your own code (most PHP libraries support dependency injection, which will let you override any of the libraries' classes), or alternatively you can fork the library on github, then reference your own fork in composer.json, or submit the pull request so everyone can benefit from it.
As far as I'm aware, you cannot add to a Composer package as it is external and therefore out of your control. You should treat the packages as libraries only, and add all classes into your own project, ensuring that the packages you need are still set up in your .json file