<?php namespace SGalinski\SgJobs\Controller; /*************************************************************** * Copyright notice * * (c) sgalinski Internet Services (https://www.sgalinski.de) * * All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is * free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * The GNU General Public License can be found at * http://www.gnu.org/copyleft/gpl.html. * * This script is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ use SGalinski\SgJobs\Domain\Model\Contact; use SGalinski\SgJobs\Domain\Model\Job; use SGalinski\SgJobs\Domain\Model\JobApplication; use SGalinski\SgJobs\Property\TypeConverter\UploadedFileReferenceConverter; use SGalinski\SgJobs\Service\FrontendFilterService; use SGalinski\SgMail\Service\MailTemplateService; use SJBR\StaticInfoTables\Domain\Repository\CountryRepository; use TYPO3\CMS\Core\Resource\FileReference; use TYPO3\CMS\Core\Resource\ResourceFactory; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException; /** * The joblist plugin controller */ class JoblistController extends ActionController { /** * @var \SGalinski\SgJobs\Domain\Repository\CompanyRepository * @inject */ private $companyRepository; /** * @var \SGalinski\SgJobs\Domain\Repository\JobRepository * @inject */ private $jobRepository; /** * @var \SGalinski\SgJobs\Domain\Repository\ContactRepository * @inject */ private $contactRepository; /** * @var \SGalinski\SgJobs\Domain\Repository\JobApplicationRepository * @inject */ private $jobApplicationRepository; /** * Show all job offers and options to manage them * * @param array $filters * @param int $jobId * @return void * @throws \InvalidArgumentException */ public function indexAction(array $filters = [], $jobId = NULL) { if ($filters) { $this->view->assign('selectedCountry', $filters['filterCountry']); $this->view->assign('selectedCompany', $filters['filterCompany']); $this->view->assign('selectedLocation', $filters['filterLocation']); $this->view->assign('selectedArea', $filters['filterArea']); $this->view->assign('selectedFunction', $filters['filterFunction']); } $storagePid = (int) $this->configurationManager->getConfiguration( ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK )['persistence']['storagePid']; $this->assignFilterValues($storagePid); $this->view->assign('recordPageId', $storagePid); $jobLimit = (int) $this->settings['jobLimit']; if ($jobId) { /** @var Job $job */ $job = $this->jobRepository->findByUid($jobId); if (!$job) { throw new \InvalidArgumentException('Given Job Id is invalid!'); } $GLOBALS['TSFE']->page['titlebyextension'] = $job->getTitle(); $GLOBALS['TSFE']->page['description'] = substr($job->getDescription(), 0, 200); $jobs = [$job]; $numberOfPages = 1; } else { // pagination logic $offset = 0; $currentPageBrowserPage = (int) GeneralUtility::_GP('tx_sgjobs_pagebrowser')['currentPage']; if ($currentPageBrowserPage && $jobLimit) { $offset = $currentPageBrowserPage * $jobLimit; } // get all jobs for the current page $jobs = FrontendFilterService::getJobs($filters, $storagePid, $jobLimit, $offset); // get all jobs for the current page $jobsCount = \count(FrontendFilterService::getJobs($filters, $storagePid)); $numberOfPages = ($jobLimit <= 0 ? 0 : ceil($jobsCount / $jobLimit)); } $this->view->assign('jobs', $jobs); $this->view->assign('limit', $jobLimit); $this->view->assign('numberOfPages', $numberOfPages); } /** * Renders the application form with an optional job * * @param JobApplication $applyData * @param string $error * @param int $uid * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException */ public function applyFormAction(JobApplication $applyData = NULL, $error = NULL, $uid = NULL) { if ($error !== NULL && $error !== '') { $this->view->assign('internalError', $error); $this->request->setArgument('error', NULL); } $folderName = NULL; try { $folderName = $this->request->getArgument('folderName'); } catch (\Exception $exception) { // this happens for the initial call, but works for any follow-up call as the form validation // throws you back to this one if something has failed } if ($folderName === NULL) { $folderName = md5(uniqid('sgjobs-', TRUE)); $this->request->setArgument('folderName', $folderName); } $this->view->assign('folderName', $folderName); $job = NULL; if (!$uid !== NULL) { /** @var Job $job */ $job = $this->jobRepository->findByUid($uid); if ($job) { $GLOBALS['TSFE']->page['titlebyextension'] = $job->getTitle(); $GLOBALS['TSFE']->page['description'] = substr($job->getDescription(), 0, 200); } else { $storagePid = (int) $this->configurationManager->getConfiguration( ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK )['persistence']['storagePid']; $this->view->assign('companies', $this->companyRepository->getAllCompanies($storagePid)); } $this->view->assign('job', $job); } // display country options $countryRepository = $this->objectManager->get(CountryRepository::class); $countries = $countryRepository->findAllOrderedBy('shortNameEn')->toArray(); $this->view->assign('countries', $countries); $this->view->assign('sysLanguageUid', $GLOBALS['TSFE']->sys_language_uid); $allowedMimeTypes = $this->settings['allowedMimeTypes']; $this->view->assign('allowedMimeTypes', $allowedMimeTypes); $allowedFileExtensions = $this->settings['allowedFileExtensions']; $this->view->assign('allowedFileExtensions', $allowedFileExtensions); if ($applyData === NULL) { /** @noinspection CallableParameterUseCaseInTypeContextInspection */ $applyData = $this->objectManager->get(JobApplication::class); if ($job) { $applyData->setJobId($job->getJobId()); } } $this->view->assign('applyData', $applyData); } /** * Pre-apply action setup, configures model-property mapping and handles file upload * * @return void * @throws NoSuchArgumentException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException */ protected function initializeApplyAction() { try { $uniqueFolderName = $this->request->getArgument('folderName'); } catch (NoSuchArgumentException $exception) { $exceptionMessage = 'Eine Datei konnte nicht hochgeladen werden. Ist diese eventuell zu groß?'; $this->redirect('applyForm', NULL, NULL, ['error' => $exceptionMessage]); exit; } $propertyMappingConfiguration = $this->arguments->getArgument('applyData')->getPropertyMappingConfiguration(); $propertyMappingConfiguration->forProperty('job')->allowAllProperties(); $typeConverter1 = $this->objectManager->get(UploadedFileReferenceConverter::class); $typeConverter1->setAllowedFileExtensions($this->settings['allowedFileExtensions']); $typeConverter1->setUploadFolder('1:/JobApplication/' . $uniqueFolderName); $typeConverter1->setTargetUploadFileName('coverLetter'); $propertyMappingConfiguration->forProperty('coverLetter')->setTypeConverter($typeConverter1); $typeConverter2 = $this->objectManager->get(UploadedFileReferenceConverter::class); $typeConverter2->setAllowedFileExtensions($this->settings['allowedFileExtensions']); $typeConverter2->setUploadFolder('1:/JobApplication/' . $uniqueFolderName); $typeConverter2->setTargetUploadFileName('cv'); $propertyMappingConfiguration->forProperty('cv')->setTypeConverter($typeConverter2); $typeConverter3 = $this->objectManager->get(UploadedFileReferenceConverter::class); $typeConverter3->setAllowedFileExtensions($this->settings['allowedFileExtensions']); $typeConverter3->setUploadFolder('1:/JobApplication/' . $uniqueFolderName); $typeConverter3->setTargetUploadFileName('certificate'); $propertyMappingConfiguration->forProperty('certificate')->setTypeConverter($typeConverter3); } /** * Moves the application files from temporary to permanent storage * * @param JobApplication $applicationData * @param string $folderName * @return void * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException * @throws \RuntimeException * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException */ private function submitApplicationFiles(JobApplication $applicationData, $folderName) { $resourceFactory = $this->objectManager->get(ResourceFactory::class); $newName = date('Ymd-His') . '_' . $applicationData->getJobId() . '-' . $applicationData->getFirstName() . '-' . $applicationData->getLastName(); $storage = $resourceFactory->getStorageObject(1); $applicationFilePath = PATH_site . $storage->getConfiguration()['basePath'] . 'JobApplication/' . $folderName . '/' . $newName . '.csv'; $this->writeApplicationFile($applicationData, $applicationFilePath); } /** * Saves the application send by the applyFormAction * * @param JobApplication $applyData * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException * @throws NoSuchArgumentException */ public function applyAction(JobApplication $applyData) { $folderName = $this->request->getArgument('folderName'); try { $applyData->setPid($GLOBALS['TSFE']->id); /** @var Job $job */ $job = $applyData->getJob(); // look for a configured default job, in case of unsolicited application if ($job === NULL && $this->settings['defaultJobId']) { $unsoliticedJob = $this->settings['defaultJobId']; $applyData->setJobId($unsoliticedJob); } if ($applyData->_isNew()) { $this->jobApplicationRepository->add($applyData); } else { $this->jobApplicationRepository->update($applyData); } $this->submitApplicationFiles($applyData, $folderName); /** @noinspection PhpMethodParametersCountMismatchInspection */ $mailService = $this->objectManager->get( MailTemplateService::class, 'application_mail', 'sg_jobs', $this->getApplicationMailMarkers($applyData) ); // get email from the job contact, fallback is TS settings if ($job !== NULL) { /** @var Contact $contact */ $contact = $job->getContact(); } if ($contact !== NULL) { $mailService->setToAddresses($contact->getEmail()); } else { $mailService->setToAddresses($applyData->getCompany()->getContact()->getEmail()); } $mailService->setMarkers(['application' => $applyData]); $mailService->setIgnoreMailQueue(TRUE); // add attachments for each file $coverLetter = $applyData->getCoverLetter(); if ($coverLetter) { $originalResource = $coverLetter->getOriginalResource(); if ($originalResource) { $this->addAttachmentsToMail($originalResource, $mailService); } } $cv = $applyData->getCv(); if ($cv) { $originalResource = $cv->getOriginalResource(); if ($originalResource) { $this->addAttachmentsToMail($originalResource, $mailService); } } $certificate = $applyData->getCertificate(); if ($certificate) { $originalResource = $certificate->getOriginalResource(); if ($originalResource) { $this->addAttachmentsToMail($originalResource, $mailService); } } $mailService->sendEmail(); $redirectPageUid = (int) $this->settings['redirectPage']; if ($redirectPageUid) { $url = $this->configurationManager->getContentObject()->getTypoLink_URL($redirectPageUid); $this->redirectToUri($url); } $this->redirect('applyForm'); } catch (\Exception $exception) { $job = $applyData->getJob(); $jobId = $job !== NULL ? $job->getUid() : NULL; $this->request->setArgument('folderName', $folderName); $this->forward( 'applyForm', NULL, NULL, ['applyData' => $applyData, 'error' => $exception->getMessage(), 'uid' => $jobId] ); } } /** * add FileReference as attachment to the mail service mailMessage * * @param FileReference $originalResource * @param MailTemplateService $mailService */ private function addAttachmentsToMail(FileReference $originalResource, MailTemplateService $mailService) { $storage = $originalResource->getStorage(); if (!$storage) { return; } $attachmentOriginalFile = PATH_site . rawurldecode($originalResource->getPublicUrl()); $mimeType = $originalResource->getMimeType(); $attachment = \Swift_Attachment::fromPath($attachmentOriginalFile, $mimeType); $mailService->getMailMessage()->attach($attachment); } /** * Assign filter values * * @param int $rootPageId * @throws \InvalidArgumentException */ private function assignFilterValues($rootPageId) { $countries = $this->companyRepository->getAllCountries($rootPageId); $this->view->assign('countries', $countries); $cities = $this->companyRepository->getAllCities($rootPageId); $this->view->assign('cities', $cities); $companies = $this->companyRepository->getAllCompanyNames($rootPageId); $this->view->assign('companies', $companies); $areas = $this->jobRepository->getAllAreas($rootPageId); $this->view->assign('areas', $areas); } /** * Returns the application mail markers * * @param JobApplication $applyData * @return array */ private function getApplicationMailMarkers($applyData): array { return [ 'salutation' => $applyData->getGender(), 'firstname' => $applyData->getFirstName(), 'lastname' => $applyData->getLastName(), 'street' => $applyData->getStreet(), 'city' => $applyData->getCity(), 'country' => $applyData->getCountry(), 'phone' => $applyData->getPhone(), 'mobile' => $applyData->getMobile(), 'email' => $applyData->getEmail(), 'message' => $applyData->getFirstName() ]; } /** * Writes the application files * * @param JobApplication $data * @param string $filePath * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException * @throws \InvalidArgumentException * @throws \RuntimeException */ private function writeApplicationFile(JobApplication $data, $filePath) { $dataToInsertArr = [ $data->getJobId(), $data->getFirstName(), $data->getLastName(), $data->getGender(), $data->getCountry(), $data->getBirthDate(), $data->getEducation(), $data->getStreet(), $data->getZip(), $data->getCity(), $data->getNationality(), $data->getPhone(), $data->getEmail(), $data->getCoverLetter() === NULL ? '' : $data->getCoverLetter()->getOriginalResource()->getPublicUrl(), $data->getCv() === NULL ? '' : $data->getCv()->getOriginalResource()->getPublicUrl(), $data->getCertificate() === NULL ? '' : $data->getCertificate()->getOriginalResource()->getPublicUrl(), $data->getMessage() ]; try { GeneralUtility::mkdir_deep(\dirname($filePath)); $file = fopen($filePath, 'wb+'); fputcsv($file, $dataToInsertArr); fclose($file); } catch (\RuntimeException $exception) { $this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]); } } }