PHP install package globally: apt-get vs composer - php

I found there are two options to install PHP package globally in Linux (Ubuntu 16.04):
Using composer:
composer global require symfony/finder
The package will be located at ~/.config/composer/vendor/
Using apt-get:
apt-get install php-symfony-finder
The package will be located at /usr/share/php/
This directory /usr/share/php/ is also in default PHPs include_path (I have PHP 7.2)
There are several questions I have:
Why would I want to install package globally ?
I know it's useful to install php tools globally, like phpunit - It has binary file and it allows you to run tests everywhere, so you don't have to install it in every project.
But what about symfony/finder for example ? What is particular use of this package installed globally ?
What is the difference between 1 and 2 option ?
Does it have any different use cases or different effects ?

Why would I want to install package globally ?
Normally, these are dependencies you want to use in almost every project, because they are available at a system level you can use them without duplicating their dependencies in every application you create.
For example, in my case I have php_md, php_cs for code formatting, phpunit for testing.
What is the difference between 1 and 2 option ?
Both are package managers, they make sure every package installed has the correct dependencies, so their core functionality is similar.
Now, they have several differences:
Their focus in the packages they manage, composer is specific for php based packages but apt-get is for Linux and more system level oriented.
Their package database, composer uses packagist and apt-get uses a selection of repositories and ppas (you can find them in /var/lib/apt/lists/).
The package selection, since composer is specialized in php you can expect a wider variety in anything php related.
In conclusion, you can clearly make it work with both, but I would recommend you to keep everything php related on composer, unifying them under the same manager.
Any other difference or correction I've overlooked is welcome.

Related

How can I install a single specific package from composer.json, to install developer tools?

I'm using PHP_CodeSniffer in my GitLab CI/CD pipelines to ensure my code is properly formatted. The job looks like follows:
stages:
- test
- build
- deploy
coding_standard:
stage: test
script:
- curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar
- php phpcs.phar --extensions=php .
That's working as expected. However, the exact version of the tool is not specified here. So if there's suddenly a new major version of PHP_Codesniffer, the CI/CD job might fail, although my PHP code hasn't changed.
Furthermore, I currently have the tool installed globally on my local machine. In that way, I cannot have a specific version of the tool for every PHP project.
Now I'd like to add the tool as Composer dev-dependency (require-dev).
In the CI/CD job I would then call composer install instead of downloading the tool via curl.
The problem: That will download all packages needlessly, instead of just PHP_Codesniffer and its dependencies. Can I prevent that?
You can't do this with composer. You can't even install "only the dev dependencies". It's all the dependencies, all the non-dev dependencies, and that's all.
And it's generally a bad idea to install this kind of dependency as a project dependency, since very easily you can enter in dependency hell for reasons beyond your actual application needs. Development tools should not bring that level of complexity and danger to your deployment strategy.
To get around this, you could use something like the Composer Bin Plugin to isolate these dependencies and yet install them through composer. Then on CI you'd run composer install on this directory only, and run the tool from this location (or symlink it to bin, which is what the plugin does when it's installed, but you wouldn't have it installed in CI if you are not installing all the dependencies anyway).
Why not download any tagged version from Github through https://github.com/squizlabs/PHP_CodeSniffer/releases, like https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.0/phpcs.phar?
Using a PHAR is better than installing such stuff using Composer, as you might install other incompatible dependencies that way (this is not the case with phpcs, but other tools like phpmd install other dependencies from Symfony)

What does the composer "provide" do?

I'm using Laravel + VueJS to recreate a POS system from work. I needed to install sped-nfe package to work with it on a system for work.
This package requires many other packages in order to function properly, like ext-curl, ext-soap, ext-json.
As per instructions, I added
"nfephp-org/sped-nfe" : "^5.0"
to my composer.json.
When I ran composer install or composer update, the following error ocurred:
Your requirements could not be resolved to an installable set of packages.
Problem 1
- nfephp-org/sped-nfe[v5.0.100, ..., v5.0.122] require ext-soap * -> it is missing from your system. Install or enable PHP's soap extension.
- Root composer.json requires nfephp-org/sped-nfe ^5.0 -> satisfiable by nfephp-org/sped-nfe[v5.0.100, ..., v5.0.122].
To enable extensions, verify that they are enabled in your .ini files:
- C:\laragon\bin\php\php-7.4.19-Win32-vc15-x64\php.ini
You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.
I'm using Windows and I'm not authorized to modify our local server nor the actual server, I was getting frustrated trying to find a solution to my problem - almost every answer would tell me to modify my php.ini or install curl with sudo apt-get - I arbitrarily decided to add the following lines to my composer.json:
"provide": {
"ext-curl":"*",
"ext-soap":"*"
},
Et voilĂ , composer update and composer install were working smoothly.
What's bothering me is, according to the composer documentation,
provide
Map of packages that are provided by this package. This is mostly
useful for implementations of common interfaces. A package could
depend on some virtual package e.g. psr/logger-implementation, any
library that implements this logger interface would list it in
provide. Implementors can then be found on Packagist.org.
Using provide with the name of an actual package rather than a virtual
one implies that the code of that package is also shipped, in which
case replace is generally a better choice. A common convention for
packages providing an interface and relying on other packages to
provide an implementation (for instance the PSR interfaces) is to use
a -implementation suffix for the name of the virtual package
corresponding to the interface package.
I am not providing this package, I simply wanted to require it but ended up putting it differently. Also, I've tried requiring it, but the error was still there.
Was this a good solution to my problem or should I do it differently?
Is there anything about this that I should worry?
Can someone explain the 'provide' syntax for me?
If you add a package or a PHP extension to the provide section, you tell composer that your package itself or the external system setup "provides" this one. The dependency resolver is fine with this.
This does not check further whether this dependency is actually properly resolved or not. Composer relies on your statement that this is not a lie ;) So, if you only add this to the section without properly providing that package, you cannot be sure that your application works properly.
In your example: the package you want to install requires the SOAP extension. It won't work properly without it. If you cannot install that extension on your server, you should not use this package.

How to force dev-dependencies from a dependency to also install with composer?

I'm currently working on a package (cms), which has a dev-dependency to a certain package (code-generator) to create code. This package is not needed in production.
However, when creating a website that uses the cms package, dev-dependencies (including the code-generator) are not installed (which is correct composer behavior btw).
But while developing the website, the code-generator is required.
Is there any way to force a certain dev-dependency to also install when the package is installed?
This is not possible. Dependency can either be required for the package to work properly (then it should be in require section and it is always installed), or required only for development of this package (then it should be in require-dev section and is installed only when package repository is root). There is nothing in between. If this code-generator dependency is required by your package to work it clearly fails into first category (require section).
Usually in this case the best solution is to split this package into 2 packages: regular package and dev package with all tools used only during development process. So it should be installed by 2 commands:
composer require myvendor/mypackage
composer require myvendor/mypackage-dev --dev
This will still require everyone to install two packages instead of one, but it should not be a big problem if it is properly documented. Result should is more clear (it should be quite obvious what is the purpose of myvendor/mypackage-dev package) and gives more control to package owner (he can easily add new dependencies for dev package) and end user (he can always skip installing myvendor/mypackage-dev if he don't want to use this code generator).

Difference between composer update and composer global update

What are the differences between composer update and composer global update in yii2?
It's not anything to do with Yii directly.
Composer allows you to install dependencies globally or per-project (the default).
https://getcomposer.org/doc/03-cli.md#global
This is merely a helper to manage a project stored in a central location that can hold CLI tools or Composer plugins that you want to have available everywhere.
You might want to install something like phpunit or phpcs globally (so it's available for every project) whereas installing a library or framework that you need for your project should be a per-project installation.

Manually laravel 5 package install in project

I have install a new laravel 5 project. In my other project i have several packages. I want to install my expected packages from copying package from vendor folder and paste into my new project. I want to do that because composer is really slow to install new package from online.
You just can't install manually because it will be a lot of task then. e.g when Laravel installs through composer it has some scripts which runs at different steps of install it copies .env file it generates key etc. You can see https://github.com/laravel/laravel/blob/master/composer.json#L31 & https://getcomposer.org/doc/articles/scripts.md#event-types. Now you can copy paste of your full previous code & remove controllers, models, packages from composer.json. But if you manually install it won't be a wise decision.
For composer You can use https://github.com/hirak/prestissimo
It gives you the ability to install packages and dependencies in parallel mode. This gives a huge boost during installing projects/packages.

Categories