<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom">
    <title>denniskoch.dev</title>
    <updated>2025-08-26T00:00:00+00:00</updated>
    <id>https://denniskoch.dev/feed</id>
    <link rel="self" type="application/atom+xml" href="https://denniskoch.dev/feed"/>
    <description>Articles about Laravel, Filament, PHP and web development.</description>
    <author>
        <name>Dennis Koch</name>
        <uri>https://denniskoch.dev</uri>
    </author>

    <entry>
        <title>&quot;We have Tinkerwell at home&quot;</title>
        <id>https://denniskoch.dev/articles/2026-04-10-we-have-tinkerwell-at-home</id>
        <link rel="alternate" type="text/html" href="https://denniskoch.dev/articles/2026-04-10-we-have-tinkerwell-at-home"/>
        <published>2026-04-10T00:00:00+00:00</published>
        <updated>2026-04-10T00:00:00+00:00</updated>
        <summary type="text">Tinker with your Laravel applications directly from PhpStorm without any plugins</summary>
        <content type="html"><![CDATA[<h2 id="tinkering-in-laravel"><a class="anchor-link" href="#tinkering-in-laravel">Tinkering in Laravel</a></h2>
<p>Since I started using Laravel, it has included the <code>tinker</code> command, a REPL shell for PHP with the Laravel application booted. It's the fastest way to run one-off code in your Laravel codebase, such as Eloquent queries. However, it lacks autocompletion and other useful features from your IDE.</p>
<p>For nearly as long, Beyond Code has been developing the <a href="https://tinkerwell.app">Tinkerwell</a> app. This app offers the same concept but as a separate application. Its benefits include easier code editing and no need to reload the REPL shell after making changes to your codebase. Over the years, Tinkerwell has evolved into a small editor with autocompletion, a separate output pane, support for SSH, Docker, Laravel Vapor, and more, along with history, saved snippets, and other features.</p>
<p>I used Tinkerwell regularly and particularly appreciated the SSH feature and saved snippets for quickly exporting statistics from production applications. However, I was never fond of its autocompletion and missed my keybindings from PhpStorm.</p>
<h2 id="tinkering-in-phpstorm"><a class="anchor-link" href="#tinkering-in-phpstorm">Tinkering in PhpStorm</a></h2>
<p>At one point, I discovered the <a href="https://plugins.jetbrains.com/plugin/13347-tinkerwell">Tinkerwell plugin for PhpStorm</a>. Despite the less-than-promising reviews, it worked well for me, allowing me to enjoy the best of both worlds: tinkering directly from PhpStorm and switching to Tinkerwell for SSH tinkering.</p>
<p>Eventually, I didn't use the SSH feature that much anymore. Since I was using Tinkerwell exclusively from PhpStorm, I let my license expire. I tried the free <a href="https://plugins.jetbrains.com/plugin/14957-laravel-tinker">Laravel Tinker</a> plugin, which worked great, but I disliked that it created a <code>.tinker</code> folder in my project.</p>
<h2 id="phpstorm-s-scratch-files"><a class="anchor-link" href="#phpstorm-s-scratch-files">PhpStorm's Scratch Files</a></h2>
<p>PhpStorm has its own &quot;tinker&quot; feature: Scratch files. I often use them for testing HTTP requests or vanilla PHP code, so I wondered if I could use them for tinkering within the Laravel application as well.</p>
<p>Before running any Laravel code, you need to require the vendor files and bootstrap the application.</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Bootstrap</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #f97583;">require</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">/Users/dkoch/Code/jobstartboerse-2025/vendor/autoload.php</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">app</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #f97583;">require</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">/Users/dkoch/Code/jobstartboerse-2025/bootstrap/app.php</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">kernel</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">app</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">make</span><span class="token">(</span><span class="token" style="color: #79b8ff;">Illuminate</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">Contracts</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">Console</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">Kernel</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #f97583;">class</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">kernel</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">bootstrap</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Run your code</span><span class="token" style="color: #6a737d;">
</span></span></code></pre>
<p>You can then run any code by clicking the play icon in PhpStorm's top bar.</p>
<p>As a developer, I was reluctant to use my mouse to click that little icon after every change. Additionally, remembering and typing that bootstrap code each time I wanted to tinker was annoying. Fortunately, there's a solution for both issues.</p>
<h2 id="-we-have-tinkerwell-at-home-"><a class="anchor-link" href="#-we-have-tinkerwell-at-home-">&quot;We Have Tinkerwell at Home&quot;</a></h2>
<p>Let's address the mouse issue first. In <code>Settings &gt; Keymap</code>, you can configure a keybinding for <code>Run</code>. I mapped mine to <code>⌘ + ENTER</code>. That's all it takes.</p>
<p>To avoid forgetting that code snippet, we can use another PhpStorm feature called Live Templates. Go to <code>Settings &gt; Editor &gt; Live Template</code> and create one for PHP. I named mine <code>tinker</code>. Add this content:</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Bootstrap</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #f97583;">require</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">$PROJECT_PATH$/vendor/autoload.php</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">app</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #f97583;">require</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">$PROJECT_PATH$/bootstrap/app.php</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">kernel</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">app</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">make</span><span class="token">(</span><span class="token" style="color: #79b8ff;">Illuminate</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">Contracts</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">Console</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">Kernel</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #f97583;">class</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">kernel</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">bootstrap</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Run your code</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">END</span><span class="token">$
</span></span></code></pre>
<p>Then click <code>Edit Variables</code> and add <code>PROJECT_PATH</code> with the value <code>groovyScript(&quot;_editor.getProject().getBasePath()&quot;)</code>, and check the box for &quot;Skip if defined&quot;. Apply your settings, and you are ready to tinker in PhpStorm.</p>
<p><img src="/assets/images/articles/2027-01-23-you-might-not-need-tinkwell/demo.mp4" alt="Video demonstrating tinkering in PhpStorm" /></p>
<p><strong>NOTE:</strong> PhpStorm 2026.1 broke Groovy Script support for Live Templates. Hopefully, this will be fixed with the next release (<a href="https://youtrack.jetbrains.com/issue/IJPL-241581/IDE-2026.1-broke-Live-Templates-with-groovyScript">YouTrack Issue</a>).</p>
<h2 id="wrapping-up"><a class="anchor-link" href="#wrapping-up">Wrapping Up</a></h2>
<p>Tinkerwell is an excellent app and worth every penny if you use it regularly, especially with its advanced features. However, it's always great to explore what PhpStorm already offers out of the box. If you don't need the advanced features and prefer working in PhpStorm, this might be the right choice for you.</p>
]]></content>
        <author>
            <name>Dennis Koch</name>
            <uri>https://denniskoch.dev</uri>
        </author>
    </entry>
    <entry>
        <title>Laravel Boost for Package Development</title>
        <id>https://denniskoch.dev/articles/2026-01-26-laravel-boost-for-package-development</id>
        <link rel="alternate" type="text/html" href="https://denniskoch.dev/articles/2026-01-26-laravel-boost-for-package-development"/>
        <published>2026-01-26T00:00:00+00:00</published>
        <updated>2026-01-26T00:00:00+00:00</updated>
        <summary type="text">Learn how to configure Laravel Boost with Orchestra Testbench and Workbench for AI-powered Laravel package development. Includes path fixes and MCP server setup</summary>
        <content type="html"><![CDATA[<h2 id="the-problem"><a class="anchor-link" href="#the-problem">The Problem</a></h2>
<p>When using AI agents like Claude Code, <a href="https://github.com/laravel/boost/">Laravel Boost</a> is an essential tool. It's easy to install, offers MCP servers for Laravel and Herd, and provides guidelines for installed Composer packages for AI.</p>
<p>However, while <a href="https://packages.tools/testbench">Testbench</a> allows you to run Laravel commands via a bundled Laravel app, Laravel Boost does not work out of the box. The problem occurs because Boost looks for files in the bundled app folder <code>vendor/orchestra/testbench-core/laravel</code> instead of the package folder.</p>
<p>I explored the source code and found a slightly hacky workaround.</p>
<p>In this example, I am using <a href="https://packages.tools/workbench.html">Workbench</a> from Testbench. It provides a partial Laravel app skeleton in your package folder, which integrates with the Testbench core.</p>
<h2 id="solution"><a class="anchor-link" href="#solution">Solution</a></h2>
<h3 id="fixing-paths-for-laravel-boost-commands"><a class="anchor-link" href="#fixing-paths-for-laravel-boost-commands">Fixing Paths for Laravel Boost Commands</a></h3>
<p>Laravel Boost uses <code>base_path()</code> in many places. I tried to overwrite the base path globally, but since Testbench lives in the vendor folder, this would break other functionalities. I considered replacing some components, but that would result in numerous overwritten classes, which I wanted to avoid.</p>
<p>Fortunately, it seems that changing the base path only for the Boost commands works. Additionally, we need to adjust the path to <code>CLAUDE.md</code>, as the default is a relative path. We can hook into the command execution via the <code>CommandStarting</code> event and modify the necessary paths. Place this in a <code>ServiceProvider</code> like the <code>WorkbenchServiceProvider</code>:</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #79b8ff;">Event</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #b392f0;">listen</span><span class="token">(</span><span class="token" style="color: #79b8ff;">CommandStarting</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #f97583;">class</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #f97583;">function</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">event</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #79b8ff;">str_starts_with</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">event</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #e1e4e8;">command</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">boost:</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Make sure this actually points to your package root!</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #b392f0;">app</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">setBasePath</span><span class="token">(</span><span class="token" style="color: #79b8ff;">realpath</span><span class="token">(</span><span class="token" style="color: #79b8ff;">__DIR__</span><span class="token" style="color: #f97583;">.</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">/../../../</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #b392f0;">app</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">useAppPath</span><span class="token">(</span><span class="token" style="color: #b392f0;">base_path</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">src</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #b392f0;">config</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">set</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">boost.code_environments.claude_code.guidelines_path</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #b392f0;">base_path</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">CLAUDE.md</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span></code></pre>
<h3 id="fixing-mcp-servers-support"><a class="anchor-link" href="#fixing-mcp-servers-support">Fixing MCP Servers Support</a></h3>
<p>When installing the MCP servers, Laravel Boost points to the <code>artisan</code> file. Initially, I thought about changing the <code>.mcp.json</code> config, but it still contains references to <code>artisan</code>. Therefore, we need to create that file and pass the commands through to Testbench. Fortunately, someone has already addressed this and shared the solution on <a href="https://github.com/laravel/boost/issues/366#issuecomment-3617492581">GitHub</a>:</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">!/usr/bin/env php</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #f97583;">&lt;</span><span class="token" style="color: #f97583;">?</span><span class="token" style="color: #79b8ff;">php</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Set cache driver to array to avoid database connection</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #79b8ff;">putenv</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">CACHE_STORE=array</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">_ENV</span><span class="token">[</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">CACHE_STORE</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">array</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Get the path to Testbench</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">testbenchPath</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #79b8ff;">__DIR__</span><span class="token"> </span><span class="token" style="color: #f97583;">.</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">/vendor/bin/testbench</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Check if Testbench exists</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #f97583;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #f97583;">!</span><span class="token" style="color: #79b8ff;">file_exists</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">testbenchPath</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #79b8ff;">fwrite</span><span class="token">(</span><span class="token" style="color: #79b8ff;">STDERR</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #9ecbff;">Error: vendor/bin/testbench not found. Run &#039;composer install&#039; first.</span><span class="token" style="color: #79b8ff;">\n</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">exit</span><span class="token">(</span><span class="token" style="color: #79b8ff;">1</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Get all command line arguments (skip script name)</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">args</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #79b8ff;">array_slice</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">argv</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #79b8ff;">1</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Build the command</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">command</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #79b8ff;">escapeshellarg</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">testbenchPath</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #f97583;">!</span><span class="token" style="color: #79b8ff;">empty</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">args</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">command</span><span class="token"> </span><span class="token" style="color: #f97583;">.=</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token"> </span><span class="token" style="color: #f97583;">.</span><span class="token"> </span><span class="token" style="color: #79b8ff;">implode</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #79b8ff;">array_map</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">escapeshellarg</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">args</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Execute and pass through exit code</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #79b8ff;">passthru</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">command</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">exitCode</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">exit</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">exitCode</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span></code></pre>
<h2 id="wrapping-up"><a class="anchor-link" href="#wrapping-up">Wrapping Up</a></h2>
<p>Laravel Boost should now generate guidelines for the correct packages and communicate with the MCP servers properly. The solution feels a bit fragile, so let's hope for official support in the future.</p>
]]></content>
        <author>
            <name>Dennis Koch</name>
            <uri>https://denniskoch.dev</uri>
        </author>
    </entry>
    <entry>
        <title>Stop Hardcoding Email Addresses in Laravel</title>
        <id>https://denniskoch.dev/articles/2026-01-19-stop-hardcoding-email-addresses-in-laravel</id>
        <link rel="alternate" type="text/html" href="https://denniskoch.dev/articles/2026-01-19-stop-hardcoding-email-addresses-in-laravel"/>
        <published>2026-01-19T00:00:00+00:00</published>
        <updated>2026-01-19T00:00:00+00:00</updated>
        <summary type="text">A clean approach to managing static email addresses in Laravel</summary>
        <content type="html"><![CDATA[<h2 id="the-problem-hardcoded-email-addresses-everywhere"><a class="anchor-link" href="#the-problem-hardcoded-email-addresses-everywhere">The Problem: Hardcoded Email Addresses Everywhere</a></h2>
<p>From time to time, I need to send notifications to fixed email addresses that don't have user accounts in the database – like a booking manager or support team.</p>
<p>The quick solution is to hardcode the email throughout your codebase. It works, but it's messy.</p>
<h2 id="the-basic-solution-config-files-and-mailables"><a class="anchor-link" href="#the-basic-solution-config-files-and-mailables">The Basic Solution: Config Files and Mailables</a></h2>
<p>The first step toward cleaner code is centralizing email addresses in a config file:</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> config/emails.php</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #f97583;">return</span><span class="token"> </span><span class="token">[</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">booking_manager</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token"> </span><span class="token" style="color: #f97583;">=&gt;</span><span class="token"> </span><span class="token" style="color: #b392f0;">env</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">BOOKING_MANAGER_EMAIL</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">bookings@example.com</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">support_team</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token"> </span><span class="token" style="color: #f97583;">=&gt;</span><span class="token"> </span><span class="token" style="color: #b392f0;">env</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">SUPPORT_EMAIL</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">support@example.com</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">]</span><span class="token">;</span><span class="token">
</span></span></code></pre>
<p>Now you can reference these email addresses when sending mails.</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #79b8ff;">Mail</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #b392f0;">to</span><span class="token">(</span><span class="token" style="color: #b392f0;">config</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">emails.booking_manager</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">send</span><span class="token">(</span><span class="token" style="color: #f97583;">new</span><span class="token"> </span><span class="token" style="color: #79b8ff;">Mailables</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">BookingReceived</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">booking</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span></code></pre>
<p>This works fine, but I prefer using notifications.</p>
<h2 id="why-i-prefer-notifications"><a class="anchor-link" href="#why-i-prefer-notifications">Why I Prefer Notifications</a></h2>
<p>I always reach for Laravel's notification system instead of Mailables because:</p>
<ul>
<li>You can send to multiple channels (email, Slack, SMS) from one place</li>
<li>All your communication logic lives in dedicated notification classes</li>
</ul>
<p>But notifications need a <code>Notifiable</code> instance, typically a <code>User</code> model.</p>
<h2 id="using-"><a class="anchor-link" href="#using-">Using <code>AnonymousNotifiable</code></a></h2>
<p>Laravel has a solution for this: <code>AnonymousNotifiable</code>. It lets you send notifications without a database-backed user.</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">bookingManager</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #f97583;">new</span><span class="token"> </span><span class="token" style="color: #79b8ff;">AnonymousNotifiable</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">route</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">mail</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #b392f0;">config</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">emails.booking_manager</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">bookingManager</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">notify</span><span class="token">(</span><span class="token" style="color: #f97583;">new</span><span class="token"> </span><span class="token" style="color: #79b8ff;">Notifications</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">BookingReceived</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">booking</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span></code></pre>
<p>This gets the job done, but I don't like creating <code>⁠AnonymousNotifiable</code> instances all over the place. It's repetitive and verbose.</p>
<h2 id="the-clean-solution-wrapper-classes"><a class="anchor-link" href="#the-clean-solution-wrapper-classes">The Clean Solution: Wrapper Classes</a></h2>
<p>My solution is to wrap each <code>AnonymousNotifiable</code> in a dedicated class with a static factory method:</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #f97583;">&lt;</span><span class="token" style="color: #f97583;">?</span><span class="token" style="color: #79b8ff;">php</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">namespace</span><span class="token"> </span><span class="token" style="color: #b392f0;">App</span><span class="token" style="color: #b392f0;">\</span><span class="token" style="color: #b392f0;">Notifications</span><span class="token" style="color: #b392f0;">\</span><span class="token" style="color: #b392f0;">Notifiables</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">use</span><span class="token"> </span><span class="token" style="color: #79b8ff;">Illuminate</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">Notifications</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">AnonymousNotifiable</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">final</span><span class="token"> </span><span class="token" style="color: #f97583;">class</span><span class="token"> </span><span class="token" style="color: #b392f0;">BookingManager</span><span class="token">
</span></span><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">public</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token"> </span><span class="token" style="color: #f97583;">function</span><span class="token"> </span><span class="token" style="color: #b392f0;">make</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #f97583;">:</span><span class="token"> </span><span class="token" style="color: #79b8ff;">AnonymousNotifiable</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">return</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #f97583;">new</span><span class="token"> </span><span class="token" style="color: #79b8ff;">AnonymousNotifiable</span><span class="token">(</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">route</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">mail</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #b392f0;">config</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">emails.booking_manager</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">route</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">slack</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #b392f0;">config</span><span class="token">(</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token" style="color: #9ecbff;">phone.booking_channel</span><span class="token" style="color: #9ecbff;">&#039;</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre>
<p>Now I can reuse this across the codebase:</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #79b8ff;">BookingManager</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #b392f0;">make</span><span class="token">(</span><span class="token">)</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">notify</span><span class="token">(</span><span class="token" style="color: #f97583;">new</span><span class="token"> </span><span class="token" style="color: #79b8ff;">Notifications</span><span class="token" style="color: #79b8ff;">\</span><span class="token" style="color: #79b8ff;">BookingReceived</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">booking</span><span class="token">)</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span></code></pre>
<h2 id="why-i-like-this"><a class="anchor-link" href="#why-i-like-this">Why I Like This</a></h2>
<ul>
<li>It's simple and readable. Your IDE autocompletes <code>⁠BookingManager::make()</code>.</li>
<li>You can discover more <code>Notifiable</code>s in the <code>Notifiables</code> folder.</li>
<li>If you need to change the email address, you do it in one place. Want to add Slack or SMS? Just add another route without touching your business logic.</li>
<li>The return type hint also catches errors early instead of at runtime.</li>
</ul>
<p>How do you handle static email notifications in your Laravel applications?</p>
]]></content>
        <author>
            <name>Dennis Koch</name>
            <uri>https://denniskoch.dev</uri>
        </author>
    </entry>
    <entry>
        <title>Recap 2025</title>
        <id>https://denniskoch.dev/articles/2025-12-30-recap-2025</id>
        <link rel="alternate" type="text/html" href="https://denniskoch.dev/articles/2025-12-30-recap-2025"/>
        <published>2025-12-30T00:00:00+00:00</published>
        <updated>2025-12-30T00:00:00+00:00</updated>
        <summary type="text">Personal and work-related year-in-review recap for 2025</summary>
        <content type="html"><![CDATA[<p><em>This is primarily a personal recap of my year, mixed with some notes on work and side projects.</em></p>
<h2 id="personal"><a class="anchor-link" href="#personal">Personal</a></h2>
<h3 id="other-side-of-the-globe"><a class="anchor-link" href="#other-side-of-the-globe">Other Side of the Globe</a></h3>
<p>This year began 7,800 km from home in Northern Thailand, marking the halfway point of a motorbike trip through Southeast Asia with my girlfriend. It was an amazing experience, we saw many beautiful places, met wonderful people, and immersed ourselves in the culture of these countries. However, it was also exhausting. Riding over 15,000 km two-up on a motorbike with luggage over bumpy roads in high humidity, with lots of sun and temperatures reaching 35°C, took its toll over time. Constantly searching for accommodations, vegan food, and sightseeing activities while trying to squeeze in some work added to the stress. My &quot;well-thought-out&quot; daily schedule didn't last a week. I don't regret the trip, but in hindsight, I would do things differently. We finished our journey in Vietnam in May, which was a fantastic way to end the adventure.</p>
<h3 id="back-home"><a class="anchor-link" href="#back-home">Back Home</a></h3>
<p>We looked forward to returning home to Germany and enjoying the summer that was just beginning. As soon as I got back, I wanted to attend the upcoming <a href="https://laravel.swiss">Laravel Switzerland Meetup</a>. Unfortunately, Deutsche Bahn had different plans, and I found myself stranded at the train station before I could even leave my hometown.</p>
<p>Transitioning from 40–50% work back to 100% was a challenge, and I felt overwhelmed by too many projects at once. Due to my girlfriend's job, my schedule shifted from the classic 9–5 to working more in the evenings and on weekends. I tried to work from the local co-working space as much as possible to get out of the house, meet more people, and improve my focus.</p>
<p>I also decided to take more time for myself. I had regular lunch dates with a friend and attended every Laravel Switzerland Meetup after May, despite Deutsche Bahn's efforts to sabotage those journeys. These meetups were great for connecting with fellow developers, making new friends, and simply getting out of the house. I tried to combine each meetup with a little sightseeing trip, arriving early to explore the cities on foot and by bike. I visited five Swiss cities this way and truly enjoyed it. After some persuasion, I also had the opportunity to give <a href="https://www.youtube.com/watch?v=8qyV696TALA">my first tech talk</a> about all the new features of Filament v4 at the meetup in Zurich. I was initially very nervous, but it felt great to share my experience. I would love to do another one in the future.</p>
<p>In October, we had a wonderful week off in Lisbon, filled with exploration but still relaxing compared to our longer trip. We enjoyed the city, great food, and the nature and coastline outside of Lisbon.</p>
<p>This year, I focused more on reading. While I neglected the RSS feeds I collected via <a href="https://readwise.io/read">Readwise Reader</a>, I read 16 books — up from 7 in 2023 and 14 in 2024 — so this trend is positive.</p>
<p>Unfortunately, I also brought back some bad habits from traveling. While I spent a lot of time on my phone planning the trip, that turned into excessive social media use at home. Especially after launching <a href="https://laramap.dev">Laramap</a>, I wasted countless hours on various (un)social media platforms, following the conversation and commenting on posts of people sharing Laramap. I'm trying to regain control with new habits and the <a href="https://apps.apple.com/us/app/screenzen-screen-time-control/id1541027222">Screen Zen</a> app.</p>
<p>Another bad habit — or rather, a lack of habit — is that I haven't done any serious sports this year. I'm not the type for &quot;boring gym workouts&quot;. I need something more playful that disguises the fact that I'm exercising, which wasn't possible during the trip. Since we've been back, I've struggled to find a good routine, as my free time is now in the mornings and I work in the evenings. I had a streak of running — yes, also not very playful — for a few weeks, but that was interrupted by a cold just before Christmas.</p>
<h2 id="professional-work"><a class="anchor-link" href="#professional-work">Professional Work</a></h2>
<p>Most of my time this year was spent working on the following projects:</p>
<ul>
<li>For <a href="https://www.padmission.com/">Padmission</a>, I developed a Filament plugin that will hopefully be released in early 2026.</li>
<li>For <a href="https://bluedom.swiss">blueDOM</a>, I worked on <a href="https://ortenau.deindinglaeuft.de">Dein Ding #laeuft</a>, a project aimed at connecting companies with applicants. I developed <a href="https://unsere-liebe-feiern.de">Unsere Liebe Feiern</a>, a website for inquiries about church services. We are also relaunching <a href="https://jobstartboerse.de">Jobstartbörse</a>, the website for a local job fair. All of these projects are backed by Filament as the admin panel, and two of them also have a user panel. Additionally, we relaunched <a href="https://schladerer.de">Schladerer's webshop</a> this year.</li>
<li>Together with <a href="https://koch-it-solutions.de">KOCH IT Solutions</a>, I am working on a PWA for <a href="https://fenster-tueren-freiburg.de">Paul</a> that will digitize the workflow of their field service employees, reducing the need for paperwork and connecting it directly with their ERP system.</li>
<li>With <a href="https://leitsch.org">Lukas</a>, I continued working on an internal multi-purpose app for <a href="https://www.milupa.de/">Milupa</a>.</li>
</ul>
<p>In addition to these larger projects, I worked on 38 other projects, mostly for existing customers.</p>
<h2 id="personal-projects"><a class="anchor-link" href="#personal-projects">Personal Projects</a></h2>
<p>I dedicated a lot of time to Filament projects, spending countless hours supporting people on the Filament Discord and working on my <a href="https://denniskoch.dev/projects">open source packages</a>. Most of the work involved adding support for Filament v4 and enhancing my <a href="https://denniskoch.dev/projects/filament-spotlight-pro/docs">Spotlight Pro plugin</a>. Furthermore, I released two new Filament plugins: <a href="https://github.com/pxlrbt/filament-favicon">Favicon</a> and <a href="https://github.com/pxlrbt/filament-image-compare">Image Compare</a>.</p>
<p>With the launch of Filament v4, I also released my first non-plugin product, <a href="https://filamentstudio.dev/?utm_source=website">Filament Studio</a>, a visual editor for building Filament themes. While it's a solid MVP, I realized it lacks many useful features, so I hope to improve it in 2026.</p>
<p>I launched <a href="https://laramap.dev">Laramap</a> in November, which was a huge success, collecting over 240,000 views since then. Over 4,000 Laravel developers signed up and shared it on social media. The challenge for next year is to add new features to make the platform more useful and keep it attractive.</p>
<p>Last but not least, I also launched this website in 2025. After almost two decades in tech, I finally have my own space to share my thoughts with you.</p>
<h2 id="reflection-and-looking-ahead"><a class="anchor-link" href="#reflection-and-looking-ahead">Reflection and Looking Ahead</a></h2>
<p>2025 has had its ups and downs. While some parts of this post may sound negative, it was a great year filled with wonderful experiences, and I am grateful for all the opportunities I had.</p>
<p>Personally, I hope to establish a routine for exercising more and ideally lose some weight. We have a wedding to attend in May, which could serve as a good goal. I want to continue reading — two books per month would be a great target — and reduce my phone screen time to less than an hour per day. I plan to attend many meetups and conferences, and I want to keep blogging.</p>
<p>Regarding work, I will try to limit the number of projects I work on simultaneously. I'm also considering focusing more on my personal projects and releasing more paid plugins. However, these two intentions might contradict each other.</p>
<p>How was your year? What are your goals for next year? I'd be happy to hear your thoughts.</p>
<!--
## Recaps from my Bubble

 - [Moritz Glanz](https://moritzglantz.de/blog/posts/2025/)
-->
]]></content>
        <author>
            <name>Dennis Koch</name>
            <uri>https://denniskoch.dev</uri>
        </author>
    </entry>
    <entry>
        <title>Black Friday Deals for Filament &amp; Laravel – 2025</title>
        <id>https://denniskoch.dev/articles/2025-11-18-laravel-black-friday-deals-2025</id>
        <link rel="alternate" type="text/html" href="https://denniskoch.dev/articles/2025-11-18-laravel-black-friday-deals-2025"/>
        <published>2025-11-18T00:00:00+00:00</published>
        <updated>2025-11-27T00:00:00+00:00</updated>
        <summary type="text">Collection of Black Friday deals for the Filament and Laravel community.</summary>
        <content type="html"><![CDATA[<p>Black Friday is just around the corner (28th November), and I'm working on a collection of deals for Filament and Laravel.</p>
<h2 id="filament"><a class="anchor-link" href="#filament">Filament</a></h2>
<ul>
<li><strong><a href="https://custom-fields.relaticle.com/?ref=denniskoch.dev">Custom Fields</a></strong>, 30% off with <code>BUILDFASTER30</code></li>
<li><strong><a href="https://filaforms.app/?ref=denniskoch.dev">FilaForms</a></strong>, 30% off with <code>BUILDFASTER30</code></li>
<li><strong><a href="https://filafly.com/themes?ref=denniskoch.dev">FilaFly Themes</a></strong>, 50% off with <code>BF2025</code></li>
<li><strong><a href="https://filamentexamples.com/?ref=denniskoch.dev">FilamentExamples.com</a></strong>: 40% off with <code>FRIDAY25</code></li>
<li><strong><a href="https://filamentstudio.dev/?ref=denniskoch.dev">Filament Studio</a></strong>, 20% off with <code>BF25</code></li>
<li><strong><a href="https://larazeus.com/packages/premium?ref=denniskoch.dev">LaraZeus Plugins</a></strong>, 30% off applied at checkout</li>
<li><strong><a href="https://filament.pxlrbt.de/spotlight-pro/?ref=denniskoch.dev">Spotlight Pro</a></strong>, 20% off with <code>BF25</code></li>
<li><strong><a href="https://tillythecoder.com/pricing?ref=denniskoch.dev">Tilly The Coder Pro</a></strong>, 70% off, only on Black Friday (40% until then)</li>
</ul>
<h2 id="services-for-laravel"><a class="anchor-link" href="#services-for-laravel">Services for Laravel</a></h2>
<ul>
<li><strong><a href="https://lettermint.co/?ref=denniskoch.dev">Lettermint</a></strong>, 30% off all Lettermint plans for the next 6 months with code <code>BF2025</code></li>
<li><strong><a href="https://bifrost.nativephp.com/pricing?ref=denniskoch.dev">Bifrost for NativePHP plans</a></strong>, up to 40% off</li>
</ul>
<h2 id="tools-for-laravel"><a class="anchor-link" href="#tools-for-laravel">Tools for Laravel</a></h2>
<ul>
<li><strong><a href="https://devdojo.com/blackfriday?ref=denniskoch.dev">Dev Dojo</a></strong>, 40% off</li>
<li><strong><a href="https://herd.laravel.com/?ref=denniskoch.dev#plans">Herd Pro</a></strong>, 30% off, no code needed</li>
<li><strong><a href="https://observer.dev?ref=denniskoch.dev">Observer</a></strong>, 30% off with <code>BLACKFRIDAY</code></li>
<li><strong><a href="https://spatie.be/products/ray?ref=denniskoch.dev">Ray</a></strong>, 30% off, no code needed</li>
<li><strong><a href="https://tinkerwell.app/#pricing?ref=denniskoch.dev">Tinkerwell</a></strong>, 25% off, no code needed</li>
</ul>
<h2 id="components-starter-kits-admin-panels-for-laravel"><a class="anchor-link" href="#components-starter-kits-admin-panels-for-laravel">Components, Starter Kits, Admin Panels for Laravel</a></h2>
<ul>
<li><strong><a href="https://backpackforlaravel.com/?ref=denniskoch.dev">Backpack for Laravel</a></strong>, 50% off with <code>BLACKWEEK2025</code></li>
<li><strong><a href="https://fluxui.dev/pricing?ref=denniskoch.dev">flux Pro</a></strong>, 40% off</li>
<li><strong><a href="https://larafast.com/?ref=denniskoch.dev">Larafast</a></strong>, 50% off with <code>BLACKFRIDAY2025</code></li>
<li><strong><a href="https://spatie.be/products/mailcoach?ref=denniskoch.dev">Mailcoach</a></strong>, 30% off, no code needed</li>
<li><strong><a href="https://spatie.be/products/media-library-pro?ref=denniskoch.dev">Media Library Pro</a></strong>, 30% off, no code needed</li>
<li><strong><a href="https://spatie.be/products/laravel-comments?ref=denniskoch.dev">Laravel Comments</a></strong>, 30% off, no code needed</li>
<li><strong><a href="https://tailwindcss.com/plus/black-friday?ref=denniskoch.dev">Tailwind Plus</a></strong>, 20% off</li>
<li><strong><a href="https://wire-elements.dev/pro?ref=denniskoch.dev">Wire Elements Pro</a></strong>, 30% off with <code>BLACKFRIDAY</code></li>
</ul>
<h2 id="laravel-learning-resources-courses"><a class="anchor-link" href="#laravel-learning-resources-courses">Laravel Learning Resources &amp; Courses</a></h2>
<ul>
<li><strong><a href="https://codecourse.com/?ref=denniskoch.dev">Codecourse</a></strong>, 50% off with <code>BLACKFRIDAY2025</code></li>
<li><strong><a href="https://filamentexamples.com/?ref=denniskoch.dev">FilamentExamples.com</a></strong>: 40% off with <code>FRIDAY25</code></li>
<li><strong><a href="https://laracasts.com/?ref=denniskoch.dev">Laracasts</a></strong>: 50% off, no coupon needed.</li>
<li><strong><a href="https://laraveldaily.com/?ref=denniskoch.dev">LaravelDaily.com</a></strong>: 40% off, no coupon needed.</li>
<li><strong><a href="https://radicaldesigncourse.com/?ref=denniskoch.dev">Radical Design Course</a></strong>, by Jack McDade, 30% off with <code>RADFRIDAY25</code></li>
<li><strong><a href="https://tillythecoder.com/pricing?ref=denniskoch.dev">Tilly The Coder Pro</a></strong>, 70% off, only on Black Friday (40% until then)</li>
</ul>
<h2 id="ebooks-for-laravel"><a class="anchor-link" href="#ebooks-for-laravel">Ebooks for Laravel</a></h2>
<ul>
<li><strong><a href="https://battle-ready-laravel.com/?ref=denniskoch.dev">Battle Ready Laravel</a></strong> by Ash Allen, 30% off with <code>30BLACKFRIDAY2025</code></li>
<li><strong><a href="https://wendelladriel.com/best-practices-for-laravel-enterprise-applications?ref=denniskoch.dev">Best Practices for Laravel Enterprise Applications</a></strong> by Wendell Adriel,50% off with <code>BLACKFRIDAY</code></li>
<li><strong><a href="https://shrutibalasa.gumroad.com/l/css-flex-and-grid/BLACKFRIDAY25/?ref=denniskoch.dev">Complete Guide to CSS Flexbox and Grid</a></strong> by Shruti Balasa, 60% off with <code>BLACKFRIDAY25</code></li>
<li><strong><a href="https://consuming-apis-in-laravel.com/?ref=denniskoch.dev">Consuming APIs in Laravel</a></strong> by Ash Allen, 30% off with <code>30BLACKFRIDAY2025</code></li>
<li><strong><a href="https://ryangjchandler.lemonsqueezy.com/buy/ef8e5b93-1c3b-4e32-8bae-f0798e537f11?logo=0">Data Structures in PHP</a></strong> by Ryan Chandler, 50% off with <code>BF2025</code></li>
<li><strong><a href="https://spatie.be/products/event-sourcing-in-laravel?ref=denniskoch.dev">Event Sourcing in Laravel</a></strong> by Spatie, 30% off</li>
<li><strong><a href="https://spatie.be/products/front-line-php?ref=denniskoch.dev">Front Line PHP</a></strong> by Spatie, 30% off</li>
<li><strong><a href="https://spatie.be/products/laravel-package-training?ref=denniskoch.dev">Laravel Package Training v2.0</a></strong> by Spatie, 30% off</li>
<li><strong><a href="https://spatie.be/products/laravel-beyond-crud?ref=denniskoch.dev">Laravel Beyond CRUD</a></strong> by Spatie, 30% off</li>
<li><strong><a href="https://shrutibalasa.gumroad.com/l/level-up-with-tailwind-css/BLACKFRIDAY25/?ref=denniskoch.dev">Level up with Tailwind CSS</a></strong> by Shruti Balasa, 60% off with <code>BLACKFRIDAY25</code></li>
<li><strong><a href="https://tailwindcss.com/plus/black-friday?ref=denniskoch.dev">Refactoring UI</a></strong>, by Adam Wathan &amp; Steve Schoger, 20% off</li>
<li><strong><a href="https://spatie.be/products/testing-laravel?ref=denniskoch.dev">Testing Laravel</a></strong> by Spatie, 30% off</li>
<li><strong><a href="https://web-dev-freelancing.com/?ref=denniskoch.dev">The Web Dev's Guide to Freelancing</a></strong> by Ash Allen, 30% off with <code>50BLACKFRIDAY2025</code></li>
<li><strong><a href="https://spatie.be/products/writing-readable-php?ref=denniskoch.dev">Writing Readable PHP</a></strong> by Spatie, 30% off</li>
</ul>
]]></content>
        <author>
            <name>Dennis Koch</name>
            <uri>https://denniskoch.dev</uri>
        </author>
    </entry>
    <entry>
        <title>Automatic autocompletion for make()</title>
        <id>https://denniskoch.dev/articles/2025-11-02-laravel-idea-make</id>
        <link rel="alternate" type="text/html" href="https://denniskoch.dev/articles/2025-11-02-laravel-idea-make"/>
        <published>2025-11-02T00:00:00+00:00</published>
        <updated>2025-11-02T00:00:00+00:00</updated>
        <summary type="text">How Laravel Idea can help you reduce repetition when using make() methods</summary>
        <content type="html"><![CDATA[<h2 id="introduction"><a class="anchor-link" href="#introduction">Introduction</a></h2>
<p>The <code>make()</code> method is a common pattern in the Laravel ecosystem. Some might argue that it's no longer necessary since we can now <a href="https://wiki.php.net/rfc/new_without_parentheses">chain methods directly after a new call</a> starting from PHP 8.4. However, I believe it remains useful for resolving elements from the Laravel container.</p>
<p>You could place the <code>make()</code> method in a trait and apply it to all your classes while passing the arguments along. However, this approach would result in the loss of autocompletion.</p>
<p><img src="/assets/images/articles/2025-11-02-laravel-idea-make/missing-autocompletion.png" alt="Screenshot demonstrating missing autocompletion in PhpStorm" /></p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #f97583;">&lt;</span><span class="token" style="color: #f97583;">?</span><span class="token" style="color: #79b8ff;">php</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">class</span><span class="token"> </span><span class="token" style="color: #b392f0;">Action</span><span class="token">
</span></span><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">public</span><span class="token"> </span><span class="token" style="color: #f97583;">function</span><span class="token"> </span><span class="token" style="color: #79b8ff;">__construct</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">protected</span><span class="token"> </span><span class="token" style="color: #f97583;">string</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg1</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">protected</span><span class="token"> </span><span class="token" style="color: #f97583;">string</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg2</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">protected</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg3</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">public</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token"> </span><span class="token" style="color: #f97583;">function</span><span class="token"> </span><span class="token" style="color: #b392f0;">make</span><span class="token">(</span><span class="token" style="color: #f97583;">...</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">args</span><span class="token">)</span><span class="token" style="color: #f97583;">:</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">return</span><span class="token"> </span><span class="token" style="color: #b392f0;">resolve</span><span class="token">(</span><span class="token" style="color: #f97583;">static</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #f97583;">class</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">args</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre>
<p>Consequently, you often end up duplicating your constructor code. This can become frustrating, especially with more than one or two arguments.</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #f97583;">&lt;</span><span class="token" style="color: #f97583;">?</span><span class="token" style="color: #79b8ff;">php</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">class</span><span class="token"> </span><span class="token" style="color: #b392f0;">Action</span><span class="token">
</span></span><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">public</span><span class="token"> </span><span class="token" style="color: #f97583;">function</span><span class="token"> </span><span class="token" style="color: #79b8ff;">__construct</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">protected</span><span class="token"> </span><span class="token" style="color: #f97583;">string</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg1</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">protected</span><span class="token"> </span><span class="token" style="color: #f97583;">string</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg2</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">protected</span><span class="token"> </span><span class="token" style="color: #f97583;">string</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg3</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">public</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token"> </span><span class="token" style="color: #f97583;">function</span><span class="token"> </span><span class="token" style="color: #b392f0;">make</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">        protected </span><span class="token" style="color: #f97583;">string</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg1</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">        protected </span><span class="token" style="color: #f97583;">string</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg2</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">        protected </span><span class="token" style="color: #f97583;">string</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg3</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">)</span><span class="token" style="color: #f97583;">:</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">return</span><span class="token"> </span><span class="token" style="color: #b392f0;">resolve</span><span class="token">(</span><span class="token" style="color: #f97583;">static</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #f97583;">class</span><span class="token">,</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg1</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg2</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">arg3</span><span class="token">]</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre>
<h2 id="laravel-idea-to-the-rescue"><a class="anchor-link" href="#laravel-idea-to-the-rescue">Laravel Idea To The Rescue</a></h2>
<p>Unfortunately, there is no built-in way for the IDE to automatically use the same arguments as the constructor. However, Adelf, the creator of <a href="https://laravel-idea.com/">Laravel Idea</a>, quickly provided a solution. Laravel Idea offers a <a href="https://laravel-idea.com/docs/ide_json/overview"><code>ide.json</code></a> file that allows you to configure additional autocompletion for your project. While this is typically Laravel-specific, in this case, he added support for type-hinting constructor arguments in other methods.</p>
<p>To implement this, create the <code>ide.json</code> file in your project root, add the following JSON, and regenerate your helper code.</p>
<pre class="phiki language-json github-dark" data-language="json" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token" style="color: #79b8ff;">$schema</span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #9ecbff;">https://laravel-ide.com/schema/laravel-ide-v2.json</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token" style="color: #79b8ff;">helperCode</span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token" style="color: #79b8ff;">methodsWithConstructorParameters</span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token">[</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token" style="color: #79b8ff;">baseFqn</span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #9ecbff;">App</span><span class="token" style="color: #79b8ff;">\\</span><span class="token" style="color: #9ecbff;">Traits</span><span class="token" style="color: #79b8ff;">\\</span><span class="token" style="color: #9ecbff;">Makable</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token" style="color: #79b8ff;">methods</span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token">[</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                        </span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token" style="color: #79b8ff;">name</span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #9ecbff;">make</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">                        </span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token" style="color: #79b8ff;">returnType</span><span class="token" style="color: #79b8ff;">&quot;</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #9ecbff;">static</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">                    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre>
<h2 id="reusable-"><a class="anchor-link" href="#reusable-">Reusable <code>make()</code> Method</a></h2>
<p>The <code>baseFqn</code> also accepts parent classes or traits, allowing you to reuse this across your codebase. When using a trait, PhpStorm will display two definitions, however.</p>
<p><img src="/assets/images/articles/2025-11-02-laravel-idea-make/double-autocompletion.png" alt="Screenshot demonstrating double autocompletion in PhpStorm" /></p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #f97583;">&lt;</span><span class="token" style="color: #f97583;">?</span><span class="token" style="color: #79b8ff;">php</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">trait</span><span class="token"> </span><span class="token" style="color: #b392f0;">Makable</span><span class="token">
</span></span><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">public</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token"> </span><span class="token" style="color: #f97583;">function</span><span class="token"> </span><span class="token" style="color: #b392f0;">make</span><span class="token">(</span><span class="token" style="color: #f97583;">...</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">args</span><span class="token">)</span><span class="token" style="color: #f97583;">:</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">return</span><span class="token"> </span><span class="token" style="color: #f97583;">new</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token">(</span><span class="token" style="color: #f97583;">...</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">args</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre>
<h2 id="supporting-"><a class="anchor-link" href="#supporting-">Supporting <code>resolve()</code></a></h2>
<p>Returning to the original example of passing arguments to <code>resolve()</code> to create a class via the Laravel container, you quickly realize that this approach doesn't always work. <code>resolve()</code> requires the parameter name as the key, so the simple version only works with named arguments, which are not always provided.</p>
<p>Fortunately, we can bridge this gap using <a href="https://www.php.net/manual/en/intro.reflection.php">Reflection</a> to add positional arguments. The complete trait looks like this:</p>
<pre class="phiki language-php github-dark" data-language="php" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #f97583;">&lt;</span><span class="token" style="color: #f97583;">?</span><span class="token" style="color: #79b8ff;">php</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">trait</span><span class="token"> </span><span class="token" style="color: #b392f0;">Makable</span><span class="token">
</span></span><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">public</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token"> </span><span class="token" style="color: #f97583;">function</span><span class="token"> </span><span class="token" style="color: #b392f0;">make</span><span class="token">(</span><span class="token" style="color: #f97583;">...</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">positionalParams</span><span class="token">)</span><span class="token" style="color: #f97583;">:</span><span class="token"> </span><span class="token" style="color: #f97583;">static</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">reflector</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #f97583;">new</span><span class="token"> </span><span class="token" style="color: #79b8ff;">ReflectionClass</span><span class="token">(</span><span class="token" style="color: #f97583;">static</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #f97583;">class</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">constructor</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">reflector</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">getConstructor</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #f97583;">!</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">constructor</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #f97583;">return</span><span class="token"> </span><span class="token" style="color: #b392f0;">app</span><span class="token">(</span><span class="token" style="color: #f97583;">static</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #f97583;">class</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">constructorParams</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">constructor</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">getParameters</span><span class="token">(</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">namedParams</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token">[</span><span class="token">]</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">foreach</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">positionalParams</span><span class="token"> </span><span class="token" style="color: #f97583;">as</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">index</span><span class="token"> </span><span class="token" style="color: #f97583;">=&gt;</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">value</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #f97583;">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #79b8ff;">is_string</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">index</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> This is already a named parameter</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">namedParams</span><span class="token">[</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">index</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">value</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token"> </span><span class="token" style="color: #f97583;">elseif</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #79b8ff;">isset</span><span class="token">(</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">constructorParams</span><span class="token">[</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">index</span><span class="token">]</span><span class="token">)</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> This is a positional parameter - convert to named</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">namedParams</span><span class="token">[</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">constructorParams</span><span class="token">[</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">index</span><span class="token">]</span><span class="token" style="color: #f97583;">-&gt;</span><span class="token" style="color: #b392f0;">getName</span><span class="token">(</span><span class="token">)</span><span class="token">]</span><span class="token"> </span><span class="token" style="color: #f97583;">=</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">value</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #f97583;">return</span><span class="token"> </span><span class="token" style="color: #b392f0;">app</span><span class="token">(</span><span class="token" style="color: #f97583;">static</span><span class="token" style="color: #f97583;">::</span><span class="token" style="color: #f97583;">class</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">namedParams</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre>
<h2 id="conclusion"><a class="anchor-link" href="#conclusion">Conclusion</a></h2>
<p>So, this was quite some effort to avoid repeating the constructor arguments. Is it really worth it? I'll leave that decision to you, but I think it's cool that it's possible.</p>
]]></content>
        <author>
            <name>Dennis Koch</name>
            <uri>https://denniskoch.dev</uri>
        </author>
    </entry>
    <entry>
        <title>Fixing Herd with Xdebug forever</title>
        <id>https://denniskoch.dev/articles/2025-08-19-fixing-herd-with-xdebug-forever</id>
        <link rel="alternate" type="text/html" href="https://denniskoch.dev/articles/2025-08-19-fixing-herd-with-xdebug-forever"/>
        <published>2025-08-19T00:00:00+00:00</published>
        <updated>2025-08-26T00:00:00+00:00</updated>
        <summary type="text">A short journey into debugging Xdebug issues with Laravel Herd and Fish shell</summary>
        <content type="html"><![CDATA[<h2 id="my-xdebug-setup-broke-again"><a class="anchor-link" href="#my-xdebug-setup-broke-again">My Xdebug Setup Broke … Again</a></h2>
<p>Every now and then my Xdebug setup stops working. Initially, I blamed Xdebug. However, I could still debug the app through the browser. Running PHP scripts on CLI via <code>herd debug</code> or just <code>XDEBUG_SESSION=1 php</code> didn't work. I checked every PhpStorm setting for Xdebug and deleted some server configs that had previously caused issues, but nothing worked.</p>
<p>Eventually, I googled for Laravel Herd issues but didn't find one immediately. I checked the Herd documentation again, and everything seemed properly configured. Somehow, I stumbled on an issue I didn't find before, which felt way too familiar. It was about issues with the <strong>Fish shell</strong> that I am using and I recalled that I had fixed this exact problem a year ago.</p>
<h2 id="so-what-happened-"><a class="anchor-link" href="#so-what-happened-">So What Happened?</a></h2>
<p>Herd configures the directory where PHP looks for ini files via environment variables and automatically adds them to macOS's default shell, &quot;zsh&quot;. With Fish shell, you need set these variables manually. I had done this, but each version has its own environment var, and since PHP8.4 was new, that variable wasn't configured. Therefore, it wasn't loading my properly configured ini files.</p>
<h2 id="the-quick-fix"><a class="anchor-link" href="#the-quick-fix">The Quick Fix</a></h2>
<p>I quickly opened my Fish config and added the environment var for PHP 8.4:</p>
<pre class="phiki language-shellscript github-dark" data-language="shellscript" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token">HERD_PHP_84_INI_SCAN_DIR </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/84/
</span></span></code></pre>
<p>However, I had encountered this issue in the past, and I didn't want to debug this again in a year when PHP8.5 is released. So, I decided to fix it permanently:</p>
<pre class="phiki language-shellscript github-dark" data-language="shellscript" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token">set -x HERD_PHP_85_INI_SCAN_DIR </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/85/</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">set -x HERD_PHP_86_INI_SCAN_DIR </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/86/</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">set -x HERD_PHP_87_INI_SCAN_DIR </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/87/</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">set -x HERD_PHP_88_INI_SCAN_DIR </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/88/</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">set -x HERD_PHP_89_INI_SCAN_DIR </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/89/</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">set -x HERD_PHP_90_INI_SCAN_DIR </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/90/</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">set -x HERD_PHP_91_INI_SCAN_DIR </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/91/</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span></code></pre>
<p>That should give me some years of peace!</p>
<h2 id="the-better-solution"><a class="anchor-link" href="#the-better-solution">The Better Solution</a></h2>
<p>While that quick fix works, and I could even add more version to be safe for even longer, it feels dirty. Fortunately, you can use commands and loops inside the config file, so this will fix it forever (hopefully 🤞🏽)</p>
<pre class="phiki language-shellscript github-dark" data-language="shellscript" style="background-color: #24292e;color: #e1e4e8;"><code><span class="line"><span class="token" style="color: #f97583;">for</span><span class="token"> </span><span class="token" style="color: #e1e4e8;">version_dir</span><span class="token"> </span><span class="token" style="color: #f97583;">in</span><span class="token"> </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #9ecbff;">*</span><span class="token" style="color: #9ecbff;">/</span><span class="token">
</span></span><span class="line"><span class="token">    set php_version (basename </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">version_dir</span><span class="token">)
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">if</span><span class="token"> test </span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">php_version</span><span class="token"> </span><span class="token" style="color: #f97583;">!</span><span class="token">= </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">        set -x HERD_</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">php_version</span><span class="token" style="color: #79b8ff;">\_</span><span class="token">INI_SCAN_DIR </span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">HOME</span><span class="token" style="color: #9ecbff;">/Library/Application Support/Herd/config/php/</span><span class="token" style="color: #e1e4e8;">$</span><span class="token" style="color: #e1e4e8;">php_version</span><span class="token" style="color: #9ecbff;">/</span><span class="token" style="color: #9ecbff;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #f97583;">end</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #f97583;">end</span><span class="token">
</span></span></code></pre>
<h2 id="changelog"><a class="anchor-link" href="#changelog">Changelog</a></h2>
<p>26.08.2025: Removed the &quot;Bonus&quot; section because it only worked with Herd CLI, but not through FPM.</p>
]]></content>
        <author>
            <name>Dennis Koch</name>
            <uri>https://denniskoch.dev</uri>
        </author>
    </entry>
</feed>
