April 13, 2023 · personal

New job, new challenges

For the past few years, I’ve been working as a contractor for several clients. Although I knew I would have work for the next few months, the tasks were becoming repetitive and not particularly challenging. I realized I had fallen into a comfort zone, which can be a dangerous spot to be in.

I asked myself what would David Goggins do? And the answer was that I don`t know. He would probably stay hard while running shitload of miles.

Joining the project has been a roller coaster of emotions. At first, I was hesitant to take on such a big challenge and had doubts about my ability to keep up. But I’m glad I pushed myself out of my comfort zone and took the opportunity.

It’s been tough, but I’m learning so much and enjoying the experience of working with such a talented team. And who knows, maybe now that I’m taking on new challenges and expanding my skills, I’ll even have some time to write a few articles for this site!

October 27, 2022 · php

How to add sqlsrv extension for docker (alpine)

Getting the sqlsrv and pdo_sqlsrv PHP extensions working on an Alpine-based image is annoying: there’s no prebuilt package for musl libc, so you have to install Microsoft’s ODBC driver first and then compile the extensions yourself with pecl.

Read more →

June 30, 2022 · php

PHPDoc for Doctrine Collections

When working with collections in PHP entities, it’s recommended to use the Doctrine\Common\Collections\Collection interface as a type. This lets you use either the ArrayCollection or PersistentCollection implementation, depending on your needs, without changing any code that consumes the property.

The problem is that plain PHP has no generics: Collection alone doesn’t tell you, or your IDE, what’s actually inside it. That’s where PHPDoc comes in:

/** @var Collection<int, Article> $articles */
private Collection $articles;

The first type parameter is the key type Doctrine uses internally (int for a plain array-like collection), and the second is the entity class actually stored inside, Article here. Annotate it this way and static analysis tools like PHPStan or Psalm, and IDEs like PhpStorm, understand that iterating over $articles gives you Article instances, with proper autocompletion and type checking.

Keep in mind this annotation has no effect at runtime. PHP itself ignores it completely. It only helps if something is actually reading it, your IDE or a static analysis tool in your CI pipeline.

June 30, 2022 · git

Do you use a global .gitignore file? Why not?

Every Git user knows about the .gitignore file, but many don’t use it correctly. Its purpose is to keep project artifacts out of version control. So what are artifacts? In general, they are all the generated files needed to run the project. For a PHP app, this would typically include the vendor directory, cache, and any generated reports.

However, I often see a lot of IDE- or OS-specific stuff in .gitignore files, like .DS_STORE. If these files aren’t ignored, they can be accidentally versioned in the project, which is not what we want. To prevent this, every developer should set up their environment to not commit their specific files with a global .gitignore.

To set up a global .gitignore, you first need to be in the versioned directory. If you’re not, you can create a temporary directory like this:

mkdir ~/Temp
cd ~/Temp
git init

To search for global .gitignore files, you can use this command:

git config --global core.excludesFile

By default, there are no global .gitignore files. To create one, create a .gitignore file with the content you want. Here’s an example:

nano ~/.gitignore
# Node
npm-debug.log

# Mac
.DS_Store

# Windows
Thumbs.db

# JetBrains stuff
.idea/

# vi
*~

Once you have your .gitignore file, you can tell Git to use it globally:

git config --global core.excludesFile ~/.gitignore

June 02, 2021 · tools

Adminer

Adminer is a database management tool, similar to phpMyAdmin, but it ships as a single PHP file. No installation, no dependencies, no folder full of assets. You just drop it next to your project (or run its Docker image) and open it in the browser.

A few reasons I reach for it over phpMyAdmin:

  • It talks to more than MySQL/MariaDB out of the box: PostgreSQL, SQLite, MS SQL, Oracle, and a couple more.
  • The UI is lighter and loads faster, since there’s a lot less markup and JavaScript behind it.
  • Being one file makes it trivial to drop into any project without touching the rest of your setup.

In practice I add it as a service in my docker-compose.yml during local development:

services:
  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080

Point your browser at localhost:8080, log in with your database container’s service name as the host, and you’re browsing your data without installing any client.

One warning though: never leave Adminer running on a production server. It’s a full database admin panel reachable straight from a browser, and exposing that publicly is a real security risk. Keep it in your local or dev compose file only, and if you genuinely need it somewhere shared, put it behind a VPN or an IP allowlist, never open to the internet.

June 01, 2021 · tips

How to rename master to main in Git

Do you want to rename your main branch from the deprecated master to main? No problem at all. First check what your remote repository is called, it’s usually origin:

git remote -v

And now you are ready to go:

git branch -m master main
git push -u origin main
git push origin --delete master

Do you see this error message?

 ! [remote rejected] master (deletion of the current branch prohibited)

You’ll need to change the default branch in your remote Git host’s settings first (Bitbucket in this example):

Bitbucket setup

And don’t forget to set the default branch in your local Git repository:

git config --global init.defaultBranch main