Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
31 / 31 |
|
100.00% |
4 / 4 |
CRAP | |
100.00% |
1 / 1 |
ClientHintsLookupResults | |
100.00% |
31 / 31 |
|
100.00% |
4 / 4 |
12 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getGroupedClientHintsDataForReferenceIds | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
5 | |||
getClientHintsDataForReferenceId | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
5 | |||
getRawData | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace MediaWiki\CheckUser\ClientHints; |
4 | |
5 | use InvalidArgumentException; |
6 | use MediaWiki\CheckUser\Services\UserAgentClientHintsManager; |
7 | |
8 | /** |
9 | * Value object for the result of UserAgentClientHintsLookup::getClientHintsByReferenceIds |
10 | * which contains reference IDs to ClientHintsData objects. |
11 | * |
12 | * This is used, instead of a two-dimensional list, to enforce that |
13 | * the map IDs are valid. This class stores the data as a two-dimensional |
14 | * list. |
15 | */ |
16 | class ClientHintsLookupResults { |
17 | /** @var int[][] */ |
18 | private array $referenceIdsToClientHintsDataIndex; |
19 | |
20 | /** @var ClientHintsData[] */ |
21 | private array $clientHintsDataObjects; |
22 | |
23 | /** |
24 | * @param int[][] $referenceIdsToClientHintsDataIndex A map of reference type and reference ID values |
25 | * to integer keys in $clientHintsDataObjects array. |
26 | * @param ClientHintsData[] $clientHintsDataObjects An array of ClientHintsData objects where the keys are |
27 | * integers that are the second-dimension value in the first parameter. |
28 | */ |
29 | public function __construct( array $referenceIdsToClientHintsDataIndex, array $clientHintsDataObjects ) { |
30 | $this->referenceIdsToClientHintsDataIndex = $referenceIdsToClientHintsDataIndex; |
31 | $this->clientHintsDataObjects = $clientHintsDataObjects; |
32 | } |
33 | |
34 | /** |
35 | * Get unique ClientHintsData objects and the number of times they were used for a |
36 | * array of reference IDs. |
37 | * |
38 | * @param ClientHintsReferenceIds|null $referenceIds The reference IDs to get the objects for. |
39 | * Null for all reference IDs. |
40 | * @return array[] An array of two arrays. The first array has keys corresponding to a key in the second array and |
41 | * the value is the number of rows the ClientHintsData object is associated with. The second array has values |
42 | * of unique ClientHintsData objects. |
43 | */ |
44 | public function getGroupedClientHintsDataForReferenceIds( ?ClientHintsReferenceIds $referenceIds ): array { |
45 | // Store the keys to the ClientHintsData objects in $this->clientHintsDataObjects |
46 | // as values in the array $clientHintsDataObjectKeys that are associated with |
47 | // the reference IDs provided in the first parameter to this method. |
48 | $clientHintsDataObjectKeys = []; |
49 | foreach ( $this->referenceIdsToClientHintsDataIndex as $referenceType => $referenceIdsForReferenceType ) { |
50 | if ( $referenceIds ) { |
51 | // If filtering for specific reference IDs, filter so that only the reference IDs that |
52 | // were requested are used for the grouping and counting operations later in this method. |
53 | $clientHintsDataObjectKeys = array_merge( $clientHintsDataObjectKeys, array_values( array_intersect_key( |
54 | $referenceIdsForReferenceType, |
55 | array_flip( $referenceIds->getReferenceIds( $referenceType ) ), |
56 | ) ) ); |
57 | } else { |
58 | // If the $referenceIds parameter was null, then this means apply no filtering to the reference |
59 | // IDs that are used. |
60 | $clientHintsDataObjectKeys = array_merge( |
61 | $clientHintsDataObjectKeys, |
62 | array_values( $referenceIdsForReferenceType ) |
63 | ); |
64 | } |
65 | } |
66 | |
67 | // Count the number of occurrences for each integer in the $clientHintsDataObjectKeys |
68 | // array. This counts how many occurrences of a given unique ClientHintsData object |
69 | // are present for the reference IDs in $referenceIds. |
70 | $groupedClientHintsIds = array_count_values( $clientHintsDataObjectKeys ); |
71 | |
72 | // Create an array of ClientHintsData objects where the keys |
73 | // are the key for this object in $this->clientHintsDataObjects. |
74 | // This array will contain the subset of $this->clientHintsDataObjects |
75 | // where each key is present in $groupedClientHintsIds. |
76 | $clientHintsDataObjects = []; |
77 | foreach ( array_keys( $groupedClientHintsIds ) as $clientHintsId ) { |
78 | if ( array_key_exists( $clientHintsId, $this->clientHintsDataObjects ) ) { |
79 | // Add the ClientHintsData object into the return array. |
80 | $clientHintsDataObjects[$clientHintsId] = $this->clientHintsDataObjects[$clientHintsId]; |
81 | } else { |
82 | // If, for some reason, there is no ClientHintsData object in |
83 | // $this->clientHintsDataObjects, then just silently ignore |
84 | // and remove the group from the return list. |
85 | unset( $groupedClientHintsIds[$clientHintsId] ); |
86 | } |
87 | } |
88 | return [ $groupedClientHintsIds, $clientHintsDataObjects ]; |
89 | } |
90 | |
91 | /** |
92 | * Get the ClientHintsData object for a given reference ID and reference type. |
93 | * |
94 | * @param int $referenceId The reference ID |
95 | * @param int $referenceType The reference type (one of the UserAgentClientHintsManager::IDENTIFIER_* integer |
96 | * constants). |
97 | * @return ClientHintsData|null |
98 | */ |
99 | public function getClientHintsDataForReferenceId( int $referenceId, int $referenceType ): ?ClientHintsData { |
100 | // Validate that the $referenceType given is a valid reference type. If not, then |
101 | // return an exception to indicate a problem in the code. |
102 | if ( !array_key_exists( $referenceType, UserAgentClientHintsManager::IDENTIFIER_TO_TABLE_NAME_MAP ) ) { |
103 | throw new InvalidArgumentException( "Unrecognised reference type '$referenceType'" ); |
104 | } |
105 | // Check that the reference IDs to ClientHintsData object index ID map has an |
106 | // entry for this reference ID and reference type. Otherwise, return null. |
107 | // If it does then also check that the index in the ClientHintsData objects array |
108 | // exists. Otherwise, return null. |
109 | if ( |
110 | !array_key_exists( $referenceType, $this->referenceIdsToClientHintsDataIndex ) || |
111 | !array_key_exists( $referenceId, $this->referenceIdsToClientHintsDataIndex[$referenceType] ) || |
112 | !array_key_exists( |
113 | $this->referenceIdsToClientHintsDataIndex[$referenceType][$referenceId], |
114 | $this->clientHintsDataObjects |
115 | ) |
116 | ) { |
117 | return null; |
118 | } |
119 | // The reference ID matches a ClientHintsData object, so return it. |
120 | return $this->clientHintsDataObjects[$this->referenceIdsToClientHintsDataIndex[$referenceType][$referenceId]]; |
121 | } |
122 | |
123 | /** |
124 | * Allows UserAgentClientHintsFormatter to get the raw data |
125 | * for UserAgentClientHintsFormatter::batchFormatClientHintsData. |
126 | * |
127 | * @internal For use by UserAgentClientHintsFormatter only. |
128 | * @return array[] |
129 | */ |
130 | public function getRawData(): array { |
131 | return [ $this->referenceIdsToClientHintsDataIndex, $this->clientHintsDataObjects ]; |
132 | } |
133 | } |