src/Controller/Frontend/VeranstaltungenController.php line 186

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Frontend;
  3. use App\Application\Content\ContentFrontendData;
  4. use App\Application\Content\ContentService;
  5. use App\Application\Mail\MailerService;
  6. use App\Application\Vs\VsService;
  7. use App\Entity\Vs\Vs;
  8. use App\Entity\Vs\VsAbo;
  9. use App\Entity\Vs\VsImage;
  10. use App\Entity\Vs\VsStatus;
  11. use App\Entity\Vs\VsTyp;
  12. use App\Form\Vs\VsType;
  13. use App\Util\FileTool;
  14. use Psr\Log\LoggerInterface;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Symfony\Component\Filesystem\Filesystem;
  17. use Symfony\Component\Finder\Finder;
  18. use Symfony\Component\HttpFoundation\File\UploadedFile;
  19. use Symfony\Component\HttpFoundation\JsonResponse;
  20. use Symfony\Component\HttpFoundation\RedirectResponse;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use Symfony\Component\Routing\Annotation\Route;
  24. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  25. use Symfony\Component\Validator\Constraints\Image;
  26. use Symfony\Component\Validator\Validator\ValidatorInterface;
  27. #[Route(path: '/veranstaltungen')]
  28. class VeranstaltungenController extends AbstractController
  29. {
  30. #[Route(path: '/', name: 'fe.veranstaltungen')]
  31. public function liste(
  32. Request $request,
  33. VsService $vsService,
  34. ContentService $contentService
  35. ): Response {
  36. $rubriken = $vsService->findRubriken();
  37. $searchFilter = [
  38. 's' => $request->query->get('s', ''),
  39. 'd' => $request->query->get('d', ''),
  40. 'r' => $request->query->get('r', null),
  41. 'd_bis' => '', // wird unten gesetzt
  42. 'd_next' => '', // wird unten gesetzt
  43. 'd_prev' => '', // wird unten gesetzt
  44. ];
  45. // Date validate and set default
  46. $dateNow = new \DateTimeImmutable('now');
  47. if ($searchFilter['d']) {
  48. $fromDateInput = \DateTimeImmutable::createFromFormat('d.m.Y', $searchFilter['d']);
  49. if ($fromDateInput === false || (int) $fromDateInput->format('Ymd') < (int) $dateNow->format('Ymd')) {
  50. $searchFilter['d'] = '';
  51. } else {
  52. $searchFilter['d'] = $fromDateInput;
  53. }
  54. }
  55. if (!$searchFilter['d']) {
  56. $searchFilter['d'] = $dateNow; // default heute setzen
  57. }
  58. // Bis datum (bis zum letzten Tag vom nächsten Monat)
  59. // $dateBis = $searchFilter['d']->add(new \DateInterval('P1M'));
  60. // $searchFilter['d_bis'] = $dateBis->modify('last day of this month');
  61. // Previous / Bis / Next Datum rechnen (falls KEINE Suche abgesetzt wurde da dieser ueber ganzen Zeitraum gehen soll)
  62. if (!$searchFilter['s']) {
  63. $searchFilter['d_bis'] = $searchFilter['d']->add(new \DateInterval('P4D'));
  64. $searchFilter['d_next'] = $searchFilter['d_bis']->add(new \DateInterval('P1D'));
  65. // Previous Berechnen
  66. $prevDateTmp = $searchFilter['d']->sub(new \DateInterval('P15D'));
  67. if ((int) $searchFilter['d']->format('Ymd') === (int) $dateNow->format('Ymd')) {
  68. $searchFilter['d_prev'] = null; // kein, da heutiges Datum gesetzt
  69. } elseif ((int) $prevDateTmp->format('Ymd') <= (int) $dateNow->format('Ymd')) {
  70. $searchFilter['d_prev'] = $dateNow; // frühestes datum ist heute
  71. } else {
  72. $searchFilter['d_prev'] = $prevDateTmp;
  73. }
  74. }
  75. // Ende
  76. // --- Veranstaltungen finden
  77. // Filter Parameter zusammenstellen
  78. $filter['status_ids'] = [VsStatus::STAT_ANZEIGEN];
  79. $filter['from'] = $searchFilter['d'];
  80. $filter['to'] = $searchFilter['d_bis'] ?: null;
  81. $filter['title_likequery'] = strlen($searchFilter['s']) > 2 ? $searchFilter['s'] : '';
  82. $filter['rubrik_ids'] = $searchFilter['r'] != '' && is_numeric($searchFilter['r']) ? [(int) $searchFilter['r']] : [];
  83. // Einzellveranstaltungen finden
  84. $filter['typ_ids'] = [VsTyp::TYP_EINZEL_VS];
  85. $einzellVs = $vsService->findVeranstaltungen($filter, ['startdatum' => 'asc']);
  86. // Restliche Veranstaltungen finden
  87. $filter['typ_ids'] = [VsTyp::TYP_DAUER_VS, VsTyp::TYP_OHNE_FIXDATUM_VS];
  88. $restVs = $vsService->findVeranstaltungen($filter, ['startdatum' => 'desc']);
  89. // --- Ende
  90. $contentSeoVeranstaltungen = $contentService->getContentByCode('ACCORDION_VERANSTALTUNGEN', new ContentFrontendData(), true);
  91. return $this->render('frontend/veranstaltungen/liste.html.twig', [
  92. 'rubriken' => $rubriken,
  93. 'filter' => $searchFilter,
  94. 'einzellVs' => $einzellVs,
  95. 'restVs' => $restVs,
  96. 'contentSeoVeranstaltungen' => $contentSeoVeranstaltungen,
  97. ]);
  98. }
  99. /**
  100. * JSON-Datenexport aktuellster Veranstaltungen für Integration seitens UriOnline.ch.
  101. */
  102. #[Route(path: '/urionline-export', name: 'fe.veranstaltungen_urionline')]
  103. public function urionlineExport(VsService $vsService): JsonResponse
  104. {
  105. $maxReturn = 10;
  106. // Datum von bis
  107. $dateNow = new \DateTimeImmutable('now');
  108. $dateBis = $dateNow->add(new \DateInterval('P14D'));
  109. // Ende
  110. // --- Veranstaltungen finden
  111. $filter['status_ids'] = [VsStatus::STAT_ANZEIGEN];
  112. $filter['from'] = $dateNow;
  113. $filter['to'] = $dateBis;
  114. $filter['typ_ids'] = [VsTyp::TYP_EINZEL_VS]; // Einzellveranstaltungen finden
  115. $einzellVs = $vsService->findVeranstaltungen($filter, ['startdatum' => 'asc'], [$maxReturn, 1]);
  116. // --- Ende
  117. // JSON Datenarray bilden
  118. $data = [
  119. 'veranstaltungskalender_url' => $this->generateUrl('fe.veranstaltungen', [], UrlGeneratorInterface::ABSOLUTE_URL),
  120. 'veranstaltungen_einzel' => [],
  121. 'veranstaltungen_dauer' => 'not implemented yet',
  122. 'veranstaltungen_ohnefixdatum' => 'not implemented yet',
  123. ];
  124. foreach ($einzellVs['data'] as $vs) {
  125. /*
  126. * @var Vs $vs
  127. */
  128. $data['veranstaltungen_einzel'][] = [
  129. 'titel' => $vs->getTitel(),
  130. 'datum' => $vs->getStartdatum()->format('Y-m-d'),
  131. 'adresse' => $vs->getAdresse(),
  132. 'ort' => $vs->getRegion()?->getRegionname(),
  133. ];
  134. }
  135. $response = $this->json($data);
  136. $response->setPublic();
  137. $response->setMaxAge(3600);
  138. $response->setSharedMaxAge(3600);
  139. $response->headers->set('Access-Control-Allow-Origin', '*');
  140. return $response;
  141. }
  142. #[Route(path: '/{id}/{slug}', name: 'fe.veranstaltungen_detail', requirements: ['id' => '\d+'])]
  143. public function detail(int $id, $slug, VsService $vsService): RedirectResponse|Response
  144. {
  145. $vs = $vsService->findVsById($id);
  146. if (!$vs || !$vs->getAbo()->isPremium()) {
  147. throw $this->createNotFoundException();
  148. }
  149. // Falls Slug nicht mehr passend zur id, redirect einleiten!
  150. if ($vs->getSlug() !== $slug) {
  151. return $this->redirectToRoute('fe.veranstaltungen_detail', ['id' => $id, 'slug' => $vs->getSlug()], 301);
  152. }
  153. return $this->render('frontend/veranstaltungen/detail.html.twig', [
  154. 'vs' => $vs,
  155. ]);
  156. }
  157. #[Route(path: '/produkt', name: 'fe.veranstaltungen_produkt')]
  158. public function produkt(): Response
  159. {
  160. return $this->render('frontend/veranstaltungen/produkt.html.twig');
  161. }
  162. #[Route(path: '/melden-ok', name: 'fe.veranstaltungen_melden_ok')]
  163. public function meldenOk(): Response
  164. {
  165. return $this->render('frontend/veranstaltungen/melden-ok.html.twig');
  166. }
  167. #[Route(path: '/melden/std-online', name: 'fe.veranstaltungen_melden_std_online', defaults: ['aboId' => VsAbo::ABO_STD_MIT_INSERAT])]
  168. #[Route(path: '/melden/premium', name: 'fe.veranstaltungen_melden_premium_ohne_inserat', defaults: ['aboId' => VsAbo::ABO_PREM_OHNE_INSERAT])]
  169. #[Route(path: '/melden/premium-mit-inserat', name: 'fe.veranstaltungen_melden_premium_mit_inserat', defaults: ['aboId' => VsAbo::ABO_PREM_MIT_INSERAT])]
  170. public function melden(Request $request, $aboId, VsService $vsService, MailerService $mailerService): Response
  171. {
  172. $abo = $vsService->getAboById($aboId);
  173. if (!$abo) {
  174. throw $this->createNotFoundException();
  175. }
  176. $vs = new Vs();
  177. $vs->setStatus($vsService->getStatusById(VsStatus::STAT_NONE)); // weise "Nicht zugewiesen" dem Objekt Status, wenn nichts angegeben wurde
  178. $vs->setAbo($abo);
  179. $vs->setTyp($vsService->getTypById(VsTyp::TYP_EINZEL_VS)); // weise "Einzelveranstaltung" als Standard zu, weil dies zu 90 % zutrifft
  180. $form = $this->createForm(VsType::class, $vs); // referenziere auf gleiches Formular wie im Backend, damit ich nur ein grosses Formular anpassen muss!
  181. // Entferne Felder aus Formular, da ich diesen oben fixe Werte zugewiesen werden
  182. $form->remove('status');
  183. $form->remove('abo');
  184. $form->remove('typ');
  185. // Ende
  186. // Entferne nicht mehr erwünschte Felder
  187. $form->remove('kkontaktieren');
  188. $form->remove('kbemerkung');
  189. // Ende
  190. $form->handleRequest($request);
  191. if ($form->isSubmitted() && $form->isValid()) {
  192. // dump($form->getData());die;
  193. /**
  194. * @var Vs $vs
  195. */
  196. $vs = $form->getData();
  197. // Bild Objekt erzeugen, falls vorhanden
  198. $vsImageFilename = basename((string) $form->get('vsImageFilepath')->getData());
  199. $vsImageAlt = $form->get('vsImageAlt')->getData();
  200. $vsImageCaption = $form->get('vsImageCaption')->getData();
  201. $vs->setVsImage($vsImageFilename, $vsImageAlt, $vsImageCaption);
  202. // Ende
  203. // Standardmässig Export Uristier / Export UW
  204. $vs->setExportUristier(true);
  205. $vs->setExportUw(true);
  206. // End
  207. $vsService->saveVs($vs);
  208. // Kopiere File von Temp Verzeichnis ins Finale Verzeichnis
  209. if ($vsImageFilename !== '' && $vsImageFilename !== '0') {
  210. $tmpSaveDirPath = __DIR__.'/../../../var/data/public/vs/images/tmp';
  211. $vsImageFilenameThumb = VsImage::PREFIX_THUMBNAME.$vsImageFilename;
  212. $fs = new Filesystem();
  213. $fs->copy($tmpSaveDirPath.'/'.$vsImageFilename, $vs::baseObjectServerDirPathStatic($vs->getUuid()).'/'.$vsImageFilename);
  214. $fs->copy($tmpSaveDirPath.'/'.$vsImageFilenameThumb, $vs::baseObjectServerDirPathStatic($vs->getUuid()).'/'.$vsImageFilenameThumb);
  215. $fs->remove($tmpSaveDirPath.'/'.$vsImageFilename);
  216. $fs->remove($tmpSaveDirPath.'/'.$vsImageFilenameThumb);
  217. }
  218. // Mail an Inserate versenden
  219. $emailTo = $this->getParameter('veranstaltungen_email');
  220. $emailFrom = $this->getParameter('mailer_from');
  221. $emailFromName = $this->getParameter('mailer_from_name');
  222. $subject = 'Neue Veranstaltung "'.$vs->getTitel().'" erfasst';
  223. $body = '<p>Auf www.urnerwochenblatt.ch wurde eine neue Veranstaltung erfasst.<br><br>';
  224. $body .= 'Weitere Infos zur Veranstaltung und dessen Aufschaltung erfolgt über die VK-Administration oder falls bereits angemeldet über Direktlink ';
  225. $body .= $this->generateUrl('app.vs_edit', ['id' => $vs->getId()], UrlGeneratorInterface::ABSOLUTE_URL).' </p>';
  226. $body .= '<br>';
  227. $body .= '<b>Veranstaltung</b><br>';
  228. $body .= '<p>'.$vs->getTitel().'<br>';
  229. $body .= $vs->getAdresse().'<br>';
  230. $body .= ''.$vs->getRegion().'</p>';
  231. $body .= '<br>';
  232. $body .= '<b>Kunde</b><br><br>';
  233. $body .= '<table cellpadding="0", cellspacing="0">';
  234. $body .= '<tr><td>Firma/Verein&nbsp;&nbsp;</td><td>'.$vs->getKveranstalter().'</td></tr>';
  235. $body .= '<tr><td>Vor-/Nachname&nbsp;&nbsp;</td><td>'.$vs->getKvorname().' '.$vs->getKname().'</td></tr>';
  236. $body .= '<tr><td>Adresse</td><td>'.$vs->getKstrasse().'</td></tr>';
  237. $body .= '<tr><td>PLZ/Ort</td><td>'.$vs->getKplz().' '.$vs->getKort().'</td></tr>';
  238. $body .= '<tr><td>E-Mail</td><td>'.$vs->getKemail().'</td></tr>';
  239. $body .= '<tr><td>Telefon</td><td>'.$vs->getKtel().'</td></tr>';
  240. $body .= '<tr><td>Bemerkung</td><td>'.$vs->getKbemerkung().'</td></tr>';
  241. $body .= $vs->isKkontaktieren() ? '<tr><td><br>HINWEIS:</td><td><br>Kunde wünscht Kontaktaufnahme!</td></tr>' : '';
  242. $body .= '</table>';
  243. $body .= '<br><br>';
  244. $mailerService->setFrom($emailFrom, $emailFromName);
  245. $mailerService->setTo($emailTo);
  246. $mailerService->setSubject($subject);
  247. $mailerService->setBody($body, 'text/html');
  248. $mailerService->send();
  249. // Ende
  250. return $this->redirectToRoute('fe.veranstaltungen_melden_ok');
  251. }
  252. return $this->render('frontend/veranstaltungen/melden.html.twig', [
  253. 'abo' => $abo,
  254. 'vs' => $vs,
  255. 'form' => $form->createView(),
  256. ]);
  257. }
  258. #[Route(path: '/fileupload/{action}', name: 'fe.veranstaltungen_jqueryfileupload')]
  259. public function jqueryFileUpload(Request $request, $action, LoggerInterface $logger, ValidatorInterface $validator): JsonResponse
  260. {
  261. if (!$action) {
  262. throw new \InvalidArgumentException('Action nicht definiert! Benötigt zur korrekten Ablage des hochgeladenen Files auf dem Server.');
  263. }
  264. $return_ = [
  265. 'success' => null,
  266. 'msg' => '',
  267. 'uploadedFileWebPath' => null,
  268. 'requestQueryParams' => $request->query->all(), // Alle URL Übergabeparameter zurückgeben zur möglichen Hilfe und Weiterverwendung in Frontend
  269. ];
  270. try {
  271. /**
  272. * @var UploadedFile $uploadedFile
  273. */
  274. foreach ($request->files as $uploadedFile) {
  275. switch ($action) {
  276. case 'VSIMAGE_FRONTEND':
  277. $uuid = $request->query->get('vsUuid');
  278. if (!$uuid) {
  279. throw new \InvalidArgumentException('URL Parameter "uuid" leer oder nicht vorhanden!');
  280. }
  281. // Validierung Bildupload
  282. $violations = $validator->validate($uploadedFile, [
  283. new Image(['maxWidth' => 5120, 'mimeTypes' => ['image/jpeg', 'image/png', 'image/gif']]), // 5120 als Schutz, Bild wird unten runtergerechnet
  284. ]);
  285. if (0 !== count($violations)) {
  286. $return_['success'] = false;
  287. foreach ($violations as $violation) {
  288. $return_['msg'] .= $violation->getMessage();
  289. }
  290. } else {
  291. $saveDirPath = __DIR__.'/../../../var/data/public/vs/images/tmp';
  292. // directory protection/security for overloading: delete all images bevor
  293. $fs = new Filesystem();
  294. if ($fs->exists($saveDirPath)) {
  295. $finder = new Finder();
  296. $finder->files()->in($saveDirPath)->name('*'.$uuid.'*');
  297. foreach ($finder as $file) {
  298. $fs->remove($file->getPathname());
  299. }
  300. $finder->files()->in($saveDirPath)->date('before 1 hour ago');
  301. foreach ($finder as $file) {
  302. $fs->remove($file->getPathname());
  303. }
  304. }
  305. // end
  306. // Erstelle neuen "sauberen", fixen Filename
  307. $newFileName = $uuid.'-'.mt_rand(1000, 9999).'.'.$uploadedFile->getClientOriginalExtension();
  308. $newFileNameThumb = VsImage::PREFIX_THUMBNAME.$newFileName;
  309. $serverPathToFile = $saveDirPath.'/'.$newFileName;
  310. $serverPathToThumbFile = $saveDirPath.'/'.$newFileNameThumb;
  311. $webPathToFile = $request->getBasePath().'/data/vs/images/tmp/'.$newFileName;
  312. // Datei in Projektverzeichnis speichern
  313. $uploadedFile->move($saveDirPath, $newFileName);
  314. // Erstellt Thumbnail Bild (falls grösser max Image size), sonst einfach eine Kopie als Thumbnailbild
  315. $resizedFilepath = FileTool::createImageWithWidth($serverPathToFile, Vs::MAX_WIDTH_VSIMAGE, true);
  316. copy($resizedFilepath, $serverPathToThumbFile);
  317. // copy file to new Pfad und Filename
  318. // if ($serverPathToFile !== $resizedFilepath) {
  319. // rename($resizedFilepath, $serverPathToFile);
  320. // }
  321. // Webpath zum hochgeladenen File
  322. $return_['filename'] = $newFileName;
  323. $return_['success'] = true;
  324. $return_['uploadedFileWebPath'] = $webPathToFile;
  325. }
  326. break;
  327. default:
  328. throw new \InvalidArgumentException('File-Action "'.$action.'" nicht definiert oder ungültig !');
  329. }
  330. }
  331. } catch (\InvalidArgumentException $e) {
  332. $return_['success'] = false;
  333. $return_['msg'] = $e->getMessage();
  334. } catch (\Exception $e) {
  335. $logger->critical($e->getMessage());
  336. $return_['success'] = false;
  337. $return_['msg'] = 'Es ist ein Fehler beim Dateiupload passiert. Bitte versuchen Sie es noch einmal.';
  338. }
  339. return new JsonResponse($return_);
  340. }
  341. }