5

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?

secondman
  • 3,233
  • 6
  • 43
  • 66
  • Rather than me just answering to point to AWS' model, why don't you write up a self-answer once you have formulated a strategy for your own project to accept. – Michael Berkowski Oct 04 '15 at 23:54

2 Answers2

1

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:

  1. Create a temporary working directory:

    $ mkdir -p ~/.tmp && cd ~/.tmp
    
  2. Clone your package:

    $ git clone <package>
    
  3. 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
    
  4. Remove .git directory.

  5. Create the zip/tar archive from ~/.tmp/<package>

  6. 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.

Alexandru Guzinschi
  • 5,675
  • 1
  • 29
  • 40
  • Don't blindly run with `--optimize-autloader` if you didn't check it is faster, and how much. – Sven Oct 05 '15 at 01:36
  • @Sven Can you give a concrete example where classmap is slower than PSR-0/4 ? – Alexandru Guzinschi Oct 05 '15 at 09:44
  • All the details are in this answer: https://stackoverflow.com/questions/22803419/why-use-a-psr-0-or-psr-4-autoload-in-composer-if-classmap-is-actually-faster/22823995#22823995 It is essentially a tradeoff between the minimum amount of lookup work needed on the filesystem vs. always wasting resources to create the classmap. – Sven Oct 05 '15 at 11:31
0

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.

Sven
  • 69,403
  • 10
  • 107
  • 109
  • 1
    If the -1 voter could explain what I answered badly, all would profit. – Sven Oct 02 '15 at 18:07
  • 3
    It took PHP 15+ years to arrive at a place where interoperability could be made consistent and reliable. It is terrible advice to avoid making use of existing shared code just because versioning _without_ the very tool meant to handle (Composer) it is complicated. The age of "not invented here" in PHP code has finally passed. Since you emphatically use Guzzle as your example, can you replace all Guzzle's functionality with in-built PHP features? Yes. But it is unproductive to reinvent all that boilerplate unless you use only a small fraction of its functionality. – Michael Berkowski Oct 02 '15 at 18:20
  • @MichaelBerkowski The Internet connectivity is still not easy or good enough for notable number of people around the world. Composer is an Internet dependent tool. – SaidbakR Oct 02 '15 at 18:29
  • @sємsєм The proposed ZIP archive for download is also Internet dependent. I think it is safe to assume that anyone running a PHP ecommerce web application _on a server_ has reliable connectivity, as it is the server that is the integration and deployment target, not the developer's environment where connectivity may be more limited. – Michael Berkowski Oct 02 '15 at 18:36
  • 1
    @MichaelBerkowski I totally agree with you. Hence the reason I'm developing this WITH composer. Sadly not all developers build their frameworks with composer because they cater to consumers who don't have access to their hosting environment, which severely limits your ability to use composer. Creating a freestanding version, while more work, is the best solution to allow all of our potential customer to use our product. – secondman Oct 02 '15 at 18:51
  • 1
    @Sven, this is pretty much what I meant in the question. But I think I've got it sorted out. I just downloaded all the dependencies and then extracted them and properly placed them so their namespacing will be accurate. Create an autoloader and viola, self contained app with all it's dependencies. Maintaining it however .... is another ball of wax. – secondman Oct 02 '15 at 18:55
  • @VinceKronlein don't do that! you need automatize your build and that includes dependency installation and autoloading preparations. If you can't repeat it with one command, there is something wrong and you'll regret it in the future. – markus Oct 02 '15 at 20:51
  • @MichaelBerkowski I challenge you to provide a better answer to get out of the situation the OP is in, instead of whining about me supposedly proposing against interoperability. I have my reasons made more clear in my answers' update, which are particularly tied to the situation given in the question. – Sven Oct 03 '15 at 15:43
  • @VinceKronlein: Downloading Guzzle and putting it into your own package under it's orginal namespace will still lead to conflicts. I cannot know whether this is a problem for you. – Sven Oct 03 '15 at 15:45
  • My _opinion_ is to only target platforms using modern toolchains (like the AWS SDK does, for example http://docs.aws.amazon.com/aws-sdk-php/v2/guide/installation.html) precisely because of the support headaches involved in working around the lack of tooling. But this is no better a recommendation to the OP than to avoid dependencies, and therefore not an answer. – Michael Berkowski Oct 03 '15 at 16:18
  • @MichaelBerkowski This is what I said in the beginning of the question. A version setup to download with composer, and a zip archive that contains all the required dependencies already. How is this different than what AWS offers? – secondman Oct 03 '15 at 20:12
  • @VinceKronlein It isn't, and I didn't think of AWS yesterday. AWS' distribution model works because they do not support PHP versions older than 5.5 as far as I know. (its dependencies probably don't either). So if you can use AWS .phar & .zip as a model for your own purposes, that's excellent. You may run into difficulty with ecommerce platforms that haven't adopted composer though, because those projects are more likely to still be supporting older PHP versions. – Michael Berkowski Oct 03 '15 at 21:00
  • @MichaelBerkowski yeah that's exactly why we'd have the zip archive. Everything included with no need for composer, basically just like the AWS version does. Classmap autoloader and whatever else is needed. Thanks for that link, that gives me a great pattern to follow. Appreciate your help. You should submit that as an answer so I can accept it. – secondman Oct 04 '15 at 16:44