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!
***************************************************************/
use SGalinski\SgJobs\Domain\Model\JobApplication;
use SGalinski\SgJobs\Service\FrontendFilterService;
use SGalinski\SgMail\Service\MailTemplateService;
Sergiu-Lucian Petrica
committed
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Resource\DuplicationBehavior;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
/**
* The joblist plugin controller
*/
class JoblistController extends ActionController {
/**
* @var \SGalinski\SgJobs\Domain\Repository\CompanyRepository
/**
* @var \SGalinski\SgJobs\Domain\Repository\JobRepository
* @inject
*/
private $jobRepository;
/**
* Show all job offers and options to manage them
*
* @return void
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
* @throws \InvalidArgumentException
*/
public function indexAction(array $filters = []) {
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);
// pagination logic
$jobLimit = (int) $this->settings['jobLimit'];
$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
Sergiu-Lucian Petrica
committed
* @param string $error
* @throws \InvalidArgumentException
Sergiu-Lucian Petrica
committed
public function applyFormAction(JobApplication $applyData = NULL, $error = NULL) {
if ($this->request->getOriginalRequest()) {
$uploadedFiles = $this->request->getOriginalRequest()->getArguments()['uploadedFiles'];
$this->view->assign('uploadedFiles', $uploadedFiles);
}
if ($error !== NULL && $error !== '') {
$logger = $this->objectManager->get(LogManager::class)->getLogger(__CLASS__);
$logger->log(LogLevel::ALERT, $error);
Sergiu-Lucian Petrica
committed
$this->view->assign('error', 1);
}
$jobId = $this->request->getArguments()['jobData']['uid'];
if (!empty($jobId)) {
$jobData = $this->jobRepository->findByUid($jobId);
$this->view->assign('job', $jobData);
}
$allowedMimeTypes = $this->settings['allowedMimeTypes'];
$this->view->assign('allowedMimeTypes', $allowedMimeTypes);
$allowedFileExtensions = $this->settings['allowedFileExtensions'];
$this->view->assign('allowedFileExtensions', $allowedFileExtensions);
$this->view->assign('applyData', $applyData);
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/**
* Pre-apply action setup, configures model-property mapping and handles file upload
*
* @return void
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
* @throws \InvalidArgumentException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException
* @throws \Exception
*/
protected function initializeApplyAction() {
$propertyMappingConfiguration = $this->arguments->getArgument('applyData')->getPropertyMappingConfiguration();
$propertyMappingConfiguration->forProperty('coverLetter')->allowAllProperties();
$propertyMappingConfiguration->forProperty('cv')->allowAllProperties();
$propertyMappingConfiguration->forProperty('certificates')->allowAllProperties();
$propertyMappingConfiguration->allowAllProperties();
if ($this->request->hasArgument('folderName')) {
$uniqueFolderName = $this->request->getArgument('folderName');
} else {
$uniqueFolderName = uniqid('sgjobs-', TRUE);
}
try {
$this->handleFileUpload('coverLetter', $uniqueFolderName);
$this->handleFileUpload('cv', $uniqueFolderName);
$this->handleFileUpload('certificates', $uniqueFolderName);
} catch (\Exception $exception) {
$this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
}
$uploadedFiles = $this->getExistingApplicationFiles($uniqueFolderName);
$this->request->setArgument('uploadedFiles', $uploadedFiles);
$this->request->setArgument('folderName', $uniqueFolderName);
}
* Saves the application send by the applyFormAction
*
* @param JobApplication $applyData
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
* @throws \InvalidArgumentException
public function applyAction(JobApplication $applyData) {
$folderName = $this->request->getArgument('folderName');
$this->submitApplicationFiles($applyData, $folderName);
/** @noinspection PhpMethodParametersCountMismatchInspection */
$mailService = $this->objectManager->get(
MailTemplateService::class, 'application_mail', 'sg_jobs',
$this->getApplicationMailMarkers($applyData)
);
$mailService->setIgnoreMailQueue(TRUE);
$mailService->setToAddresses($this->settings['applicationEmail']);

Torsten Oppermann
committed
// redirect to the given page id from the flexform
$redirectPageId = (int) $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
)['settings']['redirectPage'];
$uriBuilder = $this->uriBuilder;
$uri = $uriBuilder
->reset()
->setTargetPageUid($redirectPageId)
->build();

Torsten Oppermann
committed
$this->redirectToUri($uri);
} catch (\Exception $exception) {
// possible errors, because of wrong mails (maybe log that somewhere? Does this makes sense?)
Sergiu-Lucian Petrica
committed
$this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
Sergiu-Lucian Petrica
committed
}

Torsten Oppermann
committed
/**

Torsten Oppermann
committed
* @param int $rootPageId
*/
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);
$functions = $this->jobRepository->getAllFunctions($rootPageId);
$this->view->assign('functions', $functions);
}
* Returns the application mail markers
*
* @param JobApplication $applyData
private function getApplicationMailMarkers($applyData): array {
'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()
Sergiu-Lucian Petrica
committed
* Returns all the files in a folder
*
* @return \TYPO3\CMS\Core\Resource\File[]
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
* @throws \Exception
* @throws \InvalidArgumentException
private function getExistingFiles($folder): array {
$resourceFactory = $this->objectManager->get(ResourceFactory::class);
$storage = $resourceFactory->getStorageObject(1);
Sergiu-Lucian Petrica
committed
$folderObject = $storage->getFolder('/Extension/' . $folder);
return $storage->getFilesInFolder($folderObject);
Sergiu-Lucian Petrica
committed
/**
* Returns all the application files based on a folder
*
Sergiu-Lucian Petrica
committed
* @return array
Sergiu-Lucian Petrica
committed
*/
private function getExistingApplicationFiles($folder): array {
Sergiu-Lucian Petrica
committed
$files['coverLetter'] = $this->getExistingFiles('temp/' . $folder . '/coverLetter');
$files['cv'] = $this->getExistingFiles('temp/' . $folder . '/cv');
$files['certificates'] = $this->getExistingFiles('temp/' . $folder . '/certificates');
return $files;
}
/**
* Moves the application files from temporary to permanent storage
*
* @param JobApplication $applicationData
* @param string $folderName
Sergiu-Lucian Petrica
committed
* @return void
* @throws \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException
* @throws \TYPO3\CMS\Core\Resource\Exception\InvalidTargetFolderException
* @throws \TYPO3\CMS\Core\Exception
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException
* @throws \RuntimeException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
* @throws \Exception
* @throws \InvalidArgumentException
Sergiu-Lucian Petrica
committed
*/
private function submitApplicationFiles(JobApplication $applicationData, $folderName) {
$resourceFactory = $this->objectManager->get(ResourceFactory::class);
Sergiu-Lucian Petrica
committed
$storage = $resourceFactory->getStorageObject(1);
$newName = date('Ymd-His') . '_' . $applicationData->getFirstName();
$sourceFolder = $storage->getFolder('/Extension/temp/' . $folderName);
Sergiu-Lucian Petrica
committed
$subFolders = $storage->getFoldersInFolder($sourceFolder);
$fileNames = [];
foreach ($subFolders as $subFolder) {
$files = $subFolder->getFiles();
foreach ($files as $file) {
$currentFile = $file->rename($newName . '_' . $subFolder->getName() . '.pdf');
$fileNames[$subFolder->getName()][] = $currentFile->getName();
$file->moveTo($sourceFolder);
}
$subFolder->delete();
}
$sourceFolder->rename($newName);
Sergiu-Lucian Petrica
committed
$sourceFolder = $storage->getFolder('/Extension/temp/' . $newName);
if (!$storage->hasFolder('/Extension/JobApplication/')) {
$storage->createFolder('/Extension/JobApplication/');
Sergiu-Lucian Petrica
committed
$targetFolder = $storage->getFolder('/Extension/JobApplication/');
Sergiu-Lucian Petrica
committed
$applicationFile = $storage->createFile($newName . '.csv', $sourceFolder);
$applicationFilePath = str_replace('/', '', $storage->getConfiguration()['basePath']) .
$applicationFile->getIdentifier();
Sergiu-Lucian Petrica
committed
$this->writeApplicationFile($applicationData, $applicationFilePath, $fileNames);
Sergiu-Lucian Petrica
committed
$storage->moveFolder($sourceFolder, $targetFolder);
}
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, $fileNames) {
Sergiu-Lucian Petrica
committed
$certificatesArr = [];
/** @var array[][] $fileNames */
if (isset($fileNames['certificates'])) {
foreach ($fileNames['certificates'] as $certificateName) {
$certificatesArr[] = $certificateName;
}
$certificateNames = implode($certificatesArr, ', ');
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(),
$fileNames['coverLetter'][0],
$fileNames['cv'][0],
$certificateNames
];
try {
$file = fopen($filePath, 'wb+');
} catch (\RuntimeException $exception) {
Sergiu-Lucian Petrica
committed
$this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
}
}
/**
* Registers an uploaded file for TYPO3 native upload handling.
*
* @param array &$data
* @param string $namespace
* @param string $fieldName
* @param string $targetDirectory
* @return void
*/
private function registerUploadField(array &$data, $namespace, $fieldName, $targetDirectory = '1:/_temp_/') {
if (!\is_array($_FILES[$namespace])) {
return;
}
if (!isset($data['upload'])) {
$data['upload'] = [];
}
$counter = \count($data['upload']) + 1;
$keys = array_keys($_FILES[$namespace]);
foreach ($keys as $key) {
$_FILES['upload_' . $counter][$key] = $_FILES[$namespace][$key]['applyData'][$fieldName];
}
$data['upload'][$counter] = [
'data' => $counter,
'target' => $targetDirectory,
];
Sergiu-Lucian Petrica
committed
}
/**
* @param string $fieldName
* @param string $folderName
* @throws \UnexpectedValueException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException
* @throws \Exception
* @throws \InvalidArgumentException
* @throws \TYPO3\CMS\Core\Resource\Exception
private function handleFileUpload($fieldName, $folderName): array {
$data = [];
$namespace = key($_FILES);
$resourceFactory = $this->objectManager->get(ResourceFactory::class);
$storage = $resourceFactory->getStorageObject(1);
if (!$storage->hasFolder('/Extension/temp/' . $folderName . '/' . $fieldName)) {
$storage->createFolder('/Extension/temp/' . $folderName . '/' . $fieldName);
$targetFalDirectory = '1:/Extension/temp/' . $folderName . '/' . $fieldName;
// Register every upload field from the form:
$this->registerUploadField($data, $namespace, $fieldName, $targetFalDirectory);
$fileProcessor = $this->objectManager->get(ExtendedFileUtility::class);
$fileProcessor->setActionPermissions(['addFile' => TRUE]);
$fileProcessor->setFileExtensionPermissions($this->settings['allowedFileExtensions'], '');
// Actual upload
$fileProcessor->start($data);
// This was previously passed as empty string, why and from where? It breaks the upload if it's not set.
$fileProcessor->setExistingFilesConflictMode(DuplicationBehavior::REPLACE);
$result = $fileProcessor->processData();
foreach ((array) $result['upload'] as $files) {
/** @var array $files */
foreach ($files as $file) {
$uploadedFiles[] = $file;
}