Make Visit::jsonSerialize() return different props for orphan visits

This commit is contained in:
Alejandro Celaya 2024-03-24 16:54:49 +01:00
parent fbd35b7974
commit a327e6c0a7
3 changed files with 60 additions and 55 deletions

View file

@ -54,7 +54,10 @@ abstract class AbstractVisitsListCommand extends Command
$extraKeys = array_keys($extraFields);
$rowData = [
...$visit->jsonSerialize(),
'referer' => $visit->referer,
'date' => $visit->getDate()->toAtomString(),
'userAgent' => $visit->userAgent,
'potentialBot' => $visit->potentialBot,
'country' => $visit->getVisitLocation()?->countryName ?? 'Unknown',
'city' => $visit->getVisitLocation()?->cityName ?? 'Unknown',
...$extraFields,

View file

@ -25,17 +25,60 @@ class Visit extends AbstractEntity implements JsonSerializable
public readonly VisitType $type,
public readonly string $userAgent,
public readonly string $referer,
private readonly bool $potentialBot,
public readonly bool $potentialBot,
public readonly ?string $remoteAddr = null,
public readonly ?string $visitedUrl = null,
private ?VisitLocation $visitLocation = null,
// TODO Make public readonly once VisitRepositoryTest does not try to set it
private Chronos $date = new Chronos(),
) {
}
public static function forValidShortUrl(ShortUrl $shortUrl, Visitor $visitor, bool $anonymize = true): self
{
return self::hydrateFromVisitor($shortUrl, VisitType::VALID_SHORT_URL, $visitor, $anonymize);
return self::fromVisitor($shortUrl, VisitType::VALID_SHORT_URL, $visitor, $anonymize);
}
public static function forBasePath(Visitor $visitor, bool $anonymize = true): self
{
return self::fromVisitor(null, VisitType::BASE_URL, $visitor, $anonymize);
}
public static function forInvalidShortUrl(Visitor $visitor, bool $anonymize = true): self
{
return self::fromVisitor(null, VisitType::INVALID_SHORT_URL, $visitor, $anonymize);
}
public static function forRegularNotFound(Visitor $visitor, bool $anonymize = true): self
{
return self::fromVisitor(null, VisitType::REGULAR_404, $visitor, $anonymize);
}
private static function fromVisitor(?ShortUrl $shortUrl, VisitType $type, Visitor $visitor, bool $anonymize): self
{
return new self(
shortUrl: $shortUrl,
type: $type,
userAgent: $visitor->userAgent,
referer: $visitor->referer,
potentialBot: $visitor->isPotentialBot(),
remoteAddr: self::processAddress($visitor->remoteAddress, $anonymize),
visitedUrl: $visitor->visitedUrl,
);
}
private static function processAddress(?string $address, bool $anonymize): ?string
{
// Localhost address does not need to be anonymized
if (! $anonymize || $address === null || $address === IpAddress::LOCALHOST) {
return $address;
}
try {
return IpAddress::fromString($address)->getAnonymizedCopy()->__toString();
} catch (InvalidArgumentException) {
return null;
}
}
public static function fromImport(ShortUrl $shortUrl, ImportedShlinkVisit $importedVisit): self
@ -69,52 +112,6 @@ class Visit extends AbstractEntity implements JsonSerializable
);
}
public static function forBasePath(Visitor $visitor, bool $anonymize = true): self
{
return self::hydrateFromVisitor(null, VisitType::BASE_URL, $visitor, $anonymize);
}
public static function forInvalidShortUrl(Visitor $visitor, bool $anonymize = true): self
{
return self::hydrateFromVisitor(null, VisitType::INVALID_SHORT_URL, $visitor, $anonymize);
}
public static function forRegularNotFound(Visitor $visitor, bool $anonymize = true): self
{
return self::hydrateFromVisitor(null, VisitType::REGULAR_404, $visitor, $anonymize);
}
private static function hydrateFromVisitor(
?ShortUrl $shortUrl,
VisitType $type,
Visitor $visitor,
bool $anonymize,
): self {
return new self(
shortUrl: $shortUrl,
type: $type,
userAgent: $visitor->userAgent,
referer: $visitor->referer,
potentialBot: $visitor->isPotentialBot(),
remoteAddr: self::processAddress($anonymize, $visitor->remoteAddress),
visitedUrl: $visitor->visitedUrl,
);
}
private static function processAddress(bool $anonymize, ?string $address): ?string
{
// Localhost addresses do not need to be anonymized
if (! $anonymize || $address === null || $address === IpAddress::LOCALHOST) {
return $address;
}
try {
return IpAddress::fromString($address)->getAnonymizedCopy()->__toString();
} catch (InvalidArgumentException) {
return null;
}
}
public function hasRemoteAddr(): bool
{
return ! empty($this->remoteAddr);
@ -160,12 +157,21 @@ class Visit extends AbstractEntity implements JsonSerializable
public function jsonSerialize(): array
{
return [
$base = [
'referer' => $this->referer,
'date' => $this->date->toAtomString(),
'userAgent' => $this->userAgent,
'visitLocation' => $this->visitLocation,
'potentialBot' => $this->potentialBot,
];
if (! $this->isOrphan()) {
return $base;
}
return [
...$base,
'visitedUrl' => $this->visitedUrl,
'type' => $this->type->value,
];
}
}

View file

@ -14,10 +14,6 @@ class OrphanVisitDataTransformer implements DataTransformerInterface
*/
public function transform($visit): array // phpcs:ignore
{
$serializedVisit = $visit->jsonSerialize();
$serializedVisit['visitedUrl'] = $visit->visitedUrl;
$serializedVisit['type'] = $visit->type->value;
return $serializedVisit;
return $visit->jsonSerialize();
}
}