<?php
namespace Aqarmap\Bundle\DiscussionBundle\Controller;
use App\Exception\BadRequestHttpException;
use Aqarmap\Bundle\DiscussionBundle\Constant\DiscussionSearchTabs;
use Aqarmap\Bundle\DiscussionBundle\Constant\DiscussionStatus;
use Aqarmap\Bundle\DiscussionBundle\Entity\Comment;
use Aqarmap\Bundle\DiscussionBundle\Entity\Discussion;
use Aqarmap\Bundle\DiscussionBundle\Form\CommentType;
use Aqarmap\Bundle\DiscussionBundle\Form\DiscussionSearchType;
use Aqarmap\Bundle\DiscussionBundle\Form\DiscussionType;
use Aqarmap\Bundle\DiscussionBundle\Repository\CategoryRepository;
use Aqarmap\Bundle\DiscussionBundle\Repository\CommentRepository;
use Aqarmap\Bundle\DiscussionBundle\Repository\DiscussionRepository;
use Aqarmap\Bundle\DiscussionBundle\Service\DiscussionManager;
use Aqarmap\Bundle\DiscussionBundle\Service\WordpressManager;
use Aqarmap\Bundle\ListingBundle\Entity\Location;
use Aqarmap\Bundle\ListingBundle\Form\QuickLeadType;
use Aqarmap\Bundle\ListingBundle\Repository\ListingRepository;
use Aqarmap\Bundle\ListingBundle\Repository\LocationRepository;
use Aqarmap\Bundle\ListingBundle\Repository\SectionRepository;
use Aqarmap\Bundle\ListingBundle\Service\LocationManager;
use Aqarmap\Bundle\ListingBundle\Service\SupplyDemandManager;
use Aqarmap\Bundle\MainBundle\Form\ConfirmFormType;
use Aqarmap\Bundle\NotificationBundle\DatabaseNotification;
use Aqarmap\Bundle\UserBundle\Entity\User;
use Aqarmap\Bundle\UserBundle\Form\QuickRegistrationFormType;
use Aqarmap\Bundle\UserBundle\Repository\UserInterestRepository;
use Aqarmap\Bundle\UserBundle\Services\UserInterestManager;
use Aqarmap\Bundle\UserBundle\Services\UserManager;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Predis\Client;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Discussion controller.
*/
class DiscussionController extends AbstractController
{
/**
* @var DiscussionManager
*/
private $discussionManager;
private $wordpressManager;
private $userInterestRepository;
private $userInterestManager;
private $em;
private $locationRepository;
private $discussionRepository;
private $listingRepository;
private $sectionRepository;
private $categoryRepository;
private $commentRepository;
private $supplyDemandManager;
private $parameterBag;
private $translator;
private $paginator;
private UserManager $userManager;
public function __construct(
DiscussionManager $discussionManager,
WordpressManager $wordpressManager,
UserInterestRepository $userInterestRepository,
UserInterestManager $userInterestManager,
EntityManagerInterface $em,
Client $redisClient,
LocationRepository $locationRepository,
DiscussionRepository $discussionRepository,
ListingRepository $listingRepository,
SectionRepository $sectionRepository,
CategoryRepository $categoryRepository,
TokenStorageInterface $tokenStorage,
SupplyDemandManager $supplyDemandManager,
ParameterBagInterface $parameterBag,
TranslatorInterface $translator,
PaginatorInterface $paginator,
UserManager $userManager,
CommentRepository $commentRepository,
EventDispatcherInterface $eventDispatcher,
LoggerInterface $logger
) {
$this->discussionManager = $discussionManager;
$this->wordpressManager = $wordpressManager;
$this->userInterestRepository = $userInterestRepository;
$this->userInterestManager = $userInterestManager;
$this->em = $em;
$this->locationRepository = $locationRepository;
$this->discussionRepository = $discussionRepository;
$this->listingRepository = $listingRepository;
$this->sectionRepository = $sectionRepository;
$this->categoryRepository = $categoryRepository;
$this->supplyDemandManager = $supplyDemandManager;
$this->parameterBag = $parameterBag;
$this->translator = $translator;
$this->paginator = $paginator;
$this->userManager = $userManager;
$this->commentRepository = $commentRepository;
}
/**
* Lists all Discussion entities.
*
* @Route("ask-neighbors/", name="neighborhood_discussion_list", methods={"GET"})
* @Route("discussion/", name="discussion_list", methods={"GET"})
* @Route("question/", name="neighborhood_question_discussion_list", methods={"GET"})
*/
public function discussions(Request $request, LocationManager $locationManager)
{
$response = $this->removePageQuery($request);
if ($response instanceof RedirectResponse) {
return $response;
}
if ('discussion_list' == $request->get('_route')) {
return $this->redirect(
$this->generateUrl('neighborhood_discussion_list', $request->query->all()),
Response::HTTP_MOVED_PERMANENTLY
);
}
$this->getDoctrine()->getManager();
$user = $this->container->get('security.token_storage')->getToken()->getUser();
$userInterests = [];
if ($user instanceof User) {
$userInterests = $this->userInterestRepository->getUserInterests($user, 4)->getQuery()->getResult();
}
$userInterests = !empty($userInterests) ? $userInterests : [$this->userInterestManager->getListingsMayBeInterested()];
$interestsListings = $this->discussionManager->getInterestsListings($userInterests);
$location = $request->query->get('location') ? $this->locationRepository->find($request->query->get('location')) : null;
$discussion = new Discussion();
$discussionForm = $form = $this->createForm(DiscussionType::class, $discussion, [
'action' => $this->generateUrl('neighborhood_discussion_create'),
'method' => 'POST',
'flatLocations' => [],
'selectedLocation' => $location ? [$location->getTitle() => $location->getId()] : [],
'selectedLocationId' => $location ? $location->getId() : null,
]);
$discussionSearchForm = $form = $this->createForm(DiscussionSearchType::class, $discussion, [
'action' => $this->generateUrl('neighborhood_discussion_list'),
'method' => 'GET',
'flatLocations' => serialize($locationManager->getFlatByMaxLevel(2)),
'selectedLocation' => $location ? [$location->getTitle() => $location->getId()] : [],
'selectedLocationId' => $location ? $location->getId() : null,
]);
$locationChildren = [];
if ($location) {
$locationChildren = $this->supplyDemandManager->getLocationChildren($location);
}
$criteria = [
'status' => DiscussionStatus::APPROVED,
'location' => $locationChildren,
'category' => $request->query->get('category'),
'tab' => $request->query->get('tab', DiscussionSearchTabs::TRENDING),
'sort' => 'commentsCounter',
];
$discussions = $this->discussionRepository->filter($criteria);
if (
$request->query->get('submitted')
&& DiscussionSearchTabs::TRENDING == $request->query->get('tab')
&& empty($discussions)
) {
$criteria = $request->query->all();
$criteria['tab'] = DiscussionSearchTabs::ALLQUESTIONS;
return $this->redirectToRoute('neighborhood_discussion_list', $criteria);
}
$discussions = $this->paginator->paginate(
$discussions,
$request->query->get('page', 1),
10
);
$latestLocationListings = [];
if ($location) {
$latestLocationListings = $this->listingRepository->getLatestListings(4, $this->supplyDemandManager->getLocationChildren($location))->getQuery()->getResult();
}
return $this->render('@AqarmapDiscussionBundle/Discussion/discussions.html.twig', [
'subLinksSections' => $this->sectionRepository->getSearchableSection(),
'discussionForm' => $discussionForm->createView(),
'responsiveDiscussionForm' => $discussionForm->createView(),
'discussionSearchForm' => $discussionSearchForm->createView(),
'discussions' => $discussions,
'interestsListings' => $interestsListings,
'quick_registration_form' => $this->createForm(QuickRegistrationFormType::class, null, [
'method' => 'POST',
'action' => $this->generateUrl('aqarmap_user_quick_registration'),
])->createView(),
'location' => $location,
'latestLocationListings' => $latestLocationListings,
'popularArticles' => json_decode(
$this->wordpressManager->getCachedPosts($request->getLocale(), 4),
true
),
'aqarmap_advice_link' => $this->parameterBag->get('aqarmap_advice_url'),
'form' => $this->createQuickLeadForm()->createView(),
'metaDescriptionContent' => $this->discussionManager->concatTitles($discussions->getItems()),
'selectedCategory' => $request->get('category') ?
$this->categoryRepository->find($request->get('category')) : null,
]);
}
/**
* Creates a new Discussion entity.
*
* @Route("question/create/", name="neighborhood_discussion_create", methods={"POST"})
*/
public function create(Request $request, LocationManager $locationManager): RedirectResponse
{
$entity = new Discussion();
$form = $this->createForm(DiscussionType::class, $entity, [
'action' => $this->generateUrl('neighborhood_discussion_create'),
'method' => 'POST',
'flatLocations' => serialize($locationManager->getLocationsArrayWithParent($request->getLocale())['searchable']) ?? serialize([]),
]);
$location = null;
if ($locationId = $request->request->get('location')) {
$location = $this->locationRepository->find($locationId);
$request->request->set('location', null);
$form->get('location')->setData(null);
}
$form->handleRequest($request);
if ($form->isValid() && $this->getUser()) {
$entity->setLocation($location);
$entity->setUser($this->getUser());
$this->em->persist($entity);
$this->em->flush();
$this->discussionManager->createSubscriber($this->getUser(), $entity);
$this->get('session')->getFlashBag()->add(
'success',
$this->translator->trans('neighborhoods.discussion.success_message')
);
}
return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
}
/**
* Lists all Discussion comments.
*
* @Route("ask-neighbors/{discussion}/answers/", name="neighborhood_discussion_comments", methods={"GET"})
* @Route("discussion/{discussion}/comments/", name="discussion_comments", methods={"GET"})
* @Route("question/{discussion}/comments/", name="neighborhood_question_discussion_comments", methods={"GET"})
*/
public function discussionComments(Request $request, DatabaseNotification $databaseNotification, LoggerInterface $logger, ?Discussion $discussion = null)
{
if ($request->get('notification')) {
try {
$databaseNotification->markOneAsRead($request->get('notification'));
} catch (\Exception $exception) {
$logger->log(LogLevel::ERROR, $exception->getMessage());
}
}
if (!$discussion) {
return $this->redirect($this->generateUrl('neighborhood_discussion_list'), Response::HTTP_MOVED_PERMANENTLY);
}
if ($discussion->getDeletedAt()) {
if ($discussion->getUser() != $this->getUser()) {
return $this->redirectWhenDiscussionDeleted($discussion);
}
$this->get('session')->getFlashBag()->add(
'warning',
$this->translator->trans('neighborhoods.discussion.already_deleted')
);
} elseif (DiscussionStatus::PENDING == $discussion->getStatus()) {
$this->get('session')->getFlashBag()->add(
'warning',
$this->translator->trans('neighborhoods.discussion.pending_approval')
);
}
if (\in_array($request->get('_route'), [
'neighborhood_question_discussion_comments',
'discussion_comments',
])) {
return $this->redirect(
$this->generateUrl(
'neighborhood_discussion_comments',
array_merge(['discussion' => $discussion->getId()], $request->query->all())
),
Response::HTTP_MOVED_PERMANENTLY
);
}
$comment = new Comment();
$commentForm = $this->createForm(CommentType::class, $comment, [
'action' => $this->generateUrl('neighborhood_comment_create', ['discussion' => $discussion->getId()]),
'method' => 'POST',
]);
$user = $this->container->get('security.token_storage')->getToken()->getUser();
$userInterests = [];
if ($user instanceof User) {
$userInterests = $this->userInterestRepository->getUserInterests($user, 4)->getQuery()->getResult();
}
$userInterests[] = $this->userInterestManager->getListingsMayBeInterested($discussion->getLocation());
$interestsListings = $this->discussionManager->getInterestsListings($userInterests);
return $this->render('@AqarmapDiscussionBundle/Discussion/discussionComments.html.twig', [
'commentForm' => $commentForm->createView(),
'discussion' => $discussion,
'discussionComments' => $this->commentRepository->getCommentsWithLikes($discussion),
'interestsListings' => $interestsListings,
'quick_registration_form' => $this->createForm(QuickRegistrationFormType::class, null, [
'method' => 'POST',
'action' => $this->generateUrl('aqarmap_user_quick_registration'),
])->createView(),
'popularArticles' => json_decode(
$this->wordpressManager->getCachedPosts($request->getLocale(), 4),
true
),
'aqarmap_advice_link' => $this->parameterBag->get('aqarmap_advice_url'),
]);
}
/**
* Add Discussion Subscribers.
*
* @Route("question/add/subscriber/{discussion}/", name="neighborhood_discussion_add_subscriber")
*/
public function addDiscussionSubscriber(Discussion $discussion, Request $request): RedirectResponse
{
$user = $this->getUser();
$this->discussionManager->createSubscriber($user, $discussion);
$this->get('session')->getFlashBag()->add(
'success',
$this->translator->trans('neighborhoods.discussion.subscriber_success_message')
);
return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
}
/**
* Remove Discussion Subscribers.
*
* @Route("question/remove/subscriber/{discussion}/", name="neighborhood_discussion_remove_subscriber")
*/
public function unsetDiscussionSubscriber(Discussion $discussion, Request $request): RedirectResponse
{
$this->discussionManager->unsetSubscriber($this->getUser(), $discussion);
$this->get('session')->getFlashBag()->add(
'success',
$this->container->get('translator')->trans('neighborhoods.discussion.subscriber_unset_message')
);
return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
}
/**
* @Route("question/un-subscribe/{user}/{discussion}/", name="neighborhood_discussion_mail_remove_subscriber")
*
* @return RedirectResponse
*
* @throws BadRequestHttpException
*/
public function unsubscribeConfirm(User $user, Discussion $discussion, Request $request)
{
/* Valid User Md5 valid */
if (md5($user->getId()).$this->parameterBag->get('secret') !== $request->query->get('token')) {
throw new BadRequestHttpException('Permission Denied !');
}
// Create confirmation form (button)
$form = $this->createForm(ConfirmFormType::class, null, [
'method' => 'POST',
'action' => $this->generateUrl(
'neighborhood_discussion_mail_remove_subscriber',
['discussion' => $discussion->getId(), 'user' => $user->getId(), 'token' => $request->query->get('token')]
),
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($form->get('confirm')->isClicked()) {
$this->discussionManager->unsetSubscriber($user, $discussion);
$this->get('session')->getFlashBag()->add(
'success',
$this->translator->trans('neighborhoods.discussion.subscriber_unset_message')
);
return $this->redirect($this->generateUrl('homepage'));
}
}
return $this->render('@AqarmapDiscussionBundle/Discussion/unsubscribeConfirm.html.twig', [
'form' => $form->createView(),
'discussion' => $discussion,
]);
}
/**
* Edit Comment entity.
*
* @Route("question/{discussion}/edit", name="neighborhood_discussion_edit")
*
* @return array|RedirectResponse
*/
public function edit(Request $request, Discussion $discussion, LocationManager $locationManager)
{
$form = $this->createForm(DiscussionType::class, $discussion, [
'action' => $this->generateUrl('neighborhood_discussion_edit', [
'discussion' => $discussion->getId(),
]),
'method' => 'POST',
'flatLocations' => serialize($locationManager->getLocationsArrayWithParent($request->getLocale())['searchable']) ?? serialize([]),
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$discussion->setStatus(DiscussionStatus::PENDING);
$em->persist($discussion);
$em->flush();
$this->get('session')->getFlashBag()->add(
'success',
$this->translator->trans('neighborhoods.comment.edit_success_message')
);
return $this->redirect($this->generateUrl('neighborhood_discussion_comments', ['discussion' => $discussion->getId()]));
}
return $this->render('@AqarmapDiscussionBundle/Discussion/edit.html.twig', [
'form' => $form->createView(),
'discussion' => $discussion,
]);
}
/**
* Delete Discussion.
*
* @Route("question/{discussion}/delete", name="discussion_delete")
*
* @return RedirectResponse|Response
*/
public function delete(Discussion $discussion): RedirectResponse
{
if (!$discussion) {
throw $this->createNotFoundException('The Discussion does not exist');
}
$this->discussionManager->remove($discussion);
$this->get('session')->getFlashBag()->add(
'success',
$this->translator->trans('neighborhoods.discussion.delete_success_message')
);
return $this->redirect($this->generateUrl('neighborhood_discussion_list'));
}
/**
* Redirect when the discssuion is deleted.
*
* @return RedirectResponse
*/
public function redirectWhenDiscussionDeleted(?Discussion $discussion = null)
{
$criteria = [];
if ($discussion) {
$location = $discussion->getLocation();
if ($location) {
$criteria['location'] = $location->getId();
}
$category = $discussion->getCategory();
if ($category) {
$criteria['category'] = $category->getId();
}
}
return $this->redirect(
$this->generateUrl('neighborhood_discussion_list', $criteria),
Response::HTTP_MOVED_PERMANENTLY
);
}
/**
* Create Quick Lead Form.
*/
private function createQuickLeadForm(): FormInterface
{
return $this->createForm(
QuickLeadType::class,
null,
[
'action' => $this->generateUrl('add_quick_lead'),
'method' => 'POST',
]
);
}
/**
* @Route("unsubscribe-ask-neighbors/{token}/{location}", requirements={"id" = "\d+"}, name="aqarmap_discussion_unsubscribe", methods={"GET"})
*/
public function unsubscribe(Request $request, ?Location $location = null): RedirectResponse
{
$user = $this->userManager->findEncryptedBy($request->get('token'));
if (!$user) {
throw new \Exception('User Not Found!');
}
$criteria = [
'user' => $user,
];
if ($location) {
$criteria['location'] = $location;
}
$this->userInterestManager->removeBy($criteria);
$this->get('session')->getFlashBag()->add(
'success',
$this->translator
->trans($location ? 'neighborhoods.unsubscribe_from_successeded' : 'neighborhoods.unsubscribe_all_successeded', ['%location%' => $location])
);
return $this->redirect($this->generateUrl('homepage'));
}
/**
* Remove the page query if equals one.
*
* @return RedirectResponse|void
*/
private function removePageQuery(Request $request)
{
if ($request->query->get('page') && 1 == $request->query->get('page')) {
$request->query->remove('page');
return $this->redirect(
$this->generateUrl(
$request->get('_route'),
$request->query->all()
),
Response::HTTP_MOVED_PERMANENTLY
);
}
}
}