<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Giacomo Masseroni</title>
    <description>The latest articles on DEV Community by Giacomo Masseroni (@giacomomasseron).</description>
    <link>https://dev.to/giacomomasseron</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3562426%2F5e1c4298-16f5-4be6-a71a-6a8506cc58e0.jpg</url>
      <title>DEV Community: Giacomo Masseroni</title>
      <link>https://dev.to/giacomomasseron</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/giacomomasseron"/>
    <language>en</language>
    <item>
      <title>lazynginx: a beautiful terminal UI for Nginx management</title>
      <dc:creator>Giacomo Masseroni</dc:creator>
      <pubDate>Sat, 17 Jan 2026 17:40:38 +0000</pubDate>
      <link>https://dev.to/giacomomasseron/lazynginx-a-beautiful-terminal-ui-for-nginx-management-2ei4</link>
      <guid>https://dev.to/giacomomasseron/lazynginx-a-beautiful-terminal-ui-for-nginx-management-2ei4</guid>
      <description>&lt;h1&gt;
  
  
  LazyNginx: A Beautiful Terminal UI for Nginx Management
&lt;/h1&gt;

&lt;p&gt;Managing Nginx servers typically involves memorizing commands, juggling configuration files, and navigating complex log directories. LazyNginx simplifies this workflow with an elegant, keyboard-driven terminal interface built with Go and the Bubble Tea framework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/giacomomasseron/lazynginx" rel="noopener noreferrer"&gt;github.com/giacomomasseron/lazynginx&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;License&lt;/strong&gt;: MIT&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Requirements&lt;/strong&gt;: Go 1.21+, Nginx&lt;/p&gt;
&lt;h2&gt;
  
  
  What is LazyNginx?
&lt;/h2&gt;

&lt;p&gt;LazyNginx is a terminal-based user interface that streamlines common Nginx administration tasks. Rather than typing out systemctl commands or searching for log file locations, administrators can navigate through a clean, intuitive menu to perform essential operations.&lt;/p&gt;

&lt;p&gt;The tool brings together Nginx's most frequently used functions into a single, accessible interface. It handles platform-specific differences automatically, making it equally useful on Linux, macOS, and Windows systems.&lt;/p&gt;
&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;p&gt;The application covers the essential operations needed for day-to-day Nginx management:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service Control&lt;/strong&gt;: Start, stop, and restart Nginx services with a single keystroke. The reload function allows configuration updates without service interruption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration Management&lt;/strong&gt;: Test configuration files for syntax errors before applying changes. View the complete nginx.conf file directly within the terminal interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Log Monitoring&lt;/strong&gt;: Access the last 50 lines of both error and access logs without navigating to log directories or remembering file paths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status Checking&lt;/strong&gt;: Quickly verify whether Nginx is currently running on your system.&lt;/p&gt;
&lt;h2&gt;
  
  
  Design and Usability
&lt;/h2&gt;

&lt;p&gt;LazyNginx uses the Bubble Tea framework to create a responsive terminal UI. Navigation relies on familiar keyboard shortcuts: arrow keys or vim-style h/j/k/l movement, Enter to select, and q to quit. The interface provides clear visual feedback for each operation's success or failure.&lt;/p&gt;

&lt;p&gt;The application automatically detects the operating system and adjusts its commands accordingly. On Linux systems with systemd, it uses systemctl. Windows installations use net start/stop commands. For other Unix-like systems, it calls nginx commands directly.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation and Setup
&lt;/h2&gt;

&lt;p&gt;Building LazyNginx requires Go 1.21 or later and an existing Nginx installation. The process is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/giacomomasseron/lazynginx
&lt;span class="nb"&gt;cd &lt;/span&gt;lazynginx
go mod download
go build &lt;span class="nt"&gt;-o&lt;/span&gt; lazynginx
./lazynginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool searches common locations for Nginx configuration files and logs, including &lt;code&gt;/etc/nginx/&lt;/code&gt; on Linux, &lt;code&gt;C:\nginx\&lt;/code&gt; on Windows, and &lt;code&gt;/usr/local/nginx/&lt;/code&gt; on macOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Permissions and Platform Support
&lt;/h2&gt;

&lt;p&gt;Certain operations like starting, stopping, and restarting services require elevated privileges. Linux and macOS users should run the application with sudo when needed. Windows users need to launch it with administrator rights.&lt;/p&gt;

&lt;p&gt;The cross-platform design ensures consistent functionality across different operating systems, abstracting away platform-specific command differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;p&gt;LazyNginx proves particularly valuable in several scenarios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learning Environments&lt;/strong&gt;: New administrators can explore Nginx management without memorizing commands or worrying about syntax errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development Workflows&lt;/strong&gt;: Developers frequently restarting and reconfiguring Nginx during testing benefit from the streamlined interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Diagnostics&lt;/strong&gt;: When troubleshooting issues, rapidly checking logs and service status through a unified interface saves time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remote Server Management&lt;/strong&gt;: When SSH'd into a server, the terminal UI provides an efficient way to manage Nginx without context switching.&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>tui</category>
      <category>go</category>
    </item>
    <item>
      <title>Laravel Pulse card for Clean Architecture UseCase</title>
      <dc:creator>Giacomo Masseroni</dc:creator>
      <pubDate>Mon, 12 Jan 2026 12:08:02 +0000</pubDate>
      <link>https://dev.to/giacomomasseron/laravel-pulse-card-for-clean-architecture-usecase-4kl1</link>
      <guid>https://dev.to/giacomomasseron/laravel-pulse-card-for-clean-architecture-usecase-4kl1</guid>
      <description>&lt;p&gt;When building Laravel applications with Clean Architecture principles, tracking the performance and execution of your UseCases becomes crucial for monitoring application health.&lt;br&gt;&lt;br&gt;
Laravel Pulse provides an excellent framework for real-time application monitoring, and with the &lt;a href="https://github.com/giacomomasseron/php-clean-architecture" rel="noopener noreferrer"&gt;php-clean-architecture package&lt;/a&gt;, you can create custom recorder cards to track UseCase execution metrics.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding the Architecture
&lt;/h2&gt;

&lt;p&gt;The php-clean-architecture package helps you implement Clean Architecture patterns in Laravel by providing a structured approach to UseCases.&lt;br&gt;&lt;br&gt;
When combined with Laravel Pulse, you can gain valuable insights into how your UseCases perform in production.&lt;/p&gt;

&lt;p&gt;Our custom recorder will track two key events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UseCaseStarted&lt;/strong&gt;: Fired when a UseCase begins execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UseCaseCompleted&lt;/strong&gt;: Fired when a UseCase finishes execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By measuring the time between these events, we can calculate execution duration and aggregate statistics.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Custom Recorder
&lt;/h2&gt;

&lt;p&gt;Let's examine the UseCases recorder class that makes this possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

declare(strict_types=1);

namespace App\PulseRecorders;

use App\Events\UseCaseCompleted;
use App\Events\UseCaseStarted;
use Carbon\CarbonImmutable;
use Laravel\Pulse\Facades\Pulse;
use Laravel\Pulse\Recorders\Concerns\Groups;
use Laravel\Pulse\Recorders\Concerns\Ignores;
use Laravel\Pulse\Recorders\Concerns\Sampling;

class UseCases
{
    use Groups;
    use Ignores;
    use Sampling;

    /**
     * The time the last job started processing.
     *
     * @var list&amp;lt;int&amp;gt;
     */
    protected array $lastUseCaseStartedAt = [];

    /**
     * The events to listen for.
     *
     * @var list&amp;lt;class-string&amp;gt;
     */
    public array $listen = [
        UseCaseStarted::class,
        UseCaseCompleted::class,
    ];

    /**
     * Record the request.
     */
    public function record(UseCaseStarted|UseCaseCompleted $event): void
    {
        $now = CarbonImmutable::now();

        if ($event instanceof UseCaseStarted) {
            $this-&amp;gt;lastUseCaseStartedAt[get_class($event-&amp;gt;useCase)] = $now-&amp;gt;getTimestampMs();

            return;
        }

        [$timestamp, $timestampMs, $name, $lastUseCaseStartedAt] = [
            $now-&amp;gt;getTimestamp(),
            $now-&amp;gt;getTimestampMs(),
            get_class($event-&amp;gt;useCase),
            tap($this-&amp;gt;lastUseCaseStartedAt[get_class($event-&amp;gt;useCase)], fn () =&amp;gt; ($this-&amp;gt;lastUseCaseStartedAt[get_class($event-&amp;gt;useCase)] = null)),
        ];

        $duration = $timestampMs - $lastUseCaseStartedAt;

        Pulse::lazy(function () use ($timestamp, $name, $duration) {
            Pulse::record(
                type: 'use_cases',
                key: $name,
                value: $duration,
                timestamp: $timestamp,
            )
                -&amp;gt;count()
                -&amp;gt;avg();
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Event Listening
&lt;/h3&gt;

&lt;p&gt;The recorder listens to two events through the &lt;code&gt;$listen&lt;/code&gt; property. When either event is dispatched, the &lt;code&gt;record()&lt;/code&gt; method is automatically invoked by Laravel Pulse.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracking Start Times
&lt;/h3&gt;

&lt;p&gt;When a &lt;code&gt;UseCaseStarted&lt;/code&gt; event is received, the recorder stores the current timestamp in milliseconds, keyed by the UseCase class name. This creates a simple in-memory registry of when each UseCase type began execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calculating Duration
&lt;/h3&gt;

&lt;p&gt;When a &lt;code&gt;UseCaseCompleted&lt;/code&gt; event arrives, the recorder:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieves the start timestamp for that UseCase class.&lt;/li&gt;
&lt;li&gt;Calculates the duration by subtracting the start time from the current time.&lt;/li&gt;
&lt;li&gt;Records the metric to Pulse with both count and average aggregations.&lt;/li&gt;
&lt;li&gt;Cleans up the stored start timestamp.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Pulse Traits
&lt;/h3&gt;

&lt;p&gt;The recorder uses three standard Pulse concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Groups&lt;/strong&gt;: Allows grouping of recorded data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignores&lt;/strong&gt;: Enables filtering of certain UseCases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sampling&lt;/strong&gt;: Provides sampling capabilities to reduce overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up the Events
&lt;/h2&gt;

&lt;p&gt;You'll need to create two events that your UseCases will dispatch. Here's an example structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Events;

use Illuminate\Foundation\Events\Dispatchable;

class UseCaseStarted
{
    use Dispatchable;

    public function __construct(
        public object $useCase
    ) {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Events;

use Illuminate\Foundation\Events\Dispatchable;

class UseCaseCompleted
{
    use Dispatchable;

    public function __construct(
        public object $useCase
    ) {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring Pulse
&lt;/h2&gt;

&lt;p&gt;Register the recorder in your &lt;code&gt;config/pulse.php&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'recorders' =&amp;gt; [
    // ... other recorders

    \App\PulseRecorders\UseCases::class =&amp;gt; [
        'enabled' =&amp;gt; env('PULSE_USE_CASES_ENABLED', true),
        'sample_rate' =&amp;gt; env('PULSE_USE_CASES_SAMPLE_RATE', 1),
        'ignore' =&amp;gt; [
            // Add UseCase class names to ignore
        ],
    ],
],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the Dashboard Card
&lt;/h2&gt;

&lt;p&gt;To visualize this data, you'll want to create a custom Pulse card. Create a Livewire component that queries the recorded data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Livewire\Pulse;

use Laravel\Pulse\Livewire\Card;
use Livewire\Attributes\Lazy;

#[Lazy]
class UseCases extends Card
{
    use Thresholds;

    /**
     * Ordering.
     *
     * @var 'slowest'|'count'
     */
    #[Url(as: 'use-cases')]
    public string $orderBy = 'slowest';

    /**
     * Render the component.
     */
    public function render(): Renderable
    {
        [$useCases, $time, $runAt] = $this-&amp;gt;remember(
            fn () =&amp;gt; $this-&amp;gt;aggregate(
                'use_cases',
                ['avg', 'count'],
                match ($this-&amp;gt;orderBy) {
                    'count' =&amp;gt; 'count',
                    default =&amp;gt; 'avg',
                },
            )-&amp;gt;map(function ($row) {
                return (object) [
                    'use_case' =&amp;gt; $row-&amp;gt;key,
                    'count' =&amp;gt; $row-&amp;gt;count,
                    'avg' =&amp;gt; $row-&amp;gt;avg,
                ];
            }),
            $this-&amp;gt;orderBy,
        );

        return View::make('pulse.use-cases', [
            'time' =&amp;gt; $time,
            'runAt' =&amp;gt; $runAt,
            'useCases' =&amp;gt; $useCases,
            'config' =&amp;gt; [
                'threshold' =&amp;gt; Config::get('pulse.recorders.'.SlowRequestsRecorder::class.'.threshold'),
                'sample_rate' =&amp;gt; Config::get('pulse.recorders.'.SlowRequestsRecorder::class.'.sample_rate'),
            ],
        ]);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits of This Approach
&lt;/h2&gt;

&lt;p&gt;This recorder provides several advantages for Clean Architecture applications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance Monitoring&lt;/strong&gt;: Track how long each UseCase takes to execute&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage Patterns&lt;/strong&gt;: See which UseCases are called most frequently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bottleneck Identification&lt;/strong&gt;: Quickly identify slow UseCases that need optimization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production Insights&lt;/strong&gt;: Get real-time visibility into your application's business logic layer&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>PHPDocs for Laravel relationships</title>
      <dc:creator>Giacomo Masseroni</dc:creator>
      <pubDate>Fri, 24 Oct 2025 16:29:41 +0000</pubDate>
      <link>https://dev.to/giacomomasseron/phpdocs-for-laravel-relationships-16mh</link>
      <guid>https://dev.to/giacomomasseron/phpdocs-for-laravel-relationships-16mh</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Context&lt;/li&gt;
&lt;li&gt;
Laravel Relationships

&lt;ul&gt;
&lt;li&gt;HasOne&lt;/li&gt;
&lt;li&gt;BelongsTo&lt;/li&gt;
&lt;li&gt;HasMany&lt;/li&gt;
&lt;li&gt;HasManyThrough&lt;/li&gt;
&lt;li&gt;BelongsToMany&lt;/li&gt;
&lt;li&gt;MorphTo&lt;/li&gt;
&lt;li&gt;MorphOne&lt;/li&gt;
&lt;li&gt;MorphMany&lt;/li&gt;
&lt;li&gt;MorphToMany&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;The context: you have a Laravel 10/11/12 project, and you want to use &lt;a href="https://phpstan.org/" rel="noopener noreferrer"&gt;PHPStan&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
You use a PHPStan level 6 (or higher), because it's cool! (and you're right about that).&lt;/p&gt;

&lt;p&gt;You execute the PHPStan command, and this is one of the error you get:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;------ -----------------------------------------------------------------------------------------------------------------------------
  Line   Models\Base\Comment.php
 ------ -----------------------------------------------------------------------------------------------------------------------------
  82     Method App\Models\Base\Comment::commentable() return type with generic class Illuminate\Database\Eloquent\Relations\MorphTo
         does not specify its types: TRelatedModel, TDeclaringModel
         🪪  missingType.generics
 ------ -----------------------------------------------------------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What happened?&lt;/strong&gt; &lt;br&gt;
You have a model defined like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function commentable(): MorphTo  
{  
    return $this-&amp;gt;morphTo(__FUNCTION__, 'commentable_type', 'commentable_id');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Without PHPDoc, PHPStan is unable to check your code to verify if everything is correct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can you fix this?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add this PHPDoc to the function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return MorphTo&amp;lt;Model, $this&amp;gt;  
 */
 public function commentable(): MorphTo  
 {  
     return $this-&amp;gt;morphTo(__FUNCTION__, 'commentable_type', 'commentable_id');  
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Following are all PHPDocs you need to add to Laravel relationships to pass PHPStan level &amp;gt; 6 check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Laravel Relationships
&lt;/h2&gt;

&lt;h3&gt;
  
  
  HasOne
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return HasOne&amp;lt;PostFollowingPost, $this&amp;gt;  
 */
public function postFollowingPostsAsFollowing(): HasOne
{  
    return $this-&amp;gt;hasOne(PostFollowingPost::class, 'following_id', 'id');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  BelongsTo
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return BelongsTo&amp;lt;Post, $this&amp;gt;  
 */
public function post(): BelongsTo  
{  
    return $this-&amp;gt;belongsTo(Post::class, 'id_post');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  HasMany
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return HasMany&amp;lt;PostFollowingPost, $this&amp;gt;  
 */
public function postFollowingPostsAsFollowing(): HasMany  
{  
    return $this-&amp;gt;hasMany(PostFollowingPost::class, 'following_id', 'id');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  HasOneThrough
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return HasOneThrough&amp;lt;Post, Pivot, $this&amp;gt;
 */
public function posts(): HasOneThrough
{  
    return $this-&amp;gt;hasOneThrough(Post::class, Pivot::class, 'post_id', 'id');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  HasManyThrough
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return HasManyThrough&amp;lt;Post, Pivot, $this&amp;gt; 
 */
public function posts(): HasManyThrough
{  
    return $this-&amp;gt;hasManyThrough(Post::class, Pivot::class, 'post_id', 'id');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  BelongsToMany
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return BelongsToMany&amp;lt;Post, $this&amp;gt;
 */
public function posts(): BelongsToMany
{  
    return $this-&amp;gt;belongsToMany(Post::class, 'post_id', 'id');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  MorphTo
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return MorphTo&amp;lt;Model, $this&amp;gt;  
 */
 public function commentable(): MorphTo  
 {  
     return $this-&amp;gt;morphTo(__FUNCTION__, 'commentable_type', 'commentable_id');  
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  MorphOne
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return MorphOne&amp;lt;Post, $this&amp;gt;  
 */
public function post(): MorphOne
{  
    return $this-&amp;gt;morphOne(Post::class, 'postable');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  MorphMany
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
 * @return MorphMany&amp;lt;Post, $this&amp;gt;
 */
public function posts(): MorphMany
{  
    return $this-&amp;gt;morphMany(Post::class, 'postable');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  MorphToMany
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**  
* @return MorphToMany&amp;lt;Post, $this&amp;gt;  
*/
public function posts(): MorphToMany
{  
    return $this-&amp;gt;morphToMany(Post::class, 'name');  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I developed a package to generate Laravel Models from an existing database.&lt;br&gt;&lt;br&gt;
The package generates code PHPStan level max compliant:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/giacomomasseron/laravel-models-generator" rel="noopener noreferrer"&gt;https://github.com/giacomomasseron/laravel-models-generator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Clean Architecture in a Laravel project</title>
      <dc:creator>Giacomo Masseroni</dc:creator>
      <pubDate>Mon, 13 Oct 2025 14:21:25 +0000</pubDate>
      <link>https://dev.to/giacomomasseron/clean-architecture-in-a-laravel-project-3oh3</link>
      <guid>https://dev.to/giacomomasseron/clean-architecture-in-a-laravel-project-3oh3</guid>
      <description>&lt;h1&gt;
  
  
  What is The Clean Architecture structure?
&lt;/h1&gt;

&lt;p&gt;“Clean Architecture” is a project structure first mentioned by Robert C. Martin (Uncle Bob).&lt;/p&gt;

&lt;p&gt;At first glance, this is the diagram of the structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flu83l3grmorszz82jfbw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flu83l3grmorszz82jfbw.jpg" alt="enter image description here" width="772" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The structure is divided in layers, where each layer does have a precise function, separated from the others.&lt;br&gt;
The simplest and more important rule of this structure is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An inner circle must never know anything about the circles around it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To learn more about the benefits of this structure, and see the levels in detail, you can read the article on Uncle Bob's blog.&lt;/p&gt;

&lt;p&gt;What we want to do today, is apply this structure in a Laravel project that uses the &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" rel="noopener noreferrer"&gt;MVC (Model-View-Controller) design pattern&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s go through every level.&lt;/p&gt;
&lt;h1&gt;
  
  
  Entities
&lt;/h1&gt;

&lt;p&gt;TL;DR: this layer contains "Enterprise Business Rules”.&lt;/p&gt;

&lt;p&gt;This is the layer that should change less during the development of the project.&lt;br&gt;
Why?&lt;br&gt;
Because the objects inside this layer contain the enterprise wide business rules, and usually they are defined at the start of the project (or at the start of a new feature).&lt;/p&gt;

&lt;p&gt;In a Laravel project there is no Entity concept: we have to create it.&lt;br&gt;
We can create a folder inside the app folder, called “Entities”.&lt;/p&gt;
&lt;h1&gt;
  
  
  Use Cases
&lt;/h1&gt;

&lt;p&gt;TL;DR: this layer contains the actions your project performs.&lt;/p&gt;

&lt;p&gt;Good examples of use cases are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login&lt;/li&gt;
&lt;li&gt;Register&lt;/li&gt;
&lt;li&gt;ConfirmOrder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;A use case should be a single, very specific action. It shouldn’t do anything more than its name suggests.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you structure your project with use cases, you get an unexpected and very powerful benefit: &lt;em&gt;you are creating your project’s documentation&lt;/em&gt;.&lt;br&gt;
If an external developer looks at your use cases list, it understands exactly what your project is about.&lt;/p&gt;

&lt;p&gt;In a Laravel project there is no UseCase concept: we have to create it.&lt;br&gt;
We can create a folder inside the app folder, called “UseCases”.&lt;/p&gt;
&lt;h1&gt;
  
  
  Interface adapters
&lt;/h1&gt;

&lt;p&gt;TL;DR: this layer contains all MVC elements.&lt;/p&gt;

&lt;p&gt;This is the most controversial and ambiguous layer. &lt;br&gt;
Many classes could be inside it, it’s the developer choice.&lt;/p&gt;

&lt;p&gt;For start, the best decision in a Laravel project is to put inside it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Models&lt;/li&gt;
&lt;li&gt;Views&lt;/li&gt;
&lt;li&gt;Controllers&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  At the end of the day, how should I develop?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;In a Laravel controller, you can just call an UseCase.&lt;/li&gt;
&lt;li&gt;In an UseCase, you can just call classes in the Entity layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example of Laravel controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\UseCases\LoginUseCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Http\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;LoginUseCase&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if I have to update a database model in an UseCase?&lt;/p&gt;

&lt;p&gt;Since a model is in the Interface Adapters layer, an UseCase must not depend on a lower layer.&lt;/p&gt;

&lt;p&gt;So we add the Repository pattern to abstract the Database and to create &lt;a href="https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29" rel="noopener noreferrer"&gt;coupling&lt;/a&gt; only between UseCase and Repository.&lt;/p&gt;

&lt;p&gt;In a Laravel project there is no Repository concept: we have to create it.&lt;br&gt;
We can create a folder inside the app folder, called “Repositories”.&lt;/p&gt;

&lt;p&gt;An example of UseCase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\UseCases&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Repositories\UserRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginUseCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nv"&gt;$arguments&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;mixed&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our Laravel project structure will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app
    Http
    Entities
    Models
    Providers
    Repositories
    UseCases
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Best practices
&lt;/h1&gt;

&lt;p&gt;Always work with interfaces.&lt;/p&gt;

&lt;p&gt;You should create interfaces for every layer, in order to keep your code more stable and maintainable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EntityInterface&lt;/li&gt;
&lt;li&gt;UseCaseInterface&lt;/li&gt;
&lt;li&gt;RepositoryInterface&lt;/li&gt;
&lt;li&gt;ArchitectureControllerInterfacer&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Now what?
&lt;/h1&gt;

&lt;p&gt;There are a lot of improvements you can do. These are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Laravel validation rules for validating parameters passed to use case;&lt;/li&gt;
&lt;li&gt;Work with dependency injection and substitute the static run function with a not static run function;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I developed a &lt;a href="https://github.com/giacomomasseron/php-clean-architecture" rel="noopener noreferrer"&gt;PHP package on Github&lt;/a&gt; to use it.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>php</category>
      <category>laravel</category>
      <category>cleancode</category>
    </item>
  </channel>
</rss>
