Fixed all possible PHPStan errors

This commit is contained in:
Alejandro Celaya
2017-12-27 16:23:54 +01:00
parent 4f3995ea80
commit db956a1f40
21 changed files with 67 additions and 68 deletions

View File

@@ -71,14 +71,6 @@ class ResolveUrlCommand extends Command
try { try {
$longUrl = $this->urlShortener->shortCodeToUrl($shortCode); $longUrl = $this->urlShortener->shortCodeToUrl($shortCode);
if (! isset($longUrl)) {
$output->writeln(sprintf(
'<error>' . $this->translator->translate('No URL found for short code "%s"') . '</error>',
$shortCode
));
return;
}
$output->writeln(sprintf('%s <info>%s</info>', $this->translator->translate('Long URL:'), $longUrl)); $output->writeln(sprintf('%s <info>%s</info>', $this->translator->translate('Long URL:'), $longUrl));
} catch (InvalidShortCodeException $e) { } catch (InvalidShortCodeException $e) {
$output->writeln(sprintf('<error>' . $this->translator->translate( $output->writeln(sprintf('<error>' . $this->translator->translate(

View File

@@ -5,7 +5,7 @@ namespace Shlinkio\Shlink\Common\Exception;
class WrongIpException extends RuntimeException class WrongIpException extends RuntimeException
{ {
public static function fromIpAddress($ipAddress, \Exception $prev = null) public static function fromIpAddress($ipAddress, \Throwable $prev = null)
{ {
return new self(sprintf('Provided IP "%s" is invalid', $ipAddress), 0, $prev); return new self(sprintf('Provided IP "%s" is invalid', $ipAddress), 0, $prev);
} }

View File

@@ -22,15 +22,17 @@ class IpLocationResolver implements IpLocationResolverInterface
} }
/** /**
* @param $ipAddress * @param string $ipAddress
* @return array * @return array
* @throws WrongIpException
*/ */
public function resolveIpLocation($ipAddress) public function resolveIpLocation(string $ipAddress): array
{ {
try { try {
$response = $this->httpClient->get(sprintf(self::SERVICE_PATTERN, $ipAddress)); $response = $this->httpClient->get(sprintf(self::SERVICE_PATTERN, $ipAddress));
return json_decode((string) $response->getBody(), true); return json_decode((string) $response->getBody(), true);
} catch (GuzzleException $e) { } catch (GuzzleException $e) {
/** @var \Throwable $e */
throw WrongIpException::fromIpAddress($ipAddress, $e); throw WrongIpException::fromIpAddress($ipAddress, $e);
} }
} }

View File

@@ -3,11 +3,14 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Common\Service; namespace Shlinkio\Shlink\Common\Service;
use Shlinkio\Shlink\Common\Exception\WrongIpException;
interface IpLocationResolverInterface interface IpLocationResolverInterface
{ {
/** /**
* @param $ipAddress * @param string $ipAddress
* @return array * @return array
* @throws WrongIpException
*/ */
public function resolveIpLocation($ipAddress); public function resolveIpLocation(string $ipAddress): array;
} }

View File

@@ -6,11 +6,11 @@ namespace Shlinkio\Shlink\Common\Util;
class DateRange class DateRange
{ {
/** /**
* @var \DateTimeInterface * @var \DateTimeInterface|null
*/ */
private $startDate; private $startDate;
/** /**
* @var \DateTimeInterface * @var \DateTimeInterface|null
*/ */
private $endDate; private $endDate;
@@ -21,7 +21,7 @@ class DateRange
} }
/** /**
* @return \DateTimeInterface * @return \DateTimeInterface|null
*/ */
public function getStartDate() public function getStartDate()
{ {
@@ -29,7 +29,7 @@ class DateRange
} }
/** /**
* @return \DateTimeInterface * @return \DateTimeInterface|null
*/ */
public function getEndDate() public function getEndDate()
{ {
@@ -39,8 +39,8 @@ class DateRange
/** /**
* @return bool * @return bool
*/ */
public function isEmpty() public function isEmpty(): bool
{ {
return is_null($this->startDate) && is_null($this->endDate); return $this->startDate === null && $this->endDate === null;
} }
} }

View File

@@ -49,12 +49,6 @@ class RedirectAction implements MiddlewareInterface
try { try {
$longUrl = $this->urlShortener->shortCodeToUrl($shortCode); $longUrl = $this->urlShortener->shortCodeToUrl($shortCode);
// If provided shortCode does not belong to a valid long URL, dispatch next middleware, which will trigger
// a not-found error
if ($longUrl === null) {
return $delegate->process($request);
}
// Track visit to this short code // Track visit to this short code
$this->visitTracker->track($shortCode, $request); $this->visitTracker->track($shortCode, $request);

View File

@@ -7,9 +7,9 @@ use Shlinkio\Shlink\Common\Exception\RuntimeException;
class InvalidUrlException extends RuntimeException class InvalidUrlException extends RuntimeException
{ {
public static function fromUrl($url, \Exception $previous = null) public static function fromUrl($url, \Throwable $previous = null)
{ {
$code = isset($previous) ? $previous->getCode() : -1; $code = isset($previous) ? $previous->getCode() : -1;
return new static(sprintf('Provided URL "%s" is not an exisitng and valid URL', $url), $code, $previous); return new static(sprintf('Provided URL "%s" is not an existing and valid URL', $url), $code, $previous);
} }
} }

View File

@@ -49,9 +49,9 @@ class ShortUrlService implements ShortUrlServiceInterface
* @return ShortUrl * @return ShortUrl
* @throws InvalidShortCodeException * @throws InvalidShortCodeException
*/ */
public function setTagsByShortCode($shortCode, array $tags = []) public function setTagsByShortCode($shortCode, array $tags = []): ShortUrl
{ {
/** @var ShortUrl $shortUrl */ /** @var ShortUrl|null $shortUrl */
$shortUrl = $this->em->getRepository(ShortUrl::class)->findOneBy([ $shortUrl = $this->em->getRepository(ShortUrl::class)->findOneBy([
'shortCode' => $shortCode, 'shortCode' => $shortCode,
]); ]);

View File

@@ -24,5 +24,5 @@ interface ShortUrlServiceInterface
* @return ShortUrl * @return ShortUrl
* @throws InvalidShortCodeException * @throws InvalidShortCodeException
*/ */
public function setTagsByShortCode($shortCode, array $tags = []); public function setTagsByShortCode($shortCode, array $tags = []): ShortUrl;
} }

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Service\Tag; namespace Shlinkio\Shlink\Core\Service\Tag;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Shlinkio\Shlink\Core\Entity\Tag; use Shlinkio\Shlink\Core\Entity\Tag;
use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException; use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException;
@@ -15,7 +16,7 @@ class TagService implements TagServiceInterface
use TagManagerTrait; use TagManagerTrait;
/** /**
* @var EntityManagerInterface * @var EntityManager|EntityManagerInterface
*/ */
private $em; private $em;

View File

@@ -90,6 +90,7 @@ class UrlShortener implements UrlShortenerInterface
int $maxVisits = null int $maxVisits = null
): string { ): string {
// If the url already exists in the database, just return its short code // If the url already exists in the database, just return its short code
/** @var ShortUrl|null $shortUrl */
$shortUrl = $this->em->getRepository(ShortUrl::class)->findOneBy([ $shortUrl = $this->em->getRepository(ShortUrl::class)->findOneBy([
'originalUrl' => $url, 'originalUrl' => $url,
]); ]);
@@ -148,6 +149,7 @@ class UrlShortener implements UrlShortenerInterface
'max' => 15, 'max' => 15,
]]); ]]);
} catch (GuzzleException $e) { } catch (GuzzleException $e) {
/** @var \Throwable $e */
throw InvalidUrlException::fromUrl($url, $e); throw InvalidUrlException::fromUrl($url, $e);
} }
} }
@@ -155,13 +157,13 @@ class UrlShortener implements UrlShortenerInterface
/** /**
* Generates the unique shortcode for an autoincrement ID * Generates the unique shortcode for an autoincrement ID
* *
* @param int $id * @param float $id
* @return string * @return string
*/ */
private function convertAutoincrementIdToShortCode($id): string private function convertAutoincrementIdToShortCode(float $id): string
{ {
$id = ((int) $id) + 200000; // Increment the Id so that the generated shortcode is not too short $id += 200000; // Increment the Id so that the generated shortcode is not too short
$length = strlen($this->chars); $length = \strlen($this->chars);
$code = ''; $code = '';
while ($id > 0) { while ($id > 0) {

View File

@@ -15,7 +15,7 @@ use Shlinkio\Shlink\Core\Repository\VisitRepository;
class VisitsTracker implements VisitsTrackerInterface class VisitsTracker implements VisitsTrackerInterface
{ {
/** /**
* @var EntityManagerInterface|EntityManager * @var EntityManager|EntityManagerInterface
*/ */
private $em; private $em;
@@ -66,14 +66,14 @@ class VisitsTracker implements VisitsTrackerInterface
/** /**
* Returns the visits on certain short code * Returns the visits on certain short code
* *
* @param $shortCode * @param string $shortCode
* @param DateRange $dateRange * @param DateRange $dateRange
* @return Visit[] * @return Visit[]
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
public function info($shortCode, DateRange $dateRange = null): array public function info(string $shortCode, DateRange $dateRange = null): array
{ {
/** @var ShortUrl $shortUrl */ /** @var ShortUrl|null $shortUrl */
$shortUrl = $this->em->getRepository(ShortUrl::class)->findOneBy([ $shortUrl = $this->em->getRepository(ShortUrl::class)->findOneBy([
'shortCode' => $shortCode, 'shortCode' => $shortCode,
]); ]);

View File

@@ -21,10 +21,10 @@ interface VisitsTrackerInterface
/** /**
* Returns the visits on certain short code * Returns the visits on certain short code
* *
* @param $shortCode * @param string $shortCode
* @param DateRange $dateRange * @param DateRange $dateRange
* @return Visit[] * @return Visit[]
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
public function info($shortCode, DateRange $dateRange = null): array; public function info(string $shortCode, DateRange $dateRange = null): array;
} }

View File

@@ -50,7 +50,7 @@ class CreateShortcodeAction extends AbstractRestAction
*/ */
public function process(Request $request, DelegateInterface $delegate) public function process(Request $request, DelegateInterface $delegate)
{ {
$postData = $request->getParsedBody(); $postData = (array) $request->getParsedBody();
if (! isset($postData['longUrl'])) { if (! isset($postData['longUrl'])) {
return new JsonResponse([ return new JsonResponse([
'error' => RestUtils::INVALID_ARGUMENT_ERROR, 'error' => RestUtils::INVALID_ARGUMENT_ERROR,

View File

@@ -75,10 +75,10 @@ class GetVisitsAction extends AbstractRestAction
/** /**
* @param Request $request * @param Request $request
* @param $key * @param string $key
* @return \DateTime|null * @return \DateTime|null
*/ */
protected function getDateQueryParam(Request $request, $key) private function getDateQueryParam(Request $request, string $key)
{ {
$query = $request->getQueryParams(); $query = $request->getQueryParams();
if (! isset($query[$key]) || empty($query[$key])) { if (! isset($query[$key]) || empty($query[$key])) {

View File

@@ -27,7 +27,7 @@ class JWTService implements JWTServiceInterface
* @param int $lifetime * @param int $lifetime
* @return string * @return string
*/ */
public function create(ApiKey $apiKey, $lifetime = self::DEFAULT_LIFETIME) public function create(ApiKey $apiKey, $lifetime = self::DEFAULT_LIFETIME): string
{ {
$currentTimestamp = time(); $currentTimestamp = time();
@@ -48,7 +48,7 @@ class JWTService implements JWTServiceInterface
* @return string * @return string
* @throws AuthenticationException If the token has expired * @throws AuthenticationException If the token has expired
*/ */
public function refresh($jwt, $lifetime = self::DEFAULT_LIFETIME) public function refresh(string $jwt, $lifetime = self::DEFAULT_LIFETIME): string
{ {
$payload = $this->getPayload($jwt); $payload = $this->getPayload($jwt);
$payload['exp'] = time() + $lifetime; $payload['exp'] = time() + $lifetime;
@@ -61,7 +61,7 @@ class JWTService implements JWTServiceInterface
* @param string $jwt * @param string $jwt
* @return bool * @return bool
*/ */
public function verify($jwt) public function verify(string $jwt): bool
{ {
try { try {
// If no exception is thrown while decoding the token, it is considered valid // If no exception is thrown while decoding the token, it is considered valid
@@ -79,7 +79,7 @@ class JWTService implements JWTServiceInterface
* @return array * @return array
* @throws AuthenticationException If the token has expired * @throws AuthenticationException If the token has expired
*/ */
public function getPayload($jwt) public function getPayload(string $jwt): array
{ {
try { try {
return $this->decode($jwt); return $this->decode($jwt);
@@ -92,16 +92,16 @@ class JWTService implements JWTServiceInterface
* @param array $data * @param array $data
* @return string * @return string
*/ */
protected function encode(array $data) protected function encode(array $data): string
{ {
return JWT::encode($data, $this->appOptions->getSecretKey(), self::DEFAULT_ENCRYPTION_ALG); return JWT::encode($data, $this->appOptions->getSecretKey(), self::DEFAULT_ENCRYPTION_ALG);
} }
/** /**
* @param $jwt * @param string $jwt
* @return array * @return array
*/ */
protected function decode($jwt) protected function decode(string $jwt): array
{ {
return (array) JWT::decode($jwt, $this->appOptions->getSecretKey(), [self::DEFAULT_ENCRYPTION_ALG]); return (array) JWT::decode($jwt, $this->appOptions->getSecretKey(), [self::DEFAULT_ENCRYPTION_ALG]);
} }

View File

@@ -18,7 +18,7 @@ interface JWTServiceInterface
* @param int $lifetime * @param int $lifetime
* @return string * @return string
*/ */
public function create(ApiKey $apiKey, $lifetime = self::DEFAULT_LIFETIME); public function create(ApiKey $apiKey, $lifetime = self::DEFAULT_LIFETIME): string;
/** /**
* Refreshes a token and returns it with the new expiration * Refreshes a token and returns it with the new expiration
@@ -28,7 +28,7 @@ interface JWTServiceInterface
* @return string * @return string
* @throws AuthenticationException If the token has expired * @throws AuthenticationException If the token has expired
*/ */
public function refresh($jwt, $lifetime = self::DEFAULT_LIFETIME); public function refresh(string $jwt, $lifetime = self::DEFAULT_LIFETIME): string;
/** /**
* Verifies that certain JWT is valid * Verifies that certain JWT is valid
@@ -36,7 +36,7 @@ interface JWTServiceInterface
* @param string $jwt * @param string $jwt
* @return bool * @return bool
*/ */
public function verify($jwt); public function verify(string $jwt): bool;
/** /**
* Decodes certain token and returns the payload * Decodes certain token and returns the payload
@@ -45,5 +45,5 @@ interface JWTServiceInterface
* @return array * @return array
* @throws AuthenticationException If the token has expired * @throws AuthenticationException If the token has expired
*/ */
public function getPayload($jwt); public function getPayload(string $jwt): array;
} }

View File

@@ -55,13 +55,14 @@ class CheckAuthenticationMiddleware implements MiddlewareInterface, StatusCodeIn
* *
* @return Response * @return Response
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @throws \ErrorException
*/ */
public function process(Request $request, DelegateInterface $delegate) public function process(Request $request, DelegateInterface $delegate)
{ {
// If current route is the authenticate route or an OPTIONS request, continue to the next middleware // If current route is the authenticate route or an OPTIONS request, continue to the next middleware
/** @var RouteResult $routeResult */ /** @var RouteResult|null $routeResult */
$routeResult = $request->getAttribute(RouteResult::class); $routeResult = $request->getAttribute(RouteResult::class);
if (! isset($routeResult) if ($routeResult === null
|| $routeResult->isFailure() || $routeResult->isFailure()
|| $routeResult->getMatchedRouteName() === AuthenticateAction::class || $routeResult->getMatchedRouteName() === AuthenticateAction::class
|| $request->getMethod() === 'OPTIONS' || $request->getMethod() === 'OPTIONS'

View File

@@ -46,13 +46,9 @@ class ApiKeyService implements ApiKeyServiceInterface
*/ */
public function check($key) public function check($key)
{ {
/** @var ApiKey $apiKey */ /** @var ApiKey|null $apiKey */
$apiKey = $this->getByKey($key); $apiKey = $this->getByKey($key);
if (! isset($apiKey)) { return $apiKey !== null && $apiKey->isValid();
return false;
}
return $apiKey->isValid();
} }
/** /**
@@ -60,12 +56,13 @@ class ApiKeyService implements ApiKeyServiceInterface
* *
* @param string $key * @param string $key
* @return ApiKey * @return ApiKey
* @throws InvalidArgumentException
*/ */
public function disable($key) public function disable($key)
{ {
/** @var ApiKey $apiKey */ /** @var ApiKey|null $apiKey */
$apiKey = $this->getByKey($key); $apiKey = $this->getByKey($key);
if (! isset($apiKey)) { if ($apiKey === null) {
throw new InvalidArgumentException(sprintf('API key "%s" does not exist and can\'t be disabled', $key)); throw new InvalidArgumentException(sprintf('API key "%s" does not exist and can\'t be disabled', $key));
} }
@@ -75,7 +72,7 @@ class ApiKeyService implements ApiKeyServiceInterface
} }
/** /**
* Lists all existing appi keys * Lists all existing api keys
* *
* @param bool $enabledOnly Tells if only enabled keys should be returned * @param bool $enabledOnly Tells if only enabled keys should be returned
* @return ApiKey[] * @return ApiKey[]
@@ -94,8 +91,10 @@ class ApiKeyService implements ApiKeyServiceInterface
*/ */
public function getByKey($key) public function getByKey($key)
{ {
return $this->em->getRepository(ApiKey::class)->findOneBy([ /** @var ApiKey|null $apiKey */
$apiKey = $this->em->getRepository(ApiKey::class)->findOneBy([
'key' => $key, 'key' => $key,
]); ]);
return $apiKey;
} }
} }

View File

@@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Service; namespace Shlinkio\Shlink\Rest\Service;
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
use Shlinkio\Shlink\Rest\Entity\ApiKey; use Shlinkio\Shlink\Rest\Entity\ApiKey;
interface ApiKeyServiceInterface interface ApiKeyServiceInterface
@@ -28,11 +29,12 @@ interface ApiKeyServiceInterface
* *
* @param string $key * @param string $key
* @return ApiKey * @return ApiKey
* @throws InvalidArgumentException
*/ */
public function disable($key); public function disable($key);
/** /**
* Lists all existing appi keys * Lists all existing api keys
* *
* @param bool $enabledOnly Tells if only enabled keys should be returned * @param bool $enabledOnly Tells if only enabled keys should be returned
* @return ApiKey[] * @return ApiKey[]

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Rest\Action; namespace ShlinkioTest\Shlink\Rest\Action;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy; use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Rest\Action\AuthenticateAction; use Shlinkio\Shlink\Rest\Action\AuthenticateAction;
use Shlinkio\Shlink\Rest\Authentication\JWTService; use Shlinkio\Shlink\Rest\Authentication\JWTService;
@@ -32,6 +33,8 @@ class AuthenticateActionTest extends TestCase
{ {
$this->apiKeyService = $this->prophesize(ApiKeyService::class); $this->apiKeyService = $this->prophesize(ApiKeyService::class);
$this->jwtService = $this->prophesize(JWTService::class); $this->jwtService = $this->prophesize(JWTService::class);
$this->jwtService->create(Argument::cetera())->willReturn('');
$this->action = new AuthenticateAction( $this->action = new AuthenticateAction(
$this->apiKeyService->reveal(), $this->apiKeyService->reveal(),
$this->jwtService->reveal(), $this->jwtService->reveal(),