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!
***************************************************************/
Stefan Galinski
committed
use Psr\Http\Message\ResponseInterface;
Stefan Galinski
committed
use SGalinski\ProjectBase\Domain\Repository\CountryRepository;
use SGalinski\SgJobs\Controller\Ajax\UploadController;
Stefan Galinski
committed
use SGalinski\SgJobs\Domain\Model\Company;
use SGalinski\SgJobs\Domain\Model\Job;
use SGalinski\SgJobs\Domain\Model\JobApplication;
use SGalinski\SgJobs\Domain\Repository\CompanyRepository;
use SGalinski\SgJobs\Domain\Repository\DepartmentRepository;
use SGalinski\SgJobs\Domain\Repository\ExperienceLevelRepository;
use SGalinski\SgJobs\Domain\Repository\JobApplicationRepository;
use SGalinski\SgJobs\Domain\Repository\JobRepository;
use SGalinski\SgJobs\Service\FileAndFolderService;
use SGalinski\SgMail\Service\MailTemplateService;
use SGalinski\SgSeo\Service\HeadTagService;
use TYPO3\CMS\Core\Context\Context;
Stefan Galinski
committed
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
use TYPO3\CMS\Core\Core\Environment;
Stefan Galinski
committed
use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
Stefan Galinski
committed
use TYPO3\CMS\Core\Http\ImmediateResponseException;
Stefan Galinski
committed
use TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException;
use TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderReadPermissionsException;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
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\Exception\StopActionException;
use TYPO3\CMS\Extbase\Property\Exception\TypeConverterException;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
Stefan Galinski
committed
use TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator;
use TYPO3\CMS\Extbase\Validation\Validator\GenericObjectValidator;
Stefan Galinski
committed
use TYPO3\CMS\Frontend\Controller\ErrorController;
use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
/**
* The joblist plugin controller
*/
class JoblistController extends ActionController {
// the array key for the error message in the post array
Stefan Galinski
committed
public const ERROR_KEY_IN_POST = 'error';
private const UPLOADED_FILES = [
'coverLetter',
'cv',
'certificate',
];
* @var CompanyRepository
Stefan Galinski
committed
* @var JobRepository
*/
/**
Stefan Galinski
committed
* @var JobApplicationRepository
Stefan Galinski
committed
* @var DepartmentRepository
*/
Stefan Galinski
committed
/**
* @var ExperienceLevelRepository
*/
/**
* @var FileAndFolderService
*/
Stefan Galinski
committed
/**
* Inject the CompanyRepository
*
Stefan Galinski
committed
* @param CompanyRepository $companyRepository
*/
Stefan Galinski
committed
public function injectCompanyRepository(CompanyRepository $companyRepository): void {
$this->companyRepository = $companyRepository;
}
/**
* Inject the CompanyRepository
*
Stefan Galinski
committed
* @param FileAndFolderService $fileAndFolderService
*/
public function injectFileAndFolderService(FileAndFolderService $fileAndFolderService): void {
$this->fileAndFolderService = $fileAndFolderService;
}
/**
Stefan Galinski
committed
* Inject the DepartmentRepository
*
Stefan Galinski
committed
* @param DepartmentRepository $departmentRepository
Stefan Galinski
committed
public function injectDepartmentRepository(DepartmentRepository $departmentRepository): void {
$this->departmentRepository = $departmentRepository;
}
/**
* Inject the ExperienceLevelRepository
*
* @param ExperienceLevelRepository $experienceLevelRepository
*/
public function injectExperienceLevelRepository(ExperienceLevelRepository $experienceLevelRepository): void {
$this->experienceLevelRepository = $experienceLevelRepository;
}
* Inject the JobApplicationRepository
*
* @param JobApplicationRepository $jobApplicationRepository
*/
Stefan Galinski
committed
public function injectJobApplicationRepository(JobApplicationRepository $jobApplicationRepository): void {
$this->jobApplicationRepository = $jobApplicationRepository;
}
/**
Stefan Galinski
committed
* Inject the JobRepository
*
Stefan Galinski
committed
* @param JobRepository $jobRepository
*/
Stefan Galinski
committed
public function injectJobRepository(JobRepository $jobRepository): void {
$this->jobRepository = $jobRepository;
}
Stefan Galinski
committed
/**
* Initialize the indexAction to set the currentPageBrowserPage parameter
*/
Stefan Galinski
committed
public function initializeIndexAction(): void {
$currentPageBrowserPage = GeneralUtility::_GP('tx_sgjobs_pagebrowser') ?
(int) GeneralUtility::_GP('tx_sgjobs_pagebrowser')['currentPage'] : 0;
Stefan Galinski
committed
if ($currentPageBrowserPage > 0) {
$this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage);
}
}
/**
* Show all job offers and options to manage them
*
Stefan Galinski
committed
* @param int|null $jobId
Stefan Galinski
committed
* @param int $currentPageBrowserPage
Stefan Galinski
committed
* @return ResponseInterface|null
Stefan Galinski
committed
* @throws ImmediateResponseException
Stefan Galinski
committed
* @throws AspectNotFoundException
* @throws PageNotFoundException
public function indexAction(
array $filters = [],
int $jobId = NULL,
int $currentPageBrowserPage = 0
Stefan Galinski
committed
): ?ResponseInterface {
$this->view->assign('selectedCountry', $filters['filterCountry'] ?? '');
$this->view->assign('selectedCompany', $filters['filterCompany'] ?? '');
$this->view->assign('selectedLocation', $filters['filterLocation'] ?? '');
$this->view->assign('selectedDepartment', $filters['filterDepartment'] ?? '');
$this->view->assign('selectedExperienceLevel', $filters['filterExperienceLevel'] ?? '');
$this->view->assign('selectedFunction', $filters['filterFunction'] ?? '');
$this->view->assign('selectedRemote', $filters['filterRemote'] ?? '');
$filters['filterByDepartment'] = $this->settings['filterByDepartment'] ?? '';
$filters['filterByExperienceLevel'] = $this->settings['filterByExperienceLevel'] ?? '';
$filters['filterByLocation'] = $this->settings['filterByLocation'] ?? '';
foreach ($filters as $name => &$filter) {
if ($name === 'filterByLocation' || $name === 'filterByExperienceLevel' || $name === 'filterByDepartment') {
$filter = $filter ? GeneralUtility::trimExplode(',', $filter) : NULL;
if (!$filter) {
continue;
}
foreach ($filter as &$value) {
$value = (int) $value;
}
}
}
$storagePid = (int) $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
)['persistence']['storagePid'];

Torsten Oppermann
committed
$this->assignFilterValues($storagePid, $filters);
$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!');
}
$headTagService = GeneralUtility::makeInstance(
HeadTagService::class,
TRUE,
$job->getTitle(),
$job->getDescription(),
'&tx_sgjobs_jobapplication[jobId]=' . $jobId
);
$headTagService->execute();
$jobs = [$job];
$numberOfPages = 1;
} else {
// pagination logic
$offset = 0;
if ($currentPageBrowserPage && $jobLimit) {
$offset = $currentPageBrowserPage * $jobLimit;
}
Stefan Galinski
committed
$frontendPluginSettings = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
);
$frontendPluginSettings = $frontendPluginSettings['settings'];
Stefan Galinski
committed
$ordering = (int) $frontendPluginSettings['orderBy'];
Stefan Galinski
committed
$jobs = $this->jobRepository->findJobsByFilter($filters, $jobLimit, $offset, $ordering)->toArray();
Stefan Galinski
committed
$allJobs = $this->jobRepository->findJobsByFilter($filters)->toArray();
Stefan Galinski
committed
$numberOfPages = (int) ($jobLimit <= 0 ? 0 : \ceil(\count($allJobs) / $jobLimit));
if ($numberOfPages !== 0 && $currentPageBrowserPage >= $numberOfPages) {
Stefan Galinski
committed
/** @var ErrorController $errorController */
$errorController = GeneralUtility::makeInstance(ErrorController::class);
$response = $errorController->pageNotFoundAction(
$GLOBALS['TYPO3_REQUEST'],
'The requested page does not exist',
['code' => PageAccessFailureReasons::PAGE_NOT_FOUND]
);
throw new ImmediateResponseException($response);
}
$this->view->assign('jobs', $jobs);
$this->view->assign('jobs2', 'just a job');
$this->view->assign('limit', $jobLimit);
$this->view->assign('numberOfPages', $numberOfPages);
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
return NULL;
}
Stefan Galinski
committed
return $this->htmlResponse();
* Renders the application form with an optional job
Stefan Galinski
committed
* @param JobApplication|null $applyData
* @param string $error
Stefan Galinski
committed
* @param int|null $jobId
* @return ResponseInterface|null
* @throws AspectNotFoundException
* @throws StopActionException
* @throws SiteNotFoundException
public function applyFormAction(
JobApplication $applyData = NULL,
string $error = '',
int $jobId = NULL
Stefan Galinski
committed
): ?ResponseInterface {
Stefan Galinski
committed
if ($error !== '') {
$this->view->assign('internalError', $error);
$this->request->setArgument('error', NULL);
Sergiu-Lucian Petrica
committed
}
if ($jobId === NULL && $this->settings['disallowUnsolicitedApplication']) {
$uriBuilder = $this->uriBuilder;
$uri = $uriBuilder
->setTargetPageUid($this->settings['offersPage'])
->build();
$this->redirectToUri($uri, 0, 301);
}
$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 */
Stefan Galinski
committed
$job = $this->jobRepository->findByUid($jobId);
if ($job) {
$headTagService = GeneralUtility::makeInstance(
HeadTagService::class,
FALSE,
$job->getTitle(),
$job->getDescription(),
'&tx_sgjobs_jobapplication[jobId]=' . $jobId
);
$headTagService->execute();
}
$this->view->assign('job', $job);
$enableAutomaticRelatedJobs = (bool) $this->settings['enableAutomaticRelatedJobs'];
$automaticRelatedJobsLimit = (int) $this->settings['automaticRelatedJobsLimit'];
$relatedJobs = $this->jobRepository->findRelated($job, $automaticRelatedJobsLimit);
$this->view->assign('relatedJobs', $relatedJobs);
}
} else {
$storagePid = (int) $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
)['persistence']['storagePid'];
$this->view->assign('companies', $this->companyRepository->getAllCompanies($storagePid));
// display country options
$context = GeneralUtility::makeInstance(Context::class);
$sysLanguageUid = $context->getPropertyFromAspect('language', 'id');
$site = GeneralUtility::makeInstance(SiteFinder::class)
->getSiteByPageId($GLOBALS['TSFE']->id)
->getLanguageById($sysLanguageUid);
$countries = [];
if (ExtensionManagementUtility::isLoaded('project_base')) {
$countryRepository = $this->objectManager->get(CountryRepository::class);
$countries = $countryRepository->findAllOrderedByLanguage($site->getTwoLetterIsoCode());
}
$this->view->assign('countries', $countries);
$this->view->assign('sysLanguageUid', $sysLanguageUid);
$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('maxFileSizeMb', ((int) $this->settings['allowedMaxFileSize'] / 1000) . ' MByte');
$this->view->assign(
'maxFileSizeMessage',
LocalizationUtility::translate('error.maxFileSizeMessage', 'sg_jobs')
// This fixes a bug in the form ViewHelper that wants to serialize a Model with closures in it
$arguments = $this->request->getArguments();
if (isset($arguments['applyData']) && $arguments['applyData']) {
$arguments['applyData'] = (string) $arguments['applyData'];
$this->request->setArguments($arguments);
}
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
return NULL;
}
Stefan Galinski
committed
return $this->htmlResponse();
Stefan Galinski
committed
/**
* Moves the application files from temporary to permanent storage
*
* @param JobApplication $applicationData
* @param string $folderName
* @return void
Stefan Galinski
committed
* @throws StopActionException
Stefan Galinski
committed
*/
Stefan Galinski
committed
protected function submitApplicationFiles(JobApplication $applicationData, string $folderName): void {
Stefan Galinski
committed
$resourceFactory = $this->objectManager->get(ResourceFactory::class);
$newName = \date('Ymd-His') . '_' . $applicationData->getJobId() . '-' . $applicationData->getFirstName()
. '-' . $applicationData->getLastName();
$storage = $resourceFactory->getStorageObject(1);
$applicationFilePath = Environment::getPublicPath() . '/' . $storage->getConfiguration(
)['basePath'] . 'JobApplication/' . $folderName .
Stefan Galinski
committed
'/' . $newName . '.csv';
$this->writeApplicationFile($applicationData, $applicationFilePath);
}
/**
* Pre-apply action setup, configures model-property mapping and handles file upload
*
* @throws NoSuchArgumentException
Stefan Galinski
committed
* @throws StopActionException
Stefan Galinski
committed
protected function initializeApplyAction(): void {
$propertyMappingConfiguration = $this->arguments->getArgument('applyData')->getPropertyMappingConfiguration();
$propertyMappingConfiguration->forProperty('job')->allowAllProperties();
Stefan Galinski
committed
// remove the job validator
/** @var ConjunctionValidator $validator */
$validator = $this->arguments->getArgument('applyData')->getValidator();
foreach ($validator->getValidators() as $subValidator) {
/** @var GenericObjectValidator $subValidatorSub */
foreach ($subValidator->getValidators() as $subValidatorSub) {
$subValidatorSub->getPropertyValidators('job')->removeAll(
$subValidatorSub->getPropertyValidators('job')
);
}
}
* Saves the application send by the applyFormAction
*
* @param JobApplication $applyData
Stefan Galinski
committed
* @return ResponseInterface|null
Stefan Galinski
committed
* @throws StopActionException
Stefan Galinski
committed
public function applyAction(JobApplication $applyData): ?ResponseInterface {
$folderName = $this->request->getArgument('folderName');
Stefan Galinski
committed
if ($job) {
foreach ($job->getCompanies() as $company) {
/** @var Company $company */
$applyData->setCompany($company);
}
} elseif (!$applyData->getCompany()) {
$company = $this->companyRepository->findByUid(
(int) $_POST['tx_sgjobs_jobapplication']['applyData']['company']
);
if ($company) {
$applyData->setCompany($company);
}
Stefan Galinski
committed
}
$applyData->setPid($GLOBALS['TSFE']->id);
// look for a configured default job, in case of unsolicited application
Stefan Galinski
committed
if ((!$job || $applyData->getJobId() === NULL) && $applyData->getCompany() !== NULL) {

Torsten Oppermann
committed
$applyData->setJobId($applyData->getCompany()->getJobId());
if ($applyData->_isNew()) {
$this->jobApplicationRepository->add($applyData);
} else {
$this->jobApplicationRepository->update($applyData);
}
$this->moveTmpFolder($folderName, $applyData);
$this->submitApplicationFiles($applyData, $folderName);
$mailService = $this->objectManager->get(
MailTemplateService::class,
'application_mail',
'sg_jobs',
$this->getApplicationMailMarkers($applyData)
// set the pageId of the rootpage, otherwise the templates could be duplicated
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($GLOBALS['TSFE']->id);
$mailService->setPid($site->getRootPageId());

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

Torsten Oppermann
committed
if ($job !== NULL) {
$contact = $job->getContact();
}
if ($contact !== NULL) {
$mailService->setToAddresses($contact->getEmail());
} else {
if (($company !== NULL) && $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) {
$mailService->addFileResourceAttachment($coverLetter);
$cv = $applyData->getCv();
if ($cv) {
$mailService->addFileResourceAttachment($cv);
$certificate = $applyData->getCertificate();
if ($certificate) {
$mailService->addFileResourceAttachment($certificate);

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

Torsten Oppermann
committed
$this->redirect('applyForm');
} catch (\Exception $exception) {
if ($exception instanceof StopActionException) {

Torsten Oppermann
committed
$this->deleteTmpFolder($folderName);
$job = $applyData->getJob();
$jobId = $job !== NULL ? $job->getUid() : NULL;
$this->request->setArgument('folderName', $folderName);
$this->forward(
Kevin Ditscheid
committed
['applyData' => $applyData, 'error' => $exception->getMessage(), 'jobId' => $jobId]
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
return NULL;
}
Stefan Galinski
committed
return $this->htmlResponse();
Sergiu-Lucian Petrica
committed
}

Torsten Oppermann
committed
/**

Torsten Oppermann
committed
* @param int $rootPageId
Stefan Galinski
committed
* @throws AspectNotFoundException

Torsten Oppermann
committed
*/
protected function assignFilterValues(int $rootPageId, array $filters = []): void {
$countries = $this->companyRepository->getAllCountries($rootPageId, $filters['filterByLocation'] ?? []);

Torsten Oppermann
committed
$this->view->assign('countries', $countries);
$cities = $this->companyRepository->getAllCities($rootPageId, $filters['filterByLocation'] ?? []);

Torsten Oppermann
committed
$this->view->assign('cities', $cities);
$companies = $this->companyRepository->getAllCompanyNames($rootPageId, $filters['filterByLocation'] ?? []);

Torsten Oppermann
committed
$this->view->assign('companies', $companies);
$departments = $this->departmentRepository->findAllByFilter($filters['filterByDepartment'] ?? []);
$this->view->assign('departments', $departments);
$experienceLevels = $this->experienceLevelRepository->findAllByFilter(
$filters['filterByExperienceLevel'] ?? []
);
$this->view->assign('experienceLevels', $experienceLevels);

Torsten Oppermann
committed
}
* Returns the application mail markers
*
* @param JobApplication $applyData
Stefan Galinski
committed
protected function getApplicationMailMarkers(JobApplication $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
Stefan Galinski
committed
* @throws StopActionException
Sergiu-Lucian Petrica
committed
*/
Stefan Galinski
committed
protected function writeApplicationFile(JobApplication $data, string $filePath): void {
Stefan Galinski
committed
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
$coverLetter = '';
$coverLetterObject = $data->getCoverLetter();
if ($coverLetterObject) {
$coverLetterObject = $coverLetterObject->getOriginalResource();
if ($coverLetterObject) {
$coverLetter = $coverLetterObject->getPublicUrl();
}
}
$cv = '';
$cvObject = $data->getCv();
if ($cvObject) {
$cvObject = $cvObject->getOriginalResource();
if ($cvObject) {
$cv = $cvObject->getPublicUrl();
}
}
$certificate = '';
$certificateObject = $data->getCertificate();
if ($certificateObject) {
$certificateObject = $certificateObject->getOriginalResource();
if ($certificateObject) {
$certificate = $certificateObject->getPublicUrl();
}
}
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(),
Stefan Galinski
committed
$coverLetter,
$cv,
$certificate,
Sergiu-Lucian Petrica
committed
];
GeneralUtility::mkdir_deep(\dirname($filePath));
$file = \fopen($filePath, 'wb+');
\fputcsv($file, $dataToInsertArr);
\fclose($file);
} catch (\RuntimeException $exception) {
Sergiu-Lucian Petrica
committed
$this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
/**
* Move the temp folder to its proper location
*
* @param string $folderName
Stefan Galinski
committed
* @param JobApplication $applicationData
* @throws TypeConverterException
* @throws ExistingTargetFileNameException
* @throws ExistingTargetFolderException
* @throws InsufficientFolderAccessPermissionsException
* @throws InsufficientFolderReadPermissionsException
* @throws InsufficientFolderWritePermissionsException
protected function moveTmpFolder(string $folderName, JobApplication $applicationData): void {
$allowedFileExtensions = $this->getAllowedFileExtensions();
/** @var ResourceFactory $resourceFactory */
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$storage = $resourceFactory->getStorageObject(1);
$folder = $storage->getFolder(UploadController::JOB_APPLICATION_FOLDER);
$tempFolder = $storage->getFolderInFolder(UploadController::JOB_APPLICATION_TEMP_FOLDER, $folder);
if (!$storage->hasFolderInFolder($folderName, $folder)) {
$newFolder = $storage->createFolder($folderName, $folder);
$newFolder = $storage->getFolder(UploadController::JOB_APPLICATION_FOLDER . $folderName);
// Move uploaded files & csv fo real folder and delete the tmp folder
foreach (self::UPLOADED_FILES as $singleFilePostKey) {
if (array_key_exists($singleFilePostKey, $_POST)) {
foreach ($_POST[$singleFilePostKey] as $singleUploadedArr) {
$filePathInfo = PathUtility::pathinfo($singleUploadedArr['path']);
if (!GeneralUtility::inList($allowedFileExtensions, strtolower($filePathInfo['extension']))) {
Stefan Galinski
committed
throw new TypeConverterException(
LocalizationUtility::translate('error.TypeConverterException.type', 'sg_jobs'),
1399312430
Stefan Galinski
committed
);
if (!$newFolder->hasFile($filePathInfo['basename'])) {
Stefan Galinski
committed
/** @noinspection PhpUnreachableStatementInspection */
$singleFileToMove = $storage->getFileInFolder($filePathInfo['basename'], $tempFolder);
Stefan Galinski
committed
// when we reload etc. this image might already be moved.
$usableFile = $storage->moveFile($singleFileToMove, $newFolder);
} else {
Stefan Galinski
committed
/** @noinspection PhpUnreachableStatementInspection */
$usableFile = $newFolder->getFile($filePathInfo['basename']);
}
$fileReference = $this->fileAndFolderService->createFileReferenceFromFalFileObject($usableFile);
Stefan Galinski
committed
if ($singleFilePostKey === 'coverLetter') {
$applicationData->setCoverLetter($fileReference);
}
if ($singleFilePostKey === 'cv') {
$applicationData->setCV($fileReference);
}
if ($singleFilePostKey === 'certificate') {
$applicationData->setCertificate($fileReference);
}
}
} else {
Stefan Galinski
committed
throw new TypeConverterException(
LocalizationUtility::translate(
'error.TypeConverterException.missing.' . $singleFilePostKey,
'sg_jobs'
),
1399312430
Stefan Galinski
committed
);
/**
* returns currently set allowedFiles
*
* @return mixed
*/
protected function getAllowedFileExtensions() {
return $this->settings['allowedFileExtensions'] ?? $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
}

Torsten Oppermann
committed
/**
* Delete uploaded files in tmp folder
*
* @param string $folderName
*/
Stefan Galinski
committed
protected function deleteTmpFolder(string $folderName): void {

Torsten Oppermann
committed
/** @var ResourceFactory $resourceFactory */
$resourceFactory = $this->objectManager->get(ResourceFactory::class);
$storage = $resourceFactory->getStorageObject(1);
try {
$tempFolder = $storage->getFolder('/JobApplication/temp/' . $folderName);
$storage->deleteFolder($tempFolder, TRUE);

Torsten Oppermann
committed
// folder is already deleted for some reason
}
}
/**
* If for any reason something goes wrong, delete the tmp upload folder
*
Stefan Galinski
committed
* @return ResponseInterface

Torsten Oppermann
committed
*/
public function errorAction() {
if ($this->request->hasArgument('folderName')) {
$folderName = $this->request->getArgument('folderName');
$this->deleteTmpFolder($folderName);
}

Torsten Oppermann
committed
}
Stefan Galinski
committed
* Build TYPO3 11 Response
Stefan Galinski
committed
* @return ResponseInterface
Stefan Galinski
committed
protected function htmlResponse(string $html = NULL): ResponseInterface {
return $this->responseFactory->createResponse()
->withHeader('Content-Type', 'text/html; charset=utf-8')
->withBody($this->streamFactory->createStream($html ?? $this->view->render()));
}