1
0
Fork 0
mirror of https://github.com/wallabag/wallabag.git synced 2025-06-27 16:36:00 +00:00

Move to PHPStan level 4

This commit is contained in:
Yassine Guedidi 2025-04-05 17:34:00 +02:00
parent 31e1be4191
commit b4483023e6
22 changed files with 116 additions and 104 deletions

View file

@ -0,0 +1,6 @@
parameters:
ignoreErrors:
-
message: "#^Strict comparison using \\=\\=\\= between null and string will always evaluate to false\\.$#"
count: 1
path: src/ParamConverter/UsernameFeedTokenConverter.php

View file

@ -2,7 +2,7 @@ includes:
- phpstan-baseline.neon
parameters:
level: 3
level: 4
paths:
- src
- tests

View file

@ -554,7 +554,7 @@ class EntryRestController extends WallabagRestController
$this->entityManager->persist($entry);
$this->entityManager->flush();
$results[$key]['entry'] = $entry instanceof Entry ? $entry->getId() : false;
$results[$key]['entry'] = $entry->getId();
// entry saved, dispatch event about it!
$eventDispatcher->dispatch(new EntrySavedEvent($entry), EntrySavedEvent::NAME);
@ -734,7 +734,7 @@ class EntryRestController extends WallabagRestController
'html' => !empty($data['content']) ? $data['content'] : $entry->getContent(),
'url' => $entry->getUrl(),
'language' => !empty($data['language']) ? $data['language'] : $entry->getLanguage(),
'date' => !empty($data['publishedAt']) ? $data['publishedAt'] : $entry->getPublishedAt(),
'date' => !empty($data['publishedAt']) ? $data['publishedAt'] : $entry->getPublishedAt()?->format('Y-m-d H:i:s') ?? '',
// faking the open graph preview picture
'image' => !empty($data['picture']) ? $data['picture'] : $entry->getPreviewPicture(),
'authors' => \is_string($data['authors']) ? explode(',', $data['authors']) : $entry->getPublishedBy(),

View file

@ -125,10 +125,6 @@ class FeedController extends AbstractController
$perPage = $user->getConfig()->getFeedLimit() ?: $this->getParameter('wallabag.feed_limit');
$entries->setMaxPerPage($perPage);
if (null === $entries) {
throw $this->createNotFoundException('No entries found?');
}
try {
$entries->setCurrentPage($page);
} catch (OutOfRangeCurrentPageException) {

View file

@ -61,10 +61,10 @@ class PocketController extends AbstractController
return $this->redirect($this->generateUrl('import_pocket'));
}
$form = $request->request->get('form');
$form = $request->request->all('form');
$this->session->set('import.pocket.code', $requestToken);
if (null !== $form && \array_key_exists('mark_as_read', $form)) {
if (\array_key_exists('mark_as_read', $form)) {
$this->session->set('mark_as_read', $form['mark_as_read']);
}

View file

@ -3,6 +3,7 @@
namespace Wallabag\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Hateoas\Configuration\Annotation as Hateoas;
use JMS\Serializer\Annotation\Exclude;
@ -233,11 +234,14 @@ class Entry
#[Groups(['export_all'])]
private $user;
/**
* @var Collection<Tag>
*/
#[ORM\JoinTable(name: 'entry_tag')]
#[ORM\JoinColumn(name: 'entry_id', referencedColumnName: 'id', onDelete: 'cascade')]
#[ORM\InverseJoinColumn(name: 'tag_id', referencedColumnName: 'id', onDelete: 'cascade')]
#[ORM\ManyToMany(targetEntity: Tag::class, inversedBy: 'entries', cascade: ['persist'])]
private $tags;
private Collection $tags;
/*
* @param User $user
@ -589,7 +593,7 @@ class Entry
}
/**
* @return string
* @return string|null
*/
public function getDomainName()
{
@ -597,7 +601,7 @@ class Entry
}
/**
* @param string $domainName
* @param string|null $domainName
*/
public function setDomainName($domainName)
{
@ -605,7 +609,7 @@ class Entry
}
/**
* @return ArrayCollection
* @return Collection
*/
public function getTags()
{
@ -696,7 +700,7 @@ class Entry
/**
* Get previewPicture.
*
* @return string
* @return string|null
*/
public function getPreviewPicture()
{
@ -706,7 +710,7 @@ class Entry
/**
* Set language.
*
* @param string $language
* @param string|null $language
*
* @return Entry
*/
@ -720,7 +724,7 @@ class Entry
/**
* Get language.
*
* @return string
* @return string|null
*/
public function getLanguage()
{
@ -808,7 +812,7 @@ class Entry
}
/**
* @return \DateTimeInterface
* @return \DateTimeInterface|null
*/
public function getPublishedAt()
{

View file

@ -3,6 +3,7 @@
namespace Wallabag\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use JMS\Serializer\Annotation\ExclusionPolicy;
@ -41,8 +42,11 @@ class Tag implements \Stringable
#[Expose]
private $slug;
/**
* @var Collection<Entry>
*/
#[ORM\ManyToMany(targetEntity: Entry::class, mappedBy: 'tags', cascade: ['persist'])]
private $entries;
private Collection $entries;
public function __construct()
{
@ -121,7 +125,7 @@ class Tag implements \Stringable
/**
* Get entries for this tag.
*
* @return ArrayCollection<Entry>
* @return Collection<Entry>
*/
public function getEntries()
{

View file

@ -3,6 +3,7 @@
namespace Wallabag\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use JMS\Serializer\Annotation\Accessor;
@ -117,16 +118,16 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
protected $config;
/**
* @var ArrayCollection&iterable<SiteCredential>
* @var Collection<SiteCredential>
*/
#[ORM\OneToMany(targetEntity: SiteCredential::class, mappedBy: 'user', cascade: ['remove'])]
protected $siteCredentials;
protected Collection $siteCredentials;
/**
* @var ArrayCollection&iterable<Client>
* @var Collection<Client>
*/
#[ORM\OneToMany(targetEntity: Client::class, mappedBy: 'user', cascade: ['remove'])]
protected $clients;
protected Collection $clients;
/**
* @see getFirstClient() below
@ -162,6 +163,8 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
{
parent::__construct();
$this->entries = new ArrayCollection();
$this->siteCredentials = new ArrayCollection();
$this->clients = new ArrayCollection();
$this->roles = ['ROLE_USER'];
}
@ -216,7 +219,7 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
}
/**
* @return ArrayCollection<Entry>
* @return Collection<Entry>
*/
public function getEntries()
{
@ -338,13 +341,15 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
*/
public function addClient(Client $client)
{
$this->clients[] = $client;
if (!$this->clients->contains($client)) {
$this->clients->add($client);
}
return $this;
}
/**
* @return ArrayCollection<Client>
* @return Collection<Client>
*/
public function getClients()
{
@ -358,7 +363,7 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
*/
public function getFirstClient()
{
if (!empty($this->clients)) {
if (!$this->clients->isEmpty()) {
return $this->clients->first();
}

View file

@ -79,7 +79,7 @@ class DownloadImagesSubscriber implements EventSubscriberInterface
*
* @todo If we want to add async download, it should be done in that method
*
* @return string|false False in case of async
* @return string
*/
private function downloadImages(Entry $entry)
{

View file

@ -3,6 +3,7 @@
namespace Wallabag\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
/**
* Transforms a comma-separated list to a proper PHP array.
@ -21,8 +22,6 @@ class StringToListTransformer implements DataTransformerInterface
/**
* Transforms a list to a string.
*
* @param array|null $list
*
* @return string
*/
public function transform($list)
@ -31,14 +30,16 @@ class StringToListTransformer implements DataTransformerInterface
return '';
}
if (!\is_array($list)) {
throw new UnexpectedTypeException($list, 'array');
}
return implode($this->separator, $list);
}
/**
* Transforms a string to a list.
*
* @param string $string
*
* @return array|null
*/
public function reverseTransform($string)
@ -47,6 +48,10 @@ class StringToListTransformer implements DataTransformerInterface
return null;
}
if (!\is_string($string)) {
throw new UnexpectedTypeException($string, 'string');
}
return array_values(array_filter(array_map('trim', explode($this->separator, $string))));
}
}

View file

@ -143,11 +143,8 @@ class ContentProxy
}
try {
// is it already a DateTime?
// (it's inside the try/catch in case of fail to be parse time string)
if (!$date instanceof \DateTime) {
$date = new \DateTime($date);
}
$date = new \DateTime($date);
$entry->setPublishedAt($date);
} catch (\Exception $e) {

View file

@ -98,10 +98,10 @@ class DownloadImages
* - re-saved it (for security reason)
* - return the new local path.
*
* @param int $entryId ID of the entry
* @param string $imagePath Path to the image to retrieve
* @param string $url Url from where the image were found
* @param string $relativePath Relative local path to saved the image
* @param int $entryId ID of the entry
* @param string|null $imagePath Path to the image to retrieve
* @param string $url Url from where the image were found
* @param string $relativePath Relative local path to saved the image
*
* @return string|false Relative url to access the image from the web
*/
@ -136,7 +136,7 @@ class DownloadImages
}
$ext = $this->getExtensionFromResponse($res, $imagePath);
if (false === $res) {
if (false === $ext) {
return false;
}

View file

@ -20,8 +20,8 @@ class Redirect
}
/**
* @param string $url URL to redirect
* @param bool $ignoreActionMarkAsRead Ignore configured action when mark as read
* @param string|null $url URL to redirect
* @param bool $ignoreActionMarkAsRead Ignore configured action when mark as read
*
* @return string
*/

View file

@ -129,7 +129,8 @@ class RuleBasedTagger
private function fixEntry(Entry $entry)
{
$clonedEntry = clone $entry;
$clonedEntry->setReadingTime($entry->getReadingTime() / $entry->getUser()->getConfig()->getReadingSpeed() * 200);
$newReadingTime = (int) ($entry->getReadingTime() / $entry->getUser()->getConfig()->getReadingSpeed() * 200);
$clonedEntry->setReadingTime($newReadingTime);
return $clonedEntry;
}

View file

@ -95,7 +95,7 @@ class PinboardImport extends AbstractImport
'is_archived' => ('no' === $importedEntry['toread']) || $this->markAsRead,
'is_starred' => false,
'created_at' => $importedEntry['time'],
'tags' => explode(' ', (string) $importedEntry['tags']),
'tags' => array_filter(explode(' ', (string) $importedEntry['tags'])),
];
$entry = new Entry($this->user);

View file

@ -52,7 +52,7 @@ class AuthCodeMailer implements AuthCodeMailerInterface
]);
$email = (new Email())
->from(new Address($this->senderEmail, $this->senderName ?? $this->senderEmail))
->from(new Address($this->senderEmail, $this->senderName ?: $this->senderEmail))
->to($user->getEmailAuthRecipient())
->subject($subject)
->text($bodyText)

View file

@ -24,10 +24,10 @@ class Utils
*
* @param string $text
*
* @return float
* @return int
*/
public static function getReadingTime($text)
{
return floor(\count(preg_split('~([^\p{L}\p{N}\']+|(\p{Han}|\p{Hiragana}|\p{Katakana}|\p{Hangul}){1,2})~u', strip_tags($text))) / 200);
return (int) floor(\count(preg_split('~([^\p{L}\p{N}\']+|(\p{Han}|\p{Hiragana}|\p{Katakana}|\p{Hangul}){1,2})~u', strip_tags($text))) / 200);
}
}

View file

@ -43,8 +43,6 @@ class WallabagRestControllerTest extends WallabagApiTestCase
if (!$client->getContainer()->getParameter('fosuser_registration')) {
$this->markTestSkipped('fosuser_registration is not enabled.');
return;
}
$client->getContainer()->get(Config::class)->set('api_user_registration', 1);

View file

@ -11,8 +11,6 @@ class ExportControllerTest extends WallabagTestCase
{
private $adminEntry;
private $bobEntry;
private $sameDomainEntry;
private $sameDomainEntry2;
public function testLogin()
{

View file

@ -88,8 +88,6 @@ class SecurityControllerTest extends WallabagTestCase
if (!$client->getContainer()->getParameter('fosuser_registration')) {
$this->markTestSkipped('fosuser_registration is not enabled.');
return;
}
$client->followRedirects();

View file

@ -55,7 +55,7 @@ class ContentProxyTest extends TestCase
$this->assertEmpty($entry->getPreviewPicture());
$this->assertEmpty($entry->getMimetype());
$this->assertEmpty($entry->getLanguage());
$this->assertSame(0.0, $entry->getReadingTime());
$this->assertSame(0, $entry->getReadingTime());
$this->assertNull($entry->getDomainName());
$this->assertTrue($entry->isNotParsed());
}
@ -95,7 +95,7 @@ class ContentProxyTest extends TestCase
$this->assertEmpty($entry->getPreviewPicture());
$this->assertEmpty($entry->getMimetype());
$this->assertEmpty($entry->getLanguage());
$this->assertSame(0.0, $entry->getReadingTime());
$this->assertSame(0, $entry->getReadingTime());
$this->assertSame('0.0.0.0', $entry->getDomainName());
$this->assertTrue($entry->isNotParsed());
}
@ -138,7 +138,7 @@ class ContentProxyTest extends TestCase
$this->assertEmpty($entry->getLanguage());
$this->assertEmpty($entry->getHttpStatus());
$this->assertEmpty($entry->getMimetype());
$this->assertSame(0.0, $entry->getReadingTime());
$this->assertSame(0, $entry->getReadingTime());
$this->assertSame('domain.io', $entry->getDomainName());
$this->assertTrue($entry->isNotParsed());
}
@ -184,7 +184,7 @@ class ContentProxyTest extends TestCase
$this->assertSame('text/html', $entry->getMimetype());
$this->assertSame('fr', $entry->getLanguage());
$this->assertSame('200', $entry->getHttpStatus());
$this->assertSame(4.0, $entry->getReadingTime());
$this->assertSame(4, $entry->getReadingTime());
$this->assertSame('1.1.1.1', $entry->getDomainName());
$this->assertFalse($entry->isNotParsed());
}
@ -230,7 +230,7 @@ class ContentProxyTest extends TestCase
$this->assertSame('text/html', $entry->getMimetype());
$this->assertSame('fr', $entry->getLanguage());
$this->assertSame('200', $entry->getHttpStatus());
$this->assertSame(4.0, $entry->getReadingTime());
$this->assertSame(4, $entry->getReadingTime());
$this->assertSame('1.1.1.1', $entry->getDomainName());
$this->assertFalse($entry->isNotParsed());
}
@ -275,7 +275,7 @@ class ContentProxyTest extends TestCase
$this->assertSame('text/html', $entry->getMimetype());
$this->assertSame('fr', $entry->getLanguage());
$this->assertSame('200', $entry->getHttpStatus());
$this->assertSame(0.0, $entry->getReadingTime());
$this->assertSame(0, $entry->getReadingTime());
$this->assertSame('1.1.1.1', $entry->getDomainName());
$this->assertFalse($entry->isNotParsed());
}
@ -320,7 +320,7 @@ class ContentProxyTest extends TestCase
$this->assertSame('text/html', $entry->getMimetype());
$this->assertSame('fr', $entry->getLanguage());
$this->assertSame('200', $entry->getHttpStatus());
$this->assertSame(0.0, $entry->getReadingTime());
$this->assertSame(0, $entry->getReadingTime());
$this->assertSame('1.1.1.1', $entry->getDomainName());
$this->assertFalse($entry->isNotParsed());
}
@ -368,7 +368,7 @@ class ContentProxyTest extends TestCase
$this->assertSame('text/html', $entry->getMimetype());
$this->assertNull($entry->getLanguage());
$this->assertSame('200', $entry->getHttpStatus());
$this->assertSame(4.0, $entry->getReadingTime());
$this->assertSame(4, $entry->getReadingTime());
$this->assertSame('1.1.1.1', $entry->getDomainName());
$this->assertFalse($entry->isNotParsed());
}
@ -422,7 +422,7 @@ class ContentProxyTest extends TestCase
$this->assertSame('text/html', $entry->getMimetype());
$this->assertSame('fr', $entry->getLanguage());
$this->assertSame('200', $entry->getHttpStatus());
$this->assertSame(4.0, $entry->getReadingTime());
$this->assertSame(4, $entry->getReadingTime());
$this->assertSame('1.1.1.1', $entry->getDomainName());
$this->assertFalse($entry->isNotParsed());
}
@ -461,7 +461,7 @@ class ContentProxyTest extends TestCase
$this->assertStringContainsString('content', $entry->getContent());
$this->assertSame('text/html', $entry->getMimetype());
$this->assertSame('fr', $entry->getLanguage());
$this->assertSame(4.0, $entry->getReadingTime());
$this->assertSame(4, $entry->getReadingTime());
$this->assertSame('1.1.1.1', $entry->getDomainName());
$this->assertSame('24/03/2014', $entry->getPublishedAt()->format('d/m/Y'));
$this->assertContains('Jeremy', $entry->getPublishedBy());
@ -505,7 +505,7 @@ class ContentProxyTest extends TestCase
$this->assertStringContainsString('content', $entry->getContent());
$this->assertSame('text/html', $entry->getMimetype());
$this->assertSame('fr', $entry->getLanguage());
$this->assertSame(4.0, $entry->getReadingTime());
$this->assertSame(4, $entry->getReadingTime());
$this->assertSame('1.1.1.1', $entry->getDomainName());
$this->assertSame('08/09/2016', $entry->getPublishedAt()->format('d/m/Y'));
$this->assertFalse($entry->isNotParsed());
@ -545,7 +545,7 @@ class ContentProxyTest extends TestCase
$this->assertStringContainsString('content', $entry->getContent());
$this->assertSame('text/html', $entry->getMimetype());
$this->assertSame('fr', $entry->getLanguage());
$this->assertSame(4.0, $entry->getReadingTime());
$this->assertSame(4, $entry->getReadingTime());
$this->assertSame('1.1.1.1', $entry->getDomainName());
$this->assertNull($entry->getPublishedAt());
$this->assertFalse($entry->isNotParsed());
@ -883,42 +883,42 @@ class ContentProxyTest extends TestCase
*/
$this->markTestSkipped('Encoding issue in PHP >= 8.1');
// See http://graphemica.com for more info about the characters
// '😻<F09F98BB>z' (U+1F63B or F09F98BB; U+2124 or E284A4; invalid character 81; U+007A or 7A) in hexadecimal and UTF-8
// 0x81 is not a valid character for UTF16, UTF8 and WINDOWS-1252
$actualTitle = $this->hexToStr('F09F98BB' . 'E284A4' . '81' . '7A');
$tagger = $this->getTaggerMock();
$tagger->expects($this->once())
->method('tag');
$ruleBasedIgnoreOriginProcessor = $this->getRuleBasedIgnoreOriginProcessorMock();
$graby = $this->getMockBuilder(Graby::class)
->onlyMethods(['fetchContent'])
->disableOriginalConstructor()
->getMock();
$graby->expects($this->any())
->method('fetchContent')
->willReturn([
'html' => false,
'title' => $actualTitle,
'url' => '',
'headers' => [
'content-type' => 'application/pdf',
],
'language' => '',
]);
$proxy = new ContentProxy($graby, $tagger, $ruleBasedIgnoreOriginProcessor, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
$entry = new Entry(new User());
$proxy->updateEntry($entry, 'http://0.0.0.0');
// '😻z' (U+1F63B or F09F98BB; U+2124 or E284A4; U+007A or 7A) in hexadecimal and UTF-8
// the 0x81 (represented by <20>) is invalid for UTF16, UTF8 and WINDOWS-1252 and is removed
$expectedTitle = 'F09F98BB' . 'E284A4' . '7A';
$this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
// // See http://graphemica.com for more info about the characters
// // '😻<F09F98BB>z' (U+1F63B or F09F98BB; U+2124 or E284A4; invalid character 81; U+007A or 7A) in hexadecimal and UTF-8
// // 0x81 is not a valid character for UTF16, UTF8 and WINDOWS-1252
// $actualTitle = $this->hexToStr('F09F98BB' . 'E284A4' . '81' . '7A');
//
// $tagger = $this->getTaggerMock();
// $tagger->expects($this->once())
// ->method('tag');
//
// $ruleBasedIgnoreOriginProcessor = $this->getRuleBasedIgnoreOriginProcessorMock();
//
// $graby = $this->getMockBuilder(Graby::class)
// ->onlyMethods(['fetchContent'])
// ->disableOriginalConstructor()
// ->getMock();
//
// $graby->expects($this->any())
// ->method('fetchContent')
// ->willReturn([
// 'html' => false,
// 'title' => $actualTitle,
// 'url' => '',
// 'headers' => [
// 'content-type' => 'application/pdf',
// ],
// 'language' => '',
// ]);
//
// $proxy = new ContentProxy($graby, $tagger, $ruleBasedIgnoreOriginProcessor, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
// $entry = new Entry(new User());
// $proxy->updateEntry($entry, 'http://0.0.0.0');
//
// // '😻z' (U+1F63B or F09F98BB; U+2124 or E284A4; U+007A or 7A) in hexadecimal and UTF-8
// // the 0x81 (represented by <20>) is invalid for UTF16, UTF8 and WINDOWS-1252 and is removed
// $expectedTitle = 'F09F98BB' . 'E284A4' . '7A';
// $this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
}
/**

View file

@ -13,7 +13,7 @@ class UtilsTest extends TestCase
*/
public function testCorrectWordsCountForDifferentLanguages($filename, $text, $expectedCount)
{
static::assertSame((float) $expectedCount, Utils::getReadingTime($text), 'Reading time for: ' . $filename);
static::assertSame($expectedCount, Utils::getReadingTime($text), 'Reading time for: ' . $filename);
}
public function examples()
@ -30,7 +30,7 @@ class UtilsTest extends TestCase
$examples[] = [
$file->getRelativePathname(),
$match[1], // content
$match[2], // reading time
(int) $match[2], // reading time
];
}