Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: composer

  • More Complicated Composition

    More Complicated Composition

    Once you’ve made your basic composer.json file and you’ve got your library included, it’s time to consider a more complication situation.

    Let’s take the following example. You want to include two plugins/add-ons, a javascript library, oh and one of those plugins doesn’t use Composer. Don’t worry, we can do this.

    Organize Your Notes

    Step one is to make a list of what you need to install and where it needs to go. Because in this situation, due to the use of the javascript, we’re not going to be using that autoloader.

    1. list all your repositories 
    2. mark which ones do and don’t use Composer
    3. determine where they need to go

    For this example, we want the javascript files to go in the assets/js/ folder in our plugin, and we want the plugin/add-ons to go in plugins/

    Okay, that’s straightforward. But we need to address something.

    Avoid AutoTune

    I mentioned we’re not using the autoloader and I cited the javascript as why. That was a partial lie. You see, even though Composer makes an autoload file, and even though it is a dependancy manager, it actually tells you not to commit your dependancies to your own repository.

    The general recommendation is no. The vendor directory (or wherever your dependencies are installed) should be added to .gitignore/svn:ignore/etc.

    Official Composer Documentation

    The biggest reason why is one you absolutely will run into here, and it’s that when you add dependancies installed via git to another git repo, they end up as submodules, which are a special hell of their own. Only it’s worse. They’re not even really submodules, and you end up with empty folders.

    Seriously, I wasted two hours on this when I first ran into it.

    But that said, it’s really wise to omit your vendor folder because your plugin does not need 3 megs of files if all you want is one javascript file. Right? This means we need to add one more dependancy to Composer, and that’s Composer Copy File.

    Adding The Normal Dependancies

    Right now, our requires section looks like this:

        "require": {
            "slowprog/composer-copy-file": "^0.2.1"
        }

    So when you add in your normal dependancies, like the PHP library, you get this:

        "require": {
            "slowprog/composer-copy-file": "^0.2.1",
            "example/php-library1": "^1.3"
        }

    You’ll do this for the javascript libraries as well:

        "require": {
            "slowprog/composer-copy-file": "^0.2.1",
            "example/php-library1": "^1.3",
            "example/js-library1": "^0.2.1",
            "example/js-library2": "^2.30"
        }

    Adding the Weird Stuff

    Okay but I mentioned one of the PHP libraries I wanted to use didn’t have a composer.json file, which means I can’t include it like that. Instead, I have to add this section above the requires section, in order to create a new package to add:

        "repositories": [
            {
              "type": "package",
              "package": {
                "name": "example2/php-library",
                "version": "1.0.0",
                "source": {
                  "url": "https://github.com/example2/php-library",
                  "type": "git",
                  "reference": "master"
                }
              }
            }
        ],

    Right? That’s all kinds of weird, but basically I’m telling Composer that there’s a package called example2/php-library and it gets its data from https://github.com/example2/php-library – which means I can then add it to my requires like this:

        "require": {
            "slowprog/composer-copy-file": "^0.2.1",
            "example/php-library1": "^1.3",
            "example/js-library1": "^0.2.1",
            "example/js-library2": "^2.30",
            "example2/php-library2": "dev-master",
        }

    Copy Everything

    Once you have your files in and required, everything gets put in vendor which is great except for the part where we’re not going to use the autoloader. In fact, we’re going to add /vendor/ to our .gitignore file to make sure we keep our plugin small.

    No, we’re going to use that copy code we mentioned above like this:

        "scripts": {
            "post-install-cmd": [
                "SlowProg\\CopyFile\\ScriptHandler::copy"
            ],
            "post-update-cmd": [
                "SlowProg\\CopyFile\\ScriptHandler::copy"
            ]
        },
        "extra" : {
            "copy-file": {
                "vendor/example/php-library1/": "plugins/php-library1/",
                "vendor/example2/php-library2/": "plugins/php-library2/",
                "vendor/example/js-library1/dist/js/file.min.js":  "assets/js/file.min.js",
                "vendor/example/js-library2/dist/js/file2.min.js": "assets/js/file2.min.js"
            }
        }

    The first portion triggers a copy every time you install or update the Composer setup, and the section section (in extras) is what runs. 

    Now you include the libraries in your code like you’d downloaded and copied them, only you don’t have to worry so much about keeping them up to date. As long as you’ve got your composer versions, you’re good to go.

  • Small Steps with Composer

    Small Steps with Composer

    Like a great many people before me, I use composer to manage packages. In my case, I have a WordPress plugin that contains some fairly significant packages that other people have written. They’re libraries, and I have a bit of a love/hate relationship with them. Mostly, I hate keeping them up to date, which is where composer comes in for me.

    Composer?

    Composer bills itself as a package manager for PHP. This means it will download all the code you need for your plugins, toss it in a folder (usually called vendor) and let you get busy with the coding and not worrying about if your PHP library is out of date.

    It’s very similar to bower, which I’ve been using for a while now, and grunt, which I sometimes use with bower. However unlike those, Composer hooks in to Packagist, which allows you to include pretty much any library with a composer.json file to generate your builds. And this is where it gets hairy.

    Conceptualizing Composer

    The basics are these: You need a composer.json file to tell Composer what to do, and in that file you need to tell Composer what to do. Yep, that’s it. The complications come in with understanding exactly what it is you’re trying to do. So let’s start small.

    Today, you want to use Composer to update a library, say the AWS SDK for PHP, so you can include it in your plugin. That’s it. Like I said, small. We’re going to assume you’ve written everything else, and you went to the AWS SDK library on Github to get the files.

    The old way would be to download the zip, unzip it, and include it in your PHP code. The new way is is to make a Composer file.

    Constructing Composer

    Windows users, you need to download the setup file from getComposer.org. Mac/Linux users, I recommend you use the global install method, or if you’re lazy like me, brew install composer will get you done.

    Now that you have it installed, you need to make your file. There are a lot of options and possible calls to put in the file. All you need is the ‘requires’ section, which literally is going to tell Composer what it requires. I recommend a basic file that lists what it’s for, who wrote it, and what it needs. 

    Example:

    {
        "name": "example/my-project-name",
        "description": "This is a very cool package that uses AWS",
        "version": "1.0.0",
        "type": "wordpress plugin",
        "keywords": ["wordpress", "plugin", "self-hosted"],
        "homepage": "https://example.com",
        "license": "MIT",
        "authors": [
            {
                "name": "Test Example",
                "email": "test@example.com"
            },
        ],
        "require": {
            "aws/aws-sdk-php": "3.*"
        }
    }

    The secret sauce is that teeny requires section at the end, where I say what I want to require and what version. That’s how composer update knows what I need.

    You can also make the file without that requires section and then tell Composer to include it via command line: composer require aws/aws-sdk-php — That will write the line for you.

    Calling Composer

    So once you have that and install it and run Composer, how do you get it in WordPress? By default, Composer makes an autoloader file called autoload.php – and that will require everything it is you need. That means all you have to do is require that file in your plugin, and you’re done.

    What? You wanted more?

    Conclusion

    Getting started with Composer isn’t harder than writing a readme, even if it’s formatted pretty weirdly. It can make including large libraries a snap. But don’t worry, you can get really complicated if you want to.

  • Composer and WordPress’ Plugin Preflight Check

    Composer and WordPress’ Plugin Preflight Check

    When you upload a plugin to WordPress.org’s repository, it does some pre-flight checks to make sure the code is okay. More than once it’s caught a missing ; for me. But one day it caught this:

    PHP error in: myplugin/tags/0.6/aws/Doctrine/Common/Proxy/ProxyGenerator.php:
    Errors parsing myplugin/tags/0.6/aws/Doctrine/Common/Proxy/ProxyGenerator.php
    

    I stared for a moment, Googled to be sure, and sighed when I figured out that what was happening was my library was a PHP 5.6+ version and that didn’t pass the 5.4 checks.

    Regardless of how annoying this is, it’s not too hard to fix. No, I’m not going to tell you how to avoid the scan, nor am I going to talk about the stupidity of the scan. Instead I’d like to tell you how to get around this problem.

    It’s so easy, too.

    You see, my issue is that I use Composer to build my resource libraries and in my composer.json file, I have this:

    "require": {
    	"aws/aws-sdk-php": "2.7.*",
    	"doctrine/orm": "*",
    	"monolog/monolog": "*"
    },
    

    And for what it’s worth, this is great. I have it download all my libraries. Then I have it run a script to copy over just what I need to my aws folder and I have Git and SVN ignore the vendor folder. Everyone wins! The problem is that Composer sees that my laptop is running PHP 5.6 and so it installed version

    Fix PHP on Your Computer

    Since I use Homebrew on my Mac, this is super easy for me.

    $ brew unlink php56
    $ brew install php54
    

    Then when I re-run composer update it will install what I need.

    The problem here, though, is that this is tied to a specific computer, and if a coworker downloads my stuff and plans to fork it, they’re SOL and merges fail and it’s sad times all around. So with that in mind, uninstall 5.4 and go back to 5.6.

    If you have a problem with installing 5.6, run it this way:

    $ xcode-select --install
    $ brew unlink php54
    $ brew install php56
    

    Fix PHP in Composer

    I like this fix better. Put this above your require statement and you’ll force Composer to build based on PHP 5.4:

    "config": {
    		"platform": {
    		"php": "5.4"
    	 }
    },
    

    Now we’re cooking with fire. This works for everyone, it forces Composer to download 5.4 compatible libraries, and my very long transmission worked.

    Is This Perfect?

    Obviously not. There are going to be cases where your code absolutely has to be the code for PHP 5.5 and up. The latest version of the AWS SDK is v3, for example. But it’s for 5.5 only. I personally don’t feel there’s enough of a buy-in for PHP 5.5 and up yet to make an issue of it. And having no check at all won’t fly.