Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
78.38% |
29 / 37 |
|
60.00% |
6 / 10 |
CRAP | |
0.00% |
0 / 1 |
TaskTypeHandlerRegistry | |
78.38% |
29 / 37 |
|
60.00% |
6 / 10 |
19.92 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
has | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
get | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getByTaskType | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getKnownIds | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
register | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getChangeTags | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
getUniqueChangeTags | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getTaskTypeHandlerIdByChangeTagName | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
createHandler | |
88.89% |
8 / 9 |
|
0.00% |
0 / 1 |
2.01 |
1 | <?php |
2 | |
3 | namespace GrowthExperiments\NewcomerTasks\TaskType; |
4 | |
5 | use InvalidArgumentException; |
6 | use OutOfBoundsException; |
7 | use Wikimedia\ObjectFactory\ObjectFactory; |
8 | |
9 | /** |
10 | * Keeps track of TaskTypeHandlers. |
11 | */ |
12 | class TaskTypeHandlerRegistry { |
13 | |
14 | /** @var ObjectFactory */ |
15 | private $objectFactory; |
16 | |
17 | /** @var (array|callable)[] ObjectFactory specifications or callbacks, keyed by handler ID. */ |
18 | private $handlerSpecifications; |
19 | |
20 | /** @var TaskTypeHandler[] Task type handlers, keyed by ID. */ |
21 | private $handlers = []; |
22 | |
23 | /** |
24 | * @param ObjectFactory $objectFactory |
25 | * @param array $handlerSpecifications ObjectFactory specifications or callbacks, |
26 | * keyed by handler ID. |
27 | */ |
28 | public function __construct( ObjectFactory $objectFactory, array $handlerSpecifications = [] ) { |
29 | $this->objectFactory = $objectFactory; |
30 | $this->handlerSpecifications = $handlerSpecifications; |
31 | } |
32 | |
33 | /** |
34 | * @param string $handlerId TaskTypeHandler ID |
35 | * @return bool |
36 | */ |
37 | public function has( string $handlerId ): bool { |
38 | return array_key_exists( $handlerId, $this->handlers ) |
39 | || array_key_exists( $handlerId, $this->handlerSpecifications ); |
40 | } |
41 | |
42 | /** |
43 | * @param string $handlerId TaskTypeHandler ID |
44 | * @return TaskTypeHandler |
45 | * @throws OutOfBoundsException when invalid $handlerId is provided |
46 | */ |
47 | public function get( string $handlerId ): TaskTypeHandler { |
48 | return $this->handlers[$handlerId] ?? $this->createHandler( $handlerId ); |
49 | } |
50 | |
51 | /** |
52 | * @param TaskType $taskType |
53 | * @return TaskTypeHandler |
54 | */ |
55 | public function getByTaskType( TaskType $taskType ): TaskTypeHandler { |
56 | return $this->get( $taskType->getHandlerId() ); |
57 | } |
58 | |
59 | /** |
60 | * Returns a list of all handle TaskTypeHandler IDs that would be accepted by get(). |
61 | * @return array |
62 | */ |
63 | public function getKnownIds(): array { |
64 | $knownIds = array_keys( $this->handlerSpecifications ); |
65 | sort( $knownIds ); |
66 | return $knownIds; |
67 | } |
68 | |
69 | /** |
70 | * @param string $handlerId |
71 | * @param array|callable $spec |
72 | * @throws InvalidArgumentException When a handler is already registered for the given ID. |
73 | */ |
74 | public function register( string $handlerId, $spec ): void { |
75 | if ( array_key_exists( $handlerId, $this->handlerSpecifications ) ) { |
76 | throw new InvalidArgumentException( 'A task type handler is already registered for the ID ' |
77 | . $handlerId ); |
78 | } |
79 | $this->handlerSpecifications[$handlerId] = $spec; |
80 | } |
81 | |
82 | /** |
83 | * Gets all the edit tags defined by all the possible task types. |
84 | * @return string[] |
85 | */ |
86 | public function getChangeTags(): array { |
87 | $changeTags = []; |
88 | foreach ( $this->getKnownIds() as $handlerId ) { |
89 | $handler = $this->get( $handlerId ); |
90 | $changeTags = array_merge( $changeTags, $handler->getChangeTags() ); |
91 | } |
92 | return array_unique( $changeTags ); |
93 | } |
94 | |
95 | /** |
96 | * Get all the change tag names for all possible task types, excluding the "newcomer task" tag which applies |
97 | * to all the task types. |
98 | * |
99 | * @return string[] |
100 | */ |
101 | public function getUniqueChangeTags(): array { |
102 | return array_values( array_filter( |
103 | $this->getChangeTags(), fn ( $changeTagName ) => $changeTagName !== TaskTypeHandler::NEWCOMER_TASK_TAG |
104 | ) ); |
105 | } |
106 | |
107 | /** |
108 | * Return the task type handler ID associated with a change tag. |
109 | * |
110 | * @param string $changeTagName The change tag name, e.g. "newcomer task copyedit" |
111 | * @return string|null |
112 | * - The handler ID, e.g. "template-based" for unstructured tasks, or "link-recommendation" or |
113 | * "image-recommendation" for structured tasks. |
114 | * - null if the change tag could apply to multiple task types (e.g. "newcomer task") or if the change tag |
115 | * name is unknown. |
116 | */ |
117 | public function getTaskTypeHandlerIdByChangeTagName( string $changeTagName ): ?string { |
118 | if ( $changeTagName === TaskTypeHandler::NEWCOMER_TASK_TAG ) { |
119 | // Special-case the generic "newcomer task" tag because it applies to all task type handlers. |
120 | return null; |
121 | } |
122 | foreach ( $this->getKnownIds() as $handlerId ) { |
123 | $handler = $this->get( $handlerId ); |
124 | if ( in_array( $changeTagName, $handler->getChangeTags() ) ) { |
125 | return $handler->getId(); |
126 | } |
127 | } |
128 | return null; |
129 | } |
130 | |
131 | /** |
132 | * @param string $handlerId |
133 | * @return TaskTypeHandler |
134 | * @throws OutOfBoundsException When there is no handler registered for the given ID. |
135 | */ |
136 | private function createHandler( string $handlerId ): TaskTypeHandler { |
137 | $spec = $this->handlerSpecifications[$handlerId] ?? null; |
138 | if ( !$spec ) { |
139 | throw new OutOfBoundsException( 'No task type handler registered for the ID ' . $handlerId ); |
140 | } |
141 | $handler = $this->objectFactory->createObject( $spec, [ |
142 | 'assertClass' => TaskTypeHandler::class, |
143 | 'allowCallable' => true, |
144 | ] ); |
145 | /** @var TaskTypeHandler $handler */'@phan-var TaskTypeHandler $handler'; |
146 | $this->handlers[$handlerId] = $handler; |
147 | return $handler; |
148 | } |
149 | |
150 | } |