Skip to content

Commit 6511204

Browse files
committed
bug #1370 Fix issues reported by PHPStan #1334 (kniziol)
This PR was squashed before being merged into the main branch. Discussion ---------- Fix issues reported by PHPStan #1334 Closes #1334 Commits ------- 773f504 Fix issues reported by PHPStan #1334
2 parents 9172868 + 773f504 commit 6511204

32 files changed

+271
-518
lines changed

phpstan-baseline.neon

-457
Large diffs are not rendered by default.

phpstan.neon.dist

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
includes:
2-
- phpstan-baseline.neon
3-
41
parameters:
52
level: max
63
paths:

src/Command/AddUserCommand.php

+11-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ protected function interact(InputInterface $input, OutputInterface $output): voi
129129
}
130130

131131
// Ask for the password if it's not defined
132+
/** @var string|null $password */
132133
$password = $input->getArgument('password');
134+
133135
if (null !== $password) {
134136
$this->io->text(' > <info>Password</info>: '.u('*')->repeat(u($password)->length()));
135137
} else {
@@ -165,10 +167,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int
165167
$stopwatch = new Stopwatch();
166168
$stopwatch->start('add-user-command');
167169

170+
/** @var string $username */
168171
$username = $input->getArgument('username');
172+
173+
/** @var string $plainPassword */
169174
$plainPassword = $input->getArgument('password');
175+
176+
/** @var string $email */
170177
$email = $input->getArgument('email');
178+
179+
/** @var string $fullName */
171180
$fullName = $input->getArgument('full-name');
181+
172182
$isAdmin = $input->getOption('admin');
173183

174184
// make sure to validate the user data is correct
@@ -198,7 +208,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
198208
return Command::SUCCESS;
199209
}
200210

201-
private function validateUserData($username, $plainPassword, $email, $fullName): void
211+
private function validateUserData(string $username, string $plainPassword, string $email, string $fullName): void
202212
{
203213
// first check if a user with the same username already exists.
204214
$existingUser = $this->users->findOneBy(['username' => $username]);

src/Command/DeleteUserCommand.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ protected function interact(InputInterface $input, OutputInterface $output): voi
107107

108108
protected function execute(InputInterface $input, OutputInterface $output): int
109109
{
110-
$username = $this->validator->validateUsername($input->getArgument('username'));
110+
/** @var string|null $username */
111+
$username = $input->getArgument('username');
112+
$username = $this->validator->validateUsername($username);
111113

112114
/** @var User|null $user */
113115
$user = $this->users->findOneByUsername($username);

src/Command/ListUsersCommand.php

+12-4
Original file line numberDiff line numberDiff line change
@@ -88,20 +88,25 @@ protected function configure(): void
8888
*/
8989
protected function execute(InputInterface $input, OutputInterface $output): int
9090
{
91+
/** @var int|null $maxResults */
9192
$maxResults = $input->getOption('max-results');
93+
9294
// Use ->findBy() instead of ->findAll() to allow result sorting and limiting
9395
$allUsers = $this->users->findBy([], ['id' => 'DESC'], $maxResults);
9496

95-
// Doctrine query returns an array of objects and we need an array of plain arrays
96-
$usersAsPlainArrays = array_map(static function (User $user) {
97+
$createUserArray = static function (User $user) {
9798
return [
9899
$user->getId(),
99100
$user->getFullName(),
100101
$user->getUsername(),
101102
$user->getEmail(),
102103
implode(', ', $user->getRoles()),
103104
];
104-
}, $allUsers);
105+
};
106+
107+
// Doctrine query returns an array of objects, and we need an array of plain arrays
108+
/** @var callable $createUserArray */
109+
$usersAsPlainArrays = array_map($createUserArray, $allUsers);
105110

106111
// In your console commands you should always use the regular output type,
107112
// which outputs contents directly in the console window. However, this
@@ -119,7 +124,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int
119124
$usersAsATable = $bufferedOutput->fetch();
120125
$output->write($usersAsATable);
121126

122-
if (null !== $email = $input->getOption('send-to')) {
127+
/** @var string $email */
128+
$email = $input->getOption('send-to');
129+
130+
if (null !== $email) {
123131
$this->sendReport($usersAsATable, $email);
124132
}
125133

src/Controller/Admin/BlogController.php

+11-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Doctrine\ORM\EntityManagerInterface;
2020
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
2121
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
22+
use Symfony\Component\Form\SubmitButton;
2223
use Symfony\Component\HttpFoundation\Request;
2324
use Symfony\Component\HttpFoundation\Response;
2425
use Symfony\Component\Routing\Annotation\Route;
@@ -80,7 +81,8 @@ public function new(
8081

8182
// See https://symfony.com/doc/current/form/multiple_buttons.html
8283
$form = $this->createForm(PostType::class, $post)
83-
->add('saveAndCreateNew', SubmitType::class);
84+
->add('saveAndCreateNew', SubmitType::class)
85+
;
8486

8587
$form->handleRequest($request);
8688

@@ -98,7 +100,10 @@ public function new(
98100
// See https://symfony.com/doc/current/controller.html#flash-messages
99101
$this->addFlash('success', 'post.created_successfully');
100102

101-
if ($form->get('saveAndCreateNew')->isClicked()) {
103+
/** @var SubmitButton $submit */
104+
$submit = $form->get('saveAndCreateNew');
105+
106+
if ($submit->isClicked()) {
102107
return $this->redirectToRoute('admin_post_new');
103108
}
104109

@@ -156,7 +161,10 @@ public function edit(Request $request, Post $post, EntityManagerInterface $entit
156161
#[IsGranted('delete', subject: 'post')]
157162
public function delete(Request $request, Post $post, EntityManagerInterface $entityManager): Response
158163
{
159-
if (!$this->isCsrfTokenValid('delete', $request->request->get('token'))) {
164+
/** @var string|null $token */
165+
$token = $request->request->get('token');
166+
167+
if (!$this->isCsrfTokenValid('delete', $token)) {
160168
return $this->redirectToRoute('admin_post_index');
161169
}
162170

src/Controller/BlogController.php

+16-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use App\Entity\Comment;
1515
use App\Entity\Post;
16+
use App\Entity\Tag;
1617
use App\Entity\User;
1718
use App\Event\CommentCreatedEvent;
1819
use App\Form\CommentType;
@@ -52,6 +53,7 @@ public function index(Request $request, int $page, string $_format, PostReposito
5253
{
5354
$tag = null;
5455
if ($request->query->has('tag')) {
56+
/** @var Tag $tag */
5557
$tag = $tags->findOneBy(['name' => $request->query->get('tag')]);
5658
}
5759
$latestPosts = $posts->findLatest($page, $tag);
@@ -155,8 +157,8 @@ public function commentForm(Post $post): Response
155157
#[Route('/search', methods: ['GET'], name: 'blog_search')]
156158
public function search(Request $request, PostRepository $posts): Response
157159
{
158-
$query = $request->query->get('q', '');
159-
$limit = $request->query->get('l', 10);
160+
$query = (string) $request->query->get('q', '');
161+
$limit = (int) $request->query->get('l', 10);
160162

161163
if (!$request->isXmlHttpRequest()) {
162164
return $this->render('blog/search.html.twig', ['query' => $query]);
@@ -166,11 +168,20 @@ public function search(Request $request, PostRepository $posts): Response
166168

167169
$results = [];
168170
foreach ($foundPosts as $post) {
171+
/** @var string $author */
172+
$author = $post->getAuthor() ? $post->getAuthor()->getFullName() : '';
173+
174+
/** @var string $title */
175+
$title = $post->getTitle();
176+
177+
/** @var string $summary */
178+
$summary = $post->getSummary();
179+
169180
$results[] = [
170-
'title' => htmlspecialchars($post->getTitle(), \ENT_COMPAT | \ENT_HTML5),
181+
'title' => htmlspecialchars($title, \ENT_COMPAT | \ENT_HTML5),
171182
'date' => $post->getPublishedAt()->format('M d, Y'),
172-
'author' => htmlspecialchars($post->getAuthor()->getFullName(), \ENT_COMPAT | \ENT_HTML5),
173-
'summary' => htmlspecialchars($post->getSummary(), \ENT_COMPAT | \ENT_HTML5),
183+
'author' => htmlspecialchars($author, \ENT_COMPAT | \ENT_HTML5),
184+
'summary' => htmlspecialchars($summary, \ENT_COMPAT | \ENT_HTML5),
174185
'url' => $this->generateUrl('blog_post', ['slug' => $post->getSlug()]),
175186
];
176187
}

src/Controller/UserController.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ public function changePassword(
6868
$form->handleRequest($request);
6969

7070
if ($form->isSubmitted() && $form->isValid()) {
71-
$user->setPassword($passwordHasher->hashPassword($user, $form->get('newPassword')->getData()));
71+
/** @var string $plainPassword */
72+
$plainPassword = $form->get('newPassword')->getData();
73+
74+
$user->setPassword($passwordHasher->hashPassword($user, $plainPassword));
7275
$entityManager->flush();
7376

7477
return $this->redirectToRoute('security_logout');

src/DataFixtures/AppFixtures.php

+26-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Doctrine\Bundle\FixturesBundle\Fixture;
1919
use Doctrine\Persistence\ObjectManager;
2020
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
21+
use Symfony\Component\String\AbstractUnicodeString;
2122
use Symfony\Component\String\Slugger\SluggerInterface;
2223
use function Symfony\Component\String\u;
2324

@@ -67,6 +68,8 @@ private function loadTags(ObjectManager $manager): void
6768

6869
private function loadPosts(ObjectManager $manager): void
6970
{
71+
/** @var User $author */
72+
/** @var array<Tag> $tags */
7073
foreach ($this->getPostData() as [$title, $slug, $summary, $content, $publishedAt, $author, $tags]) {
7174
$post = new Post();
7275
$post->setTitle($title);
@@ -78,8 +81,11 @@ private function loadPosts(ObjectManager $manager): void
7881
$post->addTag(...$tags);
7982

8083
foreach (range(1, 5) as $i) {
84+
/** @var User $commentAuthor */
85+
$commentAuthor = $this->getReference('john_user');
86+
8187
$comment = new Comment();
82-
$comment->setAuthor($this->getReference('john_user'));
88+
$comment->setAuthor($commentAuthor);
8389
$comment->setContent($this->getRandomText(random_int(255, 512)));
8490
$comment->setPublishedAt(new \DateTime('now + '.$i.'seconds'));
8591

@@ -92,6 +98,9 @@ private function loadPosts(ObjectManager $manager): void
9298
$manager->flush();
9399
}
94100

101+
/**
102+
* @return array<array{string, string, string, string, array<string>}>
103+
*/
95104
private function getUserData(): array
96105
{
97106
return [
@@ -102,6 +111,9 @@ private function getUserData(): array
102111
];
103112
}
104113

114+
/**
115+
* @return string[]
116+
*/
105117
private function getTagData(): array
106118
{
107119
return [
@@ -117,6 +129,11 @@ private function getTagData(): array
117129
];
118130
}
119131

132+
/**
133+
* @throws \Exception
134+
*
135+
* @return array<int, array{0: string, 1: AbstractUnicodeString, 2: string, 3: string, 4: \DateTime, 5: object, 6: array<object>}>
136+
*/
120137
private function getPostData(): array
121138
{
122139
$posts = [];
@@ -137,6 +154,9 @@ private function getPostData(): array
137154
return $posts;
138155
}
139156

157+
/**
158+
* @return string[]
159+
*/
140160
private function getPhrases(): array
141161
{
142162
return [
@@ -226,6 +246,11 @@ private function getPostContent(): string
226246
MARKDOWN;
227247
}
228248

249+
/**
250+
* @throws \Exception
251+
*
252+
* @return array<object>
253+
*/
229254
private function getRandomTags(): array
230255
{
231256
$tagNames = $this->getTagData();

src/Entity/Post.php

+8-2
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,14 @@ class Post
6666
private ?User $author = null;
6767

6868
/**
69-
* @var Comment[]|Collection
69+
* @var Collection<int, Comment>
7070
*/
7171
#[ORM\OneToMany(targetEntity: Comment::class, mappedBy: 'post', orphanRemoval: true, cascade: ['persist'])]
7272
#[ORM\OrderBy(['publishedAt' => 'DESC'])]
7373
private Collection $comments;
7474

7575
/**
76-
* @var Tag[]|Collection
76+
* @var Collection<int, Tag>
7777
*/
7878
#[ORM\ManyToMany(targetEntity: Tag::class, cascade: ['persist'])]
7979
#[ORM\JoinTable(name: 'symfony_demo_post_tag')]
@@ -143,6 +143,9 @@ public function setAuthor(User $author): void
143143
$this->author = $author;
144144
}
145145

146+
/**
147+
* @return Collection<int, Comment>
148+
*/
146149
public function getComments(): Collection
147150
{
148151
return $this->comments;
@@ -185,6 +188,9 @@ public function removeTag(Tag $tag): void
185188
$this->tags->removeElement($tag);
186189
}
187190

191+
/**
192+
* @return Collection<int, Tag>
193+
*/
188194
public function getTags(): Collection
189195
{
190196
return $this->tags;

src/Entity/User.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
5353
#[ORM\Column(type: Types::STRING)]
5454
private ?string $password = null;
5555

56+
/**
57+
* @var string[]
58+
*/
5659
#[ORM\Column(type: Types::JSON)]
5760
private array $roles = [];
5861

@@ -73,7 +76,7 @@ public function getFullName(): ?string
7376

7477
public function getUserIdentifier(): string
7578
{
76-
return $this->username;
79+
return (string) $this->username;
7780
}
7881

7982
public function getUsername(): string
@@ -121,6 +124,9 @@ public function getRoles(): array
121124
return array_unique($roles);
122125
}
123126

127+
/**
128+
* @param string[] $roles
129+
*/
124130
public function setRoles(array $roles): void
125131
{
126132
$this->roles = $roles;
@@ -151,12 +157,18 @@ public function eraseCredentials(): void
151157
// $this->plainPassword = null;
152158
}
153159

160+
/**
161+
* @return array{int|null, string|null, string|null}
162+
*/
154163
public function __serialize(): array
155164
{
156165
// add $this->salt too if you don't use Bcrypt or Argon2i
157166
return [$this->id, $this->username, $this->password];
158167
}
159168

169+
/**
170+
* @param array{int|null, string, string} $data
171+
*/
160172
public function __unserialize(array $data): void
161173
{
162174
// add $this->salt too if you don't use Bcrypt or Argon2i

src/EventSubscriber/CheckRequirementsSubscriber.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace App\EventSubscriber;
1313

1414
use Doctrine\DBAL\Exception\DriverException;
15+
use Doctrine\DBAL\Platforms\SqlitePlatform;
1516
use Doctrine\ORM\EntityManagerInterface;
1617
use Symfony\Component\Console\ConsoleEvents;
1718
use Symfony\Component\Console\Event\ConsoleErrorEvent;
@@ -94,6 +95,6 @@ private function isSQLitePlatform(): bool
9495
{
9596
$databasePlatform = $this->entityManager->getConnection()->getDatabasePlatform();
9697

97-
return $databasePlatform ? 'sqlite' === $databasePlatform->getName() : false;
98+
return $databasePlatform instanceof SqlitePlatform;
9899
}
99100
}

0 commit comments

Comments
 (0)