Migrated from standard datetime objects to chronos objects

This commit is contained in:
Alejandro Celaya 2018-09-29 12:52:32 +02:00
parent 9a2ca35e6e
commit 0183c8a4b7
31 changed files with 271 additions and 198 deletions

View File

@ -16,6 +16,7 @@
"ext-json": "*",
"ext-pdo": "*",
"acelaya/ze-content-based-error-handler": "^2.2",
"cakephp/chronos": "^1.2",
"cocur/slugify": "^3.0",
"doctrine/cache": "^1.6",
"doctrine/migrations": "^1.4",
@ -32,7 +33,7 @@
"theorchard/monolog-cascade": "^0.4",
"zendframework/zend-config": "^3.0",
"zendframework/zend-config-aggregator": "^1.0",
"zendframework/zend-diactoros": "^1.7",
"zendframework/zend-diactoros": "^2.0",
"zendframework/zend-expressive": "^3.0",
"zendframework/zend-expressive-fastroute": "^3.0",
"zendframework/zend-expressive-helpers": "^5.0",

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\CLI\Command\Api;
use Cake\Chronos\Chronos;
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
@ -46,7 +47,7 @@ class GenerateKeyCommand extends Command
public function execute(InputInterface $input, OutputInterface $output)
{
$expirationDate = $input->getOption('expirationDate');
$apiKey = $this->apiKeyService->create(isset($expirationDate) ? new \DateTime($expirationDate) : null);
$apiKey = $this->apiKeyService->create(isset($expirationDate) ? Chronos::parse($expirationDate) : null);
(new SymfonyStyle($input, $output))->success(
sprintf($this->translator->translate('Generated API key: "%s"'), $apiKey)

View File

@ -66,7 +66,7 @@ class ListKeysCommand extends Command
if (! $enabledOnly) {
$rowData[] = \sprintf($messagePattern, $this->getEnabledSymbol($row));
}
$rowData[] = $expiration !== null ? $expiration->format(\DateTime::ATOM) : '-';
$rowData[] = $expiration !== null ? $expiration->toAtomString() : '-';
$rows[] = $rowData;
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
use Cake\Chronos\Chronos;
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
use Shlinkio\Shlink\Core\Service\UrlShortenerInterface;
@ -143,9 +144,9 @@ class GenerateShortUrlCommand extends Command
}
}
private function getOptionalDate(InputInterface $input, string $fieldName): ?\DateTime
private function getOptionalDate(InputInterface $input, string $fieldName): ?Chronos
{
$since = $input->getOption($fieldName);
return $since !== null ? new \DateTime($since) : null;
return $since !== null ? Chronos::parse($since) : null;
}
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
use Cake\Chronos\Chronos;
use Shlinkio\Shlink\Common\Util\DateRange;
use Shlinkio\Shlink\Core\Service\VisitsTrackerInterface;
use Symfony\Component\Console\Command\Command;
@ -107,10 +108,6 @@ class GetVisitsCommand extends Command
private function getDateOption(InputInterface $input, $key)
{
$value = $input->getOption($key);
if (! empty($value)) {
$value = new \DateTime($value);
}
return $value;
return ! empty($value) ? Chronos::parse($value) : $value;
}
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\Api;
use Cake\Chronos\Chronos;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
@ -50,8 +51,8 @@ class GenerateKeyCommandTest extends TestCase
*/
public function expirationDateIsDefinedIfProvided()
{
$this->apiKeyService->create(Argument::type(\DateTime::class))->shouldBeCalledTimes(1)
->willReturn(new ApiKey());
$this->apiKeyService->create(Argument::type(Chronos::class))->shouldBeCalledTimes(1)
->willReturn(new ApiKey());
$this->commandTester->execute([
'command' => 'api-key:generate',
'--expirationDate' => '2016-01-01',

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
use Cake\Chronos\Chronos;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
@ -58,7 +59,7 @@ class GetVisitsCommandTest extends TestCase
$shortCode = 'abc123';
$startDate = '2016-01-01';
$endDate = '2016-02-01';
$this->visitsTracker->info($shortCode, new DateRange(new \DateTime($startDate), new \DateTime($endDate)))
$this->visitsTracker->info($shortCode, new DateRange(Chronos::parse($startDate), Chronos::parse($endDate)))
->willReturn([])
->shouldBeCalledTimes(1);

View File

@ -5,10 +5,13 @@ namespace Shlinkio\Shlink\Common\Factory;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\Tools\Setup;
use Interop\Container\ContainerInterface;
use Interop\Container\Exception\ContainerException;
use Shlinkio\Shlink\Common\Type\ChronosDateTimeType;
use Zend\ServiceManager\Exception\ServiceNotCreatedException;
use Zend\ServiceManager\Exception\ServiceNotFoundException;
use Zend\ServiceManager\Factory\FactoryInterface;
@ -16,15 +19,10 @@ use Zend\ServiceManager\Factory\FactoryInterface;
class EntityManagerFactory implements FactoryInterface
{
/**
* Create an object
*
* @param ContainerInterface $container
* @param string $requestedName
* @param null|array $options
* @return object
* @throws ServiceNotFoundException if unable to resolve the service.
* @throws ServiceNotCreatedException if an exception is raised when creating a service.
* @throws ContainerException if any other error occurs
* @throws ORMException
* @throws DBALException
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
@ -35,6 +33,8 @@ class EntityManagerFactory implements FactoryInterface
$connectionConfig = $emConfig['connection'] ?? [];
$ormConfig = $emConfig['orm'] ?? [];
Type::addType(ChronosDateTimeType::CHRONOS_DATETIME, ChronosDateTimeType::class);
return EntityManager::create($connectionConfig, Setup::createAnnotationMetadataConfiguration(
$ormConfig['entities_paths'] ?? [],
$isDevMode,

View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Common\Type;
use Cake\Chronos\Chronos;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\DateTimeImmutableType;
class ChronosDateTimeType extends DateTimeImmutableType
{
public const CHRONOS_DATETIME = 'chronos_datetime';
public function getName(): string
{
return self::CHRONOS_DATETIME;
}
/**
* @throws ConversionException
*/
public function convertToPHPValue($value, AbstractPlatform $platform): ?Chronos
{
if ($value === null) {
return null;
}
$dateTime = parent::convertToPHPValue($value, $platform);
return Chronos::instance($dateTime);
}
/**
* @throws ConversionException
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if (null === $value) {
return $value;
}
if ($value instanceof \DateTimeInterface) {
return $value->format($platform->getDateTimeFormatString());
}
throw ConversionException::conversionFailedInvalidType(
$value,
$this->getName(),
['null', \DateTimeInterface::class]
);
}
}

View File

@ -3,42 +3,35 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Common\Util;
class DateRange
use Cake\Chronos\Chronos;
final class DateRange
{
/**
* @var \DateTimeInterface|null
* @var Chronos|null
*/
private $startDate;
/**
* @var \DateTimeInterface|null
* @var Chronos|null
*/
private $endDate;
public function __construct(\DateTimeInterface $startDate = null, \DateTimeInterface $endDate = null)
public function __construct(?Chronos $startDate = null, ?Chronos $endDate = null)
{
$this->startDate = $startDate;
$this->endDate = $endDate;
}
/**
* @return \DateTimeInterface|null
*/
public function getStartDate()
public function getStartDate(): ?Chronos
{
return $this->startDate;
}
/**
* @return \DateTimeInterface|null
*/
public function getEndDate()
public function getEndDate(): ?Chronos
{
return $this->endDate;
}
/**
* @return bool
*/
public function isEmpty(): bool
{
return $this->startDate === null && $this->endDate === null;

View File

@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace ShlinkioTest\Shlink\Common\Type;
use Cake\Chronos\Chronos;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\Type;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Common\Type\ChronosDateTimeType;
class ChronosDateTimeTypeTest extends TestCase
{
/**
* @var ChronosDateTimeType
*/
private $type;
public function setUp()
{
if (! Type::hasType(ChronosDateTimeType::CHRONOS_DATETIME)) {
Type::addType(ChronosDateTimeType::CHRONOS_DATETIME, ChronosDateTimeType::class);
}
$this->type = Type::getType(ChronosDateTimeType::CHRONOS_DATETIME);
}
/**
* @test
*/
public function nameIsReturned()
{
$this->assertEquals(ChronosDateTimeType::CHRONOS_DATETIME, $this->type->getName());
}
/**
* @test
* @dataProvider provideValues
*/
public function valueIsConverted(?string $value, ?string $expected)
{
$platform = $this->prophesize(AbstractPlatform::class);
$platform->getDateTimeFormatString()->willReturn('Y-m-d H:i:s');
$result = $this->type->convertToPHPValue($value, $platform->reveal());
if ($expected === null) {
$this->assertNull($result);
} else {
$this->assertInstanceOf($expected, $result);
}
}
public function provideValues(): array
{
return [
[null, null],
['now', Chronos::class],
['2017-01-01', Chronos::class],
];
}
/**
* @test
* @dataProvider providePhpValues
*/
public function valueIsConvertedToDatabaseFormat(?\DateTimeInterface $value, ?string $expected)
{
$platform = $this->prophesize(AbstractPlatform::class);
$platform->getDateTimeFormatString()->willReturn('Y-m-d');
$this->assertEquals($expected, $this->type->convertToDatabaseValue($value, $platform->reveal()));
}
public function providePhpValues(): array
{
return [
[null, null],
[new \DateTimeImmutable('2017-01-01'), '2017-01-01'],
[Chronos::parse('2017-02-01'), '2017-02-01'],
[new \DateTime('2017-03-01'), '2017-03-01'],
];
}
/**
* @test
*/
public function exceptionIsThrownIfInvalidValueIsParsedToDatabase()
{
$this->expectException(ConversionException::class);
$this->type->convertToDatabaseValue(new \stdClass(), $this->prophesize(AbstractPlatform::class)->reveal());
}
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Common\Util;
use Cake\Chronos\Chronos;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Common\Util\DateRange;
@ -24,8 +25,8 @@ class DateRangeTest extends TestCase
*/
public function providedDatesAreSet()
{
$startDate = new \DateTime();
$endDate = new \DateTime();
$startDate = Chronos::now();
$endDate = Chronos::now();
$range = new DateRange($startDate, $endDate);
$this->assertSame($startDate, $range->getStartDate());
$this->assertSame($endDate, $range->getEndDate());

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Entity;
use Cake\Chronos\Chronos;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
@ -36,8 +37,8 @@ class ShortUrl extends AbstractEntity
*/
private $shortCode;
/**
* @var \DateTime
* @ORM\Column(name="date_created", type="datetime")
* @var Chronos
* @ORM\Column(name="date_created", type="chronos_datetime")
*/
private $dateCreated;
/**
@ -56,13 +57,13 @@ class ShortUrl extends AbstractEntity
*/
private $tags;
/**
* @var \DateTime
* @ORM\Column(name="valid_since", type="datetime", nullable=true)
* @var Chronos|null
* @ORM\Column(name="valid_since", type="chronos_datetime", nullable=true)
*/
private $validSince;
/**
* @var \DateTime
* @ORM\Column(name="valid_until", type="datetime", nullable=true)
* @var Chronos|null
* @ORM\Column(name="valid_until", type="chronos_datetime", nullable=true)
*/
private $validUntil;
/**
@ -74,7 +75,7 @@ class ShortUrl extends AbstractEntity
public function __construct()
{
$this->shortCode = '';
$this->dateCreated = new \DateTime();
$this->dateCreated = Chronos::now();
$this->visits = new ArrayCollection();
$this->tags = new ArrayCollection();
}
@ -117,12 +118,12 @@ class ShortUrl extends AbstractEntity
return $this;
}
public function getDateCreated(): \DateTime
public function getDateCreated(): Chronos
{
return $this->dateCreated;
}
public function setDateCreated(\DateTime $dateCreated): self
public function setDateCreated(Chronos $dateCreated): self
{
$this->dateCreated = $dateCreated;
return $this;
@ -151,23 +152,23 @@ class ShortUrl extends AbstractEntity
return $this;
}
public function getValidSince(): ?\DateTime
public function getValidSince(): ?Chronos
{
return $this->validSince;
}
public function setValidSince(?\DateTime $validSince): self
public function setValidSince(?Chronos $validSince): self
{
$this->validSince = $validSince;
return $this;
}
public function getValidUntil(): ?\DateTime
public function getValidUntil(): ?Chronos
{
return $this->validUntil;
}
public function setValidUntil(?\DateTime $validUntil): self
public function setValidUntil(?Chronos $validUntil): self
{
$this->validUntil = $validUntil;
return $this;

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Entity;
use Cake\Chronos\Chronos;
use Doctrine\ORM\Mapping as ORM;
use Shlinkio\Shlink\Common\Entity\AbstractEntity;
use Shlinkio\Shlink\Common\Exception\WrongIpException;
@ -25,8 +26,8 @@ class Visit extends AbstractEntity implements \JsonSerializable
*/
private $referer;
/**
* @var \DateTime
* @ORM\Column(type="datetime", nullable=false)
* @var Chronos
* @ORM\Column(type="chronos_datetime", nullable=false)
*/
private $date;
/**
@ -54,7 +55,7 @@ class Visit extends AbstractEntity implements \JsonSerializable
public function __construct()
{
$this->date = new \DateTime();
$this->date = Chronos::now();
}
public function getReferer(): string
@ -68,12 +69,12 @@ class Visit extends AbstractEntity implements \JsonSerializable
return $this;
}
public function getDate(): \DateTime
public function getDate(): Chronos
{
return $this->date;
}
public function setDate(\DateTime $date): self
public function setDate(Chronos $date): self
{
$this->date = $date;
return $this;
@ -148,7 +149,7 @@ class Visit extends AbstractEntity implements \JsonSerializable
{
return [
'referer' => $this->referer,
'date' => isset($this->date) ? $this->date->format(\DateTime::ATOM) : null,
'date' => isset($this->date) ? $this->date->toAtomString() : null,
'userAgent' => $this->userAgent,
'visitLocation' => $this->visitLocation,

View File

@ -3,17 +3,19 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Model;
use Cake\Chronos\Chronos;
use Shlinkio\Shlink\Core\Exception\ValidationException;
use Shlinkio\Shlink\Core\Validation\ShortUrlMetaInputFilter;
use function is_string;
final class ShortUrlMeta
{
/**
* @var \DateTime|null
* @var Chronos|null
*/
private $validSince;
/**
* @var \DateTime|null
* @var Chronos|null
*/
private $validUntil;
/**
@ -43,8 +45,8 @@ final class ShortUrlMeta
}
/**
* @param string|\DateTimeInterface|null $validSince
* @param string|\DateTimeInterface|null $validUntil
* @param string|Chronos|null $validSince
* @param string|Chronos|null $validUntil
* @param string|null $customSlug
* @param int|null $maxVisits
* @return ShortUrlMeta
@ -86,26 +88,23 @@ final class ShortUrlMeta
}
/**
* @param string|\DateTime|null $date
* @return \DateTime|null
* @param string|Chronos|null $date
* @return Chronos|null
*/
private function parseDateField($date): ?\DateTime
private function parseDateField($date): ?Chronos
{
if ($date === null || $date instanceof \DateTime) {
if ($date === null || $date instanceof Chronos) {
return $date;
}
if (\is_string($date)) {
return new \DateTime($date);
if (is_string($date)) {
return Chronos::parse($date);
}
return null;
}
/**
* @return \DateTime|null
*/
public function getValidSince(): ?\DateTime
public function getValidSince(): ?Chronos
{
return $this->validSince;
}
@ -115,10 +114,7 @@ final class ShortUrlMeta
return $this->validSince !== null;
}
/**
* @return \DateTime|null
*/
public function getValidUntil(): ?\DateTime
public function getValidUntil(): ?Chronos
{
return $this->validUntil;
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Repository;
use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Shlinkio\Shlink\Core\Entity\ShortUrl;
@ -131,7 +132,7 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
*/
public function findOneByShortCode(string $shortCode): ?ShortUrl
{
$now = new \DateTimeImmutable();
$now = Chronos::now();
$qb = $this->createQueryBuilder('s');
$qb->where($qb->expr()->eq('s.shortCode', ':shortCode'))

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Service;
use Cake\Chronos\Chronos;
use Cocur\Slugify\Slugify;
use Cocur\Slugify\SlugifyInterface;
use Doctrine\ORM\EntityManagerInterface;
@ -61,14 +62,6 @@ class UrlShortener implements UrlShortenerInterface
}
/**
* Creates and persists a unique shortcode generated for provided url
*
* @param UriInterface $url
* @param string[] $tags
* @param \DateTime|null $validSince
* @param \DateTime|null $validUntil
* @param string|null $customSlug
* @param int|null $maxVisits
* @throws NonUniqueSlugException
* @throws InvalidUrlException
* @throws RuntimeException
@ -76,10 +69,10 @@ class UrlShortener implements UrlShortenerInterface
public function urlToShortCode(
UriInterface $url,
array $tags = [],
\DateTime $validSince = null,
\DateTime $validUntil = null,
string $customSlug = null,
int $maxVisits = null
?Chronos $validSince = null,
?Chronos $validUntil = null,
?string $customSlug = null,
?int $maxVisits = null
): ShortUrl {
// If the URL validation is enabled, check that the URL actually exists
if ($this->urlValidationEnabled) {

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Service;
use Cake\Chronos\Chronos;
use Psr\Http\Message\UriInterface;
use Shlinkio\Shlink\Core\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Exception\EntityDoesNotExistException;
@ -14,14 +15,6 @@ use Shlinkio\Shlink\Core\Exception\RuntimeException;
interface UrlShortenerInterface
{
/**
* Creates and persists a unique shortcode generated for provided url
*
* @param UriInterface $url
* @param string[] $tags
* @param \DateTime|null $validSince
* @param \DateTime|null $validUntil
* @param string|null $customSlug
* @param int|null $maxVisits
* @throws NonUniqueSlugException
* @throws InvalidUrlException
* @throws RuntimeException
@ -29,10 +22,10 @@ interface UrlShortenerInterface
public function urlToShortCode(
UriInterface $url,
array $tags = [],
\DateTime $validSince = null,
\DateTime $validUntil = null,
string $customSlug = null,
int $maxVisits = null
?Chronos $validSince = null,
?Chronos $validUntil = null,
?string $customSlug = null,
?int $maxVisits = null
): ShortUrl;
/**

View File

@ -24,7 +24,6 @@ class ShortUrlDataTransformer implements DataTransformerInterface
/**
* @param ShortUrl $value
* @return array
*/
public function transform($value): array
{
@ -36,7 +35,7 @@ class ShortUrlDataTransformer implements DataTransformerInterface
'shortCode' => $shortCode,
'shortUrl' => $this->buildShortUrl($this->domainConfig, $shortCode),
'longUrl' => $longUrl,
'dateCreated' => $dateCreated !== null ? $dateCreated->format(\DateTime::ATOM) : null,
'dateCreated' => $dateCreated !== null ? $dateCreated->toAtomString() : null,
'visitsCount' => $value->getVisitsCount(),
'tags' => \array_map([$this, 'serializeTag'], $value->getTags()->toArray()),

View File

@ -12,12 +12,12 @@ class ShortUrlMetaInputFilter extends InputFilter
{
use InputFactoryTrait;
const VALID_SINCE = 'validSince';
const VALID_UNTIL = 'validUntil';
const CUSTOM_SLUG = 'customSlug';
const MAX_VISITS = 'maxVisits';
public const VALID_SINCE = 'validSince';
public const VALID_UNTIL = 'validUntil';
public const CUSTOM_SLUG = 'customSlug';
public const MAX_VISITS = 'maxVisits';
public function __construct(array $data = null)
public function __construct(?array $data = null)
{
$this->initialize();
if ($data !== null) {
@ -25,7 +25,7 @@ class ShortUrlMetaInputFilter extends InputFilter
}
}
private function initialize()
private function initialize(): void
{
$validSince = $this->createInput(self::VALID_SINCE, false);
$validSince->getValidatorChain()->attach(new Date(['format' => \DateTime::ATOM]));

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Repository;
use Cake\Chronos\Chronos;
use Doctrine\Common\Collections\ArrayCollection;
use Shlinkio\Shlink\Core\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Entity\Tag;
@ -41,7 +42,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
$bar = new ShortUrl();
$bar->setOriginalUrl('bar')
->setShortCode('bar_very_long_text')
->setValidSince((new \DateTime())->add(new \DateInterval('P1M')));
->setValidSince(Chronos::now()->addMonth());
$this->getEntityManager()->persist($bar);
$visits = [];

View File

@ -3,12 +3,14 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Repository;
use Cake\Chronos\Chronos;
use Shlinkio\Shlink\Common\Util\DateRange;
use Shlinkio\Shlink\Core\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Entity\Visit;
use Shlinkio\Shlink\Core\Entity\VisitLocation;
use Shlinkio\Shlink\Core\Repository\VisitRepository;
use ShlinkioTest\Shlink\Common\DbUnit\DatabaseTestCase;
use function sprintf;
class VisitRepositoryTest extends DatabaseTestCase
{
@ -61,7 +63,7 @@ class VisitRepositoryTest extends DatabaseTestCase
for ($i = 0; $i < 6; $i++) {
$visit = new Visit();
$visit->setShortUrl($shortUrl)
->setDate(new \DateTime('2016-01-0' . ($i + 1)));
->setDate(Chronos::parse(sprintf('2016-01-0%s', $i + 1)));
$this->getEntityManager()->persist($visit);
}
@ -70,11 +72,11 @@ class VisitRepositoryTest extends DatabaseTestCase
$this->assertCount(0, $this->repo->findVisitsByShortUrl('invalid'));
$this->assertCount(6, $this->repo->findVisitsByShortUrl($shortUrl->getId()));
$this->assertCount(2, $this->repo->findVisitsByShortUrl($shortUrl->getId(), new DateRange(
new \DateTime('2016-01-02'),
new \DateTime('2016-01-03')
Chronos::parse('2016-01-02'),
Chronos::parse('2016-01-03')
)));
$this->assertCount(4, $this->repo->findVisitsByShortUrl($shortUrl->getId(), new DateRange(
new \DateTime('2016-01-03')
Chronos::parse('2016-01-03')
)));
}
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Model;
use Cake\Chronos\Chronos;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\ValidationException;
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
@ -42,10 +43,10 @@ class ShortUrlMetaTest extends TestCase
*/
public function properlyCreatedInstanceReturnsValues()
{
$meta = ShortUrlMeta::createFromParams((new \DateTime('2015-01-01'))->format(\DateTime::ATOM), null, 'foobar');
$meta = ShortUrlMeta::createFromParams(Chronos::parse('2015-01-01')->toAtomString(), null, 'foobar');
$this->assertTrue($meta->hasValidSince());
$this->assertEquals(new \DateTime('2015-01-01'), $meta->getValidSince());
$this->assertEquals(Chronos::parse('2015-01-01'), $meta->getValidSince());
$this->assertFalse($meta->hasValidUntil());
$this->assertNull($meta->getValidUntil());

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Service;
use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use PHPUnit\Framework\TestCase;
@ -104,15 +105,15 @@ class ShortUrlServiceTest extends TestCase
$flush = $this->em->flush($shortUrl)->willReturn(null);
$result = $this->service->updateMetadataByShortCode('abc123', ShortUrlMeta::createFromParams(
(new \DateTime('2017-01-01 00:00:00'))->format(\DateTime::ATOM),
(new \DateTime('2017-01-05 00:00:00'))->format(\DateTime::ATOM),
Chronos::parse('2017-01-01 00:00:00')->toAtomString(),
Chronos::parse('2017-01-05 00:00:00')->toAtomString(),
null,
5
));
$this->assertSame($shortUrl, $result);
$this->assertEquals(new \DateTime('2017-01-01 00:00:00'), $shortUrl->getValidSince());
$this->assertEquals(new \DateTime('2017-01-05 00:00:00'), $shortUrl->getValidUntil());
$this->assertEquals(Chronos::parse('2017-01-01 00:00:00'), $shortUrl->getValidSince());
$this->assertEquals(Chronos::parse('2017-01-05 00:00:00'), $shortUrl->getValidUntil());
$this->assertEquals(5, $shortUrl->getMaxVisits());
$findShortUrl->shouldHaveBeenCalled();
$getRepo->shouldHaveBeenCalled();

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Action\ShortUrl;
use Cake\Chronos\Chronos;
use Psr\Http\Message\ServerRequestInterface as Request;
use Shlinkio\Shlink\Core\Exception\InvalidArgumentException;
use Shlinkio\Shlink\Core\Model\CreateShortUrlData;
@ -40,8 +41,8 @@ class CreateShortUrlAction extends AbstractCreateShortUrlAction
);
}
private function getOptionalDate(array $postData, string $fieldName)
private function getOptionalDate(array $postData, string $fieldName): ?Chronos
{
return isset($postData[$fieldName]) ? new \DateTime($postData[$fieldName]) : null;
return isset($postData[$fieldName]) ? Chronos::parse($postData[$fieldName]) : null;
}
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Action\Visit;
use Cake\Chronos\Chronos;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Log\LoggerInterface;
@ -75,18 +76,9 @@ class GetVisitsAction extends AbstractRestAction
}
}
/**
* @param Request $request
* @param string $key
* @return \DateTime|null
*/
private function getDateQueryParam(Request $request, string $key)
private function getDateQueryParam(Request $request, string $key): ?Chronos
{
$query = $request->getQueryParams();
if (! isset($query[$key]) || empty($query[$key])) {
return null;
}
return new \DateTime($query[$key]);
return ! isset($query[$key]) || empty($query[$key]) ? null : Chronos::parse($query[$key]);
}
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Entity;
use Cake\Chronos\Chronos;
use Doctrine\ORM\Mapping as ORM;
use Shlinkio\Shlink\Common\Entity\AbstractEntity;
use Shlinkio\Shlink\Common\Util\StringUtilsTrait;
@ -25,8 +26,8 @@ class ApiKey extends AbstractEntity
*/
private $key;
/**
* @var \DateTime|null
* @ORM\Column(name="expiration_date", nullable=true, type="datetime")
* @var Chronos|null
* @ORM\Column(name="expiration_date", nullable=true, type="chronos_datetime")
*/
private $expirationDate;
/**
@ -52,12 +53,12 @@ class ApiKey extends AbstractEntity
return $this;
}
public function getExpirationDate(): ?\DateTime
public function getExpirationDate(): ?Chronos
{
return $this->expirationDate;
}
public function setExpirationDate(\DateTime $expirationDate): self
public function setExpirationDate(Chronos $expirationDate): self
{
$this->expirationDate = $expirationDate;
return $this;
@ -69,7 +70,7 @@ class ApiKey extends AbstractEntity
return false;
}
return $this->expirationDate < new \DateTime();
return $this->expirationDate->lt(Chronos::now());
}
public function isEnabled(): bool

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Service;
use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityManagerInterface;
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
@ -20,13 +21,7 @@ class ApiKeyService implements ApiKeyServiceInterface
$this->em = $em;
}
/**
* Creates a new ApiKey with provided expiration date
*
* @param \DateTime $expirationDate
* @return ApiKey
*/
public function create(\DateTime $expirationDate = null): ApiKey
public function create(?Chronos $expirationDate = null): ApiKey
{
$key = new ApiKey();
if ($expirationDate !== null) {
@ -39,12 +34,6 @@ class ApiKeyService implements ApiKeyServiceInterface
return $key;
}
/**
* Checks if provided key is a valid api key
*
* @param string $key
* @return bool
*/
public function check(string $key): bool
{
/** @var ApiKey|null $apiKey */
@ -53,10 +42,6 @@ class ApiKeyService implements ApiKeyServiceInterface
}
/**
* Disables provided api key
*
* @param string $key
* @return ApiKey
* @throws InvalidArgumentException
*/
public function disable(string $key): ApiKey
@ -72,12 +57,6 @@ class ApiKeyService implements ApiKeyServiceInterface
return $apiKey;
}
/**
* Lists all existing api keys
*
* @param bool $enabledOnly Tells if only enabled keys should be returned
* @return ApiKey[]
*/
public function listKeys(bool $enabledOnly = false): array
{
$conditions = $enabledOnly ? ['enabled' => true] : [];
@ -86,12 +65,6 @@ class ApiKeyService implements ApiKeyServiceInterface
return $apiKeys;
}
/**
* Tries to find one API key by its key string
*
* @param string $key
* @return ApiKey|null
*/
public function getByKey(string $key): ?ApiKey
{
/** @var ApiKey|null $apiKey */

View File

@ -3,49 +3,22 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Service;
use Cake\Chronos\Chronos;
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
interface ApiKeyServiceInterface
{
/**
* Creates a new ApiKey with provided expiration date
*
* @param \DateTime $expirationDate
* @return ApiKey
*/
public function create(\DateTime $expirationDate = null): ApiKey;
public function create(?Chronos $expirationDate = null): ApiKey;
/**
* Checks if provided key is a valid api key
*
* @param string $key
* @return bool
*/
public function check(string $key): bool;
/**
* Disables provided api key
*
* @param string $key
* @return ApiKey
* @throws InvalidArgumentException
*/
public function disable(string $key): ApiKey;
/**
* Lists all existing api keys
*
* @param bool $enabledOnly Tells if only enabled keys should be returned
* @return ApiKey[]
*/
public function listKeys(bool $enabledOnly = false): array;
/**
* Tries to find one API key by its key string
*
* @param string $key
* @return ApiKey|null
*/
public function getByKey(string $key): ?ApiKey;
}

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Rest\Action\Visit;
use Cake\Chronos\Chronos;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
@ -77,7 +78,7 @@ class GetVisitsActionTest extends TestCase
public function datesAreReadFromQuery()
{
$shortCode = 'abc123';
$this->visitsTracker->info($shortCode, new DateRange(null, new \DateTime('2016-01-01 00:00:00')))
$this->visitsTracker->info($shortCode, new DateRange(null, Chronos::parse('2016-01-01 00:00:00')))
->willReturn([])
->shouldBeCalledTimes(1);

View File

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace ShlinkioTest\Shlink\Rest\Service;
use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use PHPUnit\Framework\TestCase;
@ -48,7 +49,7 @@ class ApiKeyServiceTest extends TestCase
$this->em->flush()->shouldBeCalledTimes(1);
$this->em->persist(Argument::type(ApiKey::class))->shouldBeCalledTimes(1);
$date = new \DateTime('2030-01-01');
$date = Chronos::parse('2030-01-01');
$key = $this->service->create($date);
$this->assertSame($date, $key->getExpirationDate());
}
@ -87,7 +88,7 @@ class ApiKeyServiceTest extends TestCase
public function checkReturnsFalseWhenKeyIsExpired()
{
$key = new ApiKey();
$key->setExpirationDate((new \DateTime())->sub(new \DateInterval('P1D')));
$key->setExpirationDate(Chronos::now()->subDay());
$repo = $this->prophesize(EntityRepository::class);
$repo->findOneBy(['key' => '12345'])->willReturn($key)
->shouldBeCalledTimes(1);