How to run scripts after a user installs my package via Composer? - php

I use the command composer require otra/otra:dev-develop --no-update --no-cache && composer update --no-autoloader to install my own framework.
I have put this section in my composer.json from my framework :
"scripts": {
"pre-install-cmd": "#composer config bin-dir bin/"
}
But Composer does not run it. Is this normal, does Composer consider this as a dependency and not the root package so it does not allow my script to run?
If this is the case, how can I have the same behaviour?
I want to :
have my binary in the bin folder, not vendor/bin without having to ask the user to do a symlink manually (or another solution)
copy a web folder from my framework to the root of the project.
Edit : with create-project command
If I type composer create-project otra/otra:dev-develop crashtest --remove-vcs, I get this composer.json :
{
"name": "otra/otra",
"type": "library",
"description": "The OTRA PHP framework",
"keywords": ["framework"],
"homepage": "https://github.com/lperamo/otra",
"license": "X11",
"authors": [
{
"name": "Lionel Péramo",
"email": "contact#lionel-peramo.com",
"homepage": "https://wexample.com"
}
],
"bin" : ["otra.php"],
"config": {
"bin-dir" : "bin/",
"sort-packages": true
},
"require": {
"ext-mbstring": "*",
"php": ">=7.4.0",
"symfony/yaml": "^4.0"
},
"require-dev": {
"ext-pdo": "*",
"ext-pdo_mysql": "*"
},
"scripts": {
"pre-install-cmd": "#composer config bin-dir bin/"
}
}
which is exactly the same as my framework so I cannot update it via Composer. I could with git if I do not use --remove-vcs but it is not the goal.
The output of the composer command is :
Installing otra/otra (dev-develop ab37237565155dab11812a7b2982d30ee240f051)
Installing otra/otra (dev-develop ab37237): Cloning ab37237565 from cache
Created project in crashtest
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file

Only scripts defined in the project's proper composer.json file are executed.
Scripts from required and installed packages are never executed because it would be terrible safety risk.
This is summarily explained in the docs:
Only scripts defined in the root package's composer.json are executed. If a dependency of the root package specifies its own scripts, Composer does not execute those additional scripts.
If your package users need to perform additional steps to use your package or library, explain those steps in your package documentation, and or provide scripts that they can execute manually and will perform those steps for them.
If your package is a "framework", as opposed to a library, what you could do is take advantage of composers create-project command.
That would require you to setup are repository with the default structure for a project, which would in turn depend on your package.
That's the way it's done with Symfony's Skeleton, for example.
With this kind of setup, you can create custom installation scripts and activate them with the post-create-project-cmd, and do some some extra setup steps, even interactive one, with something like this. (docs)
Be mindful that this script would only run when the package is installed using create-project, and never when using require.

Nobody mentioned, this can be achieved by creating a composer plugin and defining event handler for event post-package-install

Related

How to develop with symlinked composer package, but build from a vcs repository?

While refactoring legacy code, I try to work on a composer package while at the same time work on a project which uses this package.
Composer allows me to add local path repositories for retrieving the package in-development, and symlinking this package into my project.
<composer.json excerpt>
"repositories": [
{
"type": "path",
"url": "../my-package/",
"options": {
"symlink": true
}
}
],
...
"require": {
"my/package": "#dev"
}
I then do
composer update my/package --prefer-source
Which symlinks just fine. However, when building my project on a CI server, I want the project to retrieve the package from a remote git repository, this is why I added the vcs section to my composer.json.
{
"type": "vcs",
"url": "git#bitbucket.org:my/package.git"
}
However, during building via composer install it still tries to retrieve the package locally, which is not available on the CI server of course. I guess because my composer.lock explicitly says that the package is retrieved from a path.
How can I make it work smoothly, both locally and on the CI server? I seem to lack a decent workflow.
What I tried so far:
adding my/package again as a dev-package, but apparently the composer.json will remove if from the no-dev packages automatically then. Also, I do not know how to tell composer to use the path repository for the dev requirement, and the vcs repository for the no-dev requirement.
After tons of hours searching for a suitable workflow, I found out one. Hope it can help you.
Since repository-dev (like require-dev for repository) doesn't exist and will not exist soon (see this), we need to make two composer.json files. Let's say we call the second one composer-dev.json. I think you should commit both and having both up-to-date. To tell composer to use composer-dev.json, you need to put COMPOSER=composer-dev.json in front of every composer command. To illustrate, see this :
composer.json
{
"repositories":[
{
"type": "vcs",
"url": "{repo}"
}
],
"require": {
"vendor/package": "{version}",
}
}
composer-dev.json
{
"repositories":[
{
"type": "path",
"url": "path/to/your/package",
"options": {
"symlink": true
}
}
],
"require": {
"vendor/package" : "{version}",
}
}
As you can see, the composer.json contains the 'vcs' repository and the composer-dev.json contains the 'path' repository.
To initialise your application and start developing :
COMPOSER=composer-dev.json composer update
Composer created the vendor directory and symlink your package folder to vendor/package. It also created a composer-dev.lock file which you should commit for deployment.
To install new package :
COMPOSER=composer-dev.json composer require vendor/package
Remember that composer.json have to be up-to-date, so you have to put all new lines in it.
To build your application :
COMPOSER=composer-dev.json composer install
Which should throw you :
[RuntimeException]
Source path "path/to/your/package" is not found for package vendor/package
Now you can run :
composer update --no-dev vendor/package
or if you need specific version :
composer update --no-dev vendor/package:{version}
Notice that there is no COMPOSER=composer-dev.json in front of the last command since we are using composer.json in order to use our vcs repository. This last command will also install all missing packages.
I hope it was usefull !

Composer Not Generating Autoloads For Library

I've set up two projects, an 'init' and a library, which is required by the init. They both have PSR-0 autoloads set, but the autoload values from the library are not added to the vendor/composer/autoload_namespaces.php in the init project.
Sample composer.json from the Library:
{
"name": "lxp/library",
"description": "A test library",
"autoload": {
"psr-0": {
"LXP\\Library": "src/"
}
}
}
Sample composer.json from the project that requires that library:
{
"name": "lxp/init",
"name": "A test init",
"autoload": {
"psr-0": {
"LXP\\Init": "src/"
}
},
"repositories": [
{
"type": "composer",
"url": "http://satis.repo.redacted/"
}
],
"require": {
"lxp/library": "dev-master"
}
}
The library contains the class LXP\Library\Something in the file src/LXP/Library/Something.php.
The project that requires the library contains the class LXP\Init\Now in the file src/LXP/Init/Now.php.
When running composer install in the 'init' project, it downloads the library project and puts it in vendor correctly, but vendor/composer/autoload_namespaces.php doesn't contain the library's autoload information, only that of the current project.
What am I doing wrong? If I run dump-autoload in the library project then the autoload_namespaces.php file is correct, and a quick bootstrap script confirms that it does indeed pick up the class.
EDIT - This is a problem with the satis-generated packages.json. To fix it, I had to add the autoload information from the library's composer.json into the json file I supply to satis, which seems like an unnecessary duplication and so I'm probably doing it wrong. Is there a single place that autoload information can be stored for satis libraries? For example, can satis read the composer.json files that exist in the libraries it scans?
EDIT #2 - Satis does not read the composer.jsons from repositories specified as 'package' type. This is obvious in hindsight, because 'package' is used for libraries that do not have a composer.json, and is a way to wrap composer-like dependency management around them.
Changing the satis.json's repository to 'vcs' type meant that the composer.json was read, and the information (including the autoload specification) was parsed and stored in the packages.json.
#Seldaek - thank you for suggesting that my satis config was the problem, and I hope that this clarifies satis / composer behaviour for anyone else in my position.
I see two possible mistakes you may have done that would cause this:
You forgot to update your satis repo so the autoload config for lxp/init is not up to date in there
You are running composer install from a lock file, and that means composer just reads the info from the composer.lock file and does not update package metadata to the latest version available in satis. To solve this you should run composer update instead.
Try composer dump-autoload command.
It depends how you installing your library via Composer. For example, when downloading it as package type (same I believe with composer type), Composer never reads the composer.json file, so instead you should use vcs or git type. See: GH-6846.
Here is composer.json which should work:
{
"require": {
"lxp/library": "dev-master"
},
"repositories": [
{
"type": "vcs",
"url": "http://satis.repo.redacted/"
}
]
}
Then run: composer install.
For troubleshooting, try running:
composer dump-autoload -o -vvv.
composer diagnose -vvv

How to add FirePHP using composer to Zend Framework 2

I'm trying to add FirePHP to my Zend Framework 2 project using composer, but I get errors.
My OS is a Windows 7.
I tried following ways to make it working:
I added following code to composer.json file:
"repositories": [{
"type": "vcs",
"url": "https://github.com/RobLoach/firephp-core"
}],
"require": {
"firephp/firephp-core": "dev-master" // Tried also: "firephp/firephp-core": "*"
}
Here is a error I got:
[RuntimeException]
Failed to clone http://github.com/RobLoach/firephp-core.git, git was not found, check that it is installed and in your PATH env.
I tried add to composer.json following code, which I found in firephp pull request. :
"require": {
"firephp/firephp-core": "*"
}
But it gives me same error I have posted above.
Composer is totally new for me. I couldn't find any helpful tutorial for it, so I'm not sure how does it work yet, but I'm doing my best to get familiar with it.
I hope someone can tell me what I'm doing wrong.
Thanks.
EDIT:
I got it working thanks to #Seldaek help, but it removed my Zend library folder.
Here is log from cmd:
E:\xampp\htdocs\ZendSkeleton>php composer.phar update
Loading composer repositories with package information
Updating dependencies (including require-dev)
- Installing firephp/firephp-core (dev-master f60753a)
Cloning f60753a8dd7817e4da6bc73e0e717387a9a0866a
- Removing zendframework/zendframework (2.0.5)
Writing lock file
Generating autoload files
Is there any way to stop removing Zend folder?
Here is my full composer.json file:
{
"name": "zendframework/skeleton-application",
"description": "Skeleton Application for ZF2",
"license": "BSD-3-Clause",
"keywords": [
"framework",
"zf2"
],
"homepage": "http://framework.zend.com/",
"require": {
"php": ">=5.3.3",
"zendframework/zendframework": "2.*"
},
"require": {
"firephp/firephp-core": "dev-master"
},
"config": {
"bin-dir": "E:/xampp/htdocs/ZendSkeleton/"
}
}
The problem is the package only has a dev-master version available, and those are by default installed with git. If you don't have git available in your PATH you can run composer with --prefer-dist which will force it to install from zip archives instead of via git. Something like composer update --prefer-dist should work out.
The better fix though would be to make sure that the git executable is accessible in your PATH environment variable. If you have no idea what I'm asking, maybe another option is to run composer from the "Git Bash" shell instead of cmd.exe.

Composer phar package not found

I am trying to create a new composer library package.
I created the composer.json file using the
composer.phar create-project xlix vendor/xlix/xlix 0.3
command.
In the filesystem the file composer.json exists under vendor/xlix/xlix and for testing purposes I copied it to vendor/xlix.
The composer.json file content is the following:
{
"name": "xlix/xlix",
"type": "library",
"description": "XLIX package",
"keywords": ["core"],
"homepage": "http://myhomepage",
"license": "GPL",
"authors": [
{
"name": "Florian Kasper",
"email": "florian.kasper#mymail"
}
],
"require": {
"php": ">=5.2.4"
},
"autoload": {
"psr-0" : {
"Xlix\\Bundle" : "lib/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0"
}
}
}
Then I tried the following commands:
git:(master) ✗ php composer.phar require xlix/xlix
git:(master) ✗ php composer.phat require vendor/xlix
...
git:(master) ✗ php composer.phar install vendor/xlix
git:(master) ✗ php composer.phar install xlix/xlix
...
Every time the same output:
Please provide a version constraint for the xlix/xlix requirement: *
composer.json has been updated
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.
Problem 1
- The requested package xlix/xlix could not be found in any version, there may be a typo in the package name.
Potential causes:
- A typo in the package name
- The package is not available in a stable-enough version according to your minimum-stability setting
see <https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion> for more details.
In my ROOTDIR/composer.json file the package is registered in the require section.
"jms/security-extra-bundle": "1.2.*",
"jms/di-extra-bundle": "1.1.*",
"kriswallsmith/assetic": "1.1.*#dev",
"xlix/xlix": ">=0.*"
Now I am on the edge of despair an don't know what to do anymore.
Question:
Are there any mistakes I've made or is there anything i missed?
Packages live on the internet, not on your filesystem.
Composer searches by default for a package called xlix/xlix on packagist and that does not exists. You can add more package repositories by using the repositories configuration, more about that in the documentation.
So, in order to require your package with composer you need to upload your xlix directory somewhere.
I don't see what you are trying to do in the lxix directory? You are in the lxix package, why do you want to require it in the same package? It looks like you don't understand what those commands do and how composer works. Maybe a good read in their own documentation -- or some other tutorials about Composer (like the one on nettuts+) -- will help you to get a better understanding of composer.

Composer does not fetch dependencies from local repository

I am trying to add a local project A as dependency to project B. Using git daemon I am able to fetch project A as dependency, but the dependencies defined with require in the composer.json in project A are not recognized. What am I missing?
project A:
{
"name": "project/a",
"require": {
"monolog/monolog": "dev-master"
}
}
project B:
"repositories": [
{
"type": "vcs",
"url": "git://localhost/home/user/project-a"
}
],
"require": {
"project/a": "dev-master"
}
result (in project B):
vendor/
project/a
expected:
vendor/
project/a
monolog/monolog
The most likely explanation is that you forgot to commit the changes to your composer.json in /home/user/project-a.
To debug this you can use composer show project-a dev-master -v. The -v will output more verbose info while it loads the repository, and then you will see details about the version you are installing, if it does not contain the monolog require, then I would say my guess above was correct. If it does contain it, we got a serious bug in composer and you should report it on github.
I encountered a similar issue and my issue was that I was running composer update instead of composer install and one of the libraries that I required defined some of its dependencies as zipballs from GitHub.

Categories