PHPStan and Doctrine: $id is never written, only read
Asked Answered
R

4

9

I am using PHP8, symfony5 and doctrine2 with phpstan and getting these errors:

Property App\Entity\User::$id is never written, only read.  

The code:

<?php

namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;

/**
 * @ORM\Table(name="`user`")
 * @ORM\Entity(repositoryClass=UserRepository::class)
 * @UniqueEntity(fields={"email"}, message="There is already an account with this email")
 */
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    public const ROLE_USER = 'ROLE_USER';
    public const ROLE_ADMIN = 'ROLE_ADMIN';

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, unique=true)
     */
    private $email;

    /**
     * @ORM\Column(type="json")
     */
    private $roles = [];

    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\Column(type="boolean")
     */
    private $isVerified = false;

    public function __construct()
    {
        $this->audioSessions = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUserIdentifier(): string
    {
        return (string) $this->email;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

    /**
     * @see PasswordAuthenticatedUserInterface
     */
    public function getPassword(): string
    {
        return $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    public function isVerified(): bool
    {
        return $this->isVerified;
    }

    public function setIsVerified(bool $isVerified): self
    {
        $this->isVerified = $isVerified;

        return $this;
    }
}

The code is correct which is also acknowledged by PHPStan as described here: https://phpstan.org/blog/detecting-unused-private-properties-methods-constants#what-if-my-code-is-%E2%80%9Cspecial%E2%80%9D%3F

So how can i solve these error message in PHPStan?

I tried installing https://github.com/phpstan/phpstan-doctrine and enabled this in my phpstan.neon file:

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

But the error still persists.

Rema answered 5/11, 2021 at 10:4 Comment(4)
Please show your Doctrine entity in question.Ovate
@OndřejMirtes i added the entitiy code.Rema
This should work fine. Please create a small reproducing repository and submit this as an issue to github.com/phpstan/phpstan-doctrine. Thanks.Ovate
Repository is created and issue is filed: github.com/phpstan/phpstan-doctrine/issues/229Rema
H
5

You need to configure objectManagerLoader so that the extension can see the entity metadata. This will allow DQL validation, and the correct entity repositoryClass to be inferred when accessing $entityManager->getRepository(). Add to your phpstan.neon:

parameters:
    doctrine:
        objectManagerLoader: tests/object-manager.php

Example for Symfony 5:

// tests/object-manager.php

use App\Kernel;
use Symfony\Component\Dotenv\Dotenv;

require __DIR__ . '/../vendor/autoload.php';

(new Dotenv())->bootEnv(__DIR__ . '/../.env');

$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$kernel->boot();
return $kernel->getContainer()->get('doctrine')->getManager();

From the documentation: https://github.com/phpstan/phpstan-doctrine#configuration

Hamhung answered 19/11, 2021 at 15:38 Comment(3)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Stress
This works indeed :).Rema
i accept the answer but it would probably be better if you copy the necessary parts from the docs to your answer.Rema
T
5

I am using phpstan ignore errors (https://phpstan.org/user-guide/ignoring-errors). To narrow the scope, my path is set to entity directory only.

# ./phpstan.neon

parameters:
    ignoreErrors:
        -
          message: '#Property [a-zA-Z0-9\\_]+::\$id is never written, only read.#'
          path: src/Entity/*
Travel answered 21/12, 2021 at 14:3 Comment(0)
A
0

Since this RFC is implemented, PHPStan implemented this feature in the 1.4 version. Unforthunully, there is no @readonly attribute (at least for the moment) that can be used with PHP < 8. For more detail, feel free to see this issue.

Ani answered 21/2, 2022 at 14:15 Comment(0)
O
0

i've ignored this error by adding this lines to my phpstan.dist.neon file

    ignoreErrors:
    - '#Property .+::\$id is never written, only read\.#'
Oakes answered 15/1 at 9:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.