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 contentBlueprintsEvents 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 contentBlueprintsEvents, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 11 | class contentBlueprintsEvents extends ResourcesPage  | 
            ||
| 12 | { | 
            ||
| 13 | public $_errors = array();  | 
            ||
| 14 | |||
| 15 | public function __viewIndex($resource_type)  | 
            ||
| 16 |     { | 
            ||
| 17 | parent::__viewIndex(ResourceManager::RESOURCE_TYPE_EVENT);  | 
            ||
| 18 | |||
| 19 |         $this->setTitle(__('%1$s – %2$s', array(__('Events'), __('Symphony')))); | 
            ||
| 20 |         $this->appendSubheading(__('Events'), Widget::Anchor(__('Create New'), Administration::instance()->getCurrentPageURL().'new/', __('Create a new event'), 'create button', null, array('accesskey' => 'c'))); | 
            ||
| 21 | }  | 
            ||
| 22 | |||
| 23 | public function __viewNew()  | 
            ||
| 24 |     { | 
            ||
| 25 | $this->__form();  | 
            ||
| 26 | }  | 
            ||
| 27 | |||
| 28 | public function __viewEdit()  | 
            ||
| 29 |     { | 
            ||
| 30 | $this->__form();  | 
            ||
| 31 | }  | 
            ||
| 32 | |||
| 33 | public function __viewInfo()  | 
            ||
| 36 | }  | 
            ||
| 37 | |||
| 38 | public function __form($readonly = false)  | 
            ||
| 39 |     { | 
            ||
| 40 | $formHasErrors = (is_array($this->_errors) && !empty($this->_errors));  | 
            ||
| 41 | |||
| 42 |         if ($formHasErrors) { | 
            ||
| 43 | $this->pageAlert(  | 
            ||
| 44 |                 __('An error occurred while processing this form. See below for details.'), | 
            ||
| 45 | Alert::ERROR  | 
            ||
| 46 | );  | 
            ||
| 47 | |||
| 48 | // These alerts are only valid if the form doesn't have errors  | 
            ||
| 49 |         } elseif (isset($this->_context[2])) { | 
            ||
| 50 | $time = Widget::Time();  | 
            ||
| 51 | |||
| 52 |             switch ($this->_context[2]) { | 
            ||
| 53 | case 'saved':  | 
            ||
| 54 |                     $message = __('Event updated at %s.', array($time->generate())); | 
            ||
| 55 | break;  | 
            ||
| 56 | case 'created':  | 
            ||
| 57 |                     $message = __('Event created at %s.', array($time->generate())); | 
            ||
| 58 | }  | 
            ||
| 59 | |||
| 60 | $this->pageAlert(  | 
            ||
| 61 | $message  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 62 | . ' <a href="' . SYMPHONY_URL . '/blueprints/events/new/" accesskey="c">'  | 
            ||
| 63 |                 . __('Create another?') | 
            ||
| 64 | . '</a> <a href="' . SYMPHONY_URL . '/blueprints/events/" accesskey="a">'  | 
            ||
| 65 |                 . __('View all Events') | 
            ||
| 66 | . '</a>',  | 
            ||
| 67 | Alert::SUCCESS  | 
            ||
| 68 | );  | 
            ||
| 69 | }  | 
            ||
| 70 | |||
| 71 | $isEditing = ($readonly ? true : false);  | 
            ||
| 72 |         $fields = array('name' => null, 'filters' => null); | 
            ||
| 73 |         $about = array('name' => null); | 
            ||
| 74 | $providers = Symphony::ExtensionManager()->getProvidersOf(iProvider::EVENT);  | 
            ||
| 75 | $canonical_link = null;  | 
            ||
| 76 | |||
| 77 |         if (isset($_POST['fields'])) { | 
            ||
| 78 | $fields = $_POST['fields'];  | 
            ||
| 79 | |||
| 80 |             if ($this->_context[0] == 'edit') { | 
            ||
| 81 | $isEditing = true;  | 
            ||
| 82 | }  | 
            ||
| 83 |         } elseif ($this->_context[0] == 'edit' || $this->_context[0] == 'info') { | 
            ||
| 84 | $isEditing = true;  | 
            ||
| 85 | $handle = $this->_context[1];  | 
            ||
| 86 | $existing = EventManager::create($handle);  | 
            ||
| 87 |             $about = General::array_map_recursive('stripslashes', $existing->about()); | 
            ||
| 88 | |||
| 89 |             if ($this->_context[0] == 'edit' && !$existing->allowEditorToParse()) { | 
            ||
| 90 | redirect(SYMPHONY_URL . '/blueprints/events/info/' . $handle . '/');  | 
            ||
| 91 | }  | 
            ||
| 92 | |||
| 93 | $fields['name'] = $about['name'];  | 
            ||
| 94 | $fields['source'] = stripslashes($existing->getSource());  | 
            ||
| 95 | $provided = false;  | 
            ||
| 96 | |||
| 97 |             if (!empty($providers)) { | 
            ||
| 98 |                 foreach ($providers as $providerClass => $provider) { | 
            ||
| 99 |                     if ($fields['source'] == call_user_func(array($providerClass, 'getClass'))) { | 
            ||
| 100 | $fields = array_merge($fields, $existing->settings());  | 
            ||
| 101 | $provided = true;  | 
            ||
| 102 | break;  | 
            ||
| 103 | }  | 
            ||
| 104 | }  | 
            ||
| 105 | }  | 
            ||
| 106 | |||
| 107 |             if (!$provided) { | 
            ||
| 108 |                 if (isset($existing->eParamFILTERS)) { | 
            ||
| 109 |                     $fields['filters'] = array_map('stripslashes', $existing->eParamFILTERS); | 
            ||
| 110 | }  | 
            ||
| 111 | }  | 
            ||
| 112 | |||
| 113 | $canonical_link = '/blueprints/events/' . $this->_context[0] . '/' . $handle . '/';  | 
            ||
| 114 | }  | 
            ||
| 115 | |||
| 116 | // Handle name on edited changes, or from reading an edited datasource  | 
            ||
| 117 |         if (isset($about['name'])) { | 
            ||
| 118 | $name = $about['name'];  | 
            ||
| 119 |         } elseif (isset($fields['name'])) { | 
            ||
| 120 | $name = $fields['name'];  | 
            ||
| 121 | }  | 
            ||
| 122 | |||
| 123 |         $this->setPageType('form'); | 
            ||
| 124 |         $this->setTitle(__(($isEditing ? '%1$s – %2$s – %3$s' : '%2$s – %3$s'), array($name, __('Events'), __('Symphony')))); | 
            ||
| 125 |         if ($canonical_link) { | 
            ||
| 126 |             $this->addElementToHead(new XMLElement('link', null, array( | 
            ||
| 127 | 'rel' => 'canonical',  | 
            ||
| 128 | 'href' => SYMPHONY_URL . $canonical_link,  | 
            ||
| 129 | )));  | 
            ||
| 130 | }  | 
            ||
| 131 |         $this->appendSubheading(($isEditing ? $about['name'] : __('Untitled'))); | 
            ||
| 132 | $this->insertBreadcrumbs(array(  | 
            ||
| 133 |             Widget::Anchor(__('Events'), SYMPHONY_URL . '/blueprints/events/'), | 
            ||
| 134 | ));  | 
            ||
| 135 | |||
| 136 |         if (!$readonly) { | 
            ||
| 137 |             $fieldset = new XMLElement('fieldset'); | 
            ||
| 138 |             $fieldset->setAttribute('class', 'settings'); | 
            ||
| 139 |             $fieldset->appendChild(new XMLElement('legend', __('Essentials'))); | 
            ||
| 140 | |||
| 141 | // Target  | 
            ||
| 142 |             $sources = new XMLElement('div', null, array('class' => 'apply actions')); | 
            ||
| 143 |             $div = new XMLElement('div'); | 
            ||
| 144 |             $label = Widget::Label(__('Target'), null, 'apply-label-left'); | 
            ||
| 145 | $sources->appendChild($label);  | 
            ||
| 146 | $sources->appendChild($div);  | 
            ||
| 147 | |||
| 148 | $sections = (new SectionManager)->select()->execute()->rows();  | 
            ||
| 149 | $options = array();  | 
            ||
| 150 | $section_options = array();  | 
            ||
| 151 | $source = isset($fields['source']) ? $fields['source'] : null;  | 
            ||
| 152 | |||
| 153 |             if (is_array($sections) && !empty($sections)) { | 
            ||
| 154 |                 $section_options = array('label' => __('Sections'), 'options' => array()); | 
            ||
| 155 | |||
| 156 |                 foreach ($sections as $s) { | 
            ||
| 157 |                     $section_options['options'][] = array($s->get('id'), $source == $s->get('id'), General::sanitize($s->get('name'))); | 
            ||
| 158 | }  | 
            ||
| 159 | }  | 
            ||
| 160 | |||
| 161 | $options[] = $section_options;  | 
            ||
| 162 | |||
| 163 | // Loop over the event providers  | 
            ||
| 164 |             if (!empty($providers)) { | 
            ||
| 165 |                 $p = array('label' => __('From extensions'), 'options' => array()); | 
            ||
| 166 | |||
| 167 |                 foreach ($providers as $providerClass => $provider) { | 
            ||
| 168 | $p['options'][] = array(  | 
            ||
| 169 | $providerClass, ($fields['source'] == $providerClass), $provider  | 
            ||
| 170 | );  | 
            ||
| 171 | }  | 
            ||
| 172 | |||
| 173 | $options[] = $p;  | 
            ||
| 174 | }  | 
            ||
| 175 | |||
| 176 | $div->appendChild(  | 
            ||
| 177 |                 Widget::Select('source', $options, array('id' => 'event-context')) | 
            ||
| 178 | );  | 
            ||
| 179 | |||
| 180 |             if (isset($this->_errors['source'])) { | 
            ||
| 181 | $this->Context->prependChild(Widget::Error($sources, $this->_errors['source']));  | 
            ||
| 182 |             } else { | 
            ||
| 183 | $this->Context->prependChild($sources);  | 
            ||
| 184 | }  | 
            ||
| 185 | |||
| 186 | $this->Form->appendChild(  | 
            ||
| 187 |                 Widget::Input('fields[source]', $options[0]['options'][0][0], 'hidden', array('id' => 'event-source')) | 
            ||
| 188 | );  | 
            ||
| 189 | |||
| 190 | // Name  | 
            ||
| 191 |             $group = new XMLElement('div'); | 
            ||
| 192 |             $label = Widget::Label(__('Name')); | 
            ||
| 193 |             $label->appendChild(Widget::Input('fields[name]', General::sanitize($fields['name']))); | 
            ||
| 194 | |||
| 195 |             $div = new XMLElement('div'); | 
            ||
| 196 |             $div->setAttribute('class', 'column'); | 
            ||
| 197 | |||
| 198 |             if (isset($this->_errors['name'])) { | 
            ||
| 199 | $div->appendChild(Widget::Error($label, $this->_errors['name']));  | 
            ||
| 200 |             } else { | 
            ||
| 201 | $div->appendChild($label);  | 
            ||
| 202 | }  | 
            ||
| 203 | $group->appendChild($div);  | 
            ||
| 204 | $fieldset->appendChild($group);  | 
            ||
| 205 | $this->Form->appendChild($fieldset);  | 
            ||
| 206 | |||
| 207 | // Filters  | 
            ||
| 208 |             $fieldset = new XMLElement('fieldset'); | 
            ||
| 209 |             $fieldset->setAttribute('class', 'settings pickable'); | 
            ||
| 210 |             $fieldset->appendChild(new XMLElement('legend', __('Filters'))); | 
            ||
| 211 |             $p = new XMLElement('p', __('Event Filters add additional conditions or actions to an event.')); | 
            ||
| 212 |             $p->setAttribute('class', 'help'); | 
            ||
| 213 | $fieldset->appendChild($p);  | 
            ||
| 214 | |||
| 215 | $filters = isset($fields['filters']) ? $fields['filters'] : array();  | 
            ||
| 216 | $options = array(  | 
            ||
| 217 |                 array('admin-only', in_array('admin-only', $filters), __('Admin Only')), | 
            ||
| 218 |                 array('send-email', in_array('send-email', $filters), __('Send Notification Email')), | 
            ||
| 219 |                 array('expect-multiple', in_array('expect-multiple', $filters), __('Allow Multiple')), | 
            ||
| 220 | );  | 
            ||
| 221 | |||
| 222 | /**  | 
            ||
| 223 | * Allows adding of new filter rules to the Event filter rule select box  | 
            ||
| 224 | *  | 
            ||
| 225 | * @delegate AppendEventFilter  | 
            ||
| 226 | * @param string $context  | 
            ||
| 227 | * '/blueprints/events/(edit|new|info)/'  | 
            ||
| 228 | * @param array $selected  | 
            ||
| 229 | * An array of all the selected filters for this Event  | 
            ||
| 230 | * @param array $options  | 
            ||
| 231 | * An array of all the filters that are available, passed by reference  | 
            ||
| 232 | */  | 
            ||
| 233 |             Symphony::ExtensionManager()->notifyMembers('AppendEventFilter', '/blueprints/events/' . $this->_context[0] . '/', array( | 
            ||
| 234 | 'selected' => $filters,  | 
            ||
| 235 | 'options' => &$options  | 
            ||
| 236 | ));  | 
            ||
| 237 | |||
| 238 |             $fieldset->appendChild(Widget::Select('fields[filters][]', $options, array('multiple' => 'multiple', 'id' => 'event-filters'))); | 
            ||
| 239 | $this->Form->appendChild($fieldset);  | 
            ||
| 240 | |||
| 241 | // Connections  | 
            ||
| 242 |             $fieldset = new XMLElement('fieldset'); | 
            ||
| 243 |             $fieldset->setAttribute('class', 'settings'); | 
            ||
| 244 |             $fieldset->appendChild(new XMLElement('legend', __('Attach to Pages'))); | 
            ||
| 245 |             $p = new XMLElement('p', __('The event will only be available on the selected pages.')); | 
            ||
| 246 |             $p->setAttribute('class', 'help'); | 
            ||
| 247 | $fieldset->appendChild($p);  | 
            ||
| 248 | |||
| 249 |             $div = new XMLElement('div'); | 
            ||
| 250 |             $label = Widget::Label(__('Pages')); | 
            ||
| 251 | |||
| 252 | $pages = (new PageManager)->select()->execute()->rows();  | 
            ||
| 253 |             $event_handle = str_replace('-', '_', Lang::createHandle($fields['name'])); | 
            ||
| 254 | $connections = ResourceManager::getAttachedPages(ResourceManager::RESOURCE_TYPE_EVENT, $event_handle);  | 
            ||
| 255 | $selected = array();  | 
            ||
| 256 | |||
| 257 |             foreach ($connections as $connection) { | 
            ||
| 258 | $selected[] = $connection['id'];  | 
            ||
| 259 | }  | 
            ||
| 260 | |||
| 261 | $options = array();  | 
            ||
| 262 | |||
| 263 |             foreach ($pages as $page) { | 
            ||
| 264 | $options[] = array($page['id'], in_array($page['id'], $selected), PageManager::resolvePageTitle($page['id']));  | 
            ||
| 265 | }  | 
            ||
| 266 | |||
| 267 |             $label->appendChild(Widget::Select('fields[connections][]', $options, array('multiple' => 'multiple'))); | 
            ||
| 268 | $div->appendChild($label);  | 
            ||
| 269 | |||
| 270 | $fieldset->appendChild($div);  | 
            ||
| 271 | $this->Form->appendChild($fieldset);  | 
            ||
| 272 | |||
| 273 | // Providers  | 
            ||
| 274 |             if (!empty($providers)) { | 
            ||
| 275 |                 foreach ($providers as $providerClass => $provider) { | 
            ||
| 276 |                     if ($isEditing && $fields['source'] !== call_user_func(array($providerClass, 'getSource'))) { | 
            ||
| 277 | continue;  | 
            ||
| 278 | }  | 
            ||
| 279 | |||
| 280 | call_user_func_array(array($providerClass, 'buildEditor'), array($this->Form, &$this->_errors, $fields, $handle));  | 
            ||
| 281 | }  | 
            ||
| 282 | }  | 
            ||
| 283 |         } else { | 
            ||
| 284 | // Author  | 
            ||
| 285 |             if (isset($about['author']['website'])) { | 
            ||
| 286 | $link = Widget::Anchor($about['author']['name'], General::validateURL($about['author']['website']));  | 
            ||
| 287 |             } elseif (isset($about['author']['email'])) { | 
            ||
| 288 | $link = Widget::Anchor($about['author']['name'], 'mailto:' . $about['author']['email']);  | 
            ||
| 289 |             } else { | 
            ||
| 290 | $link = $about['author']['name'];  | 
            ||
| 291 | }  | 
            ||
| 292 | |||
| 293 |             if ($link) { | 
            ||
| 294 |                 $fieldset = new XMLElement('fieldset'); | 
            ||
| 295 |                 $fieldset->setAttribute('class', 'settings'); | 
            ||
| 296 |                 $fieldset->appendChild(new XMLElement('legend', __('Author'))); | 
            ||
| 297 |                 $fieldset->appendChild(new XMLElement('p', $link->generate(false))); | 
            ||
| 298 | $this->Form->appendChild($fieldset);  | 
            ||
| 299 | }  | 
            ||
| 300 | |||
| 301 | // Version  | 
            ||
| 302 |             $fieldset = new XMLElement('fieldset'); | 
            ||
| 303 |             $fieldset->setAttribute('class', 'settings'); | 
            ||
| 304 |             $fieldset->appendChild(new XMLElement('legend', __('Version'))); | 
            ||
| 305 |             $version = array_key_exists('version', $about) ? $about['version'] : null; | 
            ||
| 306 |             $release_date = array_key_exists('release-date', $about) ? $about['release-date'] : filemtime(EventManager::__getDriverPath($handle)); | 
            ||
| 307 | |||
| 308 |             if (preg_match('/^\d+(\.\d+)*$/', $version)) { | 
            ||
| 309 | $fieldset->appendChild(  | 
            ||
| 310 |                     new XMLElement('p', __('%1$s released on %2$s', array($version, DateTimeObj::format($release_date, __SYM_DATE_FORMAT__)))) | 
            ||
| 311 | );  | 
            ||
| 312 |             } elseif (!is_null($version)) { | 
            ||
| 313 | $fieldset->appendChild(  | 
            ||
| 314 |                     new XMLElement('p', __('Created by %1$s at %2$s', array($version, DateTimeObj::format($release_date, __SYM_DATE_FORMAT__)))) | 
            ||
| 315 | );  | 
            ||
| 316 |             } else { | 
            ||
| 317 | $fieldset->appendChild(  | 
            ||
| 318 |                     new XMLElement('p', __('Last modified on %s', array(DateTimeObj::format($release_date, __SYM_DATE_FORMAT__)))) | 
            ||
| 319 | );  | 
            ||
| 320 | }  | 
            ||
| 321 | $this->Form->appendChild($fieldset);  | 
            ||
| 322 | }  | 
            ||
| 323 | |||
| 324 | // If we are editing an event, it assumed that the event has documentation  | 
            ||
| 325 |         $fieldset = new XMLElement('fieldset'); | 
            ||
| 326 |         $fieldset->setAttribute('id', 'event-documentation'); | 
            ||
| 327 |         $fieldset->setAttribute('class', 'settings'); | 
            ||
| 328 | |||
| 329 |         if ($isEditing && method_exists($existing, 'documentation')) { | 
            ||
| 330 | $doc = $existing->documentation();  | 
            ||
| 331 | |||
| 332 |             if ($doc) { | 
            ||
| 333 | $fieldset->setValue(  | 
            ||
| 334 |                     '<legend>' . __('Documentation') . '</legend>' . PHP_EOL . | 
            ||
| 335 | General::tabsToSpaces(is_object($doc) ? $doc->generate(true, 4) : $doc)  | 
            ||
| 336 | );  | 
            ||
| 337 | }  | 
            ||
| 338 | }  | 
            ||
| 339 | |||
| 340 | $this->Form->appendChild($fieldset);  | 
            ||
| 341 | |||
| 342 |         $div = new XMLElement('div'); | 
            ||
| 343 |         $div->setAttribute('class', 'actions'); | 
            ||
| 344 |         $div->appendChild(Widget::Input('action[save]', ($isEditing ? __('Save Changes') : __('Create Event')), 'submit', array('accesskey' => 's'))); | 
            ||
| 345 | |||
| 346 |         if ($isEditing) { | 
            ||
| 347 |             $button = new XMLElement('button', __('Delete')); | 
            ||
| 348 |             $button->setAttributeArray(array('name' => 'action[delete]', 'class' => 'button confirm delete', 'title' => __('Delete this event'), 'type' => 'submit', 'accesskey' => 'd', 'data-message' => __('Are you sure you want to delete this event?'))); | 
            ||
| 349 | $div->appendChild($button);  | 
            ||
| 350 | }  | 
            ||
| 351 | |||
| 352 |         if (!$readonly) { | 
            ||
| 353 | $this->Form->appendChild($div);  | 
            ||
| 354 | }  | 
            ||
| 355 | }  | 
            ||
| 356 | |||
| 357 | public function __actionNew()  | 
            ||
| 358 |     { | 
            ||
| 359 |         if (array_key_exists('save', $_POST['action'])) { | 
            ||
| 360 | return $this->__formAction();  | 
            ||
| 361 | }  | 
            ||
| 362 | }  | 
            ||
| 363 | |||
| 364 | public function __actionEdit()  | 
            ||
| 418 | }  | 
            ||
| 419 | }  | 
            ||
| 420 | }  | 
            ||
| 421 | |||
| 422 | public function __actionIndex($resource_type)  | 
            ||
| 425 | }  | 
            ||
| 426 | |||
| 427 | public function __formAction()  | 
            ||
| 687 | }  | 
            ||
| 688 | }  | 
            ||
| 689 | }  | 
            ||
| 690 | |||
| 691 | public function __injectFilters(&$shell, $elements)  | 
            ||
| 715 |