Complex classes like ViewHandler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ViewHandler, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 32 | class ViewHandler implements ConfigurableViewHandlerInterface |
||
| 33 | { |
||
| 34 | /** |
||
| 35 | * Key format, value a callable that returns a Response instance. |
||
| 36 | * |
||
| 37 | * @var array |
||
| 38 | */ |
||
| 39 | protected $customHandlers = []; |
||
| 40 | |||
| 41 | /** |
||
| 42 | * The supported formats as keys. |
||
| 43 | * |
||
| 44 | * @var array |
||
| 45 | */ |
||
| 46 | protected $formats; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * HTTP response status code for a failed validation. |
||
| 50 | * |
||
| 51 | * @var int |
||
| 52 | */ |
||
| 53 | protected $failedValidationCode; |
||
| 54 | |||
| 55 | /** |
||
| 56 | * HTTP response status code when the view data is null. |
||
| 57 | * |
||
| 58 | * @var int |
||
| 59 | */ |
||
| 60 | protected $emptyContentCode; |
||
| 61 | |||
| 62 | /** |
||
| 63 | * Whether or not to serialize null view data. |
||
| 64 | * |
||
| 65 | * @var bool |
||
| 66 | */ |
||
| 67 | protected $serializeNull; |
||
| 68 | |||
| 69 | /** |
||
| 70 | * If to force a redirect for the given key format, |
||
| 71 | * with value being the status code to use. |
||
| 72 | * |
||
| 73 | * @var array |
||
| 74 | */ |
||
| 75 | protected $forceRedirects; |
||
| 76 | |||
| 77 | /** |
||
| 78 | * @var string |
||
| 79 | */ |
||
| 80 | protected $defaultEngine; |
||
| 81 | |||
| 82 | /** |
||
| 83 | * @var array |
||
| 84 | */ |
||
| 85 | protected $exclusionStrategyGroups = []; |
||
| 86 | |||
| 87 | /** |
||
| 88 | * @var string |
||
| 89 | */ |
||
| 90 | protected $exclusionStrategyVersion; |
||
| 91 | |||
| 92 | /** |
||
| 93 | * @var bool |
||
| 94 | */ |
||
| 95 | protected $serializeNullStrategy; |
||
| 96 | |||
| 97 | private $urlGenerator; |
||
| 98 | private $serializer; |
||
| 99 | private $requestStack; |
||
| 100 | |||
| 101 | private $options; |
||
| 102 | |||
| 103 | /** |
||
| 104 | * Constructor. |
||
| 105 | * |
||
| 106 | * @param UrlGeneratorInterface $urlGenerator The URL generator |
||
| 107 | * @param Serializer $serializer |
||
| 108 | * @param RequestStack $requestStack The request stack |
||
| 109 | * @param array $formats the supported formats as keys |
||
| 110 | * @param int $failedValidationCode The HTTP response status code for a failed validation |
||
| 111 | * @param int $emptyContentCode HTTP response status code when the view data is null |
||
| 112 | * @param bool $serializeNull Whether or not to serialize null view data |
||
| 113 | * @param array $forceRedirects If to force a redirect for the given key format, with value being the status code to use |
||
| 114 | * @param array $options config options |
||
| 115 | */ |
||
| 116 | private function __construct( |
||
| 117 | UrlGeneratorInterface $urlGenerator, |
||
| 118 | Serializer $serializer, |
||
| 119 | 81 | RequestStack $requestStack, |
|
| 120 | array $formats = null, |
||
| 121 | $failedValidationCode = Response::HTTP_BAD_REQUEST, |
||
| 122 | $emptyContentCode = Response::HTTP_NO_CONTENT, |
||
| 123 | $serializeNull = false, |
||
| 124 | array $forceRedirects = null, |
||
| 125 | array $options = [] |
||
| 126 | ) { |
||
| 127 | $this->urlGenerator = $urlGenerator; |
||
| 128 | $this->serializer = $serializer; |
||
| 129 | $this->requestStack = $requestStack; |
||
| 130 | $this->formats = (array) $formats; |
||
| 131 | 81 | $this->failedValidationCode = $failedValidationCode; |
|
| 132 | 81 | $this->emptyContentCode = $emptyContentCode; |
|
| 133 | 81 | $this->serializeNull = $serializeNull; |
|
| 134 | 81 | $this->forceRedirects = (array) $forceRedirects; |
|
| 135 | 81 | $this->options = $options + [ |
|
| 136 | 81 | 'exclusionStrategyGroups' => [], |
|
| 137 | 81 | 'exclusionStrategyVersion' => null, |
|
| 138 | 81 | 'serializeNullStrategy' => null, |
|
| 139 | 81 | ]; |
|
| 140 | 81 | $this->reset(); |
|
| 141 | 81 | } |
|
| 142 | |||
| 143 | public static function create( |
||
| 144 | UrlGeneratorInterface $urlGenerator, |
||
| 145 | Serializer $serializer, |
||
| 146 | RequestStack $requestStack, |
||
| 147 | array $formats = null, |
||
| 148 | 1 | int $failedValidationCode = Response::HTTP_BAD_REQUEST, |
|
| 149 | int $emptyContentCode = Response::HTTP_NO_CONTENT, |
||
| 150 | 1 | bool $serializeNull = false, |
|
| 151 | 1 | array $options = [] |
|
| 152 | ): self |
||
| 153 | { |
||
| 154 | return new self($urlGenerator, $serializer, $requestStack, $formats, $failedValidationCode, $emptyContentCode, $serializeNull, [], $options, false); |
||
|
|
|||
| 155 | } |
||
| 156 | |||
| 157 | /** |
||
| 158 | 7 | * Sets the default serialization groups. |
|
| 159 | * |
||
| 160 | 7 | * @param array|string $groups |
|
| 161 | 7 | */ |
|
| 162 | public function setExclusionStrategyGroups($groups) |
||
| 163 | { |
||
| 164 | $this->exclusionStrategyGroups = (array) $groups; |
||
| 165 | } |
||
| 166 | |||
| 167 | /** |
||
| 168 | 25 | * Sets the default serialization version. |
|
| 169 | * |
||
| 170 | 25 | * @param string $version |
|
| 171 | 25 | */ |
|
| 172 | public function setExclusionStrategyVersion($version) |
||
| 173 | { |
||
| 174 | $this->exclusionStrategyVersion = $version; |
||
| 175 | } |
||
| 176 | 44 | ||
| 177 | /** |
||
| 178 | 44 | * If nulls should be serialized. |
|
| 179 | * |
||
| 180 | * @param bool $isEnabled |
||
| 181 | */ |
||
| 182 | public function setSerializeNullStrategy($isEnabled) |
||
| 183 | { |
||
| 184 | $this->serializeNullStrategy = $isEnabled; |
||
| 185 | } |
||
| 186 | |||
| 187 | /** |
||
| 188 | * {@inheritdoc} |
||
| 189 | */ |
||
| 190 | public function supports($format) |
||
| 191 | { |
||
| 192 | return isset($this->customHandlers[$format]) || isset($this->formats[$format]); |
||
| 193 | 16 | } |
|
| 194 | |||
| 195 | 16 | /** |
|
| 196 | 1 | * Registers a custom handler. |
|
| 197 | * |
||
| 198 | * The handler must have the following signature: handler(ViewHandler $viewHandler, View $view, Request $request, $format) |
||
| 199 | 15 | * It can use the public methods of this class to retrieve the needed data and return a |
|
| 200 | 15 | * Response object ready to be sent. |
|
| 201 | * |
||
| 202 | * @param string $format |
||
| 203 | * @param callable $callable |
||
| 204 | * |
||
| 205 | * @throws \InvalidArgumentException |
||
| 206 | */ |
||
| 207 | public function registerHandler($format, $callable) |
||
| 208 | { |
||
| 209 | if (!is_callable($callable)) { |
||
| 210 | throw new \InvalidArgumentException('Registered view callback must be callable.'); |
||
| 211 | } |
||
| 212 | |||
| 213 | $this->customHandlers[$format] = $callable; |
||
| 214 | 55 | } |
|
| 215 | |||
| 216 | 55 | /** |
|
| 217 | * Gets a response HTTP status code from a View instance. |
||
| 218 | 55 | * |
|
| 219 | 7 | * By default it will return 200. However if there is a FormInterface stored for |
|
| 220 | * the key 'form' in the View's data it will return the failed_validation |
||
| 221 | * configuration if the form instance has errors. |
||
| 222 | 48 | * |
|
| 223 | 48 | * @param View $view |
|
| 224 | 15 | * @param mixed $content |
|
| 225 | * |
||
| 226 | * @return int HTTP status code |
||
| 227 | 33 | */ |
|
| 228 | protected function getStatusCode(View $view, $content = null) |
||
| 229 | { |
||
| 230 | $form = $this->getFormFromView($view); |
||
| 231 | |||
| 232 | if ($form && $form->isSubmitted() && !$form->isValid()) { |
||
| 233 | return $this->failedValidationCode; |
||
| 234 | } |
||
| 235 | |||
| 236 | $statusCode = $view->getStatusCode(); |
||
| 237 | 46 | if (null !== $statusCode) { |
|
| 238 | return $statusCode; |
||
| 239 | 46 | } |
|
| 240 | |||
| 241 | return null !== $content ? Response::HTTP_OK : $this->emptyContentCode; |
||
| 242 | } |
||
| 243 | |||
| 244 | /** |
||
| 245 | * Gets or creates a JMS\Serializer\SerializationContext and initializes it with |
||
| 246 | * the view exclusion strategies, groups & versions if a new context is created. |
||
| 247 | * |
||
| 248 | * @param View $view |
||
| 249 | * |
||
| 250 | 31 | * @return Context |
|
| 251 | */ |
||
| 252 | 31 | protected function getSerializationContext(View $view) |
|
| 275 | |||
| 276 | /** |
||
| 277 | * Handles a request with the proper handler. |
||
| 278 | * |
||
| 279 | * Decides on which handler to use based on the request format. |
||
| 280 | * |
||
| 281 | * @param View $view |
||
| 282 | 40 | * @param Request $request |
|
| 283 | * |
||
| 284 | 40 | * @throws UnsupportedMediaTypeHttpException |
|
| 285 | 12 | * |
|
| 286 | 12 | * @return Response |
|
| 287 | */ |
||
| 288 | 40 | public function handle(View $view, Request $request = null) |
|
| 308 | |||
| 309 | /** |
||
| 310 | * Creates the Response from the view. |
||
| 311 | 8 | * |
|
| 312 | * @param View $view |
||
| 313 | 8 | * @param string $location |
|
| 314 | 8 | * @param string $format |
|
| 315 | 1 | * |
|
| 316 | 1 | * @return Response |
|
| 317 | 7 | */ |
|
| 318 | 7 | public function createRedirectResponse(View $view, $location, $format) |
|
| 340 | |||
| 341 | /** |
||
| 342 | 15 | * Handles creation of a Response using either redirection or the serializer service. |
|
| 343 | * |
||
| 344 | 15 | * @param View $view |
|
| 345 | * @param Request $request |
||
| 346 | 15 | * @param string $format |
|
| 347 | 15 | * |
|
| 348 | 2 | * @return Response |
|
| 349 | */ |
||
| 350 | public function createResponse(View $view, Request $request, $format) |
||
| 375 | 12 | ||
| 376 | 12 | /** |
|
| 377 | * Initializes a response object that represents the view and holds the view's status code. |
||
| 378 | 22 | * |
|
| 379 | 2 | * @param View $view |
|
| 380 | 2 | * @param string $format |
|
| 381 | * |
||
| 382 | 22 | * @return Response |
|
| 383 | 22 | */ |
|
| 384 | 2 | private function initResponse(View $view, $format) |
|
| 408 | 8 | ||
| 409 | /** |
||
| 410 | * Returns the form from the given view if present, false otherwise. |
||
| 411 | 43 | * |
|
| 412 | * @param View $view |
||
| 413 | 43 | * |
|
| 414 | 43 | * @return bool|FormInterface |
|
| 415 | 43 | */ |
|
| 416 | protected function getFormFromView(View $view) |
||
| 430 | 44 | ||
| 431 | 44 | /** |
|
| 432 | 15 | * Returns the data from a view. |
|
| 433 | 44 | * |
|
| 434 | 28 | * @param View $view |
|
| 435 | * |
||
| 436 | 28 | * @return mixed|null |
|
| 437 | 6 | */ |
|
| 438 | 6 | private function getDataFromView(View $view) |
|
| 448 | |||
| 449 | 44 | /** |
|
| 450 | 39 | * Resets internal object state at the end of the request. |
|
| 451 | 39 | */ |
|
| 452 | public function reset() |
||
| 458 | } |
||
| 459 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.