nijidigital/phpstan-rules

custom phpstan rules created by dsf-niji

Installs: 308

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 1

Open Issues: 1

Type:phpstan-extension

pkg:composer/nijidigital/phpstan-rules

v2.1.1 2025-10-02 14:49 UTC

This package is auto-updated.

Last update: 2025-10-02 14:51:24 UTC


README

Custom PhpStan rules made with ❤️ by Niji.

Installation

To use this extension, require it in Composer:

composer require --dev nijidigital/phpstan-rules

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/nijidigital/phpstan-rules/extension.neon

Existing rules

NoRelativeDatetime

Prevents usage of relative date/time strings and empty constructors in DateTime and DateTimeImmutable to ensure consistent and testable date handling.

Examples

Invalid:

// Empty constructors
$now = new \DateTime();
$now = new \DateTimeImmutable();

// Relative date strings
$yesterday = new \DateTime('yesterday');
$nextMonth = new \DateTime('next month');
$twoHoursLater = new \DateTimeImmutable('+2 hours');

Valid alternatives:

// Use absolute dates for fixed dates
$fixedDate = new \DateTime('2025-07-01 13:12:11');

// Use ClockInterface for current time and modifications
function doSomethingWithTime(ClockInterface $clock) {
    $now = $clock->now();
    $yesterday = $clock->now()->modify('-1 day');
    $nextMonth = $clock->now()->modify('+1 month');

    // (...)
}

DoctrineMigrationsSafeMigration

Detects potentially unsafe database migration operations that could break backward compatibility in Doctrine migrations. Operations can be marked as safe using PHPStan's standard @phpstan-ignore comment.

Examples

Invalid:

class UnsafeMigration extends AbstractMigration
{
    public function up(Schema $schema): void
    {
        // These operations may not be backward compatible
        $this->addSql('DROP TABLE user');
        $this->addSql('ALTER TABLE user CHANGE name email VARCHAR(255)');
        $this->addSql('ALTER TABLE user DROP COLUMN name');
        $this->addSql('DROP DATABASE test');
        $this->addSql('TRUNCATE TABLE user');
    }
}

Valid alternatives:

class SafeMigration extends AbstractMigration
{
    public function up(Schema $schema): void
    {
        // Safe operations (no ignore comment needed)
        $this->addSql('ALTER TABLE user ADD COLUMN email VARCHAR(255)');
        $this->addSql('CREATE INDEX idx_user_email ON user (email)');
        $this->addSql('INSERT INTO user (name) VALUES (\'John\')');

        // Unsafe operations marked as intentionally safe
        /* @phpstan-ignore doctrineMigrations.unsafeMigration */
        $this->addSql('DROP TABLE legacy_user');

        /* @phpstan-ignore doctrineMigrations.unsafeMigration */
        $this->addSql('ALTER TABLE user CHANGE name full_name VARCHAR(255)');
    }
}

Configuration

You can customize the behavior of this rule using the parameters section in your phpstan.neon configuration:

parameters:
    niji:
        doctrineMigrations:
            safeMigration:
                # Custom list of blacklisted SQL patterns with their error messages
                blacklistedQueries:
                    '/DROP\s+TABLE\s+/im': 'Dropping tables is not allowed'
                    '/ALTER\s+TABLE\s+.+\s+DROP\s+COLUMN/im': 'Dropping columns breaks backward compatibility'

Available options:

  • blacklistedQueries: Array of regex patterns (as keys) with their corresponding error messages (as values). If not specified, uses default patterns for common unsafe operations.

DoctrineMigrationsDescription

Ensures that Doctrine migration classes provide meaningful descriptions by validating the return value of the getDescription() method against a configurable pattern.

Examples

Invalid:

class MyMigration extends AbstractMigration
{
    public function getDescription(): string
    {
        return ''; // Empty description
    }

    public function up(Schema $schema): void
    {
        $this->addSql('ALTER TABLE user ADD COLUMN email VARCHAR(255)');
    }
}

Valid:

class MyMigration extends AbstractMigration
{
    public function getDescription(): string
    {
        return 'Add email column to user table';
    }

    public function up(Schema $schema): void
    {
        $this->addSql('ALTER TABLE user ADD COLUMN email VARCHAR(255)');
    }
}

Configuration

By default, the rule accepts any non-empty string. You can customize the accepted pattern using the parameters section in your phpstan.neon configuration:

parameters:
    niji:
        doctrineMigrations:
            description:
                # Custom regex pattern for migration descriptions
                acceptedPattern: '/^[A-Z][a-z0-9\s]+\.?$/'

Available options:

  • acceptedPattern: A regex pattern that migration descriptions must match. Defaults to /.+/im (any non-empty string).

Troubleshooting

PhpStorm doesn't provide any autocomplete on PhpStan classes

Taken from [this blog](https://blog.bitexpert.de/blog/phpstorm_phpstan_wsl2_issue) :
1. Copy the file `vendor/phpstan/phpstan/phpstan.phar` to a local folder of your choice, ie : `C:\php_include_path`.
2. In PhpStorm, go to File | Settings | PHP and add your newly created folder to the include path.