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:
Complex classes like DisplayTicketSelector 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 DisplayTicketSelector, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | class DisplayTicketSelector |
||
20 | { |
||
21 | |||
22 | /** |
||
23 | * event that ticket selector is being generated for |
||
24 | * |
||
25 | * @access protected |
||
26 | * @var \EE_Event $event |
||
27 | */ |
||
28 | protected $event; |
||
29 | |||
30 | /** |
||
31 | * Used to flag when the ticket selector is being called from an external iframe. |
||
32 | * |
||
33 | * @var bool $iframe |
||
34 | */ |
||
35 | protected $iframe = false; |
||
36 | |||
37 | /** |
||
38 | * max attendees that can register for event at one time |
||
39 | * |
||
40 | * @var int $max_attendees |
||
41 | */ |
||
42 | private $max_attendees = EE_INF; |
||
43 | |||
44 | /** |
||
45 | *@var string $date_format |
||
46 | */ |
||
47 | private $date_format = ''; |
||
48 | |||
49 | /** |
||
50 | *@var string $time_format |
||
51 | */ |
||
52 | private $time_format = ''; |
||
53 | |||
54 | |||
55 | |||
56 | /** |
||
57 | * DisplayTicketSelector constructor. |
||
58 | */ |
||
59 | public function __construct() |
||
70 | |||
71 | |||
72 | |||
73 | /** |
||
74 | * @param boolean $iframe |
||
75 | */ |
||
76 | public function setIframe( $iframe = true ) |
||
80 | |||
81 | |||
82 | |||
83 | /** |
||
84 | * finds and sets the \EE_Event object for use throughout class |
||
85 | * |
||
86 | * @param mixed $event |
||
87 | * @return bool |
||
88 | */ |
||
89 | protected function setEvent( $event = null ) |
||
90 | { |
||
91 | if ( $event === null ) { |
||
92 | global $post; |
||
93 | $event = $post; |
||
94 | } |
||
95 | if ( $event instanceof \EE_Event ) { |
||
96 | $this->event = $event; |
||
97 | } else if ( $event instanceof \WP_Post ) { |
||
|
|||
98 | if ( isset( $event->EE_Event ) && $event->EE_Event instanceof \EE_Event ) { |
||
99 | $this->event = $event->EE_Event; |
||
100 | } else if ( $event->post_type === 'espresso_events' ) { |
||
101 | $event->EE_Event = \EEM_Event::instance()->instantiate_class_from_post_object( $event ); |
||
102 | $this->event = $event->EE_Event; |
||
103 | } |
||
104 | View Code Duplication | } else { |
|
105 | $user_msg = __( 'No Event object or an invalid Event object was supplied.', 'event_espresso' ); |
||
106 | $dev_msg = $user_msg . __( |
||
107 | 'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.', |
||
108 | 'event_espresso' |
||
109 | ); |
||
110 | \EE_Error::add_error( $user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__ ); |
||
111 | return false; |
||
112 | } |
||
113 | return true; |
||
114 | } |
||
115 | |||
116 | |||
117 | |||
118 | /** |
||
119 | * @return int |
||
120 | */ |
||
121 | public function getMaxAttendees() |
||
125 | |||
126 | |||
127 | |||
128 | /** |
||
129 | * @param int $max_attendees |
||
130 | */ |
||
131 | public function setMaxAttendees($max_attendees) |
||
140 | |||
141 | |||
142 | |||
143 | /** |
||
144 | * creates buttons for selecting number of attendees for an event |
||
145 | * |
||
146 | * @param \WP_Post|int $event |
||
147 | * @param bool $view_details |
||
148 | * @return string |
||
149 | * @throws \EE_Error |
||
150 | */ |
||
151 | public function display( $event = null, $view_details = false ) |
||
152 | { |
||
153 | // reset filter for displaying submit button |
||
154 | remove_filter( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true' ); |
||
155 | // poke and prod incoming event till it tells us what it is |
||
156 | if ( ! $this->setEvent( $event ) ) { |
||
157 | return false; |
||
158 | } |
||
159 | // begin gathering template arguments by getting event status |
||
160 | $template_args = array( 'event_status' => $this->event->get_active_status() ); |
||
161 | if ( $this->activeEventAndShowTicketSelector($event, $template_args['event_status'], $view_details) ) { |
||
162 | return ! is_single() ? $this->displayViewDetailsButton() : ''; |
||
163 | } |
||
164 | // filter the maximum qty that can appear in the Ticket Selector qty dropdowns |
||
165 | $this->setMaxAttendees($this->event->additional_limit()); |
||
166 | if ($this->getMaxAttendees() < 1) { |
||
167 | return $this->ticketSalesClosedMessage(); |
||
168 | } |
||
169 | // is the event expired ? |
||
170 | $template_args['event_is_expired'] = $this->event->is_expired(); |
||
171 | if ( $template_args[ 'event_is_expired' ] ) { |
||
172 | return $this->expiredEventMessage(); |
||
173 | } |
||
174 | // get all tickets for this event ordered by the datetime |
||
175 | $tickets = $this->getTickets(); |
||
176 | if (count($tickets) < 1) { |
||
177 | return $this->noTicketAvailableMessage(); |
||
178 | } |
||
179 | // redirecting to another site for registration ?? |
||
180 | $external_url = (string) $this->event->external_url(); |
||
181 | // if redirecting to another site for registration, then we don't load the TS |
||
182 | $ticket_selector = $external_url |
||
183 | ? $this->externalEventRegistration() |
||
184 | : $this->loadTicketSelector($tickets,$template_args); |
||
185 | // now set up the form (but not for the admin) |
||
186 | $ticket_selector = ! is_admin() |
||
187 | ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector |
||
188 | : $ticket_selector; |
||
189 | // submit button and form close tag |
||
190 | $ticket_selector .= ! is_admin() ? $this->displaySubmitButton($external_url) : ''; |
||
191 | return $ticket_selector; |
||
192 | } |
||
193 | |||
194 | |||
195 | |||
196 | /** |
||
197 | * displayTicketSelector |
||
198 | * examines the event properties and determines whether a Ticket Selector should be displayed |
||
199 | * |
||
200 | * @param \WP_Post|int $event |
||
201 | * @param string $_event_active_status |
||
202 | * @param bool $view_details |
||
203 | * @return bool |
||
204 | * @throws \EE_Error |
||
205 | */ |
||
206 | protected function activeEventAndShowTicketSelector($event, $_event_active_status, $view_details) |
||
225 | |||
226 | |||
227 | |||
228 | /** |
||
229 | * noTicketAvailableMessage |
||
230 | * notice displayed if event is expired |
||
231 | * |
||
232 | * @return string |
||
233 | * @throws \EE_Error |
||
234 | */ |
||
235 | protected function expiredEventMessage() |
||
242 | |||
243 | |||
244 | |||
245 | /** |
||
246 | * noTicketAvailableMessage |
||
247 | * notice displayed if event has no more tickets available |
||
248 | * |
||
249 | * @return string |
||
250 | * @throws \EE_Error |
||
251 | */ |
||
252 | View Code Duplication | protected function noTicketAvailableMessage() |
|
272 | |||
273 | |||
274 | |||
275 | /** |
||
276 | * ticketSalesClosed |
||
277 | * notice displayed if event ticket sales are turned off |
||
278 | * |
||
279 | * @return string |
||
280 | * @throws \EE_Error |
||
281 | */ |
||
282 | View Code Duplication | protected function ticketSalesClosedMessage() |
|
302 | |||
303 | |||
304 | |||
305 | /** |
||
306 | * getTickets |
||
307 | * |
||
308 | * @return \EE_Base_Class[]|\EE_Ticket[] |
||
309 | * @throws \EE_Error |
||
310 | */ |
||
311 | protected function getTickets() |
||
332 | |||
333 | |||
334 | |||
335 | /** |
||
336 | * loadTicketSelector |
||
337 | * begins to assemble template arguments |
||
338 | * and decides whether to load a "simple" ticket selector, or the standard |
||
339 | * |
||
340 | * @param \EE_Ticket[] $tickets |
||
341 | * @param array $template_args |
||
342 | * @return string |
||
343 | * @throws \EE_Error |
||
344 | */ |
||
345 | protected function loadTicketSelector(array $tickets, array $template_args) |
||
379 | |||
380 | |||
381 | |||
382 | /** |
||
383 | * simpleTicketSelector |
||
384 | * there's one ticket, and max attendees is set to one, |
||
385 | * so if the event is free, then this is a "simple" ticket selector |
||
386 | * a.k.a. "Dude Where's my Ticket Selector?" |
||
387 | * |
||
388 | * @param \EE_Ticket[] $tickets |
||
389 | * @param array $template_args |
||
390 | * @return string |
||
391 | * @throws \EE_Error |
||
392 | */ |
||
393 | protected function simpleTicketSelector($tickets, array $template_args) |
||
418 | |||
419 | |||
420 | |||
421 | /** |
||
422 | * externalEventRegistration |
||
423 | * |
||
424 | * @return string |
||
425 | */ |
||
426 | public function externalEventRegistration() |
||
438 | |||
439 | |||
440 | |||
441 | /** |
||
442 | * formOpen |
||
443 | * |
||
444 | * @param int $ID |
||
445 | * @param string $external_url |
||
446 | * @return string |
||
447 | */ |
||
448 | public function formOpen( $ID = 0, $external_url = '' ) |
||
490 | |||
491 | |||
492 | |||
493 | /** |
||
494 | * displaySubmitButton |
||
495 | * |
||
496 | * @param string $external_url |
||
497 | * @return string |
||
498 | * @throws \EE_Error |
||
499 | */ |
||
500 | public function displaySubmitButton($external_url = '') |
||
572 | |||
573 | |||
574 | |||
575 | /** |
||
576 | * @return string |
||
577 | * @throws \EE_Error |
||
578 | */ |
||
579 | public function displayRegisterNowButton() |
||
602 | |||
603 | |||
604 | /** |
||
605 | * displayViewDetailsButton |
||
606 | * |
||
607 | * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event |
||
608 | * (ie: $_max_atndz === 1) where there are no available tickets, |
||
609 | * either because they are sold out, expired, or not yet on sale. |
||
610 | * In this case, we need to close the form BEFORE adding any closing divs |
||
611 | * @return string |
||
612 | * @throws \EE_Error |
||
613 | */ |
||
614 | public function displayViewDetailsButton( $DWMTS = false ) |
||
651 | |||
652 | |||
653 | |||
654 | /** |
||
655 | * @return string |
||
656 | */ |
||
657 | public function ticketSelectorEndDiv() |
||
661 | |||
662 | |||
663 | |||
664 | /** |
||
665 | * @return string |
||
666 | */ |
||
667 | public function clearTicketSelector() |
||
672 | |||
673 | |||
674 | |||
675 | /** |
||
676 | * @access public |
||
677 | * @return string |
||
678 | */ |
||
679 | public function formClose() |
||
683 | |||
684 | |||
685 | |||
686 | } |
||
687 | // End of file DisplayTicketSelector.php |
||
688 | // Location: /DisplayTicketSelector.php |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.