Skip to content

About

Custom PHPStan rules and extensions for EsfahanAhan.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

EsfahanAhan PHPStan rules

Latest Version on Packagist Tests Total Downloads PHP Version License

Written by Hossein Hosni.

Usage docs: https://esfahanahan.github.io/phpstan-rules

Requirements

The nested eager-load rule inspects Eloquent with() call sites. The package does not depend on illuminate/*.

Installation

composer require --dev esfahanahan/phpstan-rules

The dev keyword in composer.json makes Composer offer to install this package into require-dev when composer require is run without --dev.

With phpstan/extension-installer, that is enough. The installer loads extension.neon.

Allow the plugin once:

{
    "config": {
        "allow-plugins": {
            "phpstan/extension-installer": true
        }
    }
}

Without the installer, include the extension yourself:

includes:
    - vendor/esfahanahan/phpstan-rules/extension.neon

extension.neon is the file to export. This package will hold rules and other PHPStan extensions (type, reflection, and similar). rules.neon only fits a package that is a ruleset and nothing else.

Rules

Nested eager-load with() must not drop a parent callback

Identifier: esfahanahan.nestedEagerLoadOverwritesConstraint

A later with() for a child relation replaces the parent callback registered by an earlier with().

User has many Posts, and Post has many Comments. Users 1 and 2 exist. User 1 has published post 10 and unpublished post 12. User 2 has published post 11. Splitting the constraints across two with() calls drops where('published', true):

$users = User::query()
    ->with([
        'posts' => static function (Relation $query): void {
            $query->where('published', true);
        },
    ])
    ->with([
        'posts.comments' => static function (Relation $query): void {
            $query->where('approved', true);
        },
    ])
    ->get();

Query log:

select * from `users`
bindings: []

select * from `posts` where `posts`.`user_id` in (?, ?)
bindings: [1, 2]

select * from `comments` where `comments`.`post_id` in (?, ?, ?) and `approved` = ?
bindings: [10, 11, 12, 1]

published is missing from the posts query, so unpublished post 12 is loaded.

Pass both relations in one with() array:

$users = User::query()
    ->with([
        'posts' => static function (Relation $query): void {
            $query->where('published', true);
        },
        'posts.comments' => static function (Relation $query): void {
            $query->where('approved', true);
        },
    ])
    ->get();

Query log:

select * from `users`
bindings: []

select * from `posts` where `posts`.`user_id` in (?, ?) and `published` = ?
bindings: [1, 2, 1]

select * from `comments` where `comments`.`post_id` in (?, ?) and `approved` = ?
bindings: [10, 11, 1]

Both constraints run. Comments load only for published posts 10 and 11. The usage doc shows the safe order when a child callback calls a model scope.

load() has the same result. Each call runs immediately, and posts.comments reloads posts with an empty callback, so the published posts are replaced:

$users->load([
    'posts' => static function (Relation $query): void {
        $query->where('published', true);
    },
]);

$users->load([
    'posts.comments' => static function (Relation $query): void {
        $query->where('approved', true);
    },
]);

Pass both relations in one load() array, or call loadMissing() for posts.comments when posts is already loaded. loadMissing() does not reload posts.

Laravel Boost

The package ships a skill at resources/boost/skills/eloquent-nested-eager-loads. Boost discovers that directory on a direct dependency. Add esfahanahan/phpstan-rules to boost.json packages, keep eloquent-nested-eager-loads in skills, then run Boost's update.

Credit

Written by Hossein Hosni.

Development

composer install
composer test
composer phpstan
composer format

About

Custom PHPStan rules and extensions for EsfahanAhan.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages