Tag: PHP

Advent 2023: PSR-15

I've mentioned a few times over the course of this 2023 Advent series that the longer I'm in the tech field, the more I appreciate and favor simple solutions. I was reminded of this yesterday when I read this article on return types in Laravel controllers by Joel Clermont.

Continue reading...

Advent 2023: Doctrine DBAL

I've mostly taken database abstraction for granted since I started at Zend. We had a decent abstraction layer in ZF1, and improved it for ZF2. There were a lot quirks to it — you really had to dive in and look at the various SQL abstraction classes to understand how to do more complex stuff — but it worked, and was always right there and available in the projects I worked on.

In the last couple of years, though, we came to the realization in the Laminas Project that we didn't really have anybody with the expertise or time to maintain it. We've marked it security-only twice now, and while we've managed to keep it updated to each new PHP version, it's becoming harder and harder, and whenever there's a CI issue, it's anybody's guess as to whether or not we'll be able to get it resolved.

My alternatives have been straight PDO, or Doctrine DBAL, with the latter being my preference.

Continue reading...

Advent 2023: Forms

The first thing I was tasked with after I moved full time to the Zend Framework team (17 years ago! Yikes!) was to create a forms library. Like all the work I did for ZF in the early days, I first created a working group, gathered requirements, and prioritized features. There were a lot of requests:

  • Ability to normalize values
  • Ability to validate values
  • Ability to get validation error messages
  • Ability to render HTML forms, and have customizable markup
  • Ability to do nested values
  • Ability to handle optional values
  • Ability to report missing values

and quite a lot more. But those are some of the things that stuck out that I can remember off the top of my head.

Zend_Form was considered a big enough new feature that we actually bumped the version from 1.0 to 1.5 to call it out.

And, honestly, in hindsight, it was a mistake.

Continue reading...

Goodbye Twitter

This is a long, personal post.

tl;dr: I'm leaving Twitter. You can find me in the Fediverse as @matthew@mwop.net.

Continue reading...

TailwindCSS Tips

I've been dabbling in CSS my entire career. In the early days, it was relatively simple, as our browsers were fairly limited. But over the years, CSS has become more and more capable, allowing styles to target only tags with specific tag attributes, only apply at specific screen sizes, and even perform complex layouts using things like flexbox and grid. I take a bit of time every now and then to understand these things... but since I don't use CSS a ton, it's hard to keep up.

As such, over the past decade, I've tended to use CSS frameworks, and generally Bootstrap. Every couple years, a new major version is dropped, and I have to learn new structures and components, and struggle to get things to look the way I want. Worse, when I use these frameworks, injecting custom CSS often means understanding how the framework is already styling components so I can ensure things don't conflict.

The last couple years, I've been keeping an eye on TailwindCSS. I've been a bit skeptical, as its declarative, utility-first approach looks a lot like doing CSS inside your HTML, which, honestly, feels off. I've typically subscribed to the idea of semantic HTML, which advocates separating style from markup. Having styles directly that mimic CSS directives associated with every tag feels like an unholy mix, and a far cry from semantic HTML.

And then there's the hype. The original author and project lead of Tailwind is a huge hype man, and hype tends to turn me off. That's on me, not them, but having been in the business for over two decades, I'm finding I'm more and more likely to discount hyped products and projects, because I've seen them come and go so frequently; there's often an indirect relationship between the amount of hype and the long-term viability of a project. I've also often observed that hype serves as a way for users to deflect reasonable critique, and the more vehement the user base, the less interested I am in engaging with them because of this. Clearly, YMMV, but it was definitely something keeping me from really investigating Tailwind.

However, recently, in helping out the PHP Foundation, I volunteered to setup their static website, and the team requested using TailwindCSS, so I dove in.

And I discovered... I kind of love it.

This is one of those "I'll be googling this in the future" posts.

Continue reading...

Getting OpenSwoole and the AWS SDK to Play Nice

I have some content that I store in S3-compatible object storage, and wanted to be able to (a) push to that storage, and (b) serve items from that storage.

Easey-peasey: use the Flysystem AWS S3 adapter, point it to my storage, and be done!

Except for one monkey wrench: I'm using OpenSwoole.

Continue reading...

Exposing webhooks via mezzio-swoole

I was first introduced to the concept of webhooks via a 2009 blog post by John Herren, a former colleague at Zend. At the time, they were in their infancy; today, they're ubiquituous, as they provide a mechanism for a service to notify interested parties of events. This saves traffic; instead of consumers polling an API for event changes, the service notifies them directly. It also means that the consumer does not need to setup things like cronjobs; they instead setup a webhook endpoint, register it with the service provider, and their application takes care of the rest.

The thing is, handling a webhook can often lead to additional processing, and you are expected to send an immediate response to the provider indicating you received the event.

How can you achieve this?

Continue reading...

Running cronjobs via an Openswoole timer

Sites I build often utilize cronjobs to periodically pull in data from other sources. For example, I might want to poll an API once a day, or scrape content from another website once a month. Cronjobs are a perfect fit for this.

However, cron has a few problems:

  • If the job is writing information into the file tree of your web application, you need to ensure permissions are correct, both at the filesystem level, and when writing the cronjob (e.g., running it as the same user, or changing permissions on completion).
  • If you are running console tooling associated with your PHP application, you may need to worry about whether or not particular environment variables are in scope when you run the job.
  • In containerized environments, usage of cron is strongly discouraged, as it means running another daemon. You can get around this with tools such as the s6-overlay, but it's another vector for issues.

Since most sites I build anymore use mezzio-swoole, I started wondering if I might be able to handle these jobs another way.

Continue reading...

Caddy as a Secure Reverse Proxy

I've been using Caddy as a front-end reverse proxy for several years now, on the advice of Marco Pivetta. Somewhere along the line version 2 was released, and I updated at some point, but evidently didn't quite understand some of its configuration options, particularly around HSTS support and providing your proxied application information about how the client tried to connect.

Continue reading...

Tinker-like REPL for Mezzio

Today in the Laminas Slack, somebody asked if there was an equivalent to Laravel's Tinker REPL. The short answer is "no", but I had a suggestion for them.

Continue reading...