How to Set Environment Variables in Composer Scripts
Do you need to set environment variables for Composer scripts to work? Here’s how.
I recently refactored parts of a web application for an upcoming Twilio tutorial into three open source packages. Here’s what motivated the decision to do so, and why I think you should create them too.
Recently, I’ve been writing a PHP app for an upcoming Twilio tutorial. The premise of the app is pretty simple, and started out as a joke between my siblings and I; but that’s a story for another day.
It lets a user subscribe to be notified by their local council when their rubbish bins will next be collected. That way, they don’t have to maintain a diary or look out the window every few days to see if their overly punctual neighbours have put their bins out, to know that they need to as well.
In fairly typical style for my Twilio tutorials, I:
It took about a week, part-time, to build the application. When it was done, I was pretty proud of it. I felt that I’d architected it well enough for what I needed, and that I’d also done a good job of naming all of the classes and variables as well as the directory structure, making it reasonably intuitive.
As I sat reviewing it all, it became apparent that it was going to be quite a challenge to cover it in an engaging way in a tutorial, because there was just so much to cover.
For example, there was code for handling routes, for making requests to OpenStreetMap, Twilio, and SendGrid’s APIs, for interacting with the SQLite database (using Doctrine), and for filtering and validating user input. This was in addition to the code required to instantiate all of the required classes, such as the Twilio Client and SendGrid objects, so that the app could interact with those APIs.
While I didn’t write any of the code just for the sake of doing so, there was still too much, such that, in my opinion, it was distracting from the core focus of the tutorial.
Now this might seem like a strange thing to say. Perhaps you’re thinking that if the code needs to be there, it needs to be there. In answer to that, I’d say “yes and no”, or as I’m quite fond of saying, “it depends”.
In tutorials, the main aim is to teach a few key points, such as how to interact with a given API. The code doesn’t need to be highly performant, doesn’t need to be maintainable (though ideally you’d try to encourage that), and it doesn’t need to be efficient.
What’s more, often times, even instantiating the various objects that you’ll use isn’t important either. What is important is communicating how the code works, how to use the various classes and methods, and teaching the reader about what can go wrong. And, if your code interacts with APIs for example, you’d also cover the request options and response bodies, along with their HTTP codes.
That way, the user gets a complete picture of what they’re working with. Then, they can go off and explore further and experiment with whatever it was that you were teaching them.
Given that, to cover all of the code that I’d written so far would have taken a master job in planning, writing, and editing – in order not to lose the reader along the way or bore them to death.
To add some proverbial flesh to the bone of just how much code there was to cover, there was more 30 classes, 3 traits, 9 template files, and 5 configuration files!
Sure, only a few of the classes were more than 10 - 15 lines long. And most of them only contained 1, perhaps 2, functions at most. But, as you’ll appreciate, that’s still a lot to write about, not to mention for the reader to take in – and keep in their head through to the conclusion of the tutorial.
That way the tutorial only covered the essential information and concepts – nothing else! Given that, I started conducting a series of intense code reviews looking for where the code could be reduced, simplified, or eliminated.
I looked for absolutely anything and everything that I could remove, so that the tutorial could focus as close to the central concepts as possible. For starters, I was able to remove a lot of boilerplate code, combined classes, and extracted code out into reusable utility methods.
Then, after reviewing the handlers, I saw that they didn’t need dedicated factories for instantiation, as I was used to. The factories were only retrieving services from the DI container to instantiate the handlers. Given that, I deleted the factories and updated the DI (Dependency Injection) Container’s configuration to use the Reflection-based Abstract Factory instead.
This was a massive step forward! But, eventually, I came to a point where I felt that I couldn’t go any further. Yet, I still felt that there was too much to cover. How could I reduce it further?
Then, I thought:
Why not extract code out into libraries?
After all, it’s standard practice to only write what you need and then lean on third-party packages most other tasks. So why not create more of my own in this case too? What’s more, it’d be good practice to create some more open source packages, and in the process, potentially, help others with the same or similar needs.
Specifically, I saw that the instantiation and configuration logic for the core SendGrid, Twilio, and OpenStreetMap classes could be avoided. For these, I created three packages: laminas-sendgrid-integration, laminas-twilio-integration, and laminas-openstreetmap.
The packages each did three things:
After installing them, the user only needed to copy the default configuration files from each package to config/autoload, know which environment variables to set, and how to set them. laminas-openstreetmap didn’t even require that!
With the packages created, I now felt that I’d gone far enough in stripping anything out of the applications that could be avoided, so that as sharp a focus on teaching the core concepts was happening.
There’s quite a bit more to this story, but I won’t go on, as it’s unlikely that you’ll have the same motivations as I do, regularly, these days. It’s more likely that you just want to make whatever software you’re working on easier to reuse, whether by yourself or others.
Regardless of what your motivation is, I believe that building your own software packages is a good thing, both for yourself and for others. You can share what you know, demonstrate your skills and competency as a developer, and contribute something that others can use.
What software packages and libraries have you created and why? Let me know in the comments. I’d love to know!
Do you need to set environment variables for Composer scripts to work? Here’s how.
How well do you really know Composer? Do you just know composer install, update, and require, and some of the composer.json configuration? Or do you really know it? In this series, you’re going to take your skills to the next level; starting with the command-line.
Homebrew makes installing PHP and so many other great tools on macOS a breeze; almost as easily as a Linux package manager. But how do you install the Imagick extension? In this short post, I’ll show you the shortest way to do so.
There are a number of ways to set environment variables in PHP. But the approach I use most often in development is a wonderful package called PHP dotenv. In this tutorial, I’m going to step you through how to install and use it.
Please consider buying me a coffee. It really helps me to keep producing new tutorials.
Join the discussion
comments powered by Disqus