Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FAU-441] Inclusion of Timestamps in Existing Degree Program API Responses #16

Merged
merged 6 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@
<code><![CDATA[AdmissionRequirementTranslatedType]]></code>
</InvalidReturnType>
</file>
<file src="src/Application/DegreeProgramViewTranslated.php">
<RiskyTruthyFalsyComparison>
<code><![CDATA[empty($data[self::TRANSLATIONS])]]></code>
</RiskyTruthyFalsyComparison>
</file>
<file src="src/Application/Filter/AdmissionRequirementTypeFilter.php">
<RiskyTruthyFalsyComparison>
<code><![CDATA[$sanitizedValue]]></code>
Expand Down
15 changes: 11 additions & 4 deletions src/Application/Cache/CacheInvalidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
use Psr\SimpleCache\CacheInterface;
use Psr\SimpleCache\InvalidArgumentException;

/**
* @psalm-import-type Reason from CacheInvalidated
*/
final class CacheInvalidator
{
public function __construct(
Expand All @@ -21,7 +24,10 @@ public function __construct(
) {
}

public function invalidateFully(): bool
/**
* @psalm-param Reason $reason
*/
public function invalidateFully(string $reason = CacheInvalidated::ENFORCED): bool
{
$result = $this->cache->clear();
if (!$result) {
Expand All @@ -30,16 +36,17 @@ public function invalidateFully(): bool
}

$this->logger->info('Successful degree program full cache invalidation.');
$this->eventDispatcher->dispatch(CacheInvalidated::fully());
$this->eventDispatcher->dispatch(CacheInvalidated::fully($reason));
return true;
}

/**
* @psalm-param array<int> $ids
* @psalm-param Reason $reason
*
* @throws InvalidArgumentException
*/
public function invalidatePartially(array $ids): bool
public function invalidatePartially(array $ids, string $reason = CacheInvalidated::ENFORCED): bool
{
if (count($ids) === 0) {
$this->logger->debug(
Expand Down Expand Up @@ -81,7 +88,7 @@ public function invalidatePartially(array $ids): bool
implode(', ', $ids)
)
);
$this->eventDispatcher->dispatch(CacheInvalidated::partially($ids));
$this->eventDispatcher->dispatch(CacheInvalidated::partially($ids, $reason));

return true;
}
Expand Down
35 changes: 33 additions & 2 deletions src/Application/DegreeProgramViewTranslated.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,15 @@
* }
* @psalm-type DegreeProgramViewTranslatedArrayType = DegreeProgramTranslation & array{
* id: int,
* date: string,
* modified: string,
* translations: array<LanguageCodes, DegreeProgramTranslation>,
* }
*/
final class DegreeProgramViewTranslated implements JsonSerializable
{
public const DATE = 'date';
public const MODIFIED = 'modified';
public const LINK = 'link';
public const LANG = 'lang';
public const ADMISSION_REQUIREMENT_LINK = 'admission_requirement_link';
Expand All @@ -94,6 +98,8 @@ final class DegreeProgramViewTranslated implements JsonSerializable

public function __construct(
private DegreeProgramId $id,
private string $date,
private string $modified,
private string $link,
private string $slug,
/**
Expand Down Expand Up @@ -160,6 +166,8 @@ public static function empty(int $id, string $languageCode): self
{
return new self(
DegreeProgramId::fromInt($id),
date: '',
modified: '',
link: '',
slug: '',
lang: $languageCode,
Expand Down Expand Up @@ -220,6 +228,8 @@ public static function empty(int $id, string $languageCode): self
/**
* @psalm-param DegreeProgramTranslation & array{
* id: int | numeric-string,
* date: string,
* modified: string,
* translations?: array<LanguageCodes, DegreeProgramTranslation>,
* } $data
*
Expand All @@ -229,6 +239,8 @@ public static function fromArray(array $data): self
{
$main = new self(
id: DegreeProgramId::fromInt((int) $data[DegreeProgram::ID]),
date: $data[self::DATE] ?? '',
modified: $data[self::MODIFIED] ?? '',
link: $data[self::LINK],
slug: $data[DegreeProgram::SLUG],
lang: $data[self::LANG],
Expand Down Expand Up @@ -285,12 +297,14 @@ public static function fromArray(array $data): self
campoKeys: CampoKeys::fromArray($data[DegreeProgram::CAMPO_KEYS] ?? []),
);

if (empty($data[self::TRANSLATIONS])) {
if (!isset($data[self::TRANSLATIONS]) || count($data[self::TRANSLATIONS]) === 0) {
return $main;
}

foreach ($data[self::TRANSLATIONS] as $translationData) {
$translationData[DegreeProgram::ID] = $data[DegreeProgram::ID];
$translationData[self::DATE] = $data[self::DATE];
$translationData[self::MODIFIED] = $data[self::MODIFIED];
$main = $main->withTranslation(self::fromArray($translationData), $translationData[self::LANG]);
}

Expand All @@ -304,6 +318,8 @@ public function asArray(): array
{
return [
DegreeProgram::ID => $this->id->asInt(),
self::DATE => $this->date,
self::MODIFIED => $this->modified,
self::LINK => $this->link,
DegreeProgram::SLUG => $this->slug,
self::LANG => $this->lang,
Expand Down Expand Up @@ -408,7 +424,12 @@ private function translationsAsArray(): array
{
return array_map(static function (DegreeProgramViewTranslated $view): array {
$result = $view->asArray();
unset($result[DegreeProgram::ID], $result[self::TRANSLATIONS]);
unset(
$result[DegreeProgram::ID],
$result[self::DATE],
$result[self::MODIFIED],
$result[self::TRANSLATIONS]
);

return $result;
}, $this->translations);
Expand All @@ -419,6 +440,16 @@ public function id(): int
return $this->id->asInt();
}

public function date(): string
{
return $this->date;
}

public function modified(): string
{
return $this->modified;
}

public function link(): string
{
return $this->link;
Expand Down
27 changes: 23 additions & 4 deletions src/Application/Event/CacheInvalidated.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,41 @@

use Stringable;

/**
* @psalm-type Reason = self::ENFORCED | self::DATA_CHANGED
*/
final class CacheInvalidated implements Stringable
{
public const NAME = 'degree_program_cache_invalidated';
public const ENFORCED = 'enforced';
public const DATA_CHANGED = 'data_changed';

/**
* @param array<int> $ids
* @param Reason $reason
*/
private function __construct(
private bool $isFully,
private array $ids,
private string $reason,
) {
}

public static function fully(): self
/**
* @param Reason $reason
*/
public static function fully(string $reason): self
{
return new self(true, []);
return new self(true, [], $reason);
}

/**
* @param array<int> $ids
* @param Reason $reason
*/
public static function partially(array $ids): self
public static function partially(array $ids, string $reason): self
{
return new self(false, $ids);
return new self(false, $ids, $reason);
}

public function isFully(): bool
Expand All @@ -45,6 +56,14 @@ public function ids(): array
return $this->ids;
}

/**
* @return Reason
*/
public function reason(): string
{
return $this->reason;
}

public function __toString(): string
{
return self::NAME;
Expand Down
49 changes: 49 additions & 0 deletions src/Infrastructure/Repository/TimestampRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Fau\DegreeProgram\Common\Infrastructure\Repository;

use DateTimeImmutable;
use DateTimeInterface;
use Fau\DegreeProgram\Common\Domain\DegreeProgramId;

final class TimestampRepository
{
private const MODIFIED_META_KEY = 'degree_program_modified';

public function created(DegreeProgramId $id): ?DateTimeInterface
{
$postDateTime = get_post_datetime($id->asInt());

return $postDateTime instanceof DateTimeInterface ? $postDateTime : null;
}

/**
* The custom field is updated when the degree program or related settings or terms are updated.
* If the custom field does not exist,
* we fall back to the core WordPress "post modified" property.
*/
public function modified(DegreeProgramId $id): ?DateTimeInterface
{
$timestamp = (int) get_post_meta($id->asInt(), self::MODIFIED_META_KEY, true);

if ($timestamp < 1) {
$timestamp = get_post_timestamp($id->asInt(), 'modified');
}

if (!is_int($timestamp)) {
return null;
}

$dateTime = new DateTimeImmutable();
$dateTime = $dateTime->setTimestamp($timestamp);

return $dateTime->setTimezone(wp_timezone());
}

public function updateModified(DegreeProgramId $id): void
{
update_post_meta($id->asInt(), self::MODIFIED_META_KEY, time());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Fau\DegreeProgram\Common\Infrastructure\Repository;

use DateTimeInterface;
use Fau\DegreeProgram\Common\Application\AdmissionRequirementsTranslated;
use Fau\DegreeProgram\Common\Application\AdmissionRequirementTranslated;
use Fau\DegreeProgram\Common\Application\ConditionalFieldsFilter;
Expand Down Expand Up @@ -33,11 +34,14 @@
*/
final class WordPressDatabaseDegreeProgramViewRepository implements DegreeProgramViewRepository
{
private const DATE_TIME_FORMAT = DateTimeInterface::RFC3339;

public function __construct(
private DegreeProgramRepository $degreeProgramRepository,
private HtmlDegreeProgramSanitizer $htmlContentSanitizer,
private ConditionalFieldsFilter $conditionalFieldsFilter,
private FacultyRepository $facultyRepository,
private TimestampRepository $timestampRepository,
) {
}

Expand Down Expand Up @@ -100,6 +104,8 @@ private function translateDegreeProgram(

return new DegreeProgramViewTranslated(
id: $raw->id(),
date: (string) $this->timestampRepository->created($raw->id())?->format(self::DATE_TIME_FORMAT),
modified: (string) $this->timestampRepository->modified($raw->id())?->format(self::DATE_TIME_FORMAT),
link: $this->link(
$raw->id()->asInt(),
$raw->slug(),
Expand Down
18 changes: 18 additions & 0 deletions src/Infrastructure/RestApi/TranslatedDegreeProgramController.php
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,24 @@ public function get_item_schema(): array
),
'type' => 'integer',
],
DegreeProgramViewTranslated::DATE => [
'description' => _x(
'The date the degree program was created.',
'rest_api: schema item description',
'fau-degree-program-common'
),
'type' => 'string',
'format' => 'date-time',
],
DegreeProgramViewTranslated::MODIFIED => [
'description' => _x(
'The date the degree program was last modified.',
'rest_api: schema item description',
'fau-degree-program-common'
),
'type' => 'string',
'format' => 'date-time',
],
DegreeProgram::FEATURED_IMAGE => [
'description' => _x(
'Feature image.',
Expand Down