src/Controller/Web/DefaultController.php line 92

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Web;
  3. use App\Controller\WebController;
  4. use App\Entity\Application\Category;
  5. use App\Entity\Application\CategoryTranslation;
  6. use App\Entity\Application\Information;
  7. use App\Entity\Application\Offer;
  8. use App\Entity\Application\Store;
  9. use App\Entity\Brand;
  10. use App\Entity\Newsletter;
  11. use App\Entity\Product;
  12. use App\Entity\VIPaccount;
  13. use App\Entity\Web\Career;
  14. use App\Entity\Web\Modal;
  15. use App\Entity\Web\News;
  16. use App\Entity\Web\Site;
  17. use App\Entity\Web\TopCategory;
  18. use App\Fce\F_Ecomail;
  19. use App\Form\Eshop\NewsletterType;
  20. use App\Form\Web\ContactType;
  21. use App\Form\Web\VIPaccountType;
  22. use DateTime;
  23. use Doctrine\ORM\Query\Expr\Join;
  24. use Liip\ImagineBundle\Imagine\Cache\CacheManager;
  25. use Locale;
  26. use MobileDetectBundle\DeviceDetector\MobileDetectorInterface;
  27. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;
  28. use Symfony\Component\Form\FormInterface;
  29. use Symfony\Component\HttpFoundation\Request;
  30. use Symfony\Component\HttpFoundation\Response;
  31. use Symfony\Component\Routing\Annotation\Route;
  32. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  33. use Symfony\Contracts\Translation\TranslatorInterface;
  34. use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
  35. class DefaultController extends WebController
  36. {
  37. /**
  38. * @Route("/init", name="app_web_homepage_init")
  39. */
  40. public function init(): Response
  41. {
  42. foreach ($this->em->getRepository(Store::class)->findAll() as $store) {
  43. $store->setEditts(new DateTime());
  44. $this->em->persist($store);
  45. }
  46. $this->em->flush();
  47. die;
  48. }
  49. /**
  50. * @Route("/at/{path}", name="app_web_homepage_at", host="%domain.web%")
  51. */
  52. public function at(Request $request, ?string $path = ''): Response
  53. {
  54. return $this->redirect('https://' . $this->getParameter('domain.web_de') . '/' . $path, 301);
  55. }
  56. /**
  57. * @Route({"cs":"/","en":"/","de":"/"}, name="app_web_homepage", host="%domain.web%")
  58. */
  59. public function index(Request $request, MobileDetectorInterface $detector): Response
  60. {
  61. $request->getSession()->set('_currency', Locale::getDefault() === 'cs' ? 'CZK' : 'EUR');
  62. return $this->render('web/default/index.html.twig', [
  63. 'slides' => $this->slideShowRepository->findForHomepage($detector->isMobile()),
  64. 'news' => $this->newsRepository->findForWeb(3),
  65. 'biggestDiscount' => $this->em->getRepository(Product::class)->biggestDiscount(Locale::getDefault() === 'cs' ? 'CZK' : 'EUR'),
  66. 'news_products' => $this->em->getRepository(Product::class)->newsProducts(Locale::getDefault() === 'cs' ? 'CZK' : 'EUR'),
  67. 'offers' => $this->em->getRepository(Offer::class)->createQueryBuilder('o')->select('o,ot')->leftJoin('o.translations', 'ot')->andWhere('o.isActive = TRUE AND o.isPublic = TRUE')->orderBy('o.id', 'DESC')->getQuery()->getResult(),
  68. 'curr' => Locale::getDefault() === 'cs' ? 'CZK' : 'EUR'
  69. ]);
  70. }
  71. /**
  72. * @Route({
  73. * "cs": "/kontakty",
  74. * "en": "/contacts",
  75. * "de": "/contakte"
  76. * }, name="app_web_contact", host="%domain.web%")
  77. */
  78. public function contact(Request $request, \Swift_Mailer $mailer, TranslatorInterface $translator): Response
  79. {
  80. $form = $this->createForm(ContactType::class);
  81. $form->handleRequest($request);
  82. if ($form->isSubmitted() && $form->isValid()) {
  83. if ($this->isHoneypotFilled($form)) {
  84. $this->addFlash('success', 'Žádost byla odeslána.');
  85. return $this->redirectToRoute('app_web_contact');
  86. }
  87. if (isset($_POST['g-recaptcha-response'])) {
  88. $captcha = $_POST['g-recaptcha-response'];
  89. $secretKey = "6Lc9IQosAAAAAN1Oavyb1aiH10seSXD-0xUg05vO";
  90. $url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($secretKey) . '&response=' . urlencode($captcha);
  91. $response = file_get_contents($url);
  92. $responseKeys = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
  93. if ($responseKeys["success"]) {
  94. $message = (
  95. new \Swift_Message($translator->trans('contact.form.subject2', [], 'web')))
  96. ->setFrom($this->getParameter('from_email_web'))
  97. ->setTo($this->getParameter('from_email_web'))
  98. ->setBcc($form->get('email')->getData())
  99. ->setBody($this->renderView('web/core/email.html.twig', [
  100. 'form' => $form
  101. ]), 'text/html');
  102. $mailer->send($message);
  103. } else {
  104. $this->addFlash('danger', 'Žádost byla odeslána.');
  105. }
  106. }
  107. $this->addFlash('success', 'Žádost byla odeslána.');
  108. }
  109. return $this->render('web/default/kontakt.html.twig', [
  110. 'form' => $form->createView()
  111. ]);
  112. }
  113. /**
  114. * @Route({
  115. * "cs": "/oteviraci-doba",
  116. * "en": "/opening-hours",
  117. * "de": "/offnungszeiten"
  118. * }, name="app_web_opening")
  119. */
  120. public function openingHours(): Response
  121. {
  122. return $this->render('web/default/opening-hours.html.twig');
  123. }
  124. /**
  125. * @Route({
  126. * "cs": "/kudy-k-nam",
  127. * "en": "/how-to-find-us",
  128. * "de": "/wie-kommen-sie-zu-uns"
  129. * }, name="app_web_which")
  130. */
  131. public function howToFindUs(): Response
  132. {
  133. return $this->render('web/default/which-way.html.twig');
  134. }
  135. /**
  136. * @Route({
  137. * "cs": "/o-freeportu",
  138. * "en": "/about-freeport",
  139. * "de": "/uber-freeport"
  140. * }, name="app_web_about")
  141. */
  142. public function about(): Response
  143. {
  144. return $this->render('web/default/about.html.twig');
  145. }
  146. /**
  147. * @Route({
  148. * "cs": "/kariera",
  149. * "en": "/carrer",
  150. * "de": "/werdegang"
  151. * }, name="app_web_career")
  152. */
  153. public function career(): Response
  154. {
  155. $careers = $this->em->getRepository(Career::class)->createQueryBuilder('c')->select('c,ct')->leftJoin('c.translations', 'ct')->where('c.isActive = TRUE')->orderBy('c.datePublic', 'DESC')->getQuery()->getResult();
  156. return $this->render('web/default/career.html.twig', [
  157. 'careers' => $careers,
  158. 'categories' => $this->em->getRepository(Category::class)->createQueryBuilder('c')->select('c,ct')->leftJoin('c.translations', 'ct')->orderBy('c.orderBy', 'ASC')->getQuery()->getResult(),
  159. ]);
  160. }
  161. /**
  162. * @Route({
  163. * "cs": "/kariera-detail/{career}",
  164. * "en": "/carrer-detail/{career}",
  165. * "de": "/werdegang-detail/{career}"
  166. * }, name="app_web_career_detail")
  167. * @Entity("career", expr="repository.findOneBySlug(career, _locale)")
  168. */
  169. public function careerDetail(Career $career): Response
  170. {
  171. return $this->render('web/default/career-detail.html.twig', [
  172. 'career' => $career,
  173. ]);
  174. }
  175. /**
  176. * @Route({
  177. * "cs": "/faq",
  178. * "en": "/faq",
  179. * "de": "/faq"
  180. * }, name="app_web_faq")
  181. */
  182. public function faq(): Response
  183. {
  184. return $this->render('web/default/faq.html.twig');
  185. }
  186. /**
  187. * @Route({
  188. * "cs": "/znacky",
  189. * "en": "/brands",
  190. * "de": "/marken"
  191. * }, name="app_web_brands")
  192. */
  193. public function brands(): Response
  194. {
  195. $brands = $this->em->getRepository(Brand::class)->createQueryBuilder('b')->select('b,s')->innerJoin('b.stores', 's', Join::WITH, 's.isActive = TRUE')->orderBy('b.name')->getQuery()->getResult();
  196. $out = [];
  197. /** @var Brand $brand */
  198. foreach ($brands as $brand) {
  199. if (!isset($out[mb_strtoupper(substr($brand->getName(), 0, 1))])) {
  200. $out[mb_strtoupper(substr($brand->getName(), 0, 1))] = [];
  201. }
  202. $out[mb_strtoupper(substr($brand->getName(), 0, 1))][] = $brand;
  203. }
  204. return $this->render('web/default/brands.html.twig', [
  205. 'brands' => $out
  206. ]);
  207. }
  208. /**
  209. * @Route({
  210. * "cs": "/page/{site}",
  211. * "en": "/page/{site}",
  212. * "de": "/page/{site}"
  213. * }, name="app_web_page")
  214. * @Entity("site", expr="repository.findOneBySlug(site, _locale)")
  215. */
  216. public function page(Site $site): Response
  217. {
  218. return $this->render('web/default/page.html.twig', [
  219. 'site' => $site
  220. ]);
  221. }
  222. /**
  223. * @Route({
  224. * "cs": "/novinky",
  225. * "en": "/news",
  226. * "de": "/nachrichten"
  227. * }, name="app_web_news")
  228. */
  229. public function news(): Response
  230. {
  231. return $this->render('web/default/news.html.twig', [
  232. 'news' => $this->newsRepository->findForWeb(3)
  233. ]);
  234. }
  235. /**
  236. * @Route({
  237. * "cs": "/novinky-detail/{news}",
  238. * "en": "/news-detail/{news}",
  239. * "de": "/nachrichten-detail/{news}"
  240. * }, name="app_web_news_detail")
  241. * @Entity("news", expr="repository.findOneBySlug(news, _locale)")
  242. */
  243. public function newsDetail(News $news): Response
  244. {
  245. return $this->render('web/default/news-detail.html.twig', [
  246. 'new' => $news
  247. ]);
  248. }
  249. /**
  250. * @Route({
  251. * "cs": "/newsletter-add",
  252. * "en": "/newsletter-add",
  253. * "de": "/newsletter-add"
  254. * }, name="app_web_newsletter_add")
  255. */
  256. public function newsletterAdd(Request $request): Response
  257. {
  258. $entity = new Newsletter();
  259. $entity->setLocale(Locale::getDefault());
  260. $form = $this->createForm(NewsletterType::class, $entity);
  261. $form->handleRequest($request);
  262. if ($form->isSubmitted() && $form->isValid()) {
  263. $entity->setCreatets(new DateTime());
  264. $entity->setIp($_SERVER['REMOTE_ADDR']);
  265. $this->em->persist($entity);
  266. $this->em->flush();
  267. F_Ecomail::addSubscriberFromEntity($entity);
  268. }
  269. $this->addFlash('success', 'Byl/a jste zařazen/a do odběru newsletterů.');
  270. return $this->redirectToRoute('app_web_homepage');
  271. }
  272. /**
  273. * @Route({
  274. * "cs": "/darkovy-poukaz",
  275. * "en": "/gift-card",
  276. * "de": "/geschenkgutschein"
  277. * }, name="app_web_gift-card")
  278. */
  279. public function giftCard(Request $request, \Swift_Mailer $mailer, TranslatorInterface $translator): Response
  280. {
  281. $form = $this->createForm(ContactType::class);
  282. $form->handleRequest($request);
  283. if ($form->isSubmitted() && $form->isValid()) {
  284. if ($this->isHoneypotFilled($form)) {
  285. $this->addFlash('success', 'Žádost byla odeslána.');
  286. return $this->redirectToRoute('app_web_gift-card');
  287. }
  288. if (isset($_POST['g-recaptcha-response'])) {
  289. $captcha = $_POST['g-recaptcha-response'];
  290. $secretKey = "6LceJF4sAAAAAFYLkVpRmpXPqPhTPXDkg79Zn6y1";
  291. $url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($secretKey) . '&response=' . urlencode($captcha);
  292. $response = file_get_contents($url);
  293. $responseKeys = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
  294. // should return JSON with success as true
  295. if ($responseKeys["success"]) {
  296. $message = (
  297. new \Swift_Message($translator->trans('contact.form.subject', [], 'web')))
  298. ->setFrom($this->getParameter('from_email_web'))
  299. ->setTo($this->getParameter('from_email_web'))
  300. ->setBcc($form->get('email')->getData())
  301. ->setBody($this->renderView('web/core/email.html.twig', [
  302. 'form' => $form
  303. ]), 'text/html');
  304. $mailer->send($message);
  305. } else {
  306. $this->addFlash('danger', 'Žádost byla odeslána.');
  307. }
  308. }
  309. $this->addFlash('success', 'Žádost byla odeslána.');
  310. }
  311. return $this->render('web/default/gift-card.html.twig', [
  312. 'info' => $this->em->getRepository(Information::class)->find(1),
  313. 'form' => $form->createView()
  314. ]);
  315. }
  316. private function isHoneypotFilled(FormInterface $form): bool
  317. {
  318. return $form->has('website') && trim((string) $form->get('website')->getData()) !== '';
  319. }
  320. /**
  321. * @Route({"cs": "/obchody", "en": "/shops", "de": "/geschafte"}, name="app_web_shops")
  322. * @Route({"cs": "/obchody/{slug}", "en": "/shops/{slug}", "de": "/geschafte/{slug}"}, name="app_web_shops_categ")
  323. */
  324. public function shops(?CategoryTranslation $category, CacheManager $cacheManager, UploaderHelper $uploaderHelper): Response
  325. {
  326. $stores = $this->em->getRepository(Store::class)->createQueryBuilder('s')->select('s,c')->leftJoin('s.category', 'c')->where('s.isActive = TRUE')->orderBy('s.name', 'ASC')->getQuery()->getResult();
  327. $forMap = [];
  328. /** @var Store $store */
  329. foreach ($stores as $store) {
  330. if (empty($store->getShopNumber())) {
  331. continue;
  332. }
  333. foreach ($store->getShopNumber() as $k) {
  334. $forMap[trim($k)] = [
  335. 'name' => $store->getName(),
  336. 'number' => implode(', ', $store->getShopNumber()),
  337. 'phone' => $store->getPhone(),
  338. 'vip' => $store->getVip(),
  339. 'email' => $store->getEmail(),
  340. 'open' => $store->getVirtualOpenHoursToday(),
  341. 'url' => $this->generateUrl('app_web_shop_detail', ['slug' => $store->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL),
  342. 'logo' => !empty($store->getLogo()) ? ($cacheManager->getBrowserPath($uploaderHelper->asset($store, 'logoFile'), 'thumb300')) : ''
  343. ];
  344. }
  345. }
  346. return $this->render('web/default/shops.html.twig', [
  347. 'categories' => $this->em->getRepository(Category::class)->createQueryBuilder('c')->select('c,ct')->leftJoin('c.translations', 'ct')->orderBy('c.orderBy', 'ASC')->getQuery()->getResult(),
  348. 'stores' => $stores,
  349. 'forMap' => $forMap,
  350. 'categoryActive' => $category !== null ? $category->getTranslatable() : null
  351. ]);
  352. }
  353. /**
  354. * @Route({
  355. * "cs": "/top-akce",
  356. * "en": "/top-actions",
  357. * "de": "/top-aktionen"
  358. * }, name="app_web_top-actions")
  359. */
  360. public function topAction(): Response
  361. {
  362. $offers = $this->em->getRepository(Offer::class)->createQueryBuilder('o')->select('o,ot')->leftJoin('o.translations', 'ot')->andWhere('o.isActive = TRUE AND o.isPublic = TRUE AND o.dateTo >= :now')
  363. ->setParameter('now', (new \DateTime())->setTime(0, 10))
  364. ->orderBy('o.editts', 'DESC')->getQuery()->getResult();
  365. $stores = array_map(static function ($o) {
  366. return $o->getStore();
  367. }, $offers);
  368. $fin = [];
  369. foreach ($stores as $store) {
  370. $fin[$store->getId()] = $store;
  371. }
  372. usort($fin, function ($a, $b) {
  373. return strcmp(trim($a->getSlug()), trim($b->getSlug()));
  374. });
  375. return $this->render('web/default/top-actions.html.twig', [
  376. 'categories' => $this->em->getRepository(TopCategory::class)->getActiveKategories(),
  377. 'offers' => $offers,
  378. 'stores' => $fin
  379. ]);
  380. }
  381. /**
  382. * @Route({
  383. * "cs": "/navstevni-rad",
  384. * "en": "/visitation-order",
  385. * "de": "/besuchsordnung"
  386. * }, name="app_web_visitation-order")
  387. */
  388. public function visitationOrder(): Response
  389. {
  390. return $this->render('web/default/visitation-order.twig');
  391. }
  392. /**
  393. * @Route({
  394. * "cs": "/gdpr",
  395. * "en": "/gdpr",
  396. * "de": "/gdpr"
  397. * }, name="app_web_gdpr")
  398. */
  399. public function gdpr(): Response
  400. {
  401. return $this->render('web/default/gdpr.html.twig');
  402. }
  403. /**
  404. * @Route({
  405. * "cs": "/obchod/{slug}",
  406. * "en": "/shop/{slug}",
  407. * "de": "/shop/{slug}"
  408. * }, name="app_web_shop_detail")
  409. */
  410. public function shopDetail(Store $store): Response
  411. {
  412. if (!$store->getisActive()) {
  413. return $this->redirectToRoute('app_web_shops');
  414. }
  415. $info = $this->em->getRepository(Information::class)->find(1);
  416. return $this->render('web/default/shop-detail.html.twig', [
  417. 'store' => $store,
  418. 'opening' => $info->getOpening(),
  419. ]);
  420. }
  421. /**
  422. * @Route({
  423. * "cs": "/vip-club",
  424. * "en": "/vip-club",
  425. * "de": "/vip-club"
  426. * }, name="app_web_vip-club")
  427. */
  428. public function vipClub(Request $request, \Swift_Mailer $mailer, TranslatorInterface $translator): Response
  429. {
  430. $vip = new VIPaccount();
  431. $form = $this->createForm(VIPaccountType::class, $vip);
  432. $form->handleRequest($request);
  433. if ($form->isSubmitted() && $form->isValid()) {
  434. $message = (new \Swift_Message($translator->trans('vip.register.title', [], 'web')))
  435. ->setFrom($this->getParameter('from_email_web'))
  436. ->setTo($vip->getEmail())
  437. ->setBody($this->renderView('web/core/vip-email.html.twig'), 'text/html');
  438. $mailer->send($message);
  439. $new = new Newsletter();
  440. $new->setEmail($vip->getEmail());
  441. $new->setLocale($vip->getLanguage());
  442. $new->setIsActive(true);
  443. $new->setCreatets(new DateTime());
  444. $new->setIp($_SERVER['REMOTE_ADDR']);
  445. $new->setSource('website');
  446. $this->em->persist($new);
  447. F_Ecomail::addSubscriberFromEntity($new);
  448. $this->em->persist($vip);
  449. try {
  450. $this->em->flush();
  451. } catch (\Exception $e) {
  452. }
  453. return $this->redirectToRoute('app_web_vip-club-success');
  454. }
  455. return $this->render('web/default/vip-club.html.twig', [
  456. 'vips' => $this->em->getRepository(Store::class)->createQueryBuilder('s')->select('s,st')->leftJoin('s.translations', 'st')->andWhere('s.isActive = TRUE AND s.vip = TRUE')->orderBy('s.name', 'ASC')->getQuery()->getResult(),
  457. 'form' => $form->createView()
  458. ]);
  459. }
  460. /**
  461. * @Route({
  462. * "cs": "/vip-club-success",
  463. * "en": "/vip-club-success",
  464. * "de": "/vip-club-success"
  465. * }, name="app_web_vip-club-success")
  466. */
  467. public function vipClubSuccess(): Response
  468. {
  469. return $this->render('web/default/vip-club-success.html.twig');
  470. }
  471. public function opening(): Response
  472. {
  473. $data = $this->em->getRepository(Information::class)->find(1);
  474. if (!$data instanceof Information) {
  475. return $this->redirectToRoute('app_web_homepage');
  476. }
  477. return $this->render('web/core/opening.html.twig', [
  478. 'open' => $data->getOpening()
  479. ]);
  480. }
  481. public function menu(): Response
  482. {
  483. return $this->render('web/core/category.html.twig', [
  484. 'categories' => $this->em->getRepository(Category::class)->createQueryBuilder('c')->select('c,ct')->leftJoin('c.translations', 'ct')->orderBy('c.orderBy', 'ASC')->getQuery()->getResult()
  485. ]);
  486. }
  487. public function _modal(Request $request): Response
  488. {
  489. $cook = $request->cookies->all();
  490. $in = [];
  491. foreach ($cook as $k => $v) {
  492. if (strpos($k, 'modal_') !== false) {
  493. $in[] = (int)$v;
  494. }
  495. }
  496. return $this->render('web/core/modal.html.twig', [
  497. 'modal' => $this->em->getRepository(Modal::class)->findActive($in, $request->getLocale())
  498. ]);
  499. }
  500. public function _giftCard(CacheManager $cacheManager, UploaderHelper $uploaderHelper, Request $request): Response
  501. {
  502. $data = $this->em->getRepository(Information::class)->find(1);
  503. return new Response($cacheManager->getBrowserPath($uploaderHelper->asset($data->translate($request->getLocale()), 'imageFile'), 'coupon'), 200);
  504. }
  505. }