Skip to content

Commit 0bd799b

Browse files
committed
GQL: Introduce LabelProvider interface
This ensures that the `label` field behaves the same on all parent fields that provide it. It also enables users to create reusable fragments in queries to e.g. avoid repeating the same query part to fetch labels in multiple languages. Change-Id: I7e6863166dac23d1698ffa032f8b621b3c837809
1 parent 7a08a68 commit 0bd799b

File tree

6 files changed

+84
-65
lines changed

6 files changed

+84
-65
lines changed

repo/WikibaseRepo.datatypes.php

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,19 @@
531531
},
532532
'graphql-value-type' => static function() {
533533
$itemLabelsResolver = WbReuse::getItemLabelsResolver();
534-
$languageCodeType = WbReuse::getLanguageCodeType();
534+
$labelProviderType = WbReuse::getLabelProviderType();
535+
$labelField = clone $labelProviderType->getField( 'label' ); // cloned to not override the resolver in other places
536+
$labelField->resolveFn = function( Statement|PropertyValuePair $valueProvider, array $args ) use( $itemLabelsResolver ) {
537+
/** @var EntityIdValue $idValue */
538+
$idValue = $valueProvider->value;
539+
'@phan-var EntityIdValue $idValue';
540+
541+
/** @var ItemId $itemId */
542+
$itemId = $idValue->getEntityId();
543+
'@phan-var ItemId $itemId';
544+
545+
return $itemLabelsResolver->resolve( $itemId, $args['languageCode'] );
546+
};
535547

536548
return new ObjectType( [
537549
'name' => 'ItemValue',
@@ -546,24 +558,9 @@
546558
return $idValue->getEntityId()->getSerialization();
547559
},
548560
],
549-
'label' => [
550-
'type' => Type::string(),
551-
'args' => [
552-
'languageCode' => Type::nonNull( $languageCodeType ),
553-
],
554-
'resolve' => function( Statement|PropertyValuePair $valueProvider, array $args ) use( $itemLabelsResolver ) {
555-
/** @var EntityIdValue $idValue */
556-
$idValue = $valueProvider->value;
557-
'@phan-var EntityIdValue $idValue';
558-
559-
/** @var ItemId $itemId */
560-
$itemId = $idValue->getEntityId();
561-
'@phan-var ItemId $itemId';
562-
563-
return $itemLabelsResolver->resolve( $itemId, $args['languageCode'] );
564-
},
565-
],
561+
$labelField,
566562
],
563+
'interfaces' => [ $labelProviderType ],
567564
] );
568565
},
569566
],
@@ -600,7 +597,19 @@
600597
},
601598
'graphql-value-type' => static function() {
602599
$labelsResolver = WbReuse::getPropertyLabelsResolver();
603-
$languageCodeType = WbReuse::getLanguageCodeType();
600+
$labelProviderType = WbReuse::getLabelProviderType();
601+
$labelField = clone $labelProviderType->getField( 'label' ); // cloned to not override the resolver in other places
602+
$labelField->resolveFn = function( Statement|PropertyValuePair $valueProvider, array $args ) use( $labelsResolver ) {
603+
/** @var EntityIdValue $idValue */
604+
$idValue = $valueProvider->value;
605+
'@phan-var EntityIdValue $idValue';
606+
607+
/** @var PropertyId $propertyId */
608+
$propertyId = $idValue->getEntityId();
609+
'@phan-var PropertyId $propertyId';
610+
611+
return $labelsResolver->resolve( $propertyId, $args['languageCode'] );
612+
};
604613

605614
return new ObjectType( [
606615
'name' => 'PropertyValue',
@@ -615,24 +624,9 @@
615624
return $idValue->getEntityId()->getSerialization();
616625
},
617626
],
618-
'label' => [
619-
'type' => Type::string(),
620-
'args' => [
621-
'languageCode' => Type::nonNull( $languageCodeType ),
622-
],
623-
'resolve' => function( Statement|PropertyValuePair $valueProvider, array $args ) use( $labelsResolver ) {
624-
/** @var EntityIdValue $idValue */
625-
$idValue = $valueProvider->value;
626-
'@phan-var EntityIdValue $idValue';
627-
628-
/** @var PropertyId $propertyId */
629-
$propertyId = $idValue->getEntityId();
630-
'@phan-var PropertyId $propertyId';
631-
632-
return $labelsResolver->resolve( $propertyId, $args['languageCode'] );
633-
},
634-
],
627+
$labelField,
635628
],
629+
'interfaces' => [ $labelProviderType ],
636630
] );
637631
},
638632
],

repo/domains/reuse/src/Infrastructure/GraphQL/Schema/PredicatePropertyType.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Wikibase\Repo\Domains\Reuse\Infrastructure\GraphQL\Schema;
44

5+
use GraphQL\Type\Definition\InterfaceType;
56
use GraphQL\Type\Definition\ObjectType;
67
use GraphQL\Type\Definition\Type;
78
use Wikibase\Repo\Domains\Reuse\Domain\Model\PredicateProperty;
@@ -12,7 +13,16 @@
1213
*/
1314
class PredicatePropertyType extends ObjectType {
1415

15-
public function __construct( PropertyLabelsResolver $labelsResolver, LanguageCodeType $languageCodeType ) {
16+
public function __construct(
17+
PropertyLabelsResolver $labelsResolver,
18+
InterfaceType $labelProviderType
19+
) {
20+
$labelField = clone $labelProviderType->getField( 'label' ); // cloned to not override the resolver in other places
21+
$labelField->resolveFn = fn( PredicateProperty $property, array $args ) => $labelsResolver->resolve(
22+
$property->id,
23+
$args['languageCode']
24+
);
25+
1626
parent::__construct( [
1727
'fields' => [
1828
'id' => [
@@ -23,17 +33,9 @@ public function __construct( PropertyLabelsResolver $labelsResolver, LanguageCod
2333
'type' => Type::string(),
2434
'resolve' => fn( PredicateProperty $rootValue ) => $rootValue->dataType,
2535
],
26-
'label' => [
27-
'type' => Type::string(),
28-
'args' => [
29-
'languageCode' => Type::nonNull( $languageCodeType ),
30-
],
31-
'resolve' => fn( PredicateProperty $property, array $args ) => $labelsResolver->resolve(
32-
$property->id,
33-
$args['languageCode']
34-
),
35-
],
36+
$labelField,
3637
],
38+
'interfaces' => [ $labelProviderType ],
3739
] );
3840
}
3941

repo/domains/reuse/src/Infrastructure/GraphQL/Schema/Schema.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Wikibase\Repo\Domains\Reuse\Infrastructure\GraphQL\Schema;
44

55
use GraphQL\Type\Definition\EnumType;
6+
use GraphQL\Type\Definition\InterfaceType;
67
use GraphQL\Type\Definition\ObjectType;
78
use GraphQL\Type\Definition\Type;
89
use GraphQL\Type\Schema as GraphQLSchema;
@@ -23,7 +24,8 @@ public function __construct(
2324
private readonly SiteIdType $siteIdType,
2425
private readonly LanguageCodeType $languageCodeType,
2526
private readonly PropertyValuePairType $propertyValuePairType,
26-
private readonly PropertyIdType $propertyIdType
27+
private readonly PropertyIdType $propertyIdType,
28+
private readonly InterfaceType $labelProviderType,
2729
) {
2830
parent::__construct( [
2931
'query' => new ObjectType( [
@@ -42,21 +44,18 @@ public function __construct(
4244
}
4345

4446
private function itemType(): ObjectType {
47+
$labelField = clone $this->labelProviderType->getField( 'label' ); // cloned to not override the resolver in other places
48+
$labelField->resolveFn = fn( Item $item, array $args ) => $item->labels
49+
->getLabelInLanguage( $args['languageCode'] )?->text;
50+
4551
return new ObjectType( [
4652
'name' => 'Item',
4753
'fields' => [
4854
'id' => [
4955
'type' => Type::nonNull( $this->itemIdType ),
5056
'resolve' => fn( Item $item ) => $item->id->getSerialization(),
5157
],
52-
'label' => [
53-
'type' => Type::string(),
54-
'args' => [
55-
'languageCode' => Type::nonNull( $this->languageCodeType ),
56-
],
57-
'resolve' => fn( Item $item, array $args ) => $item->labels
58-
->getLabelInLanguage( $args['languageCode'] )?->text,
59-
],
58+
$labelField,
6059
'description' => [
6160
'type' => Type::string(),
6261
'args' => [
@@ -103,6 +102,7 @@ private function itemType(): ObjectType {
103102
->getStatementsByPropertyId( new NumericPropertyId( $args[ 'propertyId' ] ) ),
104103
],
105104
],
105+
'interfaces' => [ $this->labelProviderType ],
106106
] );
107107
}
108108

repo/domains/reuse/src/Infrastructure/GraphQL/schema.graphql

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ type Query {
44

55
scalar ItemId
66

7-
type Item {
7+
type Item implements LabelProvider {
88
id: ItemId!
99
label(languageCode: LanguageCode!): String
1010
description(languageCode: LanguageCode!): String
@@ -13,6 +13,10 @@ type Item {
1313
statements(propertyId: PropertyId!): [Statement]!
1414
}
1515

16+
interface LabelProvider {
17+
label(languageCode: LanguageCode!): String
18+
}
19+
1620
scalar LanguageCode
1721

1822
scalar SiteId
@@ -40,7 +44,7 @@ interface PropertyValuePair {
4044
valueType: ValueType!
4145
}
4246

43-
type PredicateProperty {
47+
type PredicateProperty implements LabelProvider {
4448
id: String!
4549
dataType: String
4650
label(languageCode: LanguageCode!): String
@@ -52,12 +56,12 @@ type StringValue {
5256
content: String!
5357
}
5458

55-
type ItemValue {
59+
type ItemValue implements LabelProvider {
5660
id: String!
5761
label(languageCode: LanguageCode!): String
5862
}
5963

60-
type PropertyValue {
64+
type PropertyValue implements LabelProvider {
6165
id: String!
6266
label(languageCode: LanguageCode!): String
6367
}

repo/domains/reuse/src/WbReuse.ServiceWiring.php

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php declare( strict_types=1 );
22

3+
use GraphQL\Type\Definition\InterfaceType;
34
use GraphQL\Type\Definition\ObjectType;
45
use GraphQL\Type\Definition\ResolveInfo;
56
use GraphQL\Type\Definition\Type;
@@ -42,8 +43,6 @@
4243
] );
4344
},
4445
'WbReuse.GraphQLSchema' => function( MediaWikiServices $services ): Schema {
45-
$languageCodeType = WbReuse::getLanguageCodeType( $services );
46-
4746
return new Schema(
4847
new ItemResolver(
4948
new BatchGetItems( new EntityLookupItemsBatchRetriever(
@@ -60,16 +59,17 @@
6059
WikibaseRepo::getSiteLinkGlobalIdentifiersProvider( $services ),
6160
WikibaseRepo::getSettings( $services ),
6261
),
63-
$languageCodeType,
62+
WbReuse::getLanguageCodeType( $services ),
6463
new PropertyValuePairType(
6564
new PredicatePropertyType(
6665
WbReuse::getPropertyLabelsResolver( $services ),
67-
$languageCodeType,
66+
WbReuse::getLabelProviderType( $services ),
6867
),
6968
new ValueType( WikibaseRepo::getDataTypeDefinitions( $services )->getGraphqlValueTypes() ),
7069
new ValueTypeType()
7170
),
72-
new PropertyIdType()
71+
new PropertyIdType(),
72+
WbReuse::getLabelProviderType( $services ),
7373
);
7474
},
7575
'WbReuse.GraphQLService' => function( MediaWikiServices $services ): GraphQLService {
@@ -85,6 +85,19 @@
8585
)
8686
);
8787
},
88+
'WbReuse.LabelProviderType' => function( MediaWikiServices $services ): InterfaceType {
89+
return new InterfaceType( [
90+
'name' => 'LabelProvider',
91+
'fields' => [
92+
'label' => [
93+
'type' => Type::string(),
94+
'args' => [
95+
'languageCode' => Type::nonNull( WbReuse::getLanguageCodeType( $services ) ),
96+
],
97+
],
98+
],
99+
] );
100+
},
88101
'WbReuse.LanguageCodeType' => function( MediaWikiServices $services ): LanguageCodeType {
89102
return new LanguageCodeType( WikibaseRepo::getTermsLanguages( $services )->getLanguages() );
90103
},

repo/domains/reuse/src/WbReuse.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Wikibase\Repo\Domains\Reuse;
44

5+
use GraphQL\Type\Definition\InterfaceType;
56
use GraphQL\Type\Definition\ObjectType;
67
use MediaWiki\MediaWikiServices;
78
use Psr\Container\ContainerInterface;
@@ -36,6 +37,11 @@ public static function getPropertyLabelsResolver( ?ContainerInterface $services
3637
->get( 'WbReuse.PropertyLabelsResolver' );
3738
}
3839

40+
public static function getLabelProviderType( ?ContainerInterface $services = null ): InterfaceType {
41+
return ( $services ?: MediaWikiServices::getInstance() )
42+
->get( 'WbReuse.LabelProviderType' );
43+
}
44+
3945
public static function getLanguageCodeType( ?ContainerInterface $services = null ): LanguageCodeType {
4046
return ( $services ?: MediaWikiServices::getInstance() )
4147
->get( 'WbReuse.LanguageCodeType' );

0 commit comments

Comments
 (0)