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 Module 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 Module, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class Module implements |
||
17 | AutoloaderProviderInterface, |
||
18 | BootstrapListenerInterface, |
||
19 | ConfigProviderInterface, |
||
20 | ServiceProviderInterface, |
||
21 | ViewHelperProviderInterface |
||
22 | { |
||
23 | |||
24 | public function onBootstrap(EventInterface $e) |
||
25 | { |
||
26 | $serviceManager = $e->getApplication()->getServiceManager(); |
||
27 | $config = $e->getApplication()->getServiceManager()->get('config'); |
||
28 | |||
29 | // Locale management |
||
30 | $translator = $serviceManager->get('translator'); |
||
31 | $defaultLocale = 'fr'; |
||
32 | |||
33 | // Gestion de la locale |
||
34 | if (PHP_SAPI !== 'cli') { |
||
35 | $config = $e->getApplication()->getServiceManager()->get('config'); |
||
36 | if (isset($config['playgroundLocale'])) { |
||
37 | $pgLocale = $config['playgroundLocale']; |
||
38 | $defaultLocale = $pgLocale['default']; |
||
39 | |||
40 | if (isset($pgLocale['strategies'])) { |
||
41 | $pgstrat = $pgLocale['strategies']; |
||
42 | |||
43 | // Is there a locale in the URL ? |
||
44 | if (in_array('uri', $pgstrat)) { |
||
45 | $path = $e->getRequest()->getUri()->getPath(); |
||
46 | $parts = explode('/', trim($path, '/')); |
||
47 | $localeCandidate = array_shift($parts); |
||
48 | // I switch from locale to... language |
||
49 | $localeCandidate = substr($localeCandidate, 0, 2); |
||
50 | |||
51 | if (in_array($localeCandidate, $pgLocale['supported'])) { |
||
52 | $locale = $localeCandidate; |
||
53 | } |
||
54 | } |
||
55 | |||
56 | // Is there a cookie for the locale ? |
||
57 | if (empty($locale) && in_array('cookie', $pgstrat)) { |
||
58 | $serviceManager->get('router')->setTranslator($translator); |
||
59 | if ($serviceManager->get('router')->match($serviceManager->get('request')) && |
||
60 | strpos($serviceManager->get('router')->match($serviceManager->get('request'))->getMatchedRouteName(), 'admin') !==false |
||
61 | ) { |
||
62 | View Code Duplication | if ($e->getRequest()->getCookie() && |
|
63 | $e->getRequest()->getCookie()->offsetExists('pg_locale_back') |
||
64 | ) { |
||
65 | $locale = $e->getRequest()->getCookie()->offsetGet('pg_locale_back'); |
||
66 | } |
||
67 | View Code Duplication | } else { |
|
68 | if ($e->getRequest()->getCookie() && |
||
69 | $e->getRequest()->getCookie()->offsetExists('pg_locale_frontend') |
||
70 | ) { |
||
71 | $locale = $e->getRequest()->getCookie()->offsetGet('pg_locale_frontend'); |
||
72 | } |
||
73 | } |
||
74 | } |
||
75 | |||
76 | // Is there a locale in the request Header ? |
||
77 | if (empty($locale) && in_array('header', $pgstrat)) { |
||
78 | if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { |
||
79 | $localeCandidate = \Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']); |
||
80 | // I switch from locale to... language |
||
81 | $localeCandidate = substr($localeCandidate, 0, 2); |
||
82 | if (in_array($localeCandidate, $pgLocale['supported'])) { |
||
83 | $locale = $localeCandidate; |
||
84 | } |
||
85 | } |
||
86 | } |
||
87 | } |
||
88 | // I take the default locale |
||
89 | if (empty($locale)) { |
||
90 | $locale = $defaultLocale; |
||
91 | } |
||
92 | } |
||
93 | |||
94 | // I take the default locale |
||
95 | if (empty($locale)) { |
||
96 | $locale = $defaultLocale; |
||
97 | } |
||
98 | |||
99 | $translator->setLocale($locale); |
||
100 | |||
101 | // Attach the translator to the router |
||
102 | $e->getRouter()->setTranslator($translator); |
||
103 | $e->getRouter()->setTranslatorTextDomain('routes'); |
||
104 | |||
105 | // Attach the translator to the plugins |
||
106 | $translate = $serviceManager->get('viewhelpermanager')->get('translate'); |
||
107 | $translate->getTranslator()->setLocale($locale); |
||
108 | |||
109 | $options = $serviceManager->get('playgroundcore_module_options'); |
||
110 | $options->setLocale($locale); |
||
111 | } |
||
112 | |||
113 | // positionnement de la langue pour les traductions de date avec strftime |
||
114 | setlocale(LC_TIME, "fr_FR", 'fr_FR.utf8', 'fra'); |
||
115 | |||
116 | AbstractValidator::setDefaultTranslator($translator, 'playgroundcore'); |
||
117 | |||
118 | /* |
||
119 | * Entity translation based on Doctrine Gedmo library |
||
120 | */ |
||
121 | $doctrine = $serviceManager->get('doctrine.entitymanager.orm_default'); |
||
122 | $evm = $doctrine->getEventManager(); |
||
123 | |||
124 | $translatableListener = new \Gedmo\Translatable\TranslatableListener(); |
||
125 | $translatableListener->setDefaultLocale($defaultLocale); |
||
126 | |||
127 | // If no translation is found, fallback to entity data |
||
128 | $translatableListener->setTranslationFallback(true); |
||
129 | |||
130 | // set Locale |
||
131 | if (!empty($locale)) { |
||
132 | $translatableListener->setTranslatableLocale($locale); |
||
133 | } |
||
134 | |||
135 | $evm->addEventSubscriber($translatableListener); |
||
136 | |||
137 | /** |
||
138 | * Adding a Filter to slugify a string (make it URL compliiant) |
||
139 | */ |
||
140 | $filterChain = new \Zend\Filter\FilterChain(); |
||
141 | $filterChain->getPluginManager()->setInvokableClass( |
||
142 | 'slugify', |
||
143 | 'PlaygroundCore\Filter\Slugify' |
||
144 | ); |
||
145 | $filterChain->attach(new Filter\Slugify()); |
||
146 | |||
147 | // Start the session container |
||
148 | $sessionConfig = new SessionConfig(); |
||
149 | $sessionConfig->setOptions($config['session']); |
||
150 | $sessionManager = new SessionManager($sessionConfig); |
||
151 | $sessionManager->start(); |
||
152 | |||
153 | /** |
||
154 | * Optional: If you later want to use namespaces, you can already store the |
||
155 | * Manager in the shared (static) Container (=namespace) field |
||
156 | */ |
||
157 | \Zend\Session\Container::setDefaultManager($sessionManager); |
||
158 | |||
159 | // Google Analytics : When the render event is triggered, we invoke the view helper to |
||
160 | // render the javascript code. |
||
161 | $e->getApplication()->getEventManager()->attach(\Zend\Mvc\MvcEvent::EVENT_RENDER, function (\Zend\Mvc\MvcEvent $e) use ($serviceManager) { |
||
162 | $view = $serviceManager->get('ViewHelperManager'); |
||
163 | $plugin = $view->get('googleAnalytics'); |
||
164 | $plugin(); |
||
165 | |||
166 | $pluginOG = $view->get('facebookOpengraph'); |
||
167 | $pluginOG(); |
||
168 | |||
169 | $pluginTC = $view->get('twitterCard'); |
||
170 | $pluginTC(); |
||
171 | }); |
||
172 | |||
173 | |||
174 | if (PHP_SAPI !== 'cli') { |
||
175 | $session = new Container('facebook'); |
||
176 | $fb = $e->getRequest()->getPost()->get('signed_request'); |
||
177 | if ($fb) { |
||
178 | $signedReq = explode('.', $fb, 2); |
||
179 | $payload = $signedReq[1]; |
||
180 | $data = json_decode(base64_decode(strtr($payload, '-_', '+/')), true); |
||
181 | $session->offsetSet('signed_request', $data); |
||
182 | |||
183 | // This fix exists only for safari on Windows : we need to redirect the user to the page outside of iframe |
||
184 | // for the cookie to be accepted. Core just adds a 'redir_fb_page_id' var to alert controllers |
||
185 | // that they need to send the user back to FB... |
||
186 | |||
187 | if (!count($_COOKIE) > 0 && strpos($_SERVER['HTTP_USER_AGENT'], 'Safari')) { |
||
188 | echo '<script type="text/javascript">' . |
||
189 | 'window.top.location.href = window.location.href+"?redir_fb_page_id='. $data["page"]["id"]. '";' . |
||
190 | '</script>'; |
||
191 | } |
||
192 | |||
193 | // This fix exists only for IE6+, when this app is embedded into an iFrame : The P3P policy has to be set. |
||
194 | $response = $e->getResponse(); |
||
195 | if ($response instanceof \Zend\Http\Response && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') || strpos($_SERVER['HTTP_USER_AGENT'], 'rv:11.'))) { |
||
196 | $response->getHeaders()->addHeaderLine('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"'); |
||
197 | } |
||
198 | } |
||
199 | } |
||
200 | } |
||
201 | |||
202 | public function getAutoloaderConfig() |
||
215 | |||
216 | public function getConfig() |
||
220 | |||
221 | public function getViewHelperConfig() |
||
274 | |||
275 | public function getServiceConfig() |
||
391 | } |
||
392 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.