Complex classes like RequestHandlerComponent 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 RequestHandlerComponent, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
37 | class RequestHandlerComponent extends Component { |
||
38 | |||
39 | /** |
||
40 | * The layout that will be switched to for Ajax requests |
||
41 | * |
||
42 | * @var string |
||
43 | * @see RequestHandler::setAjax() |
||
44 | */ |
||
45 | public $ajaxLayout = 'ajax'; |
||
46 | |||
47 | /** |
||
48 | * Determines whether or not callbacks will be fired on this component |
||
49 | * |
||
50 | * @var boolean |
||
51 | */ |
||
52 | public $enabled = true; |
||
53 | |||
54 | /** |
||
55 | * Holds the reference to Controller::$request |
||
56 | * |
||
57 | * @var CakeRequest |
||
58 | */ |
||
59 | public $request; |
||
60 | |||
61 | /** |
||
62 | * Holds the reference to Controller::$response |
||
63 | * |
||
64 | * @var CakeResponse |
||
65 | */ |
||
66 | public $response; |
||
67 | |||
68 | /** |
||
69 | * Contains the file extension parsed out by the Router |
||
70 | * |
||
71 | * @var string |
||
72 | * @see Router::parseExtensions() |
||
73 | */ |
||
74 | public $ext = null; |
||
75 | |||
76 | /** |
||
77 | * The template to use when rendering the given content type. |
||
78 | * |
||
79 | * @var string |
||
80 | */ |
||
81 | protected $_renderType = null; |
||
82 | |||
83 | /** |
||
84 | * A mapping between extensions and deserializers for request bodies of that type. |
||
85 | * By default only JSON and XML are mapped, use RequestHandlerComponent::addInputType() |
||
86 | * |
||
87 | * @var array |
||
88 | */ |
||
89 | protected $_inputTypeMap = array( |
||
90 | 'json' => array('json_decode', true) |
||
91 | ); |
||
92 | |||
93 | /** |
||
94 | * A mapping between type and viewClass |
||
95 | * By default only JSON and XML are mapped, use RequestHandlerComponent::viewClassMap() |
||
96 | * |
||
97 | * @var array |
||
98 | */ |
||
99 | protected $_viewClassMap = array( |
||
100 | 'json' => 'Json', |
||
101 | 'xml' => 'Xml' |
||
102 | ); |
||
103 | |||
104 | /** |
||
105 | * Constructor. Parses the accepted content types accepted by the client using HTTP_ACCEPT |
||
106 | * |
||
107 | * @param ComponentCollection $collection ComponentCollection object. |
||
108 | * @param array $settings Array of settings. |
||
109 | */ |
||
110 | public function __construct(ComponentCollection $collection, $settings = array()) { |
||
118 | |||
119 | /** |
||
120 | * Checks to see if a file extension has been parsed by the Router, or if the |
||
121 | * HTTP_ACCEPT_TYPE has matches only one content type with the supported extensions. |
||
122 | * If there is only one matching type between the supported content types & extensions, |
||
123 | * and the requested mime-types, RequestHandler::$ext is set to that value. |
||
124 | * |
||
125 | * @param Controller $controller A reference to the controller |
||
126 | * @return void |
||
127 | * @see Router::parseExtensions() |
||
128 | */ |
||
129 | public function initialize(Controller $controller) { |
||
141 | |||
142 | /** |
||
143 | * Set the extension based on the accept headers. |
||
144 | * Compares the accepted types and configured extensions. |
||
145 | * If there is one common type, that is assigned as the ext/content type |
||
146 | * for the response. |
||
147 | * Type with the highest weight will be set. If the highest weight has more |
||
148 | * then one type matching the extensions, the order in which extensions are specified |
||
149 | * determines which type will be set. |
||
150 | * |
||
151 | * If html is one of the preferred types, no content type will be set, this |
||
152 | * is to avoid issues with browsers that prefer html and several other content types. |
||
153 | * |
||
154 | * @return void |
||
155 | */ |
||
156 | protected function _setExtension() { |
||
177 | |||
178 | /** |
||
179 | * The startup method of the RequestHandler enables several automatic behaviors |
||
180 | * related to the detection of certain properties of the HTTP request, including: |
||
181 | * |
||
182 | * - Disabling layout rendering for Ajax requests (based on the HTTP_X_REQUESTED_WITH header) |
||
183 | * - If Router::parseExtensions() is enabled, the layout and template type are |
||
184 | * switched based on the parsed extension or Accept-Type header. For example, if `controller/action.xml` |
||
185 | * is requested, the view path becomes `app/View/Controller/xml/action.ctp`. Also if |
||
186 | * `controller/action` is requested with `Accept-Type: application/xml` in the headers |
||
187 | * the view path will become `app/View/Controller/xml/action.ctp`. Layout and template |
||
188 | * types will only switch to mime-types recognized by CakeResponse. If you need to declare |
||
189 | * additional mime-types, you can do so using CakeResponse::type() in your controllers beforeFilter() |
||
190 | * method. |
||
191 | * - If a helper with the same name as the extension exists, it is added to the controller. |
||
192 | * - If the extension is of a type that RequestHandler understands, it will set that |
||
193 | * Content-type in the response header. |
||
194 | * - If the XML data is POSTed, the data is parsed into an XML object, which is assigned |
||
195 | * to the $data property of the controller, which can then be saved to a model object. |
||
196 | * |
||
197 | * @param Controller $controller A reference to the controller |
||
198 | * @return void |
||
199 | */ |
||
200 | public function startup(Controller $controller) { |
||
222 | |||
223 | /** |
||
224 | * Helper method to parse xml input data, due to lack of anonymous functions |
||
225 | * this lives here. |
||
226 | * |
||
227 | * @param string $xml |
||
228 | * @return array Xml array data |
||
229 | */ |
||
230 | public function convertXml($xml) { |
||
241 | |||
242 | /** |
||
243 | * Handles (fakes) redirects for Ajax requests using requestAction() |
||
244 | * Modifies the $_POST and $_SERVER['REQUEST_METHOD'] to simulate a new GET request. |
||
245 | * |
||
246 | * @param Controller $controller A reference to the controller |
||
247 | * @param string|array $url A string or array containing the redirect location |
||
248 | * @param integer|array $status HTTP Status for redirect |
||
249 | * @param boolean $exit |
||
250 | * @return void |
||
251 | */ |
||
252 | public function beforeRedirect(Controller $controller, $url, $status = null, $exit = true) { |
||
275 | |||
276 | /** |
||
277 | * Checks if the response can be considered different according to the request |
||
278 | * headers, and the caching response headers. If it was not modified, then the |
||
279 | * render process is skipped. And the client will get a blank response with a |
||
280 | * "304 Not Modified" header. |
||
281 | * |
||
282 | * @params Controller $controller |
||
283 | * @return boolean false if the render process should be aborted |
||
284 | */ |
||
285 | public function beforeRender(Controller $controller) { |
||
290 | |||
291 | /** |
||
292 | * Returns true if the current HTTP request is Ajax, false otherwise |
||
293 | * |
||
294 | * @return boolean True if call is Ajax |
||
295 | * @deprecated use `$this->request->is('ajax')` instead. |
||
296 | */ |
||
297 | public function isAjax() { |
||
300 | |||
301 | /** |
||
302 | * Returns true if the current HTTP request is coming from a Flash-based client |
||
303 | * |
||
304 | * @return boolean True if call is from Flash |
||
305 | * @deprecated use `$this->request->is('flash')` instead. |
||
306 | */ |
||
307 | public function isFlash() { |
||
310 | |||
311 | /** |
||
312 | * Returns true if the current request is over HTTPS, false otherwise. |
||
313 | * |
||
314 | * @return boolean True if call is over HTTPS |
||
315 | * @deprecated use `$this->request->is('ssl')` instead. |
||
316 | */ |
||
317 | public function isSSL() { |
||
320 | |||
321 | /** |
||
322 | * Returns true if the current call accepts an XML response, false otherwise |
||
323 | * |
||
324 | * @return boolean True if client accepts an XML response |
||
325 | */ |
||
326 | public function isXml() { |
||
329 | |||
330 | /** |
||
331 | * Returns true if the current call accepts an RSS response, false otherwise |
||
332 | * |
||
333 | * @return boolean True if client accepts an RSS response |
||
334 | */ |
||
335 | public function isRss() { |
||
338 | |||
339 | /** |
||
340 | * Returns true if the current call accepts an Atom response, false otherwise |
||
341 | * |
||
342 | * @return boolean True if client accepts an RSS response |
||
343 | */ |
||
344 | public function isAtom() { |
||
347 | |||
348 | /** |
||
349 | * Returns true if user agent string matches a mobile web browser, or if the |
||
350 | * client accepts WAP content. |
||
351 | * |
||
352 | * @return boolean True if user agent is a mobile web browser |
||
353 | */ |
||
354 | public function isMobile() { |
||
357 | |||
358 | /** |
||
359 | * Returns true if the client accepts WAP content |
||
360 | * |
||
361 | * @return boolean |
||
362 | */ |
||
363 | public function isWap() { |
||
366 | |||
367 | /** |
||
368 | * Returns true if the current call a POST request |
||
369 | * |
||
370 | * @return boolean True if call is a POST |
||
371 | * @deprecated Use $this->request->is('post'); from your controller. |
||
372 | */ |
||
373 | public function isPost() { |
||
376 | |||
377 | /** |
||
378 | * Returns true if the current call a PUT request |
||
379 | * |
||
380 | * @return boolean True if call is a PUT |
||
381 | * @deprecated Use $this->request->is('put'); from your controller. |
||
382 | */ |
||
383 | public function isPut() { |
||
386 | |||
387 | /** |
||
388 | * Returns true if the current call a GET request |
||
389 | * |
||
390 | * @return boolean True if call is a GET |
||
391 | * @deprecated Use $this->request->is('get'); from your controller. |
||
392 | */ |
||
393 | public function isGet() { |
||
396 | |||
397 | /** |
||
398 | * Returns true if the current call a DELETE request |
||
399 | * |
||
400 | * @return boolean True if call is a DELETE |
||
401 | * @deprecated Use $this->request->is('delete'); from your controller. |
||
402 | */ |
||
403 | public function isDelete() { |
||
406 | |||
407 | /** |
||
408 | * Gets Prototype version if call is Ajax, otherwise empty string. |
||
409 | * The Prototype library sets a special "Prototype version" HTTP header. |
||
410 | * |
||
411 | * @return string|boolean When Ajax the prototype version of component making the call otherwise false |
||
412 | */ |
||
413 | public function getAjaxVersion() { |
||
417 | |||
418 | /** |
||
419 | * Adds/sets the Content-type(s) for the given name. This method allows |
||
420 | * content-types to be mapped to friendly aliases (or extensions), which allows |
||
421 | * RequestHandler to automatically respond to requests of that type in the |
||
422 | * startup method. |
||
423 | * |
||
424 | * @param string $name The name of the Content-type, i.e. "html", "xml", "css" |
||
425 | * @param string|array $type The Content-type or array of Content-types assigned to the name, |
||
426 | * i.e. "text/html", or "application/xml" |
||
427 | * @return void |
||
428 | * @deprecated use `$this->response->type()` instead. |
||
429 | */ |
||
430 | public function setContent($name, $type = null) { |
||
433 | |||
434 | /** |
||
435 | * Gets the server name from which this request was referred |
||
436 | * |
||
437 | * @return string Server address |
||
438 | * @deprecated use $this->request->referer() from your controller instead |
||
439 | */ |
||
440 | public function getReferer() { |
||
443 | |||
444 | /** |
||
445 | * Gets remote client IP |
||
446 | * |
||
447 | * @param boolean $safe |
||
448 | * @return string Client IP address |
||
449 | * @deprecated use $this->request->clientIp() from your, controller instead. |
||
450 | */ |
||
451 | public function getClientIP($safe = true) { |
||
454 | |||
455 | /** |
||
456 | * Determines which content types the client accepts. Acceptance is based on |
||
457 | * the file extension parsed by the Router (if present), and by the HTTP_ACCEPT |
||
458 | * header. Unlike CakeRequest::accepts() this method deals entirely with mapped content types. |
||
459 | * |
||
460 | * Usage: |
||
461 | * |
||
462 | * `$this->RequestHandler->accepts(array('xml', 'html', 'json'));` |
||
463 | * |
||
464 | * Returns true if the client accepts any of the supplied types. |
||
465 | * |
||
466 | * `$this->RequestHandler->accepts('xml');` |
||
467 | * |
||
468 | * Returns true if the client accepts xml. |
||
469 | * |
||
470 | * @param string|array $type Can be null (or no parameter), a string type name, or an |
||
471 | * array of types |
||
472 | * @return mixed If null or no parameter is passed, returns an array of content |
||
473 | * types the client accepts. If a string is passed, returns true |
||
474 | * if the client accepts it. If an array is passed, returns true |
||
475 | * if the client accepts one or more elements in the array. |
||
476 | * @see RequestHandlerComponent::setContent() |
||
477 | */ |
||
478 | public function accepts($type = null) { |
||
498 | |||
499 | /** |
||
500 | * Determines the content type of the data the client has sent (i.e. in a POST request) |
||
501 | * |
||
502 | * @param string|array $type Can be null (or no parameter), a string type name, or an array of types |
||
503 | * @return mixed If a single type is supplied a boolean will be returned. If no type is provided |
||
504 | * The mapped value of CONTENT_TYPE will be returned. If an array is supplied the first type |
||
505 | * in the request content type will be returned. |
||
506 | */ |
||
507 | public function requestedWith($type = null) { |
||
531 | |||
532 | /** |
||
533 | * Determines which content-types the client prefers. If no parameters are given, |
||
534 | * the single content-type that the client most likely prefers is returned. If $type is |
||
535 | * an array, the first item in the array that the client accepts is returned. |
||
536 | * Preference is determined primarily by the file extension parsed by the Router |
||
537 | * if provided, and secondarily by the list of content-types provided in |
||
538 | * HTTP_ACCEPT. |
||
539 | * |
||
540 | * @param string|array $type An optional array of 'friendly' content-type names, i.e. |
||
541 | * 'html', 'xml', 'js', etc. |
||
542 | * @return mixed If $type is null or not provided, the first content-type in the |
||
543 | * list, based on preference, is returned. If a single type is provided |
||
544 | * a boolean will be returned if that type is preferred. |
||
545 | * If an array of types are provided then the first preferred type is returned. |
||
546 | * If no type is provided the first preferred type is returned. |
||
547 | * @see RequestHandlerComponent::setContent() |
||
548 | */ |
||
549 | public function prefers($type = null) { |
||
579 | |||
580 | /** |
||
581 | * Sets the layout and template paths for the content type defined by $type. |
||
582 | * |
||
583 | * ### Usage: |
||
584 | * |
||
585 | * Render the response as an 'ajax' response. |
||
586 | * |
||
587 | * `$this->RequestHandler->renderAs($this, 'ajax');` |
||
588 | * |
||
589 | * Render the response as an xml file and force the result as a file download. |
||
590 | * |
||
591 | * `$this->RequestHandler->renderAs($this, 'xml', array('attachment' => 'myfile.xml');` |
||
592 | * |
||
593 | * @param Controller $controller A reference to a controller object |
||
594 | * @param string $type Type of response to send (e.g: 'ajax') |
||
595 | * @param array $options Array of options to use |
||
596 | * @return void |
||
597 | * @see RequestHandlerComponent::setContent() |
||
598 | * @see RequestHandlerComponent::respondAs() |
||
599 | */ |
||
600 | public function renderAs(Controller $controller, $type, $options = array()) { |
||
653 | |||
654 | /** |
||
655 | * Sets the response header based on type map index name. This wraps several methods |
||
656 | * available on CakeResponse. It also allows you to use Content-Type aliases. |
||
657 | * |
||
658 | * @param string|array $type Friendly type name, i.e. 'html' or 'xml', or a full content-type, |
||
659 | * like 'application/x-shockwave'. |
||
660 | * @param array $options If $type is a friendly type name that is associated with |
||
661 | * more than one type of content, $index is used to select which content-type to use. |
||
662 | * @return boolean Returns false if the friendly type name given in $type does |
||
663 | * not exist in the type map, or if the Content-type header has |
||
664 | * already been set by this method. |
||
665 | * @see RequestHandlerComponent::setContent() |
||
666 | */ |
||
667 | public function respondAs($type, $options = array()) { |
||
701 | |||
702 | /** |
||
703 | * Returns the current response type (Content-type header), or null if not alias exists |
||
704 | * |
||
705 | * @return mixed A string content type alias, or raw content type if no alias map exists, |
||
706 | * otherwise null |
||
707 | */ |
||
708 | public function responseType() { |
||
711 | |||
712 | /** |
||
713 | * Maps a content-type back to an alias |
||
714 | * |
||
715 | * @param string|array $cType Either a string content type to map, or an array of types. |
||
716 | * @return string|array Aliases for the types provided. |
||
717 | * @deprecated Use $this->response->mapType() in your controller instead. |
||
718 | */ |
||
719 | public function mapType($cType) { |
||
722 | |||
723 | /** |
||
724 | * Maps a content type alias back to its mime-type(s) |
||
725 | * |
||
726 | * @param string|array $alias String alias to convert back into a content type. Or an array of aliases to map. |
||
727 | * @return string Null on an undefined alias. String value of the mapped alias type. If an |
||
728 | * alias maps to more than one content type, the first one will be returned. |
||
729 | */ |
||
730 | public function mapAlias($alias) { |
||
743 | |||
744 | /** |
||
745 | * Add a new mapped input type. Mapped input types are automatically |
||
746 | * converted by RequestHandlerComponent during the startup() callback. |
||
747 | * |
||
748 | * @param string $type The type alias being converted, ie. json |
||
749 | * @param array $handler The handler array for the type. The first index should |
||
750 | * be the handling callback, all other arguments should be additional parameters |
||
751 | * for the handler. |
||
752 | * @return void |
||
753 | * @throws CakeException |
||
754 | */ |
||
755 | public function addInputType($type, $handler) { |
||
761 | |||
762 | /** |
||
763 | * Getter/setter for viewClassMap |
||
764 | * |
||
765 | * @param array|string $type The type string or array with format `array('type' => 'viewClass')` to map one or more |
||
766 | * @param array $viewClass The viewClass to be used for the type without `View` appended |
||
767 | * @return array|string Returns viewClass when only string $type is set, else array with viewClassMap |
||
768 | */ |
||
769 | public function viewClassMap($type = null, $viewClass = null) { |
||
782 | |||
783 | } |
||
784 |
Since your code implements the magic setter
_set
, this function will be called for any write access on an undefined variable. You can add the@property
annotation to your class or interface to document the existence of this variable.Since the property has write access only, you can use the @property-write annotation instead.
Of course, you may also just have mistyped another name, in which case you should fix the error.
See also the PhpDoc documentation for @property.