diff --git a/Classes/Controller/JoblistController.php b/Classes/Controller/JoblistController.php index 7050d3851158ffa061a8f466989242a98852a95c..491a896d710dd609e33df55e85ce45fa0f011c72 100644 --- a/Classes/Controller/JoblistController.php +++ b/Classes/Controller/JoblistController.php @@ -30,13 +30,13 @@ use SGalinski\SgJobs\Domain\Model\JobApplication; use SGalinski\SgJobs\Service\FrontendFilterService; use SGalinski\SgMail\Service\MailTemplateService; 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; -use TYPO3\CMS\Extbase\Object\ObjectManager; /** * The joblist plugin controller @@ -103,6 +103,7 @@ class JoblistController extends ActionController { * * @param JobApplication $applyData * @param string $error + * @throws \InvalidArgumentException */ public function applyFormAction(JobApplication $applyData = NULL, $error = NULL) { if ($this->request->getOriginalRequest()) { @@ -110,8 +111,8 @@ class JoblistController extends ActionController { $this->view->assign('uploadedFiles', $uploadedFiles); } - if ($error !== NULL) { - $logger = GeneralUtility::makeInstance('TYPO3\CMS\Core\Log\LogManager')->getLogger(__CLASS__); + if ($error !== NULL && $error !== '') { + $logger = $this->objectManager->get(LogManager::class)->getLogger(__CLASS__); $logger->log(LogLevel::ALERT, $error); $this->view->assign('error', 1); } @@ -129,6 +130,43 @@ class JoblistController extends ActionController { $this->view->assign('applyData', $applyData); } + /** + * 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 * @@ -139,6 +177,7 @@ class JoblistController extends ActionController { */ public function applyAction(JobApplication $applyData) { try { + $applyData->setPid($GLOBALS['TSFE']->id); $folderName = $this->request->getArgument('folderName'); $this->submitApplicationFiles($applyData, $folderName); @@ -149,7 +188,6 @@ class JoblistController extends ActionController { ); $mailService->setIgnoreMailQueue(TRUE); $mailService->setToAddresses($this->settings['applicationEmail']); - $mailService->sendEmail(); // redirect to the given page id from the flexform @@ -163,46 +201,11 @@ class JoblistController extends ActionController { ->setTargetPageUid($redirectPageId) ->build(); $this->redirectToUri($uri); - } catch (\Exception $exception) { - // possible errors, because of wrong mails (maybe log that somewhere? Does this makes sense?) - $this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]); - } - } - /** - * 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() { - 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) { - // possible errors, because of wrong mails + // possible errors, because of wrong mails (maybe log that somewhere? Does this makes sense?) $this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]); } - $propertyMappingConfiguration = $this->arguments->getArgument('applyData')->getPropertyMappingConfiguration(); - $propertyMappingConfiguration->forProperty('coverLetter')->allowAllProperties(); - $propertyMappingConfiguration->forProperty('cv')->allowAllProperties(); - $propertyMappingConfiguration->forProperty('certificates')->allowAllProperties(); - $uploadedFiles = $this->getExistingApplicationFiles($uniqueFolderName); - - $this->request->setArgument('uploadedFiles', $uploadedFiles); - $this->request->setArgument('folderName', $uniqueFolderName); } /** @@ -258,8 +261,7 @@ class JoblistController extends ActionController { * @throws \InvalidArgumentException */ private function getExistingFiles($folder): array { - $objectManager = GeneralUtility::makeInstance(ObjectManager::class); - $resourceFactory = $objectManager->get(ResourceFactory::class); + $resourceFactory = $this->objectManager->get(ResourceFactory::class); $storage = $resourceFactory->getStorageObject(1); $folderObject = $storage->getFolder('/Extension/' . $folder); @@ -298,8 +300,7 @@ class JoblistController extends ActionController { * @throws \InvalidArgumentException */ private function submitApplicationFiles(JobApplication $applicationData, $folderName) { - $objectManager = GeneralUtility::makeInstance(ObjectManager::class); - $resourceFactory = $objectManager->get(ResourceFactory::class); + $resourceFactory = $this->objectManager->get(ResourceFactory::class); $storage = $resourceFactory->getStorageObject(1); $newName = date('Ymd-His') . '_' . $applicationData->getFirstName(); @@ -426,8 +427,7 @@ class JoblistController extends ActionController { $data = []; $namespace = key($_FILES); - $objectManager = GeneralUtility::makeInstance(ObjectManager::class); - $resourceFactory = $objectManager->get(ResourceFactory::class); + $resourceFactory = $this->objectManager->get(ResourceFactory::class); $storage = $resourceFactory->getStorageObject(1); if (!$storage->hasFolder('/Extension/temp/' . $folderName . '/' . $fieldName)) { $storage->createFolder('/Extension/temp/' . $folderName . '/' . $fieldName); @@ -438,9 +438,7 @@ class JoblistController extends ActionController { // Register every upload field from the form: $this->registerUploadField($data, $namespace, $fieldName, $targetFalDirectory); - // Initializing: - /** @var \TYPO3\CMS\Core\Utility\File\ExtendedFileUtility $fileProcessor */ - $fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class); + $fileProcessor = $this->objectManager->get(ExtendedFileUtility::class); $fileProcessor->setActionPermissions(['addFile' => TRUE]); $fileProcessor->setFileExtensionPermissions($this->settings['allowedFileExtensions'], ''); diff --git a/Resources/Private/Templates/Joblist/ApplyForm.html b/Resources/Private/Templates/Joblist/ApplyForm.html index 2fabe81bef7adfdcc7aa0cba6012fd57e82aa56b..43d115eb1a082929d7cb134d788135ec94235179 100644 --- a/Resources/Private/Templates/Joblist/ApplyForm.html +++ b/Resources/Private/Templates/Joblist/ApplyForm.html @@ -7,192 +7,232 @@ <f:translate key="frontend.apply.error.general" /> </div> </f:if> + <f:if condition="{job}"> - <f:form.hidden value="{job.jobId}" property="jobId" /> - <label for="apply-title"><f:translate key="frontend.apply.title" /></label> - <span id="apply-title">{job.title}</span> - <br /> + <p> + <f:form.hidden value="{job.jobId}" property="jobId" /> + <label for="apply-title"><f:translate key="frontend.apply.title" /></label> + <span id="apply-title">{job.title}</span> + </p> </f:if> - <label for="apply-gender"><f:translate key="frontend.apply.gender" /></label> - <f:form.select property="gender" id="apply-gender" class="" options="{Male: '{f:translate(key: \'frontend.apply.gender.male\')}', Female: '{f:translate(key: \'frontend.apply.gender.female\')}'}" /> - <f:form.validationResults for="applyData.gender"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-firstName"><f:translate key="frontend.apply.first_name" /></label> - <f:form.textfield property="firstName" id="apply-firstName" class="" /> - <f:form.validationResults for="applyData.firstName"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-lastName"><f:translate key="frontend.apply.last_name" /></label> - <f:form.textfield property="lastName" id="apply-lastName" class="" /> - <f:form.validationResults for="applyData.lastName"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-street"><f:translate key="frontend.apply.street" /></label> - <f:form.textfield property="street" id="apply-street" class="" /> - <f:form.validationResults for="applyData.street"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-city"><f:translate key="frontend.apply.city" /></label> - <f:form.textfield property="city" id="apply-city" class="" /> - <f:form.validationResults for="applyData.city"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-zip"><f:translate key="frontend.apply.zip" /></label> - <f:form.textfield property="zip" id="apply-zip" class="" /> - <f:form.validationResults for="applyData.zip"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-country"><f:translate key="frontend.apply.country" /></label> - <f:form.textfield property="country" id="apply-country" class="" /> - <f:form.validationResults for="applyData.country"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-nationality"><f:translate key="frontend.apply.nationality" /></label> - <f:form.textfield property="nationality" id="apply-nationality" class="" /> - <f:form.validationResults for="applyData.nationality"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-education"><f:translate key="frontend.apply.education" /></label> - <f:form.textfield property="education" id="apply-education" class="" /> - <f:form.validationResults for="applyData.education"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-birthDate"><f:translate key="frontend.apply.birthDate" /></label> - <f:form.textfield property="birthDate" id="apply-birthDate" class="" /> - <f:form.validationResults for="applyData.birthDate"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-phone"><f:translate key="frontend.apply.phone" /></label> - <f:form.textfield property="phone" id="apply-phone" class="" /> - <f:form.validationResults for="applyData.phone"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-mobile"><f:translate key="frontend.apply.mobile" /></label> - <f:form.textfield property="mobile" id="apply-mobile" class="" /> - <f:form.validationResults for="applyData.mobile"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} - </div> - </f:for> - </f:form.validationResults> - <br /> - <label for="apply-email"><f:translate key="frontend.apply.email" /></label> - <f:form.textfield type="email" property="email" id="apply-email" data="{}" class="" /> - <f:form.validationResults for="applyData.email"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} + + <p> + <label for="apply-gender"><f:translate key="frontend.apply.gender" /></label> + <f:form.select property="gender" id="apply-gender" options="{Male: '{f:translate(key: \'frontend.apply.gender.male\')}', Female: '{f:translate(key: \'frontend.apply.gender.female\')}'}" /> + <f:form.validationResults for="applyData.gender"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-firstName"><f:translate key="frontend.apply.first_name" /></label> + <f:form.textfield property="firstName" id="apply-firstName" /> + <f:form.validationResults for="applyData.firstName"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-lastName"><f:translate key="frontend.apply.last_name" /></label> + <f:form.textfield property="lastName" id="apply-lastName" /> + <f:form.validationResults for="applyData.lastName"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-street"><f:translate key="frontend.apply.street" /></label> + <f:form.textfield property="street" id="apply-street" /> + <f:form.validationResults for="applyData.street"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-city"><f:translate key="frontend.apply.city" /></label> + <f:form.textfield property="city" id="apply-city" /> + <f:form.validationResults for="applyData.city"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-zip"><f:translate key="frontend.apply.zip" /></label> + <f:form.textfield property="zip" id="apply-zip" /> + <f:form.validationResults for="applyData.zip"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-country"><f:translate key="frontend.apply.country" /></label> + <f:form.textfield property="country" id="apply-country" /> + <f:form.validationResults for="applyData.country"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-nationality"><f:translate key="frontend.apply.nationality" /></label> + <f:form.textfield property="nationality" id="apply-nationality" /> + <f:form.validationResults for="applyData.nationality"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-education"><f:translate key="frontend.apply.education" /></label> + <f:form.textfield property="education" id="apply-education" /> + <f:form.validationResults for="applyData.education"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-birthDate"><f:translate key="frontend.apply.birthDate" /></label> + <f:form.textfield property="birthDate" id="apply-birthDate" /> + <f:form.validationResults for="applyData.birthDate"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-phone"><f:translate key="frontend.apply.phone" /></label> + <f:form.textfield property="phone" id="apply-phone" /> + <f:form.validationResults for="applyData.phone"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-mobile"><f:translate key="frontend.apply.mobile" /></label> + <f:form.textfield property="mobile" id="apply-mobile" /> + <f:form.validationResults for="applyData.mobile"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-email"><f:translate key="frontend.apply.email" /></label> + <f:form.textfield type="email" property="email" id="apply-email" data="{}" /> + <f:form.validationResults for="applyData.email"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-cover-letter"><f:translate key="frontend.apply.cover_letter" /></label> + <label for="apply-cover-letter"> + <f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions} + </label> + <f:form.upload multiple="true" property="coverLetter" id="apply-cover-letter" additionalAttributes="{accept: '{allowedMimeTypes}'}" /> + <f:for each="{uploadedFiles.coverLetter}" as="file"> + <div class="sg-jobs-uploaded-file"> + <span class="filename">{file.name}</span> + <a href="#" filetype="coverLetter" class="remove-file">(remove)</a> </div> </f:for> - </f:form.validationResults> - <br /> - <label for="apply-cover-letter"><f:translate key="frontend.apply.cover_letter" /></label> - <br/> - <label for="apply-cover-letter"><f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}</label> - <f:form.upload multiple="true" property="coverLetter" id="apply-cover-letter" additionalAttributes="{accept: '{allowedMimeTypes}'}" /> - <f:for each="{uploadedFiles.coverLetter}" as="file"> - <div class="sg-jobs-uploaded-file"> - <span class="filename">{file.name}</span> - <a href="#" filetype="coverLetter" class="remove-file">(remove)</a> - </div> - </f:for> - <f:form.validationResults for="applyData.coverLetter"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} + <f:form.validationResults for="applyData.coverLetter"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-cv"><f:translate key="frontend.apply.cv" /></label> + <label for="apply-cover-letter"> + <f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}</label> + <f:form.upload multiple="true" property="cv" id="apply-cv" additionalAttributes="{accept: '{allowedMimeTypes}'}" /> + <f:for each="{uploadedFiles.cv}" as="file"> + <div class="sg-jobs-uploaded-file"> + <span class="filename">{file.name}</span> + <a href="#" filetype="cv" class="remove-file">(remove)</a> </div> </f:for> - </f:form.validationResults> - <br /> - <label for="apply-cv"><f:translate key="frontend.apply.cv" /></label> - <br/> - <label for="apply-cover-letter"><f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}</label> - <f:form.upload multiple="true" property="cv" id="apply-cv" additionalAttributes="{accept: '{allowedMimeTypes}'}" /> - <f:for each="{uploadedFiles.cv}" as="file"> - <div class="sg-jobs-uploaded-file"> - <span class="filename">{file.name}</span> - <a href="#" filetype="cv" class="remove-file">(remove)</a> - </div> - </f:for> - <f:form.validationResults for="applyData.cv"> - <f:for each="{validationResults.errors}" as="error"> - <div class="sg-jobs-validation-error"> - {error.message} + <f:form.validationResults for="applyData.cv"> + <f:for each="{validationResults.errors}" as="error"> + <div class="sg-jobs-validation-error"> + {error.message} + </div> + </f:for> + </f:form.validationResults> + </p> + + <p> + <label for="apply-certificates"><f:translate key="frontend.apply.certificates" /></label> + <label for="apply-cover-letter"> + <f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}</label> + <f:form.upload multiple="true" property="certificates" id="apply-certificates" additionalAttributes="{accept: '{allowedMimeTypes}'}" /> + <f:for each="{uploadedFiles.certificates}" as="file"> + <div class="sg-jobs-uploaded-file"> + <span class="filename">{file.name}</span> + <a href="#" filetype="certificates" class="remove-file">(remove)</a> </div> </f:for> - </f:form.validationResults> - <br /> - <label for="apply-certificates"><f:translate key="frontend.apply.certificates" /></label> - <br/> - <label for="apply-cover-letter"><f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}</label> - <f:form.upload multiple="true" property="certificates" id="apply-certificates" additionalAttributes="{accept: '{allowedMimeTypes}'}" /> - <f:for each="{uploadedFiles.certificates}" as="file"> - <div class="sg-jobs-uploaded-file"> - <span class="filename">{file.name}</span> - <a href="#" filetype="certificates" class="remove-file">(remove)</a> - </div> - </f:for> - <br /> - <label for="apply-message"><f:translate key="frontend.apply.message" /></label> - <f:form.textarea property="message" id="apply-message" class="" /> - <br /> - <f:form.submit value="{f:translate(key:'frontend.applyNow')}" /> + </p> + + <p> + <label for="apply-message"><f:translate key="frontend.apply.message" /></label> + <f:form.textarea property="message" id="apply-message" /> + </p> + + <p> + <f:form.submit value="{f:translate(key:'frontend.applyNow')}" /> + </p> </f:form> </f:section>