Complex classes like PageHelper 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 PageHelper, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
39 | class PageHelper |
||
40 | { |
||
41 | protected $businessEntityHelper; |
||
42 | protected $entityManager; |
||
43 | protected $viewReferenceHelper; |
||
44 | protected $currentViewHelper; |
||
45 | protected $eventDispatcher; |
||
46 | protected $container; |
||
47 | protected $pageSeoHelper; |
||
48 | protected $session; |
||
49 | protected $tokenStorage; |
||
50 | protected $widgetMapBuilder; |
||
51 | protected $businessPageBuilder; |
||
52 | protected $businessPageHelper; |
||
53 | protected $viewReferenceRepository; |
||
54 | protected $widgetDataWarmer; |
||
55 | |||
56 | /** |
||
57 | * @param BusinessEntityHelper $businessEntityHelper |
||
58 | * @param EntityManager $entityManager |
||
59 | * @param ViewReferenceHelper $viewReferenceHelper |
||
60 | * @param CurrentViewHelper $currentViewHelper |
||
61 | * @param EventDispatcherInterface $eventDispatcher |
||
62 | * @param Container $container |
||
63 | * @param PageSeoHelper $pageSeoHelper |
||
64 | * @param Session $session |
||
65 | * @param TokenStorage $tokenStorage |
||
66 | * @param AuthorizationChecker $authorizationChecker |
||
67 | * @param WidgetMapBuilder $widgetMapBuilder |
||
68 | * @param BusinessPageBuilder $businessPageBuilder |
||
69 | * @param BusinessPageHelper $businessPageHelper |
||
70 | * @param WidgetDataWarmer $widgetDataWarmer |
||
71 | * @param ViewReferenceRepository $viewReferenceRepository |
||
72 | */ |
||
73 | public function __construct( |
||
74 | BusinessEntityHelper $businessEntityHelper, |
||
75 | EntityManager $entityManager, |
||
|
|||
76 | ViewReferenceHelper $viewReferenceHelper, |
||
77 | CurrentViewHelper $currentViewHelper, |
||
78 | EventDispatcherInterface $eventDispatcher, |
||
79 | Container $container, |
||
80 | PageSeoHelper $pageSeoHelper, |
||
81 | Session $session, |
||
82 | TokenStorage $tokenStorage, |
||
83 | AuthorizationChecker $authorizationChecker, |
||
84 | WidgetMapBuilder $widgetMapBuilder, |
||
85 | BusinessPageBuilder $businessPageBuilder, |
||
86 | BusinessPageHelper $businessPageHelper, |
||
87 | WidgetDataWarmer $widgetDataWarmer, |
||
88 | ViewReferenceRepository $viewReferenceRepository |
||
89 | ) { |
||
90 | $this->businessEntityHelper = $businessEntityHelper; |
||
91 | $this->entityManager = $entityManager; |
||
92 | $this->viewReferenceHelper = $viewReferenceHelper; |
||
93 | $this->currentViewHelper = $currentViewHelper; |
||
94 | $this->eventDispatcher = $eventDispatcher; |
||
95 | $this->container = $container; |
||
96 | $this->pageSeoHelper = $pageSeoHelper; |
||
97 | $this->session = $session; |
||
98 | $this->tokenStorage = $tokenStorage; |
||
99 | $this->authorizationChecker = $authorizationChecker; |
||
100 | $this->widgetMapBuilder = $widgetMapBuilder; |
||
101 | $this->businessPageBuilder = $businessPageBuilder; |
||
102 | $this->businessPageHelper = $businessPageHelper; |
||
103 | $this->widgetDataWarmer = $widgetDataWarmer; |
||
104 | $this->viewReferenceRepository = $viewReferenceRepository; |
||
105 | } |
||
106 | |||
107 | /** |
||
108 | * generates a response from parameters. |
||
109 | * |
||
110 | * @return View |
||
111 | */ |
||
112 | public function findPageByParameters($parameters) |
||
113 | { |
||
114 | if (!empty($parameters['id']) && !preg_match('/^ref_/', $parameters['id'])) { |
||
115 | $page = $this->entityManager->getRepository('VictoireCoreBundle:View')->findOneBy([ |
||
116 | 'id' => $parameters['id'], |
||
117 | ]); |
||
118 | |||
119 | $entity = null; |
||
120 | if (method_exists($page, 'getBusinessEntity')) { |
||
121 | $entity = $page->getBusinessEntity(); |
||
122 | } |
||
123 | $this->checkPageValidity($page, $entity, $parameters); |
||
124 | } else { |
||
125 | $viewReference = $this->viewReferenceRepository->getOneReferenceByParameters($parameters); |
||
126 | if ($viewReference === null && !empty($parameters['viewId'])) { |
||
127 | $parameters['templateId'] = $parameters['viewId']; |
||
128 | unset($parameters['viewId']); |
||
129 | $viewReference = $this->viewReferenceRepository->getOneReferenceByParameters($parameters); |
||
130 | } |
||
131 | |||
132 | if ($viewReference instanceof ViewReference) { |
||
133 | $page = $this->findPageByReference($viewReference, $this->findEntityByReference($viewReference)); |
||
134 | } else { |
||
135 | $parametersAsString = []; |
||
136 | foreach ($parameters as $key => $value) { |
||
137 | $parametersAsString[] = $key.': '.$value; |
||
138 | } |
||
139 | |||
140 | throw new \Exception(sprintf('Oh no! Cannot find a viewReference for the given parameters %s', implode(',', $parametersAsString))); |
||
141 | } |
||
142 | $page->setReference($viewReference, $viewReference->getLocale()); |
||
143 | } |
||
144 | |||
145 | return $page; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * generates a response from a page url. |
||
150 | * if seo redirect, return target. |
||
151 | * |
||
152 | * @param string $url |
||
153 | * |
||
154 | * @return Response |
||
155 | */ |
||
156 | public function renderPageByUrl($url, $locale, $isAjax = false) |
||
157 | { |
||
158 | $page = null; |
||
159 | if ($viewReference = $this->viewReferenceRepository->getReferenceByUrl($url, $locale)) { |
||
160 | $page = $this->findPageByReference($viewReference, $entity = $this->findEntityByReference($viewReference)); |
||
161 | |||
162 | if ($page instanceof BasePage |
||
163 | && $page->getSeo() |
||
164 | && $page->getSeo()->getRedirectTo() |
||
165 | && !$this->session->get('victoire.edit_mode', false)) { |
||
166 | $page = $page->getSeo()->getRedirectTo(); |
||
167 | } |
||
168 | |||
169 | $this->checkPageValidity($page, $entity, ['url' => $url, 'locale' => $locale]); |
||
170 | $page->setReference($viewReference); |
||
171 | |||
172 | return $this->renderPage($page, $isAjax); |
||
173 | } else { |
||
174 | throw new NotFoundHttpException(sprintf('Page not found (url: "%s", locale: "%s")', $url, $locale)); |
||
175 | } |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * generates a response from a page. |
||
180 | * |
||
181 | * @param View $view |
||
182 | * |
||
183 | * @return Response |
||
184 | */ |
||
185 | public function renderPage($view, $isAjax = false) |
||
186 | { |
||
187 | $event = new \Victoire\Bundle\PageBundle\Event\Menu\PageMenuContextualEvent($view); |
||
188 | |||
189 | //Set currentView and dispatch victoire.on_render_page event with this currentView |
||
190 | $this->currentViewHelper->setCurrentView($view); |
||
191 | $pageRenderEvent = new PageRenderEvent($view); |
||
192 | $this->eventDispatcher->dispatch('victoire.on_render_page', $pageRenderEvent); |
||
193 | |||
194 | //Build WidgetMap |
||
195 | $this->widgetMapBuilder->build($view, $this->entityManager, true); |
||
196 | |||
197 | //Populate widgets with their data |
||
198 | $this->widgetDataWarmer->warm($this->entityManager, $view); |
||
199 | |||
200 | //Dispatch contextual event regarding page type |
||
201 | if ($view->getType() == 'business_page') { |
||
202 | //Dispatch also an event with the Business entity name |
||
203 | $eventName = 'victoire_core.page_menu.contextual'; |
||
204 | if (!$view->getId()) { |
||
205 | $eventName = 'victoire_core.business_template_menu.contextual'; |
||
206 | $event = new \Victoire\Bundle\PageBundle\Event\Menu\PageMenuContextualEvent($view->getTemplate()); |
||
207 | } |
||
208 | $this->eventDispatcher->dispatch($eventName, $event); |
||
209 | $type = $view->getBusinessEntityId(); |
||
210 | } else { |
||
211 | $type = $view->getType(); |
||
212 | } |
||
213 | |||
214 | $eventName = 'victoire_core.'.$type.'_menu.contextual'; |
||
215 | $this->eventDispatcher->dispatch($eventName, $event); |
||
216 | |||
217 | //Determine which layout to use |
||
218 | $layout = $this->guessBestLayoutForView($view, $isAjax); |
||
219 | |||
220 | //Create the response |
||
221 | $response = $this->container->get('templating')->renderResponse('VictoireCoreBundle:Layout:'.$layout, [ |
||
222 | 'view' => $view, |
||
223 | ]); |
||
224 | |||
225 | return $response; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * populate the page with given entity. |
||
230 | * |
||
231 | * @param View $page |
||
232 | * @param BusinessEntity $entity |
||
233 | */ |
||
234 | public function updatePageWithEntity(BusinessTemplate $page, $entity) |
||
235 | { |
||
236 | $page = $this->businessPageBuilder->generateEntityPageFromTemplate($page, $entity, $this->entityManager); |
||
237 | $this->pageSeoHelper->updateSeoByEntity($page, $entity); |
||
238 | |||
239 | //update the parameters of the page |
||
240 | $this->businessPageBuilder->updatePageParametersByEntity($page, $entity); |
||
241 | |||
242 | return $page; |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * @param BusinessPageReference $viewReference |
||
247 | * |
||
248 | * @return BusinessPage |
||
249 | * read the cache to find entity according tu given url. |
||
250 | * @return object|null |
||
251 | */ |
||
252 | protected function findEntityByReference(ViewReference $viewReference) |
||
259 | |||
260 | /** |
||
261 | * find the page according to given url. |
||
262 | * |
||
263 | * @return View |
||
264 | */ |
||
265 | public function findPageByReference($viewReference, $entity = null) |
||
302 | |||
303 | /** |
||
304 | * @param View $page |
||
305 | * @param $locale |
||
306 | */ |
||
307 | private function refreshPage($page, $locale) |
||
316 | |||
317 | /** |
||
318 | * If the page is not valid, an exception is thrown. |
||
319 | * |
||
320 | * @param mixed $page |
||
321 | * @param mixed $entity |
||
322 | * @param mixed $parameters |
||
323 | * |
||
324 | * @throws \Exception |
||
325 | */ |
||
326 | protected function checkPageValidity($page, $entity = null, $parameters = null) |
||
371 | |||
372 | /** |
||
373 | * Create an instance of the business entity page. |
||
374 | * |
||
375 | * @param BusinessTemplate $BusinessTemplate The business entity page |
||
376 | * @param entity $entity The entity |
||
377 | * @param string $url The new url |
||
378 | * |
||
379 | * @return \Victoire\Bundle\PageBundle\Entity\Page |
||
380 | */ |
||
381 | public function createPageInstanceFromBusinessTemplate(BusinessTemplate $BusinessTemplate, $entity, $url) |
||
406 | |||
407 | /** |
||
408 | * Guess which layout to use for a given View. |
||
409 | * |
||
410 | * @param View $view |
||
411 | * @param bool $isAjax |
||
412 | * |
||
413 | * @return string |
||
414 | */ |
||
415 | private function guessBestLayoutForView(View $view, $isAjax) |
||
427 | } |
||
428 |
The
EntityManager
might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:If that code throws an exception and the
EntityManager
is closed. Any other code which depends on the same instance of theEntityManager
during this request will fail.On the other hand, if you instead inject the
ManagerRegistry
, thegetManager()
method guarantees that you will always get a usable manager instance.