Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
33 | class Processor implements ModelProcessor, TypeProcessor |
||
34 | { |
||
35 | |||
36 | /** |
||
37 | * Properties |
||
38 | */ |
||
39 | |||
40 | /** |
||
41 | * An input transformer to pre-process the input data before hydration. |
||
42 | * |
||
43 | * @var Transformer |
||
44 | */ |
||
45 | private $input_transformer; |
||
46 | |||
47 | /** |
||
48 | * A factory for building hydrators for a given model. |
||
49 | * |
||
50 | * @var HydratorFactory|null |
||
51 | */ |
||
52 | private $hydrator_factory; |
||
53 | |||
54 | /** |
||
55 | * A factory for building builders for a given model. |
||
56 | * |
||
57 | * @var BuilderFactory|null |
||
58 | */ |
||
59 | private $builder_factory; |
||
60 | |||
61 | /** |
||
62 | * A configuration flag that denotes whether hydration should always be run |
||
63 | * after building a new model when processing specified types. |
||
64 | * |
||
65 | * @var bool |
||
66 | */ |
||
67 | private $always_hydrate_after_building = false; |
||
68 | |||
69 | /** |
||
70 | * A configuration flag that denotes whether processing (hydration/building) |
||
71 | * should require contextual compatibility when a context is provided. |
||
72 | * |
||
73 | * @var bool |
||
74 | */ |
||
75 | private $require_contextual_processing_compatibility = false; |
||
76 | |||
77 | |||
78 | /** |
||
79 | * Methods |
||
80 | */ |
||
81 | |||
82 | /** |
||
83 | * Constructor |
||
84 | * |
||
85 | * @param Transformer|null $input_transformer The input transformer. |
||
86 | * @param HydratorFactory|null $hydrator_factory A hydrator factory. |
||
87 | * @param BuilderFactory|null $builder_factory A builder factory. |
||
88 | * @param bool $always_hydrate_after_building A configuration flag that |
||
89 | * denotes whether hydration should always be run after building a new |
||
90 | * model when processing specified types. |
||
91 | * @param bool $require_contextual_processing_compatibility A configuration |
||
92 | * flag that denotes whether processing (hydration/building) should require |
||
93 | * contextual compatibility when a context is provided. |
||
94 | */ |
||
95 | 54 | public function __construct( |
|
108 | |||
109 | /** |
||
110 | * Get the input transformer. |
||
111 | * |
||
112 | * @return Transformer The input transformer. |
||
113 | */ |
||
114 | 3 | public function getInputTransformer(): Transformer |
|
118 | |||
119 | /** |
||
120 | * Set the input transformer. |
||
121 | * |
||
122 | * @param Transformer $input_transformer The input transformer. |
||
123 | * @return $this This instance. |
||
124 | */ |
||
125 | 3 | public function setInputTransformer(Transformer $input_transformer): self |
|
131 | |||
132 | /** |
||
133 | * Get the hydrator factory. |
||
134 | * |
||
135 | * @return HydratorFactory|null The hydrator factory. |
||
136 | */ |
||
137 | 3 | public function getHydratorFactory() |
|
141 | |||
142 | /** |
||
143 | * Set the hydrator factory. |
||
144 | * |
||
145 | * @param HydratorFactory|null $hydrator_factory The hydrator factory. |
||
146 | * @return $this This instance. |
||
147 | */ |
||
148 | 9 | public function setHydratorFactory(HydratorFactory $hydrator_factory = null): self |
|
154 | |||
155 | /** |
||
156 | * Get the builder factory. |
||
157 | * |
||
158 | * @return BuilderFactory|null The builder factory. |
||
159 | */ |
||
160 | 3 | public function getBuilderFactory() |
|
164 | |||
165 | /** |
||
166 | * Set the builder factory. |
||
167 | * |
||
168 | * @param BuilderFactory|null $builder_factory The builder factory. |
||
169 | * @return $this This instance. |
||
170 | */ |
||
171 | 6 | public function setBuilderFactory(BuilderFactory $builder_factory = null): self |
|
177 | |||
178 | /** |
||
179 | * Get the value of the configuration flag that denotes whether hydration |
||
180 | * should always be run after building a new model when processing |
||
181 | * specified types. |
||
182 | * |
||
183 | * @return bool The value of the flag. |
||
184 | */ |
||
185 | 3 | public function getAlwaysHydrateAfterBuilding(): bool |
|
189 | |||
190 | /** |
||
191 | * Set the value of the configuration flag that denotes whether hydration |
||
192 | * should always be run after building a new model when processing |
||
193 | * specified types. |
||
194 | * |
||
195 | * @param bool $always_hydrate_after_building Whether or not to always |
||
196 | * hydrate after building a new model when processing types. |
||
197 | * @return $this This instance. |
||
198 | */ |
||
199 | 9 | public function setAlwaysHydrateAfterBuilding(bool $always_hydrate_after_building): self |
|
205 | |||
206 | /** |
||
207 | * Get the value of the configuration flag that denotes whether processing |
||
208 | * (hydration/building) should require contextual compatibility when a |
||
209 | * context is provided. |
||
210 | * |
||
211 | * @return bool The value of the flag. |
||
212 | */ |
||
213 | 3 | public function getRequireContextualProcessingCompatibility(): bool |
|
217 | |||
218 | /** |
||
219 | * Set the value of the configuration flag that denotes whether processing |
||
220 | * (hydration/building) should require contextual compatibility when a |
||
221 | * context is provided. |
||
222 | * |
||
223 | * @param bool $require_contextual_processing_compatibility Whether or not |
||
224 | * to require contextual processing compatibility when a context is |
||
225 | * provided. |
||
226 | * @return $this This instance. |
||
227 | */ |
||
228 | 9 | public function setRequireContextualProcessingCompatibility(bool $require_contextual_processing_compatibility): self |
|
234 | |||
235 | /** |
||
236 | * {@inheritdoc} |
||
237 | * |
||
238 | * If a hydrator isn't provided, an attempt will be made to automatically |
||
239 | * resolve and build an appropriate hydrator from the provided factory. |
||
240 | * |
||
241 | * @param mixed $input_data The input data. |
||
242 | * @param mixed $model The model to hydrate. |
||
243 | * @param Hydrator|null $hydrator The hydrator to use in the process. |
||
244 | * @param Map|null $context An optional generic key-value map, for providing |
||
245 | * contextual values during the process. |
||
246 | * @return mixed The hydrated model. |
||
247 | */ |
||
248 | 15 | public function processForModel($input_data, $model, Hydrator $hydrator = null, Map $context = null) |
|
254 | |||
255 | /** |
||
256 | * {@inheritdoc} |
||
257 | * |
||
258 | * If a builder isn't provided, an attempt will be made to automatically |
||
259 | * resolve and build an appropriate builder from the provided factory. |
||
260 | * |
||
261 | * If a hydrator is provided, it will be used to hydrate the provided type |
||
262 | * after building via the builder. |
||
263 | * |
||
264 | * If a hydrator isn't provided, but the "always_hydrate_after_building" |
||
265 | * property is set to true, an attempt to hydrate the type will be made |
||
266 | * after building via the builder, and the hydrator will be automatically |
||
267 | * resolved from the provided factory. |
||
268 | * |
||
269 | * @param mixed $input_data The input data. |
||
270 | * @param string $type The type to build. |
||
271 | * @param Builder|null $builder The builder to use in the process. |
||
272 | * @param Hydrator|null $hydrator An optional hydrator to use in the |
||
273 | * process, after the type is built, to aid in the full hydration of the |
||
274 | * resulting model. |
||
275 | * @param Map|null $context An optional generic key-value map, for providing |
||
276 | * contextual values during the process. |
||
277 | * @return mixed The built model. |
||
278 | */ |
||
279 | 24 | public function processForType( |
|
296 | |||
297 | /** |
||
298 | * Transform the input data. |
||
299 | * |
||
300 | * @param mixed $input_data The input data. |
||
301 | * @return mixed The resulting transformed data. |
||
302 | */ |
||
303 | 39 | protected function transformInput($input_data) |
|
307 | |||
308 | /** |
||
309 | * Hydrate a model from incoming data. |
||
310 | * |
||
311 | * If a hydrator isn't provided, an attempt will be made to automatically |
||
312 | * resolve and build an appropriate hydrator from the provided factory. |
||
313 | * |
||
314 | * @param mixed $input_data The input data. |
||
315 | * @param mixed $model The model to hydrate. |
||
316 | * @param Hydrator|null $hydrator The hydrator to use. |
||
317 | * @param Map|null $context An optional generic key-value map, for providing |
||
318 | * contextual values during the process. |
||
319 | * @throws IncompatibleProcessException If the hydrator isn't compatible |
||
320 | * with the given process strategy. |
||
321 | * @return mixed The hydrated model. |
||
322 | */ |
||
323 | 24 | View Code Duplication | protected function hydrateModel($input_data, $model, Hydrator $hydrator = null, Map $context = null) |
338 | |||
339 | /** |
||
340 | * Build a model from incoming data. |
||
341 | * |
||
342 | * If a builder isn't provided, an attempt will be made to automatically |
||
343 | * resolve and build an appropriate builder from the provided factory. |
||
344 | * |
||
345 | * @param mixed $input_data The input data. |
||
346 | * @param string $type The type to build. |
||
347 | * @param Builder|null $builder The builder to use. |
||
348 | * @param Map|null $context An optional generic key-value map, for providing |
||
349 | * contextual values during the process. |
||
350 | * @throws IncompatibleProcessException If the builder isn't compatible with |
||
351 | * the given process strategy. |
||
352 | * @return mixed The built model. |
||
353 | */ |
||
354 | 24 | View Code Duplication | protected function buildModel($input_data, string $type, Builder $builder = null, Map $context = null) |
369 | |||
370 | /** |
||
371 | * Get a Hydrator for a given model. |
||
372 | * |
||
373 | * @param mixed $model The model to get a hydrator for. |
||
374 | * @throws UnresolvableHydratorException If a hydrator can't be resolved for |
||
375 | * the given model. |
||
376 | * @return Hydrator The resulting hydrator. |
||
377 | */ |
||
378 | 12 | protected function getHydratorForModel($model): Hydrator |
|
386 | |||
387 | /** |
||
388 | * Get a Builder for a given model. |
||
389 | * |
||
390 | * @param string $type The type to get a builder for. |
||
391 | * @throws UnresolvableBuilderException If a builder can't be resolved for |
||
392 | * the given model. |
||
393 | * @return Builder The resulting builder. |
||
394 | */ |
||
395 | 6 | protected function getBuilderForType(string $type): Builder |
|
403 | } |
||
404 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.