Newer
Older
<?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!
***************************************************************/

Torsten Oppermann
committed
use SGalinski\SgJobs\Domain\Model\Contact;
use SGalinski\SgJobs\Domain\Model\Job;
use SGalinski\SgJobs\Domain\Model\JobApplication;
Stefan Galinski
committed
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;
use TYPO3\CMS\Extbase\Mvc\Request;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* The joblist plugin controller
*/
class JoblistController extends ActionController {
// the array key for the error message in the post array
const ERROR_KEY_IN_POST = 'error';
* @var \SGalinski\SgJobs\Domain\Repository\CompanyRepository
/**
* @var \SGalinski\SgJobs\Domain\Repository\JobRepository
* @inject
*/
private $jobRepository;
/**
* @var \SGalinski\SgJobs\Domain\Repository\JobApplicationRepository
* @inject
*/
private $jobApplicationRepository;
/**
* Show all job offers and options to manage them
*
* @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'];

Torsten Oppermann
committed
$this->assignFilterValues($storagePid);
$this->view->assign('recordPageId', $storagePid);
$jobLimit = (int) $this->settings['jobLimit'];
/** @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
$ordering = (int) $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
)['settings']['orderBy'];
$jobs = FrontendFilterService::getJobs($filters, $storagePid, $jobLimit, $offset, $ordering);
// 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
* @throws \InvalidArgumentException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
public function applyFormAction(JobApplication $applyData = NULL, $error = NULL, $jobId = NULL) {
if ($error !== NULL && $error !== '') {
$this->view->assign('internalError', $error);
$this->request->setArgument('error', NULL);
Sergiu-Lucian Petrica
committed
}
$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;
/** @var Job $job */
$job = $this->jobRepository->findByUidLocalized($jobId);
if ($job) {
$GLOBALS['TSFE']->page['titlebyextension'] = $job->getTitle();
$GLOBALS['TSFE']->page['description'] = substr($job->getDescription(), 0, 200);
}
$this->view->assign('job', $job);
} else {
$storagePid = (int) $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
)['persistence']['storagePid'];
$this->view->assign('companies', $this->companyRepository->getAllCompanies($storagePid));
// 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);
$this->view->assign('maxFileSize', $this->settings['allowedMaxFileSize']);
$this->view->assign(
'maxFileSizeMessage', LocalizationUtility::translate('error.maxFileSizeMessage', 'sg_jobs')
);
/**
* 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]);
$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\UnsupportedRequestTypeException
public function applyAction(JobApplication $applyData) {
$folderName = $this->request->getArgument('folderName');
/** @var Job $job */
$job = $applyData->getJob();
// look for a configured default job, in case of unsolicited application

Torsten Oppermann
committed
if (($job === NULL || $applyData->getJobId() === NULL) && $applyData->getCompany() !== NULL) {
$applyData->setJobId($applyData->getCompany()->getJobId());
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)

Torsten Oppermann
committed
// get email from the job contact, fallback is TS settings

Torsten Oppermann
committed
if ($job !== NULL) {
/** @var Contact $contact */
$contact = $job->getContact();
}
if ($contact !== NULL) {
$mailService->setToAddresses($contact->getEmail());
} else {
$company = $applyData->getCompany();
if ($company !== NULL) {
if ($company->getContact() !== NULL) {
$mailService->setToAddresses($company->getContact()->getEmail());
}
}

Torsten Oppermann
committed
}
$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);
}

Torsten Oppermann
committed
$redirectPageUid = (int) $this->settings['redirectPage'];
if ($redirectPageUid) {
$url = $this->configurationManager->getContentObject()->getTypoLink_URL($redirectPageUid);
$this->redirectToUri($url);
}

Torsten Oppermann
committed
$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]
);
Sergiu-Lucian Petrica
committed
}
/**
* 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);
}

Torsten Oppermann
committed
/**

Torsten Oppermann
committed
* @param int $rootPageId

Torsten Oppermann
committed
* @throws \InvalidArgumentException

Torsten Oppermann
committed
*/
private function assignFilterValues($rootPageId) {

Torsten Oppermann
committed
$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
private function getApplicationMailMarkers($applyData): array {
$location = '';
if ($applyData->getCompany() !== NULL) {
$location = $applyData->getCompany()->getCity();
}
'salutation' => $applyData->getGender(),
'location' => $location,
'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()
Sergiu-Lucian Petrica
committed
/**
* 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
Sergiu-Lucian Petrica
committed
*/
private function writeApplicationFile(JobApplication $data, $filePath) {
Sergiu-Lucian Petrica
committed
$dataToInsertArr = [
$data->getJobId(),
Sergiu-Lucian Petrica
committed
$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(),
Sergiu-Lucian Petrica
committed
];
GeneralUtility::mkdir_deep(\dirname($filePath));
$file = fopen($filePath, 'wb+');
} catch (\RuntimeException $exception) {
Sergiu-Lucian Petrica
committed
$this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
/**
* checks for allowed maximum file sizes
*
* @param JobApplication $applyData
* @return bool
* @throws \InvalidArgumentException
private function checkFileSizes($applyData): bool {
$coverLetterSize = (int) $applyData->getCoverLetter()->getOriginalResource()->getSize() / 1000;
$cvSize = (int) $applyData->getCv()->getOriginalResource()->getSize() / 1000;
$certificateSize = (int) $applyData->getCertificate()->getOriginalResource()->getSize() / 1000;
$allowedMaxFileSize = (int) $this->settings['allowedMaxFileSize'];
if ($allowedMaxFileSize === 0) {
return TRUE;
}
if ($allowedMaxFileSize < $coverLetterSize
|| $allowedMaxFileSize < $cvSize
|| $allowedMaxFileSize < $certificateSize) {
return FALSE;
}
return TRUE;
}