Zend Server updates for IBM i are now available – and strongly recommended. In this blog, learn how to install Zend Server on IBM i to build the latest and greatest PHP stack.
Month: April 2022
TailwindCSS Tips – Matthew Weier O’Phinney
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.
How it works
I won’t go into how to get started with Tailwind; their docs do a great job of doing that for you.
However, I will give a quick overview of how things work, so you can see (a) where I’m coming from, and (b) what you’ll be doing when you start with Tailwind.
The way I’ve always learned to do CSS is to first write html, and then write CSS to style that html the way you want it to appear.
<div class="box"> <h2>Title</h2> <p>Some content</p>
</div> <style>
.box { margin: 0.5rem; background-color: #333333; border: #000000 padding: 0.5rem;
} .box h2 { background-color: #dedede; padding: 0.5rem; color: #111111; font-size: 2rem; min-width: max-content;
} .box p { padding: 0.5rem; font-size: 1.2rem; min-width: max-content;
}
</style>
Tailwind instead provides a ton of “utility” classes, targetting just about every CSS directive.
You then add these html classes to elements to style them:
<div class="m-2 p-2 bg-neutral-600 border-black"> <h2 class="min-w-full p-2 bg-neutral-300 text-4xl text-neutral-800">Title</h2> <p class="min-w-full p-2 text-xl">Some content</p>
</div>
Behind the scenes, you run the Tailwind CLI tool, and it analyzes your html to generate CSS for you.
You can even have it watching for filesystem changes to files you’re interested in (templates, JS scripts, etc.), and it will regenerate the CSS automatically.
Tip 1: Layers
Out of the box, Tailwind does a CSS reset that removes all styles.
This is great, because it means that any changes you make, you can anticipate exactly what will hapen.
It’s also a pain in the ass, because everything is unstyled: your headings look just like your paragraphs, your lists look just like your paragraphs, and there’s no way to tell where one paragraph ends and another begins.
So, the first thing you’ll want to do is define your base styles.
Tailwind has a very specific suggestion for where and how to do this: in the “base” layer.
Opening your site CSS file, you’ll see these directives when you begin:
@tailwind base;
@tailwind component
Truncated by Planet PHP, read more at the original (another 14308 bytes)
Cloud Images With ZendPHP
In this blog, we take a look at how cloud images with ZendPHP make deployment of your PHP applications simple and consistent.
CI Pipelines for dockerized PHP Apps with Github & Gitlab [Tutorial Part 7] – Pascal Landau
In the seventh part of this tutorial series on developing PHP on Docker we will setup a CI
(Continuous Integration) pipeline to run code quality tools and tests on Github Actions and Gitlab
Pipelines.
All code samples are publicly available in my
Docker PHP Tutorial repository on github.
You find the branch for this tutorial at
part-7-ci-pipeline-docker-php-gitlab-github.
Published parts of the Docker PHP Tutorial
- Setting up PHP, PHP-FPM and NGINX for local development on Docker
(2018-07-08) - Setting up PhpStorm with Xdebug for local development on Docker
(2018-08-06) - Structuring the Docker setup for PHP Projects
(2019-05-20) - Docker from scratch for PHP 8.1 Applications in 2022
(2022-03-21) - PhpStorm, Docker and Xdebug 3 on PHP 8.1 in 2022
(2022-03-22) - Run Laravel 9 on Docker in 2022
(2022-03-23) - Set up PHP QA tools and control them via make
(2022-04-25) - Use git-secret to encrypt secrets in the repository
(2022-04-25) - Create a CI pipeline for dockerized PHP Apps
(2022-04-25)
If you want to follow along, please subscribe to the RSS feed
or via email
to get automatic notifications when the next part comes out 🙂
Table of contents
Truncated by Planet PHP, read more at the original (another 88826 bytes)
Use git-secret to encrypt secrets in the repository [Tutorial Part 6] – Pascal Landau
In the sixth part of this tutorial series on developing PHP on Docker we will setup git-secret
to store secrets directly in the repository. Everything will be handled through Docker and
added as make targets for a convenient workflow.
FYI:
This tutorial is a precursor to the next a part
Create a CI pipeline for dockerized PHP Apps
because dealing with secrets is an important aspect when setting up a CI system (and later when
deploying to production) – but I feel it’s complex enough to warrant its own article.
All code samples are publicly available in my
Docker PHP Tutorial repository on github.
You find the branch with the final result of this tutorial at
part-6-git-secret-encrypt-repository-docker.
Published parts of the Docker PHP Tutorial
- Setting up PHP, PHP-FPM and NGINX for local development on Docker
(2018-07-08) - Setting up PhpStorm with Xdebug for local development on Docker
(2018-08-06) - Structuring the Docker setup for PHP Projects
(2019-05-20) - Docker from scratch for PHP 8.1 Applications in 2022
(2022-03-21) - PhpStorm, Docker and Xdebug 3 on PHP 8.1 in 2022
(2022-03-22) - Run Laravel 9 on Docker in 2022
(2022-03-23) - Set up PHP QA tools and control them via make
(2022-04-25) - Use git-secret to encrypt secrets in the repository
(2022-04-25) - Create a CI pipeline for dockerized PHP Apps
(2022-04-25)
If you want to follow along, please subscribe to the RSS feed
or via email
to get automatic notifications when the next part comes out 🙂
Table of contents
- Introduction
- Tooling
- Makefile adjustments
- Workflow
Truncated by Planet PHP, read more at the original (another 54815 bytes)
Set up PHP QA tools and control them via make [Tutorial Part 5] – Pascal Landau
In the fifth part of this tutorial series on developing PHP on Docker we will setup some PHP code
quality tools and provide a convenient way to control them via GNU make.
FYI: Originally I wanted
this tutorial to be a part of
Create a CI pipeline for dockerized PHP Apps
because QA checks are imho vital part of a CI setup – but it kinda grew “too big” and took a way
too much space from, well, actually setting up the CI pipelines 🙂
All code samples are publicly available in my
Docker PHP Tutorial repository on github.
You find the branch with the final result of this tutorial at
part-5-php-qa-tools-make-docker.
Published parts of the Docker PHP Tutorial
- Setting up PHP, PHP-FPM and NGINX for local development on Docker
(2018-07-08) - Setting up PhpStorm with Xdebug for local development on Docker
(2018-08-06) - Structuring the Docker setup for PHP Projects
(2019-05-20) - Docker from scratch for PHP 8.1 Applications in 2022
(2022-03-21) - PhpStorm, Docker and Xdebug 3 on PHP 8.1 in 2022
(2022-03-22) - Run Laravel 9 on Docker in 2022
(2022-03-23) - Set up PHP QA tools and control them via make
(2022-04-25) - Use git-secret to encrypt secrets in the repository
(2022-04-25) - Create a CI pipeline for dockerized PHP Apps
(2022-04-25)
If you want to follow along, please subscribe to the RSS feed
or via email
to get automatic notifications when the next part comes out 🙂
Table of contents
Introduction
Code quality tools ensure a baseline of code quality by automatically checking certain rules,
e.g. code style definitions, proper usage of types, proper declaration of dependencies,
etc. When run regularly they are a great way to enforce better code and are thus a
perfect fit for a CI pipeline. For this tutorial, I’m going to setup the following tools:
- Style Checker: phpcs
- Static Analyzer: phpstan
- Code Linter: php-parallel-lint
- Dependency Checker: composer-require-checker
and provide convenient access through a qa
make target. The end result will look
like this:
FYI: When we started out with using code quality tools in general, we have used
GrumPHP – and I wou
Truncated by Planet PHP, read more at the original (another 38788 bytes)
A robust, powerful, easy to use attribute parser for PHP – Larry Garfield
A robust, powerful, easy to use attribute parser for PHP
After sitting on it for a while, I am pleased to release a PHP library for robust, powerful attribute handling in PHP 8.1: Crell/AttributeUtils. It’s a robust, centralized tool for slicing, dicing, and reverse engineering classes in PHP using attributes.
The basics
The basic model of Attribute Utils is to analyze a class “with respect to” some attribute. That attribute may be defined on the class, or not. (Both options have meaning.) That attribute may be associated with attributes on properties or methods, which are all scanned together to produce a picture of a class.
Continue reading this post on Hive.
Larry
21 April 2022 – 4:56pm
DDD entities and ORM entities – Matthias Noback
I was tweeting something about having separate “DDD” and “ORM” entities in a project in a project, and that I don’t understand this. There were some great comments and questions, thanks a lot for that! To be honest, I understand more about it now. In this article I’ll try to provide some more information about this.
I’m glad many developers want to use input from the book “Domain-Driven Design” by Eric Evans to improve their domain model. I recommend reading this book and getting your information from the source, because unfortunately the internet, tweets, e-books, including my own books, aren’t able to reflect a full, nor a correct view of everything there is to find out about this topic. All too often DDD is completely misinterpreted to be “an elitist, dogmatic approach to programming, where we use DTOs, layers, and CQRS”…
I think some programmers, myself included, want to escape from the framework-coupled, hype-inspired mess that web application development often seems to be. Unfortunately, while trying to move in the opposite direction, they end up with a lot of code that is written for the sake of decoupling. Or maybe it happens because they want to try something new and not-boring, something that can’t be generated from the command-line with make:entity
.
Back in the days when Symfony 2 adopted annotations for routing, and Doctrine ORM did the same for its mapping configuration, I was one of the first to be against that, pointing out that it’s “framework coupling”. I mean, “Are you coupled to the framework?!”
Ever since I’ve been thinking, experimenting, and writing a lot about this topic (e.g. my book about application architecture, and an older article about ORMless). In the end I think our applications need framework coupling in certain areas, and in other areas, like the domain model, they are better off being decoupled.
But full decoupling is usually not the best choice. Rather, 80% decoupling is fine 😉 As an example, it seems that some would like to have DDD entities that are fully decoupled from the ORM. They interpret this to mean that you can’t have ORM annotations in your entity, or that you can’t use specialized collection classes like Doctrine ORM forces you to have. This coupling is by no means dangerous, and certainly doesn’t get in the way, as long as:
- We can instantiate and modify these entities without a runtime dependency on the database.
- We can retrieve data from these entities without a runtime dependency on the database.
Once this is the case, you can even test their behavior in a unit test, because these are the only requirements for that. It does mean that most entities-in-the-wild aren’t good entities, because calling methods on them is most likely to trigger database queries (e.g. lazy-loading for child entities or referenced entities). If you use an Active Record implementation like Eloquent, many more methods will trigger database queries.
And this is where DDD comes in, with its aggregate design rules. I often refer to an excellent series of articles on this topic, by Vaughn Vernon. In summary:
- An aggregate should guarantee its own consistency, establishing relevant domain invariants (i.e. it should prevent itself from being in an invalid or incomplete state).
- Reference other aggregates by their ID (i.e. don’t pass related entities as objects, or load them lazily).
- Aggregates should be small (i.e. don’t let it manage child entities or related entities).
We can learn a lot from these DDD patterns to make our models better, and we can in most cases accomplish this while using our current ORM and its entities or model objects. We just upgrade these existing objects with insights from the DDD book; adding intention-revealing methods, making state changes in meaningful chunks instead of on a per-field basis, throwing exceptions whenever a consistent state is in danger, etc. There may be some things we have to do to please the ORM, but nothing that messes up much with our domain model. A good rule of thumb is to focus on the public methods of the entity, and ignore what goes on behind the scenes (good old encapsulation).
There is one situation where upgrading existing ORM entities to DDD entities isn’t going to work: when you want to evolve the design of your aggregates, without also evolving the database schema. I don’t have experience with this. Whenever
Truncated by Planet PHP, read more at the original (another 1503 bytes)
PHP Tricks: Multi-value match() – Larry Garfield
PHP Tricks: Multi-value match()
Last time, I talked about fun uses of the match()
expression in PHP, using unconventional types of expressions on the right-arm branch. This time, I want to expand that discussion to include fun tricks on the left-side of the `=>`, and how you can easily match by multiple values at the same time.
I’m going to assume you have read the previous installment about how match()
works and what an “expression” means. Also, I don’t claim to be the original source of these tricks. I’m just documenting them because they’re cool. Let’s dive in.
Continue reading this post on Hive.
Larry
19 April 2022 – 11:41am
PHP Tricks: Uncommon match() expressions – Larry Garfield
PHP Tricks: Uncommon match() expressions
Recently, I’ve been helping a new developer out in a chat room. He’s still learning PHP and working through tutorials, with lots of questions along the way. Earlier this week, by accident, he stumbled across a use of match()
statements I’d not considered before. While technically not right for his use case, it did suggest another, potentially valid use for match()
I’d not seen. Let’s add it to the list of cool things you can do with match()
.
Continue reading this post on Hive.