juampi92/phpstan-eloquent-bounded-context

PHPStan rules that make sure your models are only being mutated from within its Domain.

v1.1 2022-09-26 22:59 UTC

This package is auto-updated.

Last update: 2024-03-30 00:37:57 UTC


README

A set of PHPStan rules to make sure your models are only being mutated from within their Domains.

Latest Version on Packagist GitHub Tests Action Status Total Downloads

Description

These rules will detect when your Eloquent Model is being mutated outside of its Domain. The moment the Model leaves the Domain namespace, it becomes read-only.

Let's assume the following structure:

📁 app
├─ 📁 Http
│  └─ 📁 Controllers
│     └─ 📃 PostController.php
└─ 📁 Domains
   └─ 📁 Posts
      └─ 📁 Actions
         └─ 📃 CreatePostAction.php
      └─ 📁 Models
         └─ 📃 Post.php
         └─ 📃 Comment.php

If app/Http/Controllers/PostController.php has the following method:

public function store(Request $request)
{
    $post = new Post($request->validated());
    $post->save();
}

PHPStan will fail saying:

 ---------------------------------------------------------------------------
  app/Http/Controllers/PostController.php
 ---------------------------------------------------------------------------
  Calling 'save' on 'App\Models\Post' outside of its Domain is not allowed.
 ---------------------------------------------------------------------------

To fix this error, instead of calling save inside the Controller directly, create an Action inside the Post domain (or a PostService class) and use that class to create and persist the model.

This package will also detect:

  • Model attribute mutations like: $post->title = 'My title';,
  • Methods persist the data in the database, like save, update, delete, etc,
  • Static methods that persist the data, like ::create(), ::updateOrCreate(), etc.

Installation

To use this extension, require it in Composer:

composer require --dev juampi92/phpstan-eloquent-bounded-context

If you also install phpstan/extension-installer then you're all set!

Manual installation

If you don't want to use phpstan/extension-installer, include extension.neon in your project's PHPStan config:

includes:
    - vendor/juampi92/phpstan-eloquent-bounded-context/extension.neon

Configuration

No configuration

If your models are placed inside their Domain folder, the package will know they are not using Laravel's default folders, and assume the domain is App/Domains/Posts. Any class inside that domain is allowed to mutate an eloquent model.

📁 app
├─ 📁 Domains
│  └─ 📁 Posts
│  |  └─ 📁 Actions
│  |  └─ 📁 Repositories
│  |  └─ 📁 Models ✅
│  |     └─ 📃 Post.php
│  |     └─ 📃 Comment.php
│  └─ 📁 Users
│     └─  ...
└── ...

Manual configuration

If your models are placed inside App\Models, then you will have to configure your domain manually. To do so, you must first create a configuration file that holds the information about your models and domains:

domains:
  -
    namespace: App\Domain\Posts
    models:
      - App\Models\Post
      - App\Models\Comment
  -
    namespace: App\Domain\Users
    models:
      - App\Models\User
      - App\Models\UserProfile

And after you must reference this file inside the phpstan.neon.dist config:

parameters:
	eloquentBoundedContextConfigFiles:
	    - app/Domain/domains.yml

Configuring ignored namespaces

You might want to ignore some namespaces and allow Models to be modified there.

parameters:
	eloquentBoundedContextConfigFiles:
		- app/Domain/domains.yml
	eloquentBoundedContextIgnoredNamespaces:
		- Database\Factories
		- Tests

Contribute

Features to do:

  • Ignore no-configuration resolution when a config is used.
  • Propose /** @mutates */ tag or #Attribute to prohibit these methods being called outside of the domain.

Testing

./vendor/bin/phpunit

Credits

License

The MIT License (MIT). Please see License File for more information.