From 0ec4447dd84575b1300db49b3e33c4bdbfba0d6f Mon Sep 17 00:00:00 2001 From: Amin Date: Wed, 15 May 2024 21:08:11 +0200 Subject: [PATCH 1/8] feat: add campo keys to degree program --- config/schema_draft.php | 2 + config/schema_publish.php | 2 + src/Application/DegreeProgramViewRaw.php | 10 ++ .../DegreeProgramViewTranslated.php | 11 ++ .../Repository/CollectionCriteria.php | 25 ++++ src/Domain/CampoKeys.php | 133 ++++++++++++++++++ src/Domain/DegreeProgram.php | 9 ++ .../Repository/CampoKeysRepository.php | 104 ++++++++++++++ ...rdPressDatabaseDegreeProgramRepository.php | 2 + ...essDatabaseDegreeProgramViewRepository.php | 1 + .../Repository/WpQueryArgsBuilder.php | 37 ++++- .../JsonSchemaDegreeProgramDataValidator.php | 1 + tests/resources/fixtures/degree_program.json | 5 + .../FixtureDegreeProgramDataProviderTrait.php | 2 + .../StubDegreeProgramRepository.php | 1 + 15 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 src/Domain/CampoKeys.php create mode 100644 src/Infrastructure/Repository/CampoKeysRepository.php diff --git a/config/schema_draft.php b/config/schema_draft.php index e413877..144bdf5 100644 --- a/config/schema_draft.php +++ b/config/schema_draft.php @@ -4,6 +4,7 @@ use Fau\DegreeProgram\Common\Domain\AdmissionRequirement; use Fau\DegreeProgram\Common\Domain\AdmissionRequirements; +use Fau\DegreeProgram\Common\Domain\CampoKeys; use Fau\DegreeProgram\Common\Domain\Content; use Fau\DegreeProgram\Common\Domain\ContentItem; use Fau\DegreeProgram\Common\Domain\Degree; @@ -150,5 +151,6 @@ DegreeProgram::STUDENT_INITIATIVES => MultilingualLink::SCHEMA, DegreeProgram::APPLY_NOW_LINK => MultilingualLink::SCHEMA, DegreeProgram::ENTRY_TEXT => MultilingualString::SCHEMA, + DegreeProgram::CAMPO_KEYS => CampoKeys::SCHEMA, ], ]; diff --git a/config/schema_publish.php b/config/schema_publish.php index 942ea54..dba036f 100644 --- a/config/schema_publish.php +++ b/config/schema_publish.php @@ -4,6 +4,7 @@ use Fau\DegreeProgram\Common\Domain\AdmissionRequirement; use Fau\DegreeProgram\Common\Domain\AdmissionRequirements; +use Fau\DegreeProgram\Common\Domain\CampoKeys; use Fau\DegreeProgram\Common\Domain\Content; use Fau\DegreeProgram\Common\Domain\ContentItem; use Fau\DegreeProgram\Common\Domain\Degree; @@ -155,5 +156,6 @@ DegreeProgram::STUDENT_INITIATIVES => MultilingualLink::SCHEMA, DegreeProgram::APPLY_NOW_LINK => MultilingualLink::SCHEMA_REQUIRED, DegreeProgram::ENTRY_TEXT => MultilingualString::SCHEMA_REQUIRED, + DegreeProgram::CAMPO_KEYS => CampoKeys::SCHEMA_REQUIRED, ], ]; diff --git a/src/Application/DegreeProgramViewRaw.php b/src/Application/DegreeProgramViewRaw.php index 2729f74..850d007 100644 --- a/src/Application/DegreeProgramViewRaw.php +++ b/src/Application/DegreeProgramViewRaw.php @@ -5,6 +5,7 @@ namespace Fau\DegreeProgram\Common\Application; use Fau\DegreeProgram\Common\Domain\AdmissionRequirements; +use Fau\DegreeProgram\Common\Domain\CampoKeys; use Fau\DegreeProgram\Common\Domain\Content; use Fau\DegreeProgram\Common\Domain\Degree; use Fau\DegreeProgram\Common\Domain\DegreeProgram; @@ -75,6 +76,7 @@ private function __construct( private MultilingualLink $studentInitiatives, private MultilingualLink $applyNowLink, private MultilingualString $entryText, + private CampoKeys $campoKeys, ) { } @@ -134,6 +136,7 @@ public static function fromDegreeProgram(DegreeProgram $degreeProgram): self $data[DegreeProgram::STUDENT_INITIATIVES], $data[DegreeProgram::APPLY_NOW_LINK], $data[DegreeProgram::ENTRY_TEXT], + $data[DegreeProgram::CAMPO_KEYS], ); } @@ -198,6 +201,7 @@ public static function fromArray(array $data): self ), applyNowLink: MultilingualLink::fromArray($data[DegreeProgram::APPLY_NOW_LINK]), entryText: MultilingualString::fromArray($data[DegreeProgram::ENTRY_TEXT]), + campoKeys: CampoKeys::fromArray($data[DegreeProgram::CAMPO_KEYS] ?? []), // TODO: check to see why undefined value is possible. It gives fatal on revision repository due to null value. ); } @@ -261,6 +265,7 @@ public function asArray(): array DegreeProgram::STUDENT_INITIATIVES => $this->studentInitiatives->asArray(), DegreeProgram::APPLY_NOW_LINK => $this->applyNowLink->asArray(), DegreeProgram::ENTRY_TEXT => $this->entryText->asArray(), + DegreeProgram::CAMPO_KEYS => $this->campoKeys->asArray(), ]; } @@ -513,4 +518,9 @@ public function entryText(): MultilingualString { return $this->entryText; } + + public function campoKeys(): CampoKeys + { + return $this->campoKeys; + } } diff --git a/src/Application/DegreeProgramViewTranslated.php b/src/Application/DegreeProgramViewTranslated.php index c49dbc1..0c6a1a2 100644 --- a/src/Application/DegreeProgramViewTranslated.php +++ b/src/Application/DegreeProgramViewTranslated.php @@ -4,6 +4,7 @@ namespace Fau\DegreeProgram\Common\Application; +use Fau\DegreeProgram\Common\Domain\CampoKeys; use Fau\DegreeProgram\Common\Domain\DegreeProgram; use Fau\DegreeProgram\Common\Domain\DegreeProgramId; use Fau\DegreeProgram\Common\Domain\MultilingualString; @@ -73,6 +74,7 @@ * student_initiatives: LinkType, * apply_now_link: LinkType, * entry_text: string, + * campo_keys: array * } * @psalm-type DegreeProgramViewTranslatedArrayType = DegreeProgramTranslation & array{ * id: int, @@ -145,6 +147,7 @@ public function __construct( private Link $studentInitiatives, private Link $applyNowLink, private string $entryText, + private CampoKeys $campoKeys, ) { } @@ -209,6 +212,7 @@ public static function empty(int $id, string $languageCode): self studentInitiatives: Link::empty(), applyNowLink: Link::empty(), entryText: '', + campoKeys: CampoKeys::empty(), ); } @@ -277,6 +281,7 @@ public static function fromArray(array $data): self studentInitiatives: Link::fromArray($data[DegreeProgram::STUDENT_INITIATIVES]), applyNowLink: Link::fromArray($data[DegreeProgram::APPLY_NOW_LINK]), entryText: $data[DegreeProgram::ENTRY_TEXT], + campoKeys: CampoKeys::fromArray($data[DegreeProgram::CAMPO_KEYS]), ); if (empty($data[self::TRANSLATIONS])) { @@ -350,6 +355,7 @@ public function asArray(): array DegreeProgram::STUDENT_INITIATIVES => $this->studentInitiatives->asArray(), DegreeProgram::APPLY_NOW_LINK => $this->applyNowLink->asArray(), DegreeProgram::ENTRY_TEXT => $this->entryText, + DegreeProgram::CAMPO_KEYS => $this->campoKeys->asArray(), self::TRANSLATIONS => $this->translationsAsArray(), ]; } @@ -669,4 +675,9 @@ public function entryText(): string { return $this->entryText; } + + public function campoKeys(): CampoKeys + { + return $this->campoKeys; + } } diff --git a/src/Application/Repository/CollectionCriteria.php b/src/Application/Repository/CollectionCriteria.php index b9cc924..53dd383 100644 --- a/src/Application/Repository/CollectionCriteria.php +++ b/src/Application/Repository/CollectionCriteria.php @@ -18,6 +18,7 @@ * include?: array, * search?: string, * order_by: OrderBy, + * his_codes?: array * } */ final class CollectionCriteria @@ -36,6 +37,11 @@ final class CollectionCriteria */ private array $filters = []; + /** + * @var array + */ + private array $hisCodes = []; + /** * @var LanguageCodes|null */ @@ -170,6 +176,17 @@ public function withOrderBy(array $orderBy): self return $instance; } + /** + * @param array $hisCodes + * @return self + */ + public function withHisCodes(array $hisCodes): self + { + $instance = clone $this; + $instance->hisCodes = $hisCodes; + return $instance; + } + /** * @psalm-return SupportedArgs */ @@ -185,4 +202,12 @@ public function filters(): array { return $this->filters; } + + /** + * @return array + */ + public function hisCodes(): array + { + return $this->hisCodes; + } } diff --git a/src/Domain/CampoKeys.php b/src/Domain/CampoKeys.php new file mode 100644 index 0000000..56939dd --- /dev/null +++ b/src/Domain/CampoKeys.php @@ -0,0 +1,133 @@ + 'object', + 'properties' => [ + DegreeProgram::DEGREE => [ + 'type' => 'string', + ], + DegreeProgram::AREA_OF_STUDY => [ + 'type' => 'string', + ], + DegreeProgram::LOCATION => [ + 'type' => 'string', + ], + ], + ]; + + public const SCHEMA_REQUIRED = [ + 'type' => 'object', + 'properties' => [ + DegreeProgram::DEGREE => [ + 'type' => 'string', + ], + DegreeProgram::AREA_OF_STUDY => [ + 'type' => 'string', + ], + DegreeProgram::LOCATION => [ + 'type' => 'string', + ], + ], + ]; + + public const SUPPORTED_CAMPO_KEYS = [ + DegreeProgram::DEGREE, + DegreeProgram::AREA_OF_STUDY, + DegreeProgram::LOCATION, + ]; + + private const HIS_CODE_DELIMITER = '|'; + + /** @var array */ + private array $map = []; + + private function __construct() + { + } + + public static function empty(): self + { + return new self(); + } + + /** + * @psalm-param array $data + */ + public static function fromArray(array $data): self + { + $instance = new self(); + + foreach ($data as $key => $value) { + $instance->set($key, $value); + } + + return $instance; + } + + public static function fromHisCode(string $hisCode): self + { + $parts = explode(self::HIS_CODE_DELIMITER, $hisCode); + + $instance = new self(); + + if (isset($parts[0])) { + $instance->set(DegreeProgram::DEGREE, $parts[0]); + } + + if (isset($parts[1])) { + $instance->set(DegreeProgram::AREA_OF_STUDY, $parts[1]); + } + + if (isset($parts[6])) { + $instance->set(DegreeProgram::LOCATION, $parts[6]); + } + + return $instance; + } + + public function set(string $key, string $value): self + { + if (! in_array($key, self::SUPPORTED_CAMPO_KEYS)) { + throw new InvalidArgumentException('Unsupported field key.'); + } + + $this->map[$key] = $value; + return $this; + } + + public function degree(): ?string + { + return $this->get(DegreeProgram::DEGREE); + } + + public function areaOfStudy(): ?string + { + return $this->get(DegreeProgram::AREA_OF_STUDY); + } + + public function studyLocation(): ?string + { + return $this->get(DegreeProgram::LOCATION); + } + + public function get(string $key): ?string + { + return $this->map[$key] ?? null; + } + + /** + * @return array + */ + public function asArray(): array + { + return $this->map; + } +} diff --git a/src/Domain/DegreeProgram.php b/src/Domain/DegreeProgram.php index 6ed4fc0..7251c73 100644 --- a/src/Domain/DegreeProgram.php +++ b/src/Domain/DegreeProgram.php @@ -67,6 +67,7 @@ * student_initiatives: MultilingualLinkType, * apply_now_link: MultilingualLinkType, * entry_text: MultilingualStringType, + * campo_keys: array, * } */ final class DegreeProgram @@ -122,6 +123,7 @@ final class DegreeProgram public const NOTES_FOR_INTERNATIONAL_APPLICANTS = 'notes_for_international_applicants'; public const STUDENT_INITIATIVES = 'student_initiatives'; public const APPLY_NOW_LINK = 'apply_now_link'; + public const CAMPO_KEYS = 'campo_keys'; private IntegersListChangeset $combinationsChangeset; private IntegersListChangeset $limitedCombinationsChangeset; @@ -315,6 +317,10 @@ public function __construct( * Eingeschränkt Kombinationsmöglichkeiten */ private DegreeProgramIds $limitedCombinations, + /** + * CampoKeys + */ + private CampoKeys $campoKeys, ) { $this->combinationsChangeset = IntegersListChangeset::new( @@ -451,6 +457,7 @@ private function update(array $data): void $this->studentInitiatives = MultilingualLink::fromArray($data[self::STUDENT_INITIATIVES]); $this->applyNowLink = MultilingualLink::fromArray($data[self::APPLY_NOW_LINK]); $this->entryText = MultilingualString::fromArray($data[self::ENTRY_TEXT]); + $this->campoKeys = CampoKeys::fromArray($data[self::CAMPO_KEYS]); $this->combinationsChangeset = $this ->combinationsChangeset @@ -515,6 +522,7 @@ private function update(array $data): void * student_initiatives: MultilingualLink, * apply_now_link: MultilingualLink, * entry_text: MultilingualString, + * campo_keys: CampoKeys, * } * @internal Only for repositories usage * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong @@ -574,6 +582,7 @@ public function asArray(): array self::STUDENT_INITIATIVES => $this->studentInitiatives, self::APPLY_NOW_LINK => $this->applyNowLink, self::ENTRY_TEXT => $this->entryText, + self::CAMPO_KEYS => $this->campoKeys, ]; } diff --git a/src/Infrastructure/Repository/CampoKeysRepository.php b/src/Infrastructure/Repository/CampoKeysRepository.php new file mode 100644 index 0000000..b6d4c66 --- /dev/null +++ b/src/Infrastructure/Repository/CampoKeysRepository.php @@ -0,0 +1,104 @@ + DegreeProgram::DEGREE, + StudyLocationTaxonomy::KEY => DegreeProgram::LOCATION, + AreaOfStudyTaxonomy::KEY => DegreeProgram::AREA_OF_STUDY, + ]; + + public const CAMPOKEY_TERM_META_KEY = 'uniquename'; + + public function degreeProgramCampoKeys(DegreeProgramId $degreeProgramId): CampoKeys + { + $campoKeys = CampoKeys::empty(); + + /** @var WP_Error|array $terms */ + $terms = wp_get_post_terms( + $degreeProgramId->asInt(), + array_keys(self::CAMPO_KEYS_TOTAXONOMY_MAP) + ); + + if ($terms instanceof WP_Error) { + return $campoKeys; + } + + foreach ($terms as $term) { + $campoKey = (string) get_term_meta($term->term_id, self::CAMPOKEY_TERM_META_KEY, true); + + if (empty($campoKey)) { + continue; + } + + $campoKeyType = self::CAMPO_KEYS_TOTAXONOMY_MAP[$term->taxonomy] ?? null; + + if (is_null($campoKeyType)) { + continue; + } + + $campoKeys->set($campoKeyType, $campoKey); + } + + return $campoKeys; + } + + /** + * Return a map of taxonomy keys to terms based on a given HIS code. + * + * @return array + */ + public function taxonomyToTermsMapFromCampoKeys(CampoKeys $campoKeys): array + { + $result = []; + + $campoKeys = $campoKeys->asArray(); + + foreach (self::CAMPO_KEYS_TOTAXONOMY_MAP as $taxonomy => $campoKeyType) { + $campoKey = $campoKeys[$campoKeyType] ?? ''; + + if ($campoKey === '') { + continue; + } + + $term = $this->findTermByCampoKey($taxonomy, $campoKey); + $result[$taxonomy] = ! is_null($term) ? $term->term_id : 0; + } + + return $result; + } + + + private function findTermByCampoKey(string $taxonomy, string $campoKey): ?WP_Term + { + if ($campoKey === '') { + return null; + } + + /** @var WP_Error|array $terms */ + $terms = get_terms([ + 'taxonomy' => $taxonomy, + 'meta_key' => self::CAMPOKEY_TERM_META_KEY, + 'meta_value' => $campoKey, + ]); + + if ($terms instanceof WP_Error) { + return null; + } + + return $terms[0] ?? null; + } +} diff --git a/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramRepository.php b/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramRepository.php index 36a08b3..bd3f746 100644 --- a/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramRepository.php +++ b/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramRepository.php @@ -52,6 +52,7 @@ public function __construct( IdGenerator $idGenerator, private EventDispatcherInterface $eventDispatcher, private HtmlDegreeProgramSanitizer $fieldsSanitizer, + private CampoKeysRepository $campoKeysRepository, ) { parent::__construct($idGenerator); @@ -240,6 +241,7 @@ public function getById(DegreeProgramId $degreeProgramId): DegreeProgram $postId, DegreeProgram::LIMITED_COMBINATIONS ), + campoKeys: $this->campoKeysRepository->degreeProgramCampoKeys($degreeProgramId), ); } diff --git a/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramViewRepository.php b/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramViewRepository.php index f1d4c0f..7d32c54 100644 --- a/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramViewRepository.php +++ b/src/Infrastructure/Repository/WordPressDatabaseDegreeProgramViewRepository.php @@ -182,6 +182,7 @@ private function translateDegreeProgram( studentInitiatives: Link::fromMultilingualLink($raw->studentInitiatives(), $languageCode), applyNowLink: Link::fromMultilingualLink($raw->applyNowLink(), $languageCode), entryText: $this->formatContentField($raw->entryText()->asString($languageCode)), + campoKeys: $raw->campoKeys(), ); } diff --git a/src/Infrastructure/Repository/WpQueryArgsBuilder.php b/src/Infrastructure/Repository/WpQueryArgsBuilder.php index bd1d7c6..9e08436 100644 --- a/src/Infrastructure/Repository/WpQueryArgsBuilder.php +++ b/src/Infrastructure/Repository/WpQueryArgsBuilder.php @@ -17,6 +17,7 @@ use Fau\DegreeProgram\Common\Application\Filter\SubjectGroupFilter; use Fau\DegreeProgram\Common\Application\Filter\TeachingLanguageFilter; use Fau\DegreeProgram\Common\Application\Repository\CollectionCriteria; +use Fau\DegreeProgram\Common\Domain\CampoKeys; use Fau\DegreeProgram\Common\Domain\DegreeProgram; use Fau\DegreeProgram\Common\Domain\MultilingualString; use Fau\DegreeProgram\Common\Infrastructure\Content\PostType\DegreeProgramPostType; @@ -64,8 +65,10 @@ final class WpQueryArgsBuilder 'date' => 'desc', ]; - public function __construct(private TaxonomiesList $taxonomiesList) - { + public function __construct( + private TaxonomiesList $taxonomiesList, + private CampoKeysRepository $campoKeysRepository, + ){ } public function build(CollectionCriteria $criteria): WpQueryArgs @@ -84,9 +87,39 @@ public function build(CollectionCriteria $criteria): WpQueryArgs $queryArgs = $this->applyFilter($filter, $queryArgs, $criteria->languageCode()); } + foreach ($criteria->hisCodes() as $hisCode) { + $queryArgs = $this->applyHisCode($hisCode, $queryArgs); + } + return $queryArgs; } + public function applyHisCode(string $hisCode, WpQueryArgs $queryArgs): WpQueryArgs + { + $taxQueryItem = [ + 'relation' => 'AND', + ]; + + $taxonomyToTermMapping = $this->campoKeysRepository->taxonomyToTermsMapFromCampoKeys( + CampoKeys::fromHisCode($hisCode) + ); + + if (count($taxonomyToTermMapping) === 0) { + return $queryArgs; + } + + foreach ($taxonomyToTermMapping as $taxonomy => $termId) { + $taxQueryItem[] = [ + 'taxonomy' => $taxonomy, + 'terms' => [ + $termId, + ], + ]; + } + + return $queryArgs->withTaxQueryItem($taxQueryItem); + } + private function applyOrderBy( CollectionCriteria $criteria, WpQueryArgs $queryArgs diff --git a/src/Infrastructure/Validator/JsonSchemaDegreeProgramDataValidator.php b/src/Infrastructure/Validator/JsonSchemaDegreeProgramDataValidator.php index f9f2e77..83f2a0f 100644 --- a/src/Infrastructure/Validator/JsonSchemaDegreeProgramDataValidator.php +++ b/src/Infrastructure/Validator/JsonSchemaDegreeProgramDataValidator.php @@ -76,6 +76,7 @@ final class JsonSchemaDegreeProgramDataValidator implements DegreeProgramDataVal DegreeProgram::LIMITED_COMBINATIONS, DegreeProgram::NOTES_FOR_INTERNATIONAL_APPLICANTS, DegreeProgram::APPLY_NOW_LINK, + DegreeProgram::CAMPO_KEYS, ]; /** diff --git a/tests/resources/fixtures/degree_program.json b/tests/resources/fixtures/degree_program.json index 0d6446f..a92f942 100644 --- a/tests/resources/fixtures/degree_program.json +++ b/tests/resources/fixtures/degree_program.json @@ -653,5 +653,10 @@ "id": "post_meta:25:entry_text", "de": "Einstiegtext (werbend)", "en": "Entry text (promotional)" + }, + "campo_keys": { + "degree": "185", + "area_of_study": "85", + "location": "E" } } diff --git a/tests/src/FixtureDegreeProgramDataProviderTrait.php b/tests/src/FixtureDegreeProgramDataProviderTrait.php index 23e5b35..c5cb2d5 100644 --- a/tests/src/FixtureDegreeProgramDataProviderTrait.php +++ b/tests/src/FixtureDegreeProgramDataProviderTrait.php @@ -6,6 +6,7 @@ use Fau\DegreeProgram\Common\Domain\AdmissionRequirement; use Fau\DegreeProgram\Common\Domain\AdmissionRequirements; +use Fau\DegreeProgram\Common\Domain\CampoKeys; use Fau\DegreeProgram\Common\Domain\Content; use Fau\DegreeProgram\Common\Domain\ContentItem; use Fau\DegreeProgram\Common\Domain\Degree; @@ -110,6 +111,7 @@ public function createEmptyDegreeProgram(int $id): DegreeProgram applyNowLink: MultilingualLink::empty(), combinations: DegreeProgramIds::new(), limitedCombinations: DegreeProgramIds::new(), + campoKeys: CampoKeys::empty(), ); } } diff --git a/tests/src/Repository/StubDegreeProgramRepository.php b/tests/src/Repository/StubDegreeProgramRepository.php index f17d86b..cc82796 100644 --- a/tests/src/Repository/StubDegreeProgramRepository.php +++ b/tests/src/Repository/StubDegreeProgramRepository.php @@ -145,6 +145,7 @@ private function translateDegreeProgram( notesForInternationalApplicants: Link::fromMultilingualLink($raw->notesForInternationalApplicants(), $languageCode), applyNowLink: Link::fromMultilingualLink($raw->applyNowLink(), $languageCode), entryText: $raw->entryText()->asString($languageCode), + campoKeys: $raw->campoKeys()->asArray(), ); } From a2be742b673bd5d66fa130013b4454930f745ce6 Mon Sep 17 00:00:00 2001 From: Amin Date: Tue, 21 May 2024 14:40:20 +0200 Subject: [PATCH 2/8] style: fix QA errors and warnings --- src/Domain/CampoKeys.php | 2 +- src/Infrastructure/Repository/CampoKeysRepository.php | 1 - src/Infrastructure/Repository/WpQueryArgsBuilder.php | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Domain/CampoKeys.php b/src/Domain/CampoKeys.php index 56939dd..50cb948 100644 --- a/src/Domain/CampoKeys.php +++ b/src/Domain/CampoKeys.php @@ -95,7 +95,7 @@ public static function fromHisCode(string $hisCode): self public function set(string $key, string $value): self { - if (! in_array($key, self::SUPPORTED_CAMPO_KEYS)) { + if (! in_array($key, self::SUPPORTED_CAMPO_KEYS, true)) { throw new InvalidArgumentException('Unsupported field key.'); } diff --git a/src/Infrastructure/Repository/CampoKeysRepository.php b/src/Infrastructure/Repository/CampoKeysRepository.php index b6d4c66..1df3c6a 100644 --- a/src/Infrastructure/Repository/CampoKeysRepository.php +++ b/src/Infrastructure/Repository/CampoKeysRepository.php @@ -81,7 +81,6 @@ public function taxonomyToTermsMapFromCampoKeys(CampoKeys $campoKeys): array return $result; } - private function findTermByCampoKey(string $taxonomy, string $campoKey): ?WP_Term { if ($campoKey === '') { diff --git a/src/Infrastructure/Repository/WpQueryArgsBuilder.php b/src/Infrastructure/Repository/WpQueryArgsBuilder.php index 9e08436..4bb6db4 100644 --- a/src/Infrastructure/Repository/WpQueryArgsBuilder.php +++ b/src/Infrastructure/Repository/WpQueryArgsBuilder.php @@ -68,7 +68,7 @@ final class WpQueryArgsBuilder public function __construct( private TaxonomiesList $taxonomiesList, private CampoKeysRepository $campoKeysRepository, - ){ + ) { } public function build(CollectionCriteria $criteria): WpQueryArgs From 4a72cbaf0318d8804397f2d94b6884a695bbd7af Mon Sep 17 00:00:00 2001 From: Amin Date: Tue, 21 May 2024 16:45:01 +0200 Subject: [PATCH 3/8] chore: remove not reproducible to-do comment --- src/Application/DegreeProgramViewRaw.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Application/DegreeProgramViewRaw.php b/src/Application/DegreeProgramViewRaw.php index 850d007..ba26531 100644 --- a/src/Application/DegreeProgramViewRaw.php +++ b/src/Application/DegreeProgramViewRaw.php @@ -201,7 +201,7 @@ public static function fromArray(array $data): self ), applyNowLink: MultilingualLink::fromArray($data[DegreeProgram::APPLY_NOW_LINK]), entryText: MultilingualString::fromArray($data[DegreeProgram::ENTRY_TEXT]), - campoKeys: CampoKeys::fromArray($data[DegreeProgram::CAMPO_KEYS] ?? []), // TODO: check to see why undefined value is possible. It gives fatal on revision repository due to null value. + campoKeys: CampoKeys::fromArray($data[DegreeProgram::CAMPO_KEYS]), ); } From ad01d50fa3ebddb670948f23484c3b5c01877019 Mon Sep 17 00:00:00 2001 From: Amin Date: Wed, 22 May 2024 12:00:52 +0200 Subject: [PATCH 4/8] chore: remove unnecessary getters and setters from CampoKeys DO --- .../DegreeProgramViewTranslated.php | 3 +- src/Domain/CampoKeys.php | 72 +++++-------------- src/Domain/DegreeProgram.php | 3 +- .../Repository/CampoKeysRepository.php | 10 +-- 4 files changed, 28 insertions(+), 60 deletions(-) diff --git a/src/Application/DegreeProgramViewTranslated.php b/src/Application/DegreeProgramViewTranslated.php index 0c6a1a2..06503ae 100644 --- a/src/Application/DegreeProgramViewTranslated.php +++ b/src/Application/DegreeProgramViewTranslated.php @@ -22,6 +22,7 @@ * @psalm-import-type LanguageCodes from MultilingualString * @psalm-import-type ImageViewType from ImageView * @psalm-import-type NumberOfStudentsType from NumberOfStudents + * @psalm-import-type CampoKeysMap from CampoKeys * @psalm-type DegreeProgramTranslation = array{ * link: string, * slug: string, @@ -74,7 +75,7 @@ * student_initiatives: LinkType, * apply_now_link: LinkType, * entry_text: string, - * campo_keys: array + * campo_keys: CampoKeysMap * } * @psalm-type DegreeProgramViewTranslatedArrayType = DegreeProgramTranslation & array{ * id: int, diff --git a/src/Domain/CampoKeys.php b/src/Domain/CampoKeys.php index 50cb948..afb0355 100644 --- a/src/Domain/CampoKeys.php +++ b/src/Domain/CampoKeys.php @@ -4,8 +4,9 @@ namespace Fau\DegreeProgram\Common\Domain; -use InvalidArgumentException; - +/** + * @psalm-type CampoKeysMap = array, string> + */ final class CampoKeys { public const SCHEMA = [ @@ -46,85 +47,50 @@ final class CampoKeys private const HIS_CODE_DELIMITER = '|'; - /** @var array */ - private array $map = []; - - private function __construct() - { + private function __construct( + /** + * @var CampoKeysMap $map + */ + private array $map + ) { } public static function empty(): self { - return new self(); + return new self([]); } /** - * @psalm-param array $data + * @param CampoKeysMap $map */ - public static function fromArray(array $data): self + public static function fromArray(array $map): self { - $instance = new self(); - - foreach ($data as $key => $value) { - $instance->set($key, $value); - } - - return $instance; + return new self($map); } public static function fromHisCode(string $hisCode): self { $parts = explode(self::HIS_CODE_DELIMITER, $hisCode); + $map = []; - $instance = new self(); if (isset($parts[0])) { - $instance->set(DegreeProgram::DEGREE, $parts[0]); + $map[DegreeProgram::DEGREE] = $parts[0]; } if (isset($parts[1])) { - $instance->set(DegreeProgram::AREA_OF_STUDY, $parts[1]); + $map[DegreeProgram::AREA_OF_STUDY] = $parts[1]; } if (isset($parts[6])) { - $instance->set(DegreeProgram::LOCATION, $parts[6]); + $map[DegreeProgram::LOCATION] = $parts[6]; } - return $instance; - } - - public function set(string $key, string $value): self - { - if (! in_array($key, self::SUPPORTED_CAMPO_KEYS, true)) { - throw new InvalidArgumentException('Unsupported field key.'); - } - - $this->map[$key] = $value; - return $this; - } - - public function degree(): ?string - { - return $this->get(DegreeProgram::DEGREE); - } - - public function areaOfStudy(): ?string - { - return $this->get(DegreeProgram::AREA_OF_STUDY); - } - - public function studyLocation(): ?string - { - return $this->get(DegreeProgram::LOCATION); - } - - public function get(string $key): ?string - { - return $this->map[$key] ?? null; + return new self($map); } /** - * @return array + * @return CampoKeysMap */ public function asArray(): array { diff --git a/src/Domain/DegreeProgram.php b/src/Domain/DegreeProgram.php index 7251c73..e3e7243 100644 --- a/src/Domain/DegreeProgram.php +++ b/src/Domain/DegreeProgram.php @@ -17,6 +17,7 @@ * @psalm-import-type AdmissionRequirementsType from AdmissionRequirements * @psalm-import-type DegreeType from Degree * @psalm-import-type NumberOfStudentsType from NumberOfStudents + * @psalm-import-type CampoKeysMap from CampoKeys * @psalm-type DegreeProgramArrayType = array{ * id: int, * slug: MultilingualStringType, @@ -67,7 +68,7 @@ * student_initiatives: MultilingualLinkType, * apply_now_link: MultilingualLinkType, * entry_text: MultilingualStringType, - * campo_keys: array, + * campo_keys: CampoKeysMap, * } */ final class DegreeProgram diff --git a/src/Infrastructure/Repository/CampoKeysRepository.php b/src/Infrastructure/Repository/CampoKeysRepository.php index 1df3c6a..e0057f6 100644 --- a/src/Infrastructure/Repository/CampoKeysRepository.php +++ b/src/Infrastructure/Repository/CampoKeysRepository.php @@ -25,8 +25,6 @@ final class CampoKeysRepository public function degreeProgramCampoKeys(DegreeProgramId $degreeProgramId): CampoKeys { - $campoKeys = CampoKeys::empty(); - /** @var WP_Error|array $terms */ $terms = wp_get_post_terms( $degreeProgramId->asInt(), @@ -34,9 +32,11 @@ public function degreeProgramCampoKeys(DegreeProgramId $degreeProgramId): CampoK ); if ($terms instanceof WP_Error) { - return $campoKeys; + return CampoKeys::empty(); } + $map = []; + foreach ($terms as $term) { $campoKey = (string) get_term_meta($term->term_id, self::CAMPOKEY_TERM_META_KEY, true); @@ -50,10 +50,10 @@ public function degreeProgramCampoKeys(DegreeProgramId $degreeProgramId): CampoK continue; } - $campoKeys->set($campoKeyType, $campoKey); + $map[$campoKeyType] = $campoKey; } - return $campoKeys; + return CampoKeys::fromArray($map); } /** From 0816b3af8d637e943e0d8cd1ea1f80349f19a79e Mon Sep 17 00:00:00 2001 From: Amin Date: Wed, 22 May 2024 12:15:53 +0200 Subject: [PATCH 5/8] chore: rename constants --- .../Repository/CampoKeysRepository.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Infrastructure/Repository/CampoKeysRepository.php b/src/Infrastructure/Repository/CampoKeysRepository.php index e0057f6..5c68980 100644 --- a/src/Infrastructure/Repository/CampoKeysRepository.php +++ b/src/Infrastructure/Repository/CampoKeysRepository.php @@ -15,20 +15,20 @@ final class CampoKeysRepository { - public const CAMPO_KEYS_TOTAXONOMY_MAP = [ + public const TAXONOMY_TO_CAMPO_KEY_MAP = [ DegreeTaxonomy::KEY => DegreeProgram::DEGREE, StudyLocationTaxonomy::KEY => DegreeProgram::LOCATION, AreaOfStudyTaxonomy::KEY => DegreeProgram::AREA_OF_STUDY, ]; - public const CAMPOKEY_TERM_META_KEY = 'uniquename'; + public const CAMPO_KEY_TERM_META_KEY = 'uniquename'; public function degreeProgramCampoKeys(DegreeProgramId $degreeProgramId): CampoKeys { /** @var WP_Error|array $terms */ $terms = wp_get_post_terms( $degreeProgramId->asInt(), - array_keys(self::CAMPO_KEYS_TOTAXONOMY_MAP) + array_keys(self::TAXONOMY_TO_CAMPO_KEY_MAP) ); if ($terms instanceof WP_Error) { @@ -38,13 +38,13 @@ public function degreeProgramCampoKeys(DegreeProgramId $degreeProgramId): CampoK $map = []; foreach ($terms as $term) { - $campoKey = (string) get_term_meta($term->term_id, self::CAMPOKEY_TERM_META_KEY, true); + $campoKey = (string) get_term_meta($term->term_id, self::CAMPO_KEY_TERM_META_KEY, true); if (empty($campoKey)) { continue; } - $campoKeyType = self::CAMPO_KEYS_TOTAXONOMY_MAP[$term->taxonomy] ?? null; + $campoKeyType = self::TAXONOMY_TO_CAMPO_KEY_MAP[$term->taxonomy] ?? null; if (is_null($campoKeyType)) { continue; @@ -67,7 +67,7 @@ public function taxonomyToTermsMapFromCampoKeys(CampoKeys $campoKeys): array $campoKeys = $campoKeys->asArray(); - foreach (self::CAMPO_KEYS_TOTAXONOMY_MAP as $taxonomy => $campoKeyType) { + foreach (self::TAXONOMY_TO_CAMPO_KEY_MAP as $taxonomy => $campoKeyType) { $campoKey = $campoKeys[$campoKeyType] ?? ''; if ($campoKey === '') { @@ -90,7 +90,7 @@ private function findTermByCampoKey(string $taxonomy, string $campoKey): ?WP_Ter /** @var WP_Error|array $terms */ $terms = get_terms([ 'taxonomy' => $taxonomy, - 'meta_key' => self::CAMPOKEY_TERM_META_KEY, + 'meta_key' => self::CAMPO_KEY_TERM_META_KEY, 'meta_value' => $campoKey, ]); From 94c9b8029a13ff1934ad1642d84edaa9ca10f1d6 Mon Sep 17 00:00:00 2001 From: Amin Date: Wed, 22 May 2024 20:29:38 +0200 Subject: [PATCH 6/8] refactor: throw exception instead of passing invalid term id, when term not found --- src/Domain/CampoKeys.php | 1 - .../Repository/CampoKeysRepository.php | 9 ++++- .../Repository/WpQueryArgsBuilder.php | 39 ++++++++++++------- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/Domain/CampoKeys.php b/src/Domain/CampoKeys.php index afb0355..3dd2dbb 100644 --- a/src/Domain/CampoKeys.php +++ b/src/Domain/CampoKeys.php @@ -73,7 +73,6 @@ public static function fromHisCode(string $hisCode): self $parts = explode(self::HIS_CODE_DELIMITER, $hisCode); $map = []; - if (isset($parts[0])) { $map[DegreeProgram::DEGREE] = $parts[0]; } diff --git a/src/Infrastructure/Repository/CampoKeysRepository.php b/src/Infrastructure/Repository/CampoKeysRepository.php index 5c68980..3031a45 100644 --- a/src/Infrastructure/Repository/CampoKeysRepository.php +++ b/src/Infrastructure/Repository/CampoKeysRepository.php @@ -10,6 +10,7 @@ use Fau\DegreeProgram\Common\Infrastructure\Content\Taxonomy\AreaOfStudyTaxonomy; use Fau\DegreeProgram\Common\Infrastructure\Content\Taxonomy\DegreeTaxonomy; use Fau\DegreeProgram\Common\Infrastructure\Content\Taxonomy\StudyLocationTaxonomy; +use RuntimeException; use WP_Error; use WP_Term; @@ -59,6 +60,7 @@ public function degreeProgramCampoKeys(DegreeProgramId $degreeProgramId): CampoK /** * Return a map of taxonomy keys to terms based on a given HIS code. * + * @throws RuntimeException * @return array */ public function taxonomyToTermsMapFromCampoKeys(CampoKeys $campoKeys): array @@ -75,7 +77,12 @@ public function taxonomyToTermsMapFromCampoKeys(CampoKeys $campoKeys): array } $term = $this->findTermByCampoKey($taxonomy, $campoKey); - $result[$taxonomy] = ! is_null($term) ? $term->term_id : 0; + + if (! $term instanceof WP_Term) { + throw new RuntimeException('Could not find term for Campo key: ' . $campoKey); + } + + $result[$taxonomy] = $term->term_id; } return $result; diff --git a/src/Infrastructure/Repository/WpQueryArgsBuilder.php b/src/Infrastructure/Repository/WpQueryArgsBuilder.php index 4bb6db4..7a6717f 100644 --- a/src/Infrastructure/Repository/WpQueryArgsBuilder.php +++ b/src/Infrastructure/Repository/WpQueryArgsBuilder.php @@ -25,6 +25,7 @@ use Fau\DegreeProgram\Common\Infrastructure\Content\Taxonomy\MasterDegreeAdmissionRequirementTaxonomy; use Fau\DegreeProgram\Common\Infrastructure\Content\Taxonomy\TaxonomiesList; use Fau\DegreeProgram\Common\Infrastructure\Content\Taxonomy\TeachingDegreeHigherSemesterAdmissionRequirementTaxonomy; +use RuntimeException; use WP_Term; /** @@ -100,24 +101,32 @@ public function applyHisCode(string $hisCode, WpQueryArgs $queryArgs): WpQueryAr 'relation' => 'AND', ]; - $taxonomyToTermMapping = $this->campoKeysRepository->taxonomyToTermsMapFromCampoKeys( - CampoKeys::fromHisCode($hisCode) - ); + try { + $taxonomyToTermMapping = $this->campoKeysRepository->taxonomyToTermsMapFromCampoKeys( + CampoKeys::fromHisCode($hisCode) + ); - if (count($taxonomyToTermMapping) === 0) { - return $queryArgs; - } + if (count($taxonomyToTermMapping) === 0) { + return $queryArgs; + } - foreach ($taxonomyToTermMapping as $taxonomy => $termId) { - $taxQueryItem[] = [ - 'taxonomy' => $taxonomy, - 'terms' => [ - $termId, - ], - ]; + foreach ($taxonomyToTermMapping as $taxonomy => $termId) { + $taxQueryItem[] = [ + 'taxonomy' => $taxonomy, + 'terms' => [ + $termId, + ], + ]; + } + + return $queryArgs->withTaxQueryItem($taxQueryItem); + } catch (RuntimeException) { + /* + * Return an empty result if one or more campo keys in HIS code are not matched to any terms. + * Otherwise invalid HIS codes would be matched to false results. + */ + return $queryArgs->withArg('post__in', [0]); } - - return $queryArgs->withTaxQueryItem($taxQueryItem); } private function applyOrderBy( From 2c43e60ef8f33cb76666275246ce2fa9380bfbb6 Mon Sep 17 00:00:00 2001 From: Amin Abdolrezapoor <25235298+amiut@users.noreply.github.com> Date: Fri, 24 May 2024 01:42:40 +0300 Subject: [PATCH 7/8] refactor: simplify campo keys fromHis method Co-authored-by: Philipp Bammes <8144115+tyrann0us@users.noreply.github.com> --- src/Domain/CampoKeys.php | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/Domain/CampoKeys.php b/src/Domain/CampoKeys.php index 3dd2dbb..7788684 100644 --- a/src/Domain/CampoKeys.php +++ b/src/Domain/CampoKeys.php @@ -71,21 +71,13 @@ public static function fromArray(array $map): self public static function fromHisCode(string $hisCode): self { $parts = explode(self::HIS_CODE_DELIMITER, $hisCode); - $map = []; + $map = [ + DegreeProgram::DEGREE => $parts[0] ?? null, + DegreeProgram::AREA_OF_STUDY => $parts[1] ?? null, + DegreeProgram::LOCATION => $parts[6] ?? null, + ]; - if (isset($parts[0])) { - $map[DegreeProgram::DEGREE] = $parts[0]; - } - - if (isset($parts[1])) { - $map[DegreeProgram::AREA_OF_STUDY] = $parts[1]; - } - - if (isset($parts[6])) { - $map[DegreeProgram::LOCATION] = $parts[6]; - } - - return new self($map); + return new self(array_filter($map, fn($value) => !is_null($value))); } /** From df7cbd362f7e749384470e8fa0e6d5554b179432 Mon Sep 17 00:00:00 2001 From: Amin Date: Fri, 24 May 2024 16:23:35 +0200 Subject: [PATCH 8/8] refactor: move campo keys schema to common package --- .../RestApi/TranslatedDegreeProgramController.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Infrastructure/RestApi/TranslatedDegreeProgramController.php b/src/Infrastructure/RestApi/TranslatedDegreeProgramController.php index da3145c..570dcd1 100644 --- a/src/Infrastructure/RestApi/TranslatedDegreeProgramController.php +++ b/src/Infrastructure/RestApi/TranslatedDegreeProgramController.php @@ -676,6 +676,14 @@ public function get_item_schema(): array ), 'type' => 'object', ], + DegreeProgram::CAMPO_KEYS => [ + 'description' => _x( + 'Degree program Campo Keys.', + 'rest_api: schema item description', + 'fau-degree-program' + ), + 'type' => 'object', + ], ]; return $this->schema;