From d58b61b34978ca05147276b74c109ea7c6ae8ba5 Mon Sep 17 00:00:00 2001 From: Jim Safley Date: Mon, 1 Apr 2024 21:19:34 -0400 Subject: [PATCH 1/7] Differentiate linked resources by label --- .../Adapter/AbstractResourceEntityAdapter.php | 51 +++++++++++++++---- .../view/common/linked-resources.phtml | 12 +++-- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php index 12d3c2661..269fb8481 100644 --- a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php +++ b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php @@ -472,9 +472,9 @@ public function getPropertyByTerm($term) * 123 * - -: Query subject values of the specified property where * there is no corresponding resource template property, e.g. 123- - * - -: Query subject values of - * the specified property where there is a corresponding resource - * template property, e.g. 123-234 + * - -: Query subject values of + * the specified property where there are corresponding resource + * template properties, e.g. 123-234,345 * * @param Resource $resource * @param int|string|null $propertyId @@ -530,11 +530,15 @@ public function getSubjectValuesQueryBuilder(Resource $resource, $propertyId = n if (false !== strpos($propertyId, '-')) { $propertyIds = explode('-', $propertyId); $propertyId = $propertyIds[0]; - $resourceTemplatePropertyId = $propertyIds[1]; - $qb->andWhere($resourceTemplatePropertyId - ? $qb->expr()->eq('resource_template_property', $this->createNamedParameter($qb, $resourceTemplatePropertyId)) - : $qb->expr()->isNull('resource_template_property') - ); + $resourceTemplatePropertyIds = array_map('intval', explode(',', $propertyIds[1])); + if (in_array(0, $resourceTemplatePropertyIds)) { + $qb->andWhere($qb->expr()->orX( + $qb->expr()->isNull('resource_template_property'), + $qb->expr()->in('resource_template_property', $this->createNamedParameter($qb, $resourceTemplatePropertyIds)) + )); + } else { + $qb->andWhere($qb->expr()->in('resource_template_property', $this->createNamedParameter($qb, $resourceTemplatePropertyIds))); + } } $qb->andWhere($qb->expr()->eq('value.property', $this->createNamedParameter($qb, $propertyId))); } @@ -649,7 +653,6 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu ->join('value.property', 'property') ->join('property.vocabulary', 'vocabulary') ->select([ - "DISTINCT CONCAT(property.id, '-', COALESCE(resource_template_property.id, '')) id_concat", "CONCAT(vocabulary.prefix, ':', property.localName) term", 'property.id property_id', 'resource_template_property.id resource_template_property_id', @@ -657,8 +660,34 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu 'resource_template_property.alternateLabel property_alternate_label', ]) ->orderBy('property.id, resource_template_property.id'); - $results = $qb->getQuery()->getResult(); - return $results; + + $results = []; + foreach ($qb->getQuery()->getResult() as $result) { + if ($result['property_alternate_label']) { + $label = $result['property_alternate_label']; + $resourceTemplatePropertyId = $result['resource_template_property_id']; + } elseif ($result['resource_template_property_id']) { + $label = $result['property_label']; + $resourceTemplatePropertyId = $result['resource_template_property_id']; + } else { + $label = $result['property_label']; + $resourceTemplatePropertyId = 0; + } + $results[$result['property_id']][$label]['resource_template_property_ids'][] = $resourceTemplatePropertyId; + $results[$result['property_id']][$label]['term'] = $result['term']; + } + + $subjectValueProperties = []; + foreach ($results as $propertyId => $properties) { + foreach ($properties as $label => $data) { + $subjectValueProperties[] = [ + 'label' => $label, + 'term' => $data['term'], + 'compound_id' => sprintf('%s:%s-%s', $resourceType, $propertyId, implode(',', array_unique($data['resource_template_property_ids']))), + ]; + } + } + return $subjectValueProperties; } public function preprocessBatchUpdate(array $data, Request $request) diff --git a/application/view/common/linked-resources.phtml b/application/view/common/linked-resources.phtml index 72cf01cc2..27b82a525 100644 --- a/application/view/common/linked-resources.phtml +++ b/application/view/common/linked-resources.phtml @@ -37,11 +37,13 @@ foreach ($resourcePropertiesAll as $type => $resourceProperties) { 'options' => [sprintf('%s:', $type) => sprintf('%s: All', $labelMap[$type])], ]; foreach ($resourceProperties as $resourceProperty) { - $key = sprintf('%s:%s', $type, $resourceProperty['id_concat']); - $value = $resourceProperty['property_alternate_label'] - ? $this->translate($resourceProperty['property_alternate_label']) - : $this->translate($resourceProperty['property_label']); - $valueOptions[$type]['options'][$key] = sprintf('%s: %s', $labelMap[$type], $value); + $valueOptions[$type]['options'][] = [ + 'value' => $resourceProperty['compound_id'], + 'label' => sprintf('%s: %s', $labelMap[$type], $resourceProperty['label']), + 'attributes' => [ + 'title' => $resourceProperty['term'], + ], + ]; } } $resourcePropertiesSelect->setValueOptions($valueOptions); From 360f62b5d11ed4e4721b43b211064b7c87562449 Mon Sep 17 00:00:00 2001 From: Jim Safley Date: Wed, 3 Apr 2024 11:45:46 -0400 Subject: [PATCH 2/7] Add term to linked resource captions; add comments --- .../Adapter/AbstractResourceEntityAdapter.php | 18 ++++++++++++++---- application/view/common/linked-resources.phtml | 5 +++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php index 269fb8481..3d2be7920 100644 --- a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php +++ b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php @@ -474,7 +474,9 @@ public function getPropertyByTerm($term) * there is no corresponding resource template property, e.g. 123- * - -: Query subject values of * the specified property where there are corresponding resource - * template properties, e.g. 123-234,345 + * template properties, e.g. 123-234,345. Note that you can add subject + * values of the specified property where there is no corresponding + * resource template property by adding a zero ID, e.g. 123-0,234,345 * * @param Resource $resource * @param int|string|null $propertyId @@ -532,6 +534,8 @@ public function getSubjectValuesQueryBuilder(Resource $resource, $propertyId = n $propertyId = $propertyIds[0]; $resourceTemplatePropertyIds = array_map('intval', explode(',', $propertyIds[1])); if (in_array(0, $resourceTemplatePropertyIds)) { + // A zero ID means subject values of the specified property + // where there is no corresponding resource template property. $qb->andWhere($qb->expr()->orX( $qb->expr()->isNull('resource_template_property'), $qb->expr()->in('resource_template_property', $this->createNamedParameter($qb, $resourceTemplatePropertyIds)) @@ -571,12 +575,14 @@ public function getSubjectValues(Resource $resource, $page = null, $perPage = nu $offset = (is_numeric($page) && is_numeric($perPage)) ? (($page - 1) * $perPage) : null; $qb = $this->getSubjectValuesQueryBuilder($resource, $propertyId, $resourceType, $siteId) ->join('value.property', 'property') + ->join('property.vocabulary', 'vocabulary') ->select([ 'value val', 'property.id property_id', 'resource_template_property.id resource_template_property_id', 'property.label property_label', 'resource_template_property.alternateLabel property_alternate_label', + "CONCAT(vocabulary.prefix, ':', property.localName) term", ]) ->orderBy('property.id, resource_template_property.alternateLabel, resource.title') ->setMaxResults($perPage) @@ -611,7 +617,11 @@ public function getSubjectValuesSimple(Resource $resource, $propertyId = null, $ $qb = $this->getSubjectValuesQueryBuilder($resource, $propertyId, $resourceType, $siteId) ->join('value.property', 'property') ->join('property.vocabulary', 'vocabulary') - ->select("CONCAT(vocabulary.prefix, ':', property.localName) term, IDENTITY(value.resource) id, resource.title title"); + ->select([ + "CONCAT(vocabulary.prefix, ':', property.localName) term", + 'IDENTITY(value.resource) id', + 'resource.title title', + ]); $event = new Event('api.subject_values_simple.query', $this, [ 'queryBuilder' => $qb, 'resource' => $resource, @@ -660,7 +670,7 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu 'resource_template_property.alternateLabel property_alternate_label', ]) ->orderBy('property.id, resource_template_property.id'); - + // Group the properties by label. $results = []; foreach ($qb->getQuery()->getResult() as $result) { if ($result['property_alternate_label']) { @@ -676,7 +686,7 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu $results[$result['property_id']][$label]['resource_template_property_ids'][] = $resourceTemplatePropertyId; $results[$result['property_id']][$label]['term'] = $result['term']; } - + // Build the properties array from grouped array. $subjectValueProperties = []; foreach ($results as $propertyId => $properties) { foreach ($properties as $label => $data) { diff --git a/application/view/common/linked-resources.phtml b/application/view/common/linked-resources.phtml index 27b82a525..79e9d02f6 100644 --- a/application/view/common/linked-resources.phtml +++ b/application/view/common/linked-resources.phtml @@ -63,10 +63,11 @@ $resourcePropertiesSelect->setValueOptions($valueOptions); translate('%s with "%s: %s"'), + $this->translate('%s with "%s: %s" (%s)'), $this->translate($labelMap[$resourceType]), $values[0]['property_alternate_label'] ?? $this->translate($values[0]['property_label']), - $objectResource->displayTitle() + $objectResource->displayTitle(), + $values[0]['term'] ); ?> From c96c0d0c56e2a62c2997131d9e0ea21245d6ff74 Mon Sep 17 00:00:00 2001 From: Jim Safley Date: Wed, 3 Apr 2024 18:11:23 -0400 Subject: [PATCH 3/7] Avoid redundant linked resources captions --- .../src/Api/Adapter/AbstractResourceEntityAdapter.php | 6 ++---- .../Representation/AbstractResourceEntityRepresentation.php | 2 +- application/view/common/linked-resources.phtml | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php index 3d2be7920..f773ff2df 100644 --- a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php +++ b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php @@ -575,16 +575,14 @@ public function getSubjectValues(Resource $resource, $page = null, $perPage = nu $offset = (is_numeric($page) && is_numeric($perPage)) ? (($page - 1) * $perPage) : null; $qb = $this->getSubjectValuesQueryBuilder($resource, $propertyId, $resourceType, $siteId) ->join('value.property', 'property') - ->join('property.vocabulary', 'vocabulary') ->select([ 'value val', 'property.id property_id', - 'resource_template_property.id resource_template_property_id', 'property.label property_label', + 'resource_template_property.id resource_template_property_id', 'resource_template_property.alternateLabel property_alternate_label', - "CONCAT(vocabulary.prefix, ':', property.localName) term", ]) - ->orderBy('property.id, resource_template_property.alternateLabel, resource.title') + ->orderBy('resource_template_property.alternateLabel, property.label, property.id, resource.title') ->setMaxResults($perPage) ->setFirstResult($offset); $event = new Event('api.subject_values.query', $this, [ diff --git a/application/src/Api/Representation/AbstractResourceEntityRepresentation.php b/application/src/Api/Representation/AbstractResourceEntityRepresentation.php index ec2bc60d3..ed6367c29 100644 --- a/application/src/Api/Representation/AbstractResourceEntityRepresentation.php +++ b/application/src/Api/Representation/AbstractResourceEntityRepresentation.php @@ -402,7 +402,7 @@ public function subjectValues($page = null, $perPage = null, $propertyId = null, $results = $this->getAdapter()->getSubjectValues($this->resource, $page, $perPage, $propertyId, $resourceType, $siteId); $subjectValues = []; foreach ($results as $result) { - $index = sprintf('%s-%s', $result['property_id'], $result['resource_template_property_id']); + $index = $result['property_alternate_label'] ?: $result['property_label']; $result['val'] = new ValueRepresentation($result['val'], $this->getServiceLocator()); $subjectValues[$index][] = $result; } diff --git a/application/view/common/linked-resources.phtml b/application/view/common/linked-resources.phtml index 79e9d02f6..27b82a525 100644 --- a/application/view/common/linked-resources.phtml +++ b/application/view/common/linked-resources.phtml @@ -63,11 +63,10 @@ $resourcePropertiesSelect->setValueOptions($valueOptions); translate('%s with "%s: %s" (%s)'), + $this->translate('%s with "%s: %s"'), $this->translate($labelMap[$resourceType]), $values[0]['property_alternate_label'] ?? $this->translate($values[0]['property_label']), - $objectResource->displayTitle(), - $values[0]['term'] + $objectResource->displayTitle() ); ?>
From e4c918df84252f68e161bba0665f8986a3ed390f Mon Sep 17 00:00:00 2001 From: Jim Safley Date: Thu, 4 Apr 2024 10:55:29 -0400 Subject: [PATCH 4/7] Better order by for linked resources table; consistent ordering between table and select --- .../Api/Adapter/AbstractResourceEntityAdapter.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php index f773ff2df..5efde7bfd 100644 --- a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php +++ b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php @@ -581,8 +581,9 @@ public function getSubjectValues(Resource $resource, $page = null, $perPage = nu 'property.label property_label', 'resource_template_property.id resource_template_property_id', 'resource_template_property.alternateLabel property_alternate_label', + "CASE WHEN resource_template_property.alternateLabel IS NOT NULL AND resource_template_property.alternateLabel NOT LIKE '' THEN resource_template_property.alternateLabel ELSE property.label END order_by_label", ]) - ->orderBy('resource_template_property.alternateLabel, property.label, property.id, resource.title') + ->orderBy('property.id, order_by_label, resource.title') ->setMaxResults($perPage) ->setFirstResult($offset); $event = new Event('api.subject_values.query', $this, [ @@ -661,14 +662,16 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu ->join('value.property', 'property') ->join('property.vocabulary', 'vocabulary') ->select([ - "CONCAT(vocabulary.prefix, ':', property.localName) term", 'property.id property_id', 'resource_template_property.id resource_template_property_id', 'property.label property_label', 'resource_template_property.alternateLabel property_alternate_label', + "CONCAT(vocabulary.prefix, ':', property.localName) term", ]) ->orderBy('property.id, resource_template_property.id'); - // Group the properties by label. + // Group the properties by property ID then label. We must use code to + // group instead of a SQL "GROUP BY" because of the special case where + // there is no resource template property. $results = []; foreach ($qb->getQuery()->getResult() as $result) { if ($result['property_alternate_label']) { @@ -690,11 +693,14 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu foreach ($properties as $label => $data) { $subjectValueProperties[] = [ 'label' => $label, + 'property_id' => $propertyId, 'term' => $data['term'], 'compound_id' => sprintf('%s:%s-%s', $resourceType, $propertyId, implode(',', array_unique($data['resource_template_property_ids']))), ]; } } + // Sort the properties by property ID then label. + usort($subjectValueProperties, fn($a, $b) => strcmp($a['property_id'] . $a['label'], $b['property_id'] . $b['label'])); return $subjectValueProperties; } From 41d4597bcb40ce52044f235ea46932dbcb6ac87c Mon Sep 17 00:00:00 2001 From: Jim Safley Date: Thu, 4 Apr 2024 12:49:54 -0400 Subject: [PATCH 5/7] Fix cs --- application/src/Api/Adapter/AbstractResourceEntityAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php index 5efde7bfd..735556e1a 100644 --- a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php +++ b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php @@ -700,7 +700,7 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu } } // Sort the properties by property ID then label. - usort($subjectValueProperties, fn($a, $b) => strcmp($a['property_id'] . $a['label'], $b['property_id'] . $b['label'])); + usort($subjectValueProperties, fn ($a, $b) => strcmp($a['property_id'] . $a['label'], $b['property_id'] . $b['label'])); return $subjectValueProperties; } From 3478cfe6d9566e2364045ad9d69c43c43151ca7f Mon Sep 17 00:00:00 2001 From: Jim Safley Date: Wed, 17 Apr 2024 15:00:24 -0400 Subject: [PATCH 6/7] Translate label when at least one individual label is a property label --- .../Api/Adapter/AbstractResourceEntityAdapter.php | 14 ++++++++++++++ application/view/common/linked-resources.phtml | 5 ++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php index 735556e1a..8582c8076 100644 --- a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php +++ b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php @@ -676,16 +676,29 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu foreach ($qb->getQuery()->getResult() as $result) { if ($result['property_alternate_label']) { $label = $result['property_alternate_label']; + $labelIsTranslatable = false; $resourceTemplatePropertyId = $result['resource_template_property_id']; } elseif ($result['resource_template_property_id']) { $label = $result['property_label']; + $labelIsTranslatable = true; $resourceTemplatePropertyId = $result['resource_template_property_id']; } else { $label = $result['property_label']; + $labelIsTranslatable = true; $resourceTemplatePropertyId = 0; } $results[$result['property_id']][$label]['resource_template_property_ids'][] = $resourceTemplatePropertyId; $results[$result['property_id']][$label]['term'] = $result['term']; + // The shared label is translatable if at least one of the individual + // labels is a property label. A shared label is not translatable if + // all the individual labels are alternate labels. + if (isset($results[$result['property_id']][$label]['label_is_translatable'])) { + if (true === $labelIsTranslatable) { + $results[$result['property_id']][$label]['label_is_translatable'] = true; + } + } else { + $results[$result['property_id']][$label]['label_is_translatable'] = $labelIsTranslatable; + } } // Build the properties array from grouped array. $subjectValueProperties = []; @@ -695,6 +708,7 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu 'label' => $label, 'property_id' => $propertyId, 'term' => $data['term'], + 'label_is_translatable' => $data['label_is_translatable'], 'compound_id' => sprintf('%s:%s-%s', $resourceType, $propertyId, implode(',', array_unique($data['resource_template_property_ids']))), ]; } diff --git a/application/view/common/linked-resources.phtml b/application/view/common/linked-resources.phtml index 27b82a525..2ae8b38dd 100644 --- a/application/view/common/linked-resources.phtml +++ b/application/view/common/linked-resources.phtml @@ -37,9 +37,12 @@ foreach ($resourcePropertiesAll as $type => $resourceProperties) { 'options' => [sprintf('%s:', $type) => sprintf('%s: All', $labelMap[$type])], ]; foreach ($resourceProperties as $resourceProperty) { + $label = $resourceProperty['label_is_translatable'] + ? $this->translate($resourceProperty['label']) + : $resourceProperty['label']; $valueOptions[$type]['options'][] = [ 'value' => $resourceProperty['compound_id'], - 'label' => sprintf('%s: %s', $labelMap[$type], $resourceProperty['label']), + 'label' => sprintf('%s: %s', $labelMap[$type], $label), 'attributes' => [ 'title' => $resourceProperty['term'], ], From cc99173b8fb4f72e3b84502d882c4af7b89b4ab6 Mon Sep 17 00:00:00 2001 From: Jim Safley Date: Thu, 18 Apr 2024 09:03:08 -0400 Subject: [PATCH 7/7] Simplify label_is_translatable --- .../src/Api/Adapter/AbstractResourceEntityAdapter.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php index 8582c8076..3f8e3e4b2 100644 --- a/application/src/Api/Adapter/AbstractResourceEntityAdapter.php +++ b/application/src/Api/Adapter/AbstractResourceEntityAdapter.php @@ -692,12 +692,8 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu // The shared label is translatable if at least one of the individual // labels is a property label. A shared label is not translatable if // all the individual labels are alternate labels. - if (isset($results[$result['property_id']][$label]['label_is_translatable'])) { - if (true === $labelIsTranslatable) { - $results[$result['property_id']][$label]['label_is_translatable'] = true; - } - } else { - $results[$result['property_id']][$label]['label_is_translatable'] = $labelIsTranslatable; + if ($labelIsTranslatable) { + $results[$result['property_id']][$label]['label_is_translatable'] = true; } } // Build the properties array from grouped array. @@ -708,7 +704,7 @@ public function getSubjectValueProperties(Resource $resource, $resourceType = nu 'label' => $label, 'property_id' => $propertyId, 'term' => $data['term'], - 'label_is_translatable' => $data['label_is_translatable'], + 'label_is_translatable' => $data['label_is_translatable'] ?? false, 'compound_id' => sprintf('%s:%s-%s', $resourceType, $propertyId, implode(',', array_unique($data['resource_template_property_ids']))), ]; }