Tag Archives: php

How to use PostGres Enum in Phinx

Currently, Phinx doesn’t support enum for postgres: https://github.com/cakephp/phinx/issues/891. Someone mentioned a solution on the issue (https://github.com/cakephp/phinx/issues/891#issuecomment-774496499).

PHP
$this->execute("create type foo as enum ('bar1', 'bar2')");
$this->execute('alter table table_name add column foo_column foo');

This works! In my project, I’ve used this pattern multiple times. E.g.

PHP
// table to track bag-sample relationship.
$bagSample = $this->table('bag_sample_relationv1');
$bagSample->addColumn('sample_bag_code', 'string', ['null' => false])
->addColumn("sample_code", "string", ['null' => false, 'limit' => 20])
->addColumn('added_at', 'datetime', ['default' => 'CURRENT_TIMESTAMP'])
->addIndex(['sample_bag_code', 'sample_code'], ['unique' => true])
->save();
// add a column with ENUM type.
$this->execute("create type BAG_SAMPLE_STATUS as ENUM('INSIDE', 'OUTSIDE', 'REMOVED')");
$this->execute("ALTER TABLE bag_sample_relationv1 ADD COLUMN status BAG_SAMPLE_STATUS DEFAULT 'INSIDE'");

October 11, 2025: Weekly Notes 2025/17

July 26, 2025: Weekly Note 2025/06

  • I’ve been a little sick this whole week — a mild cold and occasional coughing. Running was a bit slow, and it took some effort to go out and run. Perhaps some flu.
  • Almost everyone I knew from college has left or about to leave my neighborhood — for search of job, education, status, money or other foo and bars. Sometimes I wonder if there is a point anymore in investing time in people these days?! I wish I am wrong. I have cultivated a few good relationships with my neighbors. Making friends become harder and harder as you age. Looks like it is a universal problem in industrial part of our civilization — at least major newspapers often write articles about it.
  • I am excited about what PHP has been doing lately. The language has added a few QoL improvements. Most recently the https://wiki.php.net/rfc/pipe-operator-v3.
  • I am thinking of writing down what I learnt about hiring for a startup (in Indian context) in a blog post. A lot of advice I find on internet is not very effective in our style of society.
  • I’ve been itching to pickup combinatorics — every problem requires a different trick, and the subject doesn’t require ten courses before making any progress. Like linear algebra, it is very computer friendly. One can do it a hobby or as profession.
    • I plan to implement some routing algorithms for PCB routing to integrate into KiCAD. https://github.com/freerouting/freerouting the inspiration. Of course, it is in Rust with Python bindings generated using PyO3.

Change extension of a file using PHP

Following is not the most efficient solution out there. But if you are fan of regex, it is easy to read and maintain.

PHP
/**
* Change extension of a given filepath. If filename does not have extension,
* the new extension is simply appended.
*
* @param string $newExt May or may not start with .
*/
function changeExtension(string $filepath, string $newExt): string
{
$ext = str_starts_with($newExt, '.') ? $newExt : '.' . $newExt;
return preg_replace('/\.[^.]+$/', '', $filepath) . $ext;
}

July 5, 2025: Weekly Note 2025/03

  • I finally finished a version EHR app that I had been developing for last 6 months. I expected it to be over in 2 to 3 months — along with a real time trainer app. I had to rewrite it in PHP as a monolith from Vue3/FastAPI (frontend/backend). I discussed some of mistakes I made in . Moreover, I should have spent a significant more time on planning and talking to stakeholder, a kind of discovery phase where I force ideas out of people and put them into tickets. Another lesson learnt is that don’t take “another developer joining soon” too seriously. Despite what I write in my resume, I consider this project a professional failure in planning and execution!
  • This failure lead me to https://www.coursera.org/specializations/real-world-engineering-management. I am taking this short course and enjoying it. I’ve already learnt a lot from it. A few speakers are accomplished IC turned manager. I liked a couple of soundbites from it
    1. Product manager is a advocate for customers.
    2. Engineering manager advocates for, well, engineers.
  • Working at this other startup made me notice a few things — how small small things adds up to make a huge difference. I notice them because I have something to compare against from my previous startup. Many founders perhaps don’t recognize them because they have nothing to compare against. Perhaps everyone should work at a startup (successful one, if you are lucky) before starting their own? Or at least get someone from a friendly startup as resident observer for a while?
  • I have been thinking about 247df64abb1a495fb464959900c07b42 -- A reddit user (c-digs) comment on scalable systems
    I’d love to discuss some of these ideas with some candidates in their final round of interviews — if I get the chance.
  • There are some exciting changes coming to PHP-8.5 (https://php.watch/versions/8.5). Especially |> and functions to get first and last element of an array!
  • Kaalu The Fifth was limping last night. I sensed some pain when she was climbing sofa. She is overweight — she likes to eat outside and neighbors are really love her! I ordered fish-oil and a few supplements for her joints.
  • I rewrote my resume using LaTeX (again!). I was dreading installing the whole TexLive just to compile one page of resume, but thanks to The Tectonic Typesetting System — The Tectonic Typesetting System, the UX is much better.
  • Loved the podcast https://se-radio.net/2025/06/se-radio-671-carson-gross-on-htmx/.
  • Running 20 km this week looks like a challenge — one more day is left and 7 more km to run.

June 22, 2025: Weekly Notes 2025/01

I guess, from now on, I am writing weekly notes every weekend. I learnt about weekly notes from Thej many years ago.

Currently, I am at a early stage startup. I joined them early this year after quitting my startup Subconscious Compute (more on it some other day). I’ve been building them an EHR platform to collect responses and related APIs though I was hired to do something totally different. First, a summary of what I’ve been doing here.

I started with Vue3 and fastapi and learnt Typescript along the way. It started off well. I managed to launch a demo version in a month. Most of its users are not technical and this was the first time I built a web-system for non-developers. And quickly realized why there is so much fuss about designing UI for non-tech users.

  • If you are a solo developer or a very small team, DO NOT split your frontend and backend — it creates more than 2x work. For a non-technical leadership (which might think they understand tech), it is a simple ask for adding or changing something trivial at UI, but for you it is migrating your schema, APIs and frontend models. And what is worse, you will make mistakes. You should only change things in one place. DRY and ensuring Single Source of Truth (SSoT).
  • So I bit the bullet and rewrote it in PHP8 & Codeigniter4. DX is now much better. First, I don’t have to switch between Python and Typescript/Javascript. Second, the system now crashes if someone submit invalid value rather than accepting wrong/empty values. The database schema validates the value. Perhaps I’ll add validator in the form/UI using </> htmx – high power tools for html.

This week

  • I explored a few server side qr code scanners. The most commonly used one is mchehab/zbar which doesn’t work well when image is tilted or rotated. Another tool rxing-core/rxing: cRustacean Crossing did a better job (it is in Rust). For example, in the following image, zbar detected no qr-code while rxing was able to detect two. Usually folks will do the qr code scanning using browser or camera at phone. There are some use cases where image needs to uploaded to server for QR scanning.

    IMG_20250618_185815 -- Sample QR Codes. This image contains 4 QR codes for testing various QR detection cli tools.

  • I wrote a Gitlab job to create backup of PostgreSQL server. It runs every 4 hours, uses pg_dump to create a dump, compress it and then Use curl to upload files to S3 bucket.

  • I found https://builtin.com/ on https://fosstodon.org/@ansate@social.coop/114707324371116735. It’s matches are pretty relevant. I’ve been updating my resume and thinking of reaching out to my network for opportunities.

Using monolog with codeigniter4

The standard logger in codeigniter4 is fine but its no monolog!

To use monolog codeigniter4, add the following to your app/Config/Service.php file. You can read more about supported handlers and formatters in monolog documentation. See https://github.com/Seldaek/monolog/blob/main/doc/02-handlers-formatters-processors.md#formatters. and there are many third party handlers and formatters available.

  • Note that I am logging to syslog rather than to a file (this won’t work on Windows). I think logging to syslog is better if you already have a scrapper running. And also, correlating with web-server logs is bit easier. Perhaps I am mistaken.
  • I am using a third party formatter http://github.com/bramus/monolog-colored-line-formatter to add colors to console logger. I think colors are a good idea if you need to scroll and look at the logs while developing.
<?php

// app/Config/Services.php 

use Bramus\Monolog\Formatter\ColoredLineFormatter;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\BrowserConsoleHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogHandler;
use Monolog\Logger;

class Services Extends BaseService 
{
    // Other services are not shown.

    /**
     * Use monolog logger.
     *
     * - Logs to syslogs
     * - Logs to console (colored)
     * - Logs to browser console (development only).
     */
    public static function logger(bool $getShared = true): Logger
    {
        if ($getShared) {
            return static::getSharedInstance('logger');
        }

        $logger = new Logger('my-portal');
        $consoleHandler = new StreamHandler('php://stdout', \Monolog\Level::Info);
        $consoleHandler->setFormatter(new ColoredLineFormatter());
        $logger->pushHandler($consoleHandler);

        // Also log to syslog
        $facilityName = "local6"; // See list here https://en.wikipedia.org/wiki/Syslog#Facility_levels
        $sysLogHandler = new SyslogHandler('my-portal', $facilityName);
        $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%");
        $sysLogHandler->setFormatter($formatter);
        $logger->pushHandler($sysLogHandler);

        if(ENVIRONMENT === "development") {
            $logger->pushHandler(new BrowserConsoleHandler());
        }

        return $logger;
    }
}

Continue to use your log_message function as before, and perhaps comment out all but one handlers in app/Config/Logger.php file.

I think once service with alias logger is added, most handlers in file app/Config/Logger.php stops working by themselves.

Using $\sout{\text{AJAX}}$ HTMX with Laravel + Blade

I’ve a list of uploaded files that I plan to render in a view. For each file, I want to call an API endpoint e.g. /api/v1/fileinfo to fetch some information and display it.

c7056b55f49a4c00aa56b6a26fe19f5e -- List of files in blade template

My blade template is following. A sample HTML page generated from it is shown above.

@extends('layouts.app')                                                                                                                 

@section('content')                                                                                                                     
    <div class="container">                                                                                                             
        <h3>Files</h3>                                                                                                                  

        @foreach ($files as $file)                                                                                                      
            <div class="card m-1 px-2 py-1">                                                                                            
                <div class="card-content">                                                                                              
                    {{ $file['display_name'] }}                                                                                         
                </div>                                                                                                                  
                <div>                                                                                                                   
                    <button class="btn btn-secondary">Show Information</button>                                                         
                </div>                                                                                                                  
            </div>                                                                                                                      
        @endforeach                                                                                                                     

    </div>                                                                                                                              
@endsection

Being old school, I don’t want to enable livewire/inertia just for this. I thought of of using AJAX which all the cool kids were using a decade ago.

Enter AJAX HTMX

Recently I read about HTMX. It is a good opportunity to play with it. The HTMX documentation (</> htmx ~ Documentation) is superb. The API looks great. AJAX can wait.

In code sample shown below, htmx-post define the endpoint that will be called with data defined in hx-vals when hx-trigger event occurs. The inner img with class htmx-indicator will get triggered and we’ll see a indicator spinning for a short while. The value received from server will be put into hx-target which has id $id. $id is generated randomly by PHP to create one-to-one mapping between hx-target and target div.

        @foreach ($files as $file)                                                                                                          
            <div class="card m-1 px-2 py-1">                                                                                                
                <!-- Generate a unique id to insert content received from POST                                                          
                    request -->                                                                                                             
                @php($id=uniqid("div_"))                                                                                                    
                <div class="card-content">                                                                                                  
                    {{ $file['display_name'] }}                                                                                             
                </div>                                                                                                                      
                <div>                                                                                                                       
                    <button class="btn btn-link"                                                                                            
                        hx-post="/api/v1/fileinfo"                                                                                          
                        hx-vals='{"path" : "{{ $file["path"] }}" }'                                                                         
                        hx-target='#{{ $id }}'                                                                                              
                        hx-trigger="mouseenter"                                                                                             
                        >                                                                                                                   
                        File Information                                                                                                    
                        <img class="bg-primary htmx-indicator" src="{{ asset('svg/90-ring.svg') }}" />                                      
                    </button>                                                                                                               
                    <div id="{{ $id }}">                                                                                                    
                    </div>                                                                                                                  
                </div>                                                                                                                      
            </div>                                                                                                                          
        @endforeach

Let’s see this in action. We barely see the spinner since the request doesn’t take much time.

00694da521964fe6b9c9edaf99485ca7 -- HTMX in Laravel Blade

Importantly, note that we render raw JSON😢. HTMX expects HTML from servers and doesn’t support JSON → HTML conversion natively. Well, this sucks for obvious reasons. Who returns HTML from APIs?!

So we have to turn JSON into HTML by ourselves. Thankfully there are community maintained plugins such as client-side-templates. See https://github.com/bigskysoftware/htmx-extensions/blob/main/src/client-side-templates/README.md. The plugin documentation is pretty clear. I am going to show the final solution.

  • The top-level div has hx-ext set that enables the extension.
  • hx-target is replaced by mustache-template.
  • 👉🏾 Our <template> is added. If you are using blade then you have to prefix mustache template with @ so that blade doesn’t touch them. The template create HTML out of JSON.

04c2c39271db4853b35822b149e30634 -- Code Snippet showing how to use htmx

Let’s try again! Great, I got most basic functionalities working.

05047d703e9b446d823bc8e4bff79096 -- Demo: HTMX with blade template

Apparently HTMX is quite powerful. You can search HN for resources https://hn.algolia.com/?q=htmx