Using PHP Packages without Composer - php

I'm building an SDK for developers to use to build modules for ecommerce platforms that will consume our API for a new startup.
Obviously it would be ideal to use composer, which I am doing right now. But as I examine most of the ecommerce platforms out there right now, or at least the most popular ones, they don't use composer.
So I'm wondering what's the best way to get all the dependencies all my current packages need and build them into a freestanding SDK.
This way I can have a version that will work for both composer and non-composer enabled platforms.
Is there a standardized way to do this in terms of a design pattern? How would I lay out all the dependency packages in any organized way?

Because those e-commerce platforms don't use composer, that doesn't force you to exclude composer from equation. You can't distribute your package as a plugin/module/whatever for that particular e-commerce platform, but you can still use composer's autoloader in production.
You could prepare the package for deployment on your machine or on a build server, archive the result and distribute the archive.
For the sake of simplicity, my example will assume that you will prepare your package on your local machine:
Create a temporary working directory:
$ mkdir -p ~/.tmp && cd ~/.tmp
Clone your package:
$ git clone <package>
Install dependencies1
$ cd ~/.tmp/<package> && composer.phar install --no-dev --optimize-autoloader
or if you do this from an automated tool:
$ cd ~/.tmp/<package> && composer.phar install --no-ansi --no-dev --no-interaction --no-progress --no-scripts --optimize-autoloader
Remove .git directory.
Create the zip/tar archive from ~/.tmp/<package>
Distribute the archive.
Assuming that your package is already a plugin/module for that e-commerce platform, it can be installed as usual from that zip/tar archive.
1) Regarding --optimize-autoloader, please read this answer from Sven, which explains why in some cases doesn't help your application to become faster.

Don't have dependencies!
Yes, seriously. If you'd develop an API client that would use Guzzle as the HTTP client, you'd have to make a choice: Use Guzzle version 3, 4, 5 or 6?
Guzzle 3 is out of maintenance and abandoned. You wouldn't want to use it.
Guzzle 4 is also considered end-of-life, because version 5 came very fast. Nobody really use this version.
This boils down to using either version 5 or 6. But Guzzle is using the same namespace and likely the same class names in both versions, but is incompatible to each other. No matter which version you choose: Your customer will have made the opposite choice - and now you have a codebase where two versions of Guzzle are running at the same time - this will not work.
If you don't have dependencies, but deliver everything within your own codebase, you have all of your code under your control, and are reducing the need to use Composer as a tool to easily install all your dependencies. Your package will have everything already included, it's unlikely that there will be any namespace conflicts.
You'd be able to offer a ZIP file for download. And if you additionally offer a composer.json to allow developers to include your package that way, everyone will be happy.
Update
Now after finding out that everyone thinks I am crazy proposing not to use stuff invented elsewhere, I challenge you to think about the situation once again: You find that you have to produce code that will likely be included in a codebase that is NOT managed with Composer. That means you have no idea what kind of software is put together there.
It may simply be so that you have a version of Guzzle in the existing codebase - undetectable, because there is no composer.json. Now you provide your own package with a bundled Guzzle version (whatever way made it appear there). This will likely crash the entire software at some point because of conflicts, because the autoloading will of course be merged at some point, and then some part of the code will request some Guzzle class to be loaded, which is included twice from two different versions of Guzzle.
WHAT SHOULD HAPPEN IN THIS CASE? THINGS WILL CRASH!
And it is unavoidable that this will happen. Even in the lucky case of being able to use Composer, it will conflict - the software won't crash, but the entire package won't be installed. The good thing is: You will notice this immediately.
If the primary goal is to deliver an API client anyone can use in every situation, without using a dependency manager: Don't have dependencies!
Alternatively, be completely sure that you know which software is already being used, and create a package that will not conflict in any case. However, this is still an effort, because there might be other addons also being installed, which might include conflicting software.
My central point is: If you don't have a dependency manager like Composer being able to manage the dependencies, you are better off NOT to have dependencies in your own code to make it super easy to include your own code in someone else code base.
And the question above clearly states that Composer is not an option in the general case.
Now there is one light at the end of the tunnel: When it comes to general tasks, the PHP-FIG has started to standardize interfaces that should leverage interoperability. For HTTP, the standard is PSR-7.
You COULD provide an API SDK that depends (and brings with it) the PSR-7 interface and requires the user of the SDK to provide a HTTP client that implements this interface.
The problem with this approach I see is that you will still run into trouble if you try to use for example Guzzle for the same reason: The only valid choice now is to use Guzzle 6 for the SDK - what if Guzzle 5 was already used elsewhere? Conflict! The good thing is: You can avoid using Guzzle 6 if you are already using Guzzle 5 by using any other PSR-7 capable HTTP client.

Related

Is there any way to display "Next Steps" directions after running "compose require"?

I have built a composer package that requires the user to run vendor/phpexperts/dockerize/install.php.
Is there any way for composer to actually tell them they need to do this? Or must they read the README?
There is no standard way that works for all installations, as there is no way to react to an installation in core features. For example, there's a long discussion about this in https://github.com/composer/composer/issues/1193 where the creator of Composer declines to automatically run scripts from depending packages due to security concerns - I assume the same argumentation would follow if there was a feature request to run scripts in direct dependencies directly after an installation.
But there might be workarounds. Symfony Flex is able to run scripts after an installation, and there's a contrib repository where you could add your installation scripts.
One "hacky" way to do this would be to use the "suggest" key in composer.json. Every key-value pair in "suggest" takes the format:
"<suggested-package>": "<message>"
The package names don't seem to be validated currently, so you can put anything in there.
When you run composer install, the suggests are shown as:
<vendor>/<package> suggests installing <suggested-package> (<message>)
The (<message>) part is left out if the message is an empty string.

PHP packages installed by Composer - should they be in source control?

I am reading/learning about Composer, the application-level package manager for PHP.
In this blog post written by lead dev Jordi Boggiano, he writes:
Composer on the other hand forces you to declare your project
dependencies in a one-stop location (composer.json at the root). You
just checkout the code, install dependencies, and they will sit in the
project directory, not disturbing anything else on the machine.
Another related feature is the composer.lock file that is generated
when you install or update dependencies. It stores the exact version
of every dependency that was used. If you commit it, anyone checking
out the project will be able to install exactly the same versions as
you did when you last updated that file, avoiding issues because of
minor incompatibilities or regressions in different versions of a
dependency.
If I understand Composer properly, when we're talking about packages downloaded/installed by Composer, we are talking about PHP code packages, ie, programming code written in PHP, and not system-level packages, eg, extensions to the PHP runtime installed on the server. So once these PHP code packages have been downloaded and added to a PHP project, I would have thought those packages become part of the PHP application source code, eg to be checked in to whichever version control system is being used for the project. If another developer comes along and checks out the code, why would they need to then "install the packages", as is stated in the blog post? Wouldn't they get a copy of all code packages when they check out the code from source control? This line in the blog post is confusing me, and making me think I don't understand Composer.
Any clarity on this would be greatly appreciated. Thanks.
The dependencies themselves should not be commited to source control. The composer.json and composer.lock files, on the other hand, should. There's various reasons for this, amongst them:
Every time you update the dependency you would have to commit the changes. That kind of tightly couples your code to the dependency, when it should be exactly the other way around.
The packages themselves are already in their own repository with their own history. Why repeat that in your project's history?
Those repositories can be huge, just muddling the waters around your project. Why carry around all that weight?
Instead, having each developer just run composer install (very important: not composer update) whenever they check out the project is much more efficient. Composer will install the dependencies from composer.lock, making sure everyone running the same commit is on the exact same page. The same goes for deploying.
You can read more about this here.
On the other hand, there might be situations where you have to commit your packages to get around a problem, like for example when you know you won't be able to run composer install on your production server (shared hosting)
Normally packages installed via composer don't get checked in to source control, only the code you write and the composer.json and composer.lock files.
This way the repository for your project does not get bloated with code you did not write and possibly don't really care that much about.
Yes its normal after cloning down your repository a developer will need to run the "composer install" command. The composer.lock file will ensure they get the same modules and versions of them you used when creating your project.
Not including the composer modules in your source control also allow you to easily update to the modules to get bug fixes and new features in new versions of them.

php composer install or NOT? for production environments

I am working on Laravel webapp right now and kept vendor directory out of git (version control) so far and every time for fresh install I used to have composer install command added to automated script and everything was fine.
Now just 2 days back I added added laravelcollective (https://laravelcollective.com/) to my project for helping me with forms and html in blade templates. Now somehow one of the dependency requires me to generate GIT private token to install it and that is pain as it would hurt my automation. I can still hack it by calling the url and scrapping html to read token and stuff like that but I don't like it. And then I thought is it good idea to keep vendor directory out of SVN/GIT? Isn't source code for a product contain all dependencies within itself? I am not talking about stuffing JRE in the installer but when it comes to libraries of a product in native language.
I would like to hear more about it on industry standards or best practices on this.
P.S:
This question is much generic and not just limited to laravel or even php for the matter.
Now somehow one of the dependency requires me to generate GIT private token to install it and that is pain as it would hurt my automation.
You're just running into Github's rate limits for package downloads for anonymous users. No reason you can't automate this. Generate a Github token (you only need to do it once - they get very high rate limits for authenticated requests), then have your automation use that token like so:
composer config -g github-oauth.github.com <oauthtoken>
https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens
Well, for production environment you usually run a build process first in your CI software. If 'composer install' fails during the build – application won't be deployed to production environment, so you are safe.
Yes, most (99%+) people keep 'vendor' folder out of the repo because it's a third-party code, it's not yours. You may not even have rights to host it in your repo.
If you want to be sure that your production version will have all the dependencies in order, the way you had them during CI, and will always release – you could build Docker images and ship them to production. Then, everything comes prepackaged.

PEAR: Using the framework in a distributable application

I am working on a PHP application that uses many features from PEAR. The app is meant to be distributable kind of like Wordpress but really scaled down.
Now the problem I've run into is that PEAR needs to be installed and configured alongside the PHP server without which my app simply will not function unless the users go through all the painful steps of installing PEAR on their server. Users can very well be newbies or non-technical so it's not an option for them.
Therefore there is a need to somehow package everything PEAR into the application itself. As far as I know it may not be possible.
Are there any alternate solution to this? Any solution at all will help. Thanks..
PEAR installs system wide dependencies which makes things like what you describe hard. Composer on the other hand is exactly what you'd need, because it's a per-project dependency manager with much better support for resolving and installing of dependencies. Basically, compared to Composer, PEAR sucks... it always did, Composer on the other hand rocks!
The first thing I would do for each package you need is to see if it is also provided on https://packagist.org/. If it is, problem solved, include the installation into your build process with composer. If you end up with only a few packages from PEAR, you have several options:
inspire the author to provide it on packagist
make your own mirror on packagist (not recommended but sometimes necessary)
see if the project is on github and install directly from git with composer
install the PEAR package via composer anyways, it's possible.
Short answer: switch to composer!
If you are talking about the PEAR packages or class files, you can put the PEAR packages anywhere you want. Just put the ones you use into a dir within your app dir structure and add that to the include path.

Is there risk of unavailable sources in composer-based project?

When putting together a PHP project with composer, on installation / deployment, composer would fetch the dependencies usually from their original sources.
This could lead to problems when deploying, when a source (maybe only temporarily) becomes unavailable.
Is there any included mechanism to keep at least the current, stable versions of the dependencies some where to be always able to deploy the current version to other instances?
Right now there is no one click solution for this, but I plan to work on something soon that will give you more reliability.
Broker looks like a tool which could serve as a proxy to keep files, and is now integrated into Satis (see https://github.com/researchgate/broker)
broker is a full repository proxy for composer. It takes a composer file, downloads all
requirements and all dependencies, and then publishes a new repository with all these
packages. Instead of packagist or satis, all packages, including dist and source files will > be served directly by broker.
Note: this project is not actively maintained anymore. Since satis supports a similar
functionality now, you should use satis instead.

Categories