After spending a few hours trying to make chained methods in PHP arrange itself below one and each other in a tidy manner, I have finally found a solution. In other words, on a file save I wanted to go from this:

$this->user->account->organizations()->saveMany(Organization::factory(5)
->make())->first()->update(['name' => 'A Big Brand Name']);

To something resembling this:

$this->user->account
    ->organizations()
    ->saveMany(Organization::factory(5)->make())
    ->first()
    ->update(['name' => 'A Big Brand Name']);

The above is clearly easier to read and thus it takes less time to understand what the code does.

What did not work for me

Here are a few various possibly unrelated methods to deal with the problem that did not work, in no particular order.

coc-prettier

I use coc-prettier in my current neovim setup, especially for it's ease of use on Markdown (prose-wrap anyone?) and Javascript. PHP is however not supported by prettier out of the box, and is rather supplied as a community maintained plugin under prettier/plugin-php.

Currently it looks like these two do not play along. The response is fairly recent and there is definitely a potential for prettier plugins under coc-prettier, sadly I could not find anything more on the topic.

Intelephense in coc-phpls wit coc-prettier

In conjunction with the coc-prettier above, coc-phpls can do PHP formatting on save as well with these two relevant settings in :CocConfig below:

"intelephense.format.enable": true,
"coc.preferences.formatOnSaveFiletypes": ["php"]

Sadly, at the time of writing, the only formatter configuration option is intelephense.format.braces. This setting has no effect on aligning chained PHP methods. It also somehow conflicts with prettier's tabWidth if the hard-coded Intelephense value is different. I ended up removing/turning off both above options.

vim-phpfmt

I've had absolutely no luck with the vim-phpfmt plugin whatsoever in regards to aligning chained methods in a PHP code. It could be expected as the plugin was not updated for more than a 5 years.

It utilizes phpcbf called the PHP Code Beautifier and Fixer from PHP CodeSniffer package which is under active development. I believe this approach could work, but I am not sure how long would it take to get it to work.

inotifywait script

At one point I tried to utilize the test watcher script by running globally installed prettier on the changed file, since I already had it up and running:

#!/bin/bash
while true; do
  FILE=$(inotifywait --recursive \
    --exclude=".*.*sw*" --exclude="4913" \
    ./watch_this_folder --format "%w%f" -e close_write)
  && clear
  && prettier --parser=php -w "$FILE"
done

But I had numerous issues with this approach ranging from delayed tests, through vim not re-rendering reformatted file to random file or even entire folders being reformatted on a short notice, so I did not continue down this path.

What works

There are two solutions I found are working reasonably well for aligning chained methods in PHP, both relying on prettier.

prettier/plugin-php vimscript

The modified vimscript I wrote about yesterday worked and I thought I stick with it. Go take a look over there for more details about the approach.

vim-prettier

I had no luck with the elaborate solution outlined in #119 for vim-prettier, which is currently linked as part of the documentation. I also found it weird to have both vim-prettier and coc-prettier installed as a vim plugin.

However, when I was documenting it all down, by a struck of chance I have found a gem in #263. As far as I can tell, the solution requires just a few steps. Install plugin-php as a project dependency:

npm install -D @prettier/plugin-php

Then edit your vimrc file:

call plug#begin('~/.vim/plugged')
  Plug 'prettier/vim-prettier', { 'do': 'npm install', 'for': ['php'] }
call plug#end()

autocmd BufWritePre *.php PrettierAsync

Run :PlugInstall and you are ready to go. As we can see, the vim-prettier is only enabled for PHP files, as others are handled by coc-prettier in my setup. Seeing these two actually work together side-by side without issues made me more comfortable with this setup and my reluctance diminished.

What I really like about this setup is it's simplicity and also the fact it respects the project-wide .prettierrc file, exactly according to my taste, for example:

{
  "tabWidth": 4,
  "semi": false,
  "singleQuote": true,
  "trailingComma": "es5",
  "trailingCommaPHP": true,
  "proseWrap": "always",
  "arrowParens": "avoid",
  "bracketSpacing": true,
  "phpVersion": "8.0",
  "braceStyle": "1tbs"
}

Both standard prettier options as well as ones from plugin-php configuration neatly in one place. The disadvantage is that if you want different tabWidth for different file types across project, it could not be done exactly this way. But then, this would go slightly against the prettier's philosophy being opinionated and consistent.

I wish I've found this solution right at the beginning, but hey, better later than never. Happy writing!