17
17
class FileFetcher extends AbstractPersistentJob
18
18
{
19
19
20
+ /**
21
+ * Array of processor class names provided by the configuration.
22
+ *
23
+ * @var string[]
24
+ */
20
25
protected array $ customProcessorClasses = [];
21
26
27
+ /**
28
+ * The processor this file fetcher will use.
29
+ *
30
+ * Stored here so that we don't have to recompute it.
31
+ *
32
+ * @var \FileFetcher\Processor\ProcessorInterface|null
33
+ */
34
+ private ?ProcessorInterface $ processor = null ;
35
+
36
+ /**
37
+ * {@inheritDoc}
38
+ *
39
+ * We override ::get() because it can set values for both newly constructed
40
+ * objects and re-hydrated ones.
41
+ */
42
+ public static function get (string $ identifier , $ storage , array $ config = null )
43
+ {
44
+ $ ff = parent ::get ($ identifier , $ storage , $ config );
45
+ // If we see that a processor is configured, we need to handle some
46
+ // special cases. It might be that the hydrated values for
47
+ // $customProcessorClasses are the same, but the caller could also be
48
+ // telling us to use a different processor than any that were hydrated
49
+ // from storage. We keep the existing ones and prepend the new ones.
50
+ $ ff ->addProcessors ($ config );
51
+ $ storage ->store (json_encode ($ ff ), $ identifier );
52
+ return $ ff ;
53
+ }
54
+
22
55
/**
23
56
* Constructor.
57
+ *
58
+ * Constructor is protected. Use static::get() to instantiate a file
59
+ * fetcher.
60
+ *
61
+ * @param string $identifier
62
+ * File fetcher job identifier.
63
+ * @param $storage
64
+ * File fetcher job storage object.
65
+ * @param array|NULL $config
66
+ * Configuration for the file fetcher.
67
+ *
68
+ * @see static::get()
24
69
*/
25
70
protected function __construct (string $ identifier , $ storage , array $ config = null )
26
71
{
27
- parent ::__construct ($ identifier , $ storage, $ config );
72
+ parent ::__construct ($ identifier , $ storage );
28
73
29
74
$ this ->setProcessors ($ config );
30
75
@@ -42,15 +87,6 @@ protected function __construct(string $identifier, $storage, array $config = nul
42
87
'temporary_directory ' => $ config ['temporaryDirectory ' ],
43
88
];
44
89
45
- // [State]
46
-
47
- foreach ($ this ->getProcessors () as $ processor ) {
48
- if ($ processor ->isServerCompatible ($ state )) {
49
- $ state ['processor ' ] = get_class ($ processor );
50
- break ;
51
- }
52
- }
53
-
54
90
$ this ->getResult ()->setData (json_encode ($ state ));
55
91
}
56
92
@@ -62,6 +98,9 @@ public function setTimeLimit(int $seconds): bool
62
98
return parent ::setTimeLimit ($ seconds );
63
99
}
64
100
101
+ /**
102
+ * {@inheritDoc}
103
+ */
65
104
protected function runIt ()
66
105
{
67
106
$ state = $ this ->getProcessor ()->setupState ($ this ->getState ());
@@ -71,10 +110,19 @@ protected function runIt()
71
110
return $ info ['result ' ];
72
111
}
73
112
113
+ /**
114
+ * Gets the combined custom and default processors list.
115
+ *
116
+ * @return array
117
+ * The combined custom and default processors list, prioritizing the
118
+ * custom ones in the order they were defined.
119
+ */
74
120
protected function getProcessors (): array
75
121
{
76
122
$ processors = self ::getDefaultProcessors ();
77
- foreach ($ this ->customProcessorClasses as $ processorClass ) {
123
+ // Reverse the array so when we merge it all back together it's in the
124
+ // correct order of precedent.
125
+ foreach (array_reverse ($ this ->customProcessorClasses ) as $ processorClass ) {
78
126
if ($ processor = $ this ->getCustomProcessorInstance ($ processorClass )) {
79
127
$ processors = array_merge ([get_class ($ processor ) => $ processor ], $ processors );
80
128
}
@@ -84,15 +132,32 @@ protected function getProcessors(): array
84
132
85
133
private static function getDefaultProcessors ()
86
134
{
87
- $ processors = [];
88
- $ processors [ Local::class] = new Local ();
89
- $ processors [ Remote::class] = new Remote ();
90
- return $ processors ;
135
+ return [
136
+ Local::class => new Local (),
137
+ Remote::class => new Remote (),
138
+ ] ;
91
139
}
92
140
93
- protected function getProcessor (): ProcessorInterface
141
+ /**
142
+ * Get the processor used by this file fetcher object.
143
+ *
144
+ * @return \FileFetcher\Processor\ProcessorInterface|null
145
+ * A processor object, determined by configuration, or NULL if none is
146
+ * suitable.
147
+ */
148
+ protected function getProcessor (): ?ProcessorInterface
94
149
{
95
- return $ this ->getProcessors ()[$ this ->getStateProperty ('processor ' )];
150
+ if ($ this ->processor ) {
151
+ return $ this ->processor ;
152
+ }
153
+ $ state = $ this ->getState ();
154
+ foreach ($ this ->getProcessors () as $ processor ) {
155
+ if ($ processor ->isServerCompatible ($ state )) {
156
+ $ this ->processor = $ processor ;
157
+ break ;
158
+ }
159
+ }
160
+ return $ this ->processor ;
96
161
}
97
162
98
163
private function validateConfig ($ config ): array
@@ -109,30 +174,108 @@ private function validateConfig($config): array
109
174
return $ config ;
110
175
}
111
176
177
+ /**
178
+ * Set custom processors for this file fetcher object.
179
+ *
180
+ * @param $config
181
+ * Configuration array, as passed to __construct() or Job::get(). Should
182
+ * contain an array of processor class names under the key 'processors'.
183
+ *
184
+ * @see self::addProcessors()
185
+ */
112
186
protected function setProcessors ($ config )
113
187
{
114
- if (!isset ($ config ['processors ' ])) {
115
- return ;
188
+ $ this ->processor = null ;
189
+ $ processors = $ config ['processors ' ] ?? [];
190
+ if (!is_array ($ processors )) {
191
+ $ processors = [];
116
192
}
193
+ $ this ->customProcessorClasses = $ processors ;
194
+ }
117
195
118
- if (!is_array ($ config ['processors ' ])) {
196
+ /**
197
+ * Add configured processors to the ones already set in the object.
198
+ *
199
+ * Existing custom processor classes will be preserved, but any present in
200
+ * the new config will be prioritized.
201
+ *
202
+ * @param array $config
203
+ * Configuration array, as passed to __construct() or Job::get(). Should
204
+ * contain an array of processor class names under the key 'processors'.
205
+ *
206
+ * @see self::setProcessors()
207
+ */
208
+ protected function addProcessors (array $ config ): void
209
+ {
210
+ // If we have config, and we don't have custom classes already, do the
211
+ // easy thing.
212
+ if (($ config ['processors ' ] ?? false ) && empty ($ this ->customProcessorClasses )) {
213
+ $ this ->setProcessors ($ config );
119
214
return ;
120
215
}
216
+ if ($ config_processors = $ config ['processors ' ] ?? false ) {
217
+ $ this ->processor = null ;
218
+ // Unset the configured processors from customProcessorClasses.
219
+ $ this ->unsetDuplicateCustomProcessorClasses ($ config_processors );
220
+ // Merge in the configuration.
221
+ $ this ->customProcessorClasses = array_merge (
222
+ $ config_processors ,
223
+ $ this ->customProcessorClasses
224
+ );
225
+ }
226
+ }
121
227
122
- $ this ->customProcessorClasses = $ config ['processors ' ];
228
+ /**
229
+ * Unset items in $this->customProcessorClasses present in the given array.
230
+ *
231
+ * @param array $processors
232
+ * Processor class names to be removed from the list of custom processor
233
+ * classes.
234
+ */
235
+ private function unsetDuplicateCustomProcessorClasses (array $ processors ):void
236
+ {
237
+ foreach ($ processors as $ processor ) {
238
+ // Use array_keys() with its search parameter.
239
+ foreach (array_keys ($ this ->customProcessorClasses , $ processor ) as $ existing ) {
240
+ unset($ this ->customProcessorClasses [$ existing ]);
241
+ }
242
+ }
123
243
}
124
244
125
- private function getCustomProcessorInstance ($ processorClass )
245
+ /**
246
+ * Get an instance of the given custom processor class.
247
+ *
248
+ * @param $processorClass
249
+ * Processor class name.
250
+ *
251
+ * @return \FileFetcher\Processor\ProcessorInterface|null
252
+ * An instance of the processor class. If the given class name does not
253
+ * exist, or does not implement ProcessorInterface, then null is
254
+ * returned.
255
+ */
256
+ private function getCustomProcessorInstance ($ processorClass ): ?ProcessorInterface
126
257
{
127
258
if (!class_exists ($ processorClass )) {
128
- return ;
259
+ return null ;
129
260
}
130
261
131
262
$ classes = class_implements ($ processorClass );
132
263
if (!in_array (ProcessorInterface::class, $ classes )) {
133
- return ;
264
+ return null ;
134
265
}
135
266
136
267
return new $ processorClass ();
137
268
}
269
+
270
+ /**
271
+ * {@inheritDoc}
272
+ */
273
+ protected function serializeIgnoreProperties (): array
274
+ {
275
+ // Tell our serializer to ignore processor information.
276
+ return array_merge (
277
+ parent ::serializeIgnoreProperties (),
278
+ ['processor ' ]
279
+ );
280
+ }
138
281
}
0 commit comments