Total Complexity | 66 |
Total Lines | 629 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like EntryController 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.
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 EntryController, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
21 | class EntryController extends Controller |
||
22 | { |
||
23 | /** |
||
24 | * @Route("/mass", name="mass_action") |
||
25 | * |
||
26 | * @return \Symfony\Component\HttpFoundation\Response |
||
27 | */ |
||
28 | public function massAction(Request $request) |
||
29 | { |
||
30 | $em = $this->getDoctrine()->getManager(); |
||
31 | $values = $request->request->all(); |
||
32 | |||
33 | $action = 'toggle-read'; |
||
34 | if (isset($values['toggle-star'])) { |
||
35 | $action = 'toggle-star'; |
||
36 | } elseif (isset($values['delete'])) { |
||
37 | $action = 'delete'; |
||
38 | } |
||
39 | |||
40 | if (isset($values['entry-checkbox'])) { |
||
41 | foreach ($values['entry-checkbox'] as $id) { |
||
42 | /** @var Entry * */ |
||
43 | $entry = $this->get('wallabag_core.entry_repository')->findById((int) $id)[0]; |
||
|
|||
44 | |||
45 | $this->checkUserAction($entry); |
||
46 | |||
47 | if ('toggle-read' === $action) { |
||
48 | $entry->toggleArchive(); |
||
49 | } elseif ('toggle-star' === $action) { |
||
50 | $entry->toggleStar(); |
||
51 | } elseif ('delete' === $action) { |
||
52 | $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); |
||
53 | $em->remove($entry); |
||
54 | } |
||
55 | } |
||
56 | |||
57 | $em->flush(); |
||
58 | } |
||
59 | |||
60 | $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer')); |
||
61 | |||
62 | return $this->redirect($redirectUrl); |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * @param int $page |
||
67 | * |
||
68 | * @Route("/search/{page}", name="search", defaults={"page" = 1}) |
||
69 | * |
||
70 | * Default parameter for page is hardcoded (in duplication of the defaults from the Route) |
||
71 | * because this controller is also called inside the layout template without any page as argument |
||
72 | * |
||
73 | * @return \Symfony\Component\HttpFoundation\Response |
||
74 | */ |
||
75 | public function searchFormAction(Request $request, $page = 1, $currentRoute = null) |
||
76 | { |
||
77 | // fallback to retrieve currentRoute from query parameter instead of injected one (when using inside a template) |
||
78 | if (null === $currentRoute && $request->query->has('currentRoute')) { |
||
79 | $currentRoute = $request->query->get('currentRoute'); |
||
80 | } |
||
81 | |||
82 | $form = $this->createForm(SearchEntryType::class); |
||
83 | |||
84 | $form->handleRequest($request); |
||
85 | |||
86 | if ($form->isSubmitted() && $form->isValid()) { |
||
87 | return $this->showEntries('search', $request, $page); |
||
88 | } |
||
89 | |||
90 | return $this->render('WallabagCoreBundle:Entry:search_form.html.twig', [ |
||
91 | 'form' => $form->createView(), |
||
92 | 'currentRoute' => $currentRoute, |
||
93 | ]); |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * @Route("/new-entry", name="new_entry") |
||
98 | * |
||
99 | * @return \Symfony\Component\HttpFoundation\Response |
||
100 | */ |
||
101 | public function addEntryFormAction(Request $request) |
||
102 | { |
||
103 | $entry = new Entry($this->getUser()); |
||
104 | |||
105 | $form = $this->createForm(NewEntryType::class, $entry); |
||
106 | |||
107 | $form->handleRequest($request); |
||
108 | |||
109 | if ($form->isSubmitted() && $form->isValid()) { |
||
110 | $existingEntry = $this->checkIfEntryAlreadyExists($entry); |
||
111 | |||
112 | if (false !== $existingEntry) { |
||
113 | $this->get('session')->getFlashBag()->add( |
||
114 | 'notice', |
||
115 | $this->get('translator')->trans('flashes.entry.notice.entry_already_saved', ['%date%' => $existingEntry->getCreatedAt()->format('d-m-Y')]) |
||
116 | ); |
||
117 | |||
118 | return $this->redirect($this->generateUrl('view', ['id' => $existingEntry->getId()])); |
||
119 | } |
||
120 | |||
121 | $this->updateEntry($entry); |
||
122 | |||
123 | $em = $this->getDoctrine()->getManager(); |
||
124 | $em->persist($entry); |
||
125 | $em->flush(); |
||
126 | |||
127 | // entry saved, dispatch event about it! |
||
128 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); |
||
129 | |||
130 | return $this->redirect($this->generateUrl('homepage')); |
||
131 | } |
||
132 | |||
133 | return $this->render('WallabagCoreBundle:Entry:new_form.html.twig', [ |
||
134 | 'form' => $form->createView(), |
||
135 | ]); |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * @Route("/bookmarklet", name="bookmarklet") |
||
140 | * |
||
141 | * @return \Symfony\Component\HttpFoundation\Response |
||
142 | */ |
||
143 | public function addEntryViaBookmarkletAction(Request $request) |
||
144 | { |
||
145 | $entry = new Entry($this->getUser()); |
||
146 | $entry->setUrl($request->get('url')); |
||
147 | |||
148 | if (false === $this->checkIfEntryAlreadyExists($entry)) { |
||
149 | $this->updateEntry($entry); |
||
150 | |||
151 | $em = $this->getDoctrine()->getManager(); |
||
152 | $em->persist($entry); |
||
153 | $em->flush(); |
||
154 | |||
155 | // entry saved, dispatch event about it! |
||
156 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); |
||
157 | } |
||
158 | |||
159 | return $this->redirect($this->generateUrl('homepage')); |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * @Route("/new", name="new") |
||
164 | * |
||
165 | * @return \Symfony\Component\HttpFoundation\Response |
||
166 | */ |
||
167 | public function addEntryAction() |
||
168 | { |
||
169 | return $this->render('WallabagCoreBundle:Entry:new.html.twig'); |
||
170 | } |
||
171 | |||
172 | /** |
||
173 | * Edit an entry content. |
||
174 | * |
||
175 | * @Route("/edit/{id}", requirements={"id" = "\d+"}, name="edit") |
||
176 | * |
||
177 | * @return \Symfony\Component\HttpFoundation\Response |
||
178 | */ |
||
179 | public function editEntryAction(Request $request, Entry $entry) |
||
180 | { |
||
181 | $this->checkUserAction($entry); |
||
182 | |||
183 | $form = $this->createForm(EditEntryType::class, $entry); |
||
184 | |||
185 | $form->handleRequest($request); |
||
186 | |||
187 | if ($form->isSubmitted() && $form->isValid()) { |
||
188 | $em = $this->getDoctrine()->getManager(); |
||
189 | $em->persist($entry); |
||
190 | $em->flush(); |
||
191 | |||
192 | $this->get('session')->getFlashBag()->add( |
||
193 | 'notice', |
||
194 | 'flashes.entry.notice.entry_updated' |
||
195 | ); |
||
196 | |||
197 | return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()])); |
||
198 | } |
||
199 | |||
200 | return $this->render('WallabagCoreBundle:Entry:edit.html.twig', [ |
||
201 | 'form' => $form->createView(), |
||
202 | ]); |
||
203 | } |
||
204 | |||
205 | /** |
||
206 | * Shows all entries for current user. |
||
207 | * |
||
208 | * @param int $page |
||
209 | * |
||
210 | * @Route("/all/list/{page}", name="all", defaults={"page" = "1"}) |
||
211 | * |
||
212 | * @return \Symfony\Component\HttpFoundation\Response |
||
213 | */ |
||
214 | public function showAllAction(Request $request, $page) |
||
215 | { |
||
216 | return $this->showEntries('all', $request, $page); |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Shows unread entries for current user. |
||
221 | * |
||
222 | * @param int $page |
||
223 | * |
||
224 | * @Route("/unread/list/{page}", name="unread", defaults={"page" = "1"}) |
||
225 | * |
||
226 | * @return \Symfony\Component\HttpFoundation\Response |
||
227 | */ |
||
228 | public function showUnreadAction(Request $request, $page) |
||
229 | { |
||
230 | // load the quickstart if no entry in database |
||
231 | if (1 === (int) $page && 0 === $this->get('wallabag_core.entry_repository')->countAllEntriesByUser($this->getUser()->getId())) { |
||
232 | return $this->redirect($this->generateUrl('quickstart')); |
||
233 | } |
||
234 | |||
235 | return $this->showEntries('unread', $request, $page); |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * Shows read entries for current user. |
||
240 | * |
||
241 | * @param int $page |
||
242 | * |
||
243 | * @Route("/archive/list/{page}", name="archive", defaults={"page" = "1"}) |
||
244 | * |
||
245 | * @return \Symfony\Component\HttpFoundation\Response |
||
246 | */ |
||
247 | public function showArchiveAction(Request $request, $page) |
||
248 | { |
||
249 | return $this->showEntries('archive', $request, $page); |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * Shows starred entries for current user. |
||
254 | * |
||
255 | * @param int $page |
||
256 | * |
||
257 | * @Route("/starred/list/{page}", name="starred", defaults={"page" = "1"}) |
||
258 | * |
||
259 | * @return \Symfony\Component\HttpFoundation\Response |
||
260 | */ |
||
261 | public function showStarredAction(Request $request, $page) |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * Shows untagged articles for current user. |
||
268 | * |
||
269 | * @param int $page |
||
270 | * |
||
271 | * @Route("/untagged/list/{page}", name="untagged", defaults={"page" = "1"}) |
||
272 | * |
||
273 | * @return \Symfony\Component\HttpFoundation\Response |
||
274 | */ |
||
275 | public function showUntaggedEntriesAction(Request $request, $page) |
||
276 | { |
||
277 | return $this->showEntries('untagged', $request, $page); |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Shows random entry depending on the given type. |
||
282 | * |
||
283 | * @param string $type |
||
284 | * |
||
285 | * @Route("/{type}/random", name="random_entry", requirements={"type": "unread|starred|archive|untagged|all"}) |
||
286 | * |
||
287 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
||
288 | */ |
||
289 | public function redirectRandomEntryAction($type = 'all') |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * Shows entry content. |
||
307 | * |
||
308 | * @Route("/view/{id}", requirements={"id" = "\d+"}, name="view") |
||
309 | * |
||
310 | * @return \Symfony\Component\HttpFoundation\Response |
||
311 | */ |
||
312 | public function viewAction(Entry $entry) |
||
319 | ); |
||
320 | } |
||
321 | |||
322 | /** |
||
323 | * Reload an entry. |
||
324 | * Refetch content from the website and make it readable again. |
||
325 | * |
||
326 | * @Route("/reload/{id}", requirements={"id" = "\d+"}, name="reload_entry") |
||
327 | * |
||
328 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
||
329 | */ |
||
330 | public function reloadAction(Entry $entry) |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * Changes read status for an entry. |
||
357 | * |
||
358 | * @Route("/archive/{id}", requirements={"id" = "\d+"}, name="archive_entry") |
||
359 | * |
||
360 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
||
361 | */ |
||
362 | public function toggleArchiveAction(Request $request, Entry $entry) |
||
363 | { |
||
364 | $this->checkUserAction($entry); |
||
365 | |||
366 | $entry->toggleArchive(); |
||
367 | $this->getDoctrine()->getManager()->flush(); |
||
368 | |||
369 | $message = 'flashes.entry.notice.entry_unarchived'; |
||
370 | if ($entry->isArchived()) { |
||
371 | $message = 'flashes.entry.notice.entry_archived'; |
||
372 | } |
||
373 | |||
374 | $this->get('session')->getFlashBag()->add( |
||
375 | 'notice', |
||
376 | $message |
||
377 | ); |
||
378 | |||
379 | $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer')); |
||
380 | |||
381 | return $this->redirect($redirectUrl); |
||
382 | } |
||
383 | |||
384 | /** |
||
385 | * Changes starred status for an entry. |
||
386 | * |
||
387 | * @Route("/star/{id}", requirements={"id" = "\d+"}, name="star_entry") |
||
388 | * |
||
389 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
||
390 | */ |
||
391 | public function toggleStarAction(Request $request, Entry $entry) |
||
392 | { |
||
393 | $this->checkUserAction($entry); |
||
394 | |||
395 | $entry->toggleStar(); |
||
396 | $entry->updateStar($entry->isStarred()); |
||
397 | $this->getDoctrine()->getManager()->flush(); |
||
398 | |||
399 | $message = 'flashes.entry.notice.entry_unstarred'; |
||
400 | if ($entry->isStarred()) { |
||
401 | $message = 'flashes.entry.notice.entry_starred'; |
||
402 | } |
||
403 | |||
404 | $this->get('session')->getFlashBag()->add( |
||
405 | 'notice', |
||
406 | $message |
||
407 | ); |
||
408 | |||
409 | $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer')); |
||
410 | |||
411 | return $this->redirect($redirectUrl); |
||
412 | } |
||
413 | |||
414 | /** |
||
415 | * Deletes entry and redirect to the homepage or the last viewed page. |
||
416 | * |
||
417 | * @Route("/delete/{id}", requirements={"id" = "\d+"}, name="delete_entry") |
||
418 | * |
||
419 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
||
420 | */ |
||
421 | public function deleteEntryAction(Request $request, Entry $entry) |
||
452 | } |
||
453 | |||
454 | /** |
||
455 | * Get public URL for entry (and generate it if necessary). |
||
456 | * |
||
457 | * @Route("/share/{id}", requirements={"id" = "\d+"}, name="share") |
||
458 | * |
||
459 | * @return \Symfony\Component\HttpFoundation\Response |
||
460 | */ |
||
461 | public function shareAction(Entry $entry) |
||
462 | { |
||
463 | $this->checkUserAction($entry); |
||
464 | |||
465 | if (null === $entry->getUid()) { |
||
466 | $entry->generateUid(); |
||
467 | |||
468 | $em = $this->getDoctrine()->getManager(); |
||
469 | $em->persist($entry); |
||
470 | $em->flush(); |
||
471 | } |
||
472 | |||
473 | return $this->redirect($this->generateUrl('share_entry', [ |
||
474 | 'uid' => $entry->getUid(), |
||
475 | ])); |
||
476 | } |
||
477 | |||
478 | /** |
||
479 | * Disable public sharing for an entry. |
||
480 | * |
||
481 | * @Route("/share/delete/{id}", requirements={"id" = "\d+"}, name="delete_share") |
||
482 | * |
||
483 | * @return \Symfony\Component\HttpFoundation\Response |
||
484 | */ |
||
485 | public function deleteShareAction(Entry $entry) |
||
497 | ])); |
||
498 | } |
||
499 | |||
500 | /** |
||
501 | * Ability to view a content publicly. |
||
502 | * |
||
503 | * @Route("/share/{uid}", requirements={"uid" = ".+"}, name="share_entry") |
||
504 | * @Cache(maxage="25200", smaxage="25200", public=true) |
||
505 | * |
||
506 | * @return \Symfony\Component\HttpFoundation\Response |
||
507 | */ |
||
508 | public function shareEntryAction(Entry $entry) |
||
517 | ); |
||
518 | } |
||
519 | |||
520 | /** |
||
521 | * Global method to retrieve entries depending on the given type |
||
522 | * It returns the response to be send. |
||
523 | * |
||
524 | * @param string $type Entries type: unread, starred or archive |
||
525 | * @param int $page |
||
526 | * |
||
527 | * @return \Symfony\Component\HttpFoundation\Response |
||
528 | */ |
||
529 | private function showEntries($type, Request $request, $page) |
||
530 | { |
||
531 | $repository = $this->get('wallabag_core.entry_repository'); |
||
532 | $searchTerm = (isset($request->get('search_entry')['term']) ? $request->get('search_entry')['term'] : ''); |
||
533 | $currentRoute = (null !== $request->query->get('currentRoute') ? $request->query->get('currentRoute') : ''); |
||
534 | |||
535 | $formOptions = []; |
||
536 | |||
537 | switch ($type) { |
||
538 | case 'search': |
||
539 | $qb = $repository->getBuilderForSearchByUser($this->getUser()->getId(), $searchTerm, $currentRoute); |
||
540 | break; |
||
541 | case 'untagged': |
||
542 | $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId()); |
||
543 | break; |
||
544 | case 'starred': |
||
545 | $qb = $repository->getBuilderForStarredByUser($this->getUser()->getId()); |
||
546 | $formOptions['filter_starred'] = true; |
||
547 | break; |
||
548 | case 'archive': |
||
549 | $qb = $repository->getBuilderForArchiveByUser($this->getUser()->getId()); |
||
550 | $formOptions['filter_archived'] = true; |
||
551 | break; |
||
552 | case 'unread': |
||
553 | $qb = $repository->getBuilderForUnreadByUser($this->getUser()->getId()); |
||
554 | $formOptions['filter_unread'] = true; |
||
555 | break; |
||
556 | case 'all': |
||
557 | $qb = $repository->getBuilderForAllByUser($this->getUser()->getId()); |
||
558 | break; |
||
559 | default: |
||
560 | throw new \InvalidArgumentException(sprintf('Type "%s" is not implemented.', $type)); |
||
561 | } |
||
562 | |||
563 | $form = $this->createForm(EntryFilterType::class, [], $formOptions); |
||
564 | |||
565 | if ($request->query->has($form->getName())) { |
||
566 | // manually bind values from the request |
||
567 | $form->submit($request->query->get($form->getName())); |
||
568 | |||
569 | // build the query from the given form object |
||
570 | $this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($form, $qb); |
||
571 | } |
||
572 | |||
573 | $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); |
||
574 | |||
575 | $entries = $this->get('wallabag_core.helper.prepare_pager_for_entries')->prepare($pagerAdapter); |
||
576 | |||
577 | try { |
||
578 | $entries->setCurrentPage($page); |
||
579 | } catch (OutOfRangeCurrentPageException $e) { |
||
580 | if ($page > 1) { |
||
581 | return $this->redirect($this->generateUrl($type, ['page' => $entries->getNbPages()]), 302); |
||
582 | } |
||
583 | } |
||
584 | |||
585 | $nbEntriesUntagged = $this->get('wallabag_core.entry_repository') |
||
586 | ->countUntaggedEntriesByUser($this->getUser()->getId()); |
||
587 | |||
588 | return $this->render( |
||
589 | 'WallabagCoreBundle:Entry:entries.html.twig', [ |
||
590 | 'form' => $form->createView(), |
||
591 | 'entries' => $entries, |
||
592 | 'currentPage' => $page, |
||
593 | 'searchTerm' => $searchTerm, |
||
594 | 'isFiltered' => $form->isSubmitted(), |
||
595 | 'nbEntriesUntagged' => $nbEntriesUntagged, |
||
596 | ] |
||
597 | ); |
||
598 | } |
||
599 | |||
600 | /** |
||
601 | * Fetch content and update entry. |
||
602 | * In case it fails, $entry->getContent will return an error message. |
||
603 | * |
||
604 | * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded |
||
605 | */ |
||
606 | private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved') |
||
630 | } |
||
631 | |||
632 | /** |
||
633 | * Check if the logged user can manage the given entry. |
||
634 | */ |
||
635 | private function checkUserAction(Entry $entry) |
||
639 | } |
||
640 | } |
||
641 | |||
642 | /** |
||
643 | * Check for existing entry, if it exists, redirect to it with a message. |
||
644 | * |
||
645 | * @return Entry|bool |
||
646 | */ |
||
647 | private function checkIfEntryAlreadyExists(Entry $entry) |
||
650 | } |
||
651 | } |
||
652 |