Skip to content
Snippets Groups Projects
JoblistController.php 13.1 KiB
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\SgMail\Service\MailTemplateService;
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
 */
class JoblistController extends ActionController {
	/**
	 * @var \SGalinski\SgJobs\Domain\Repository\CompanyRepository
	private $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() {
		$recordPageId = $this->configurationManager->getConfiguration(
			ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
		)['persistence']['storagePid'];
		$this->assignFilterValues($recordPageId);

		// get all jobs for the next root page
		$jobs = $this->jobRepository->findJobs($recordPageId);
		$this->view->assign('jobs', $jobs);
	}
	 * Renders the application form with an optional job
	public function applyFormAction(JobApplication $applyData = NULL) {
		if ($this->request->getOriginalRequest()) {
			$uploadedFiles = $this->request->getOriginalRequest()->getArguments()['uploadedFiles'];
			$this->view->assign('uploadedFiles', $uploadedFiles);
		}
		$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);
		$this->view->assign('jobApplication', $applyData);
	 * Saves the application send by the applyFormAction
	 *
	 * @param JobApplication $applyData
	public function applyAction(JobApplication $applyData) {
			$this->submitApplicationFiles($GLOBALS['TSFE']->fe_user->id, $applyData);

			/** @noinspection PhpMethodParametersCountMismatchInspection */
			$mailService = $this->objectManager->get(
				MailTemplateService::class, 'application_mail', 'sg_jobs',
				$this->getApplicationMailMarkers((array) $applyData)
			);
			$mailService->setIgnoreMailQueue(TRUE);
			$mailService->setToAddresses($this->settings['applicationEmail']);

			$mailService->sendEmail();
			// possible errors, because of wrong mails (maybe log that somewhere? Does this makes sense?)
	/**
	 * Pre-apply action setup, configures model-property mapping and handles file upload
	 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException
	 * @throws \Exception
		try {
			$this->handleFileUpload('coverLetter');
			$this->handleFileUpload('cv');
			$this->handleFileUpload('certificates');
		} catch (\Exception $e) {
			// possible errors, because of wrong mails
			// @TODO output them in some way?
		}

		$propertyMappingConfiguration = $this->arguments->getArgument('applyData')->getPropertyMappingConfiguration();
		$propertyMappingConfiguration->forProperty('coverLetter')->allowAllProperties();
		$propertyMappingConfiguration->forProperty('cv')->allowAllProperties();
		$propertyMappingConfiguration->forProperty('certificates')->allowAllProperties();
		$uploadedFiles = $this->getExistingApplicationFiles($GLOBALS['TSFE']->fe_user->id);

		$this->request->setArgument('uploadedFiles', $uploadedFiles);
	 * Assign filter values
	 *
	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);

		$functions = $this->jobRepository->getAllFunctions($rootPageId);
		$this->view->assign('functions', $functions);
	}

	 * Returns the application mail markers
	 *
	 * @param array $applyData
	 * @return array
	 */
	private function getApplicationMailMarkers(array $applyData = []): array {
		return [
			'jobtitle' => $applyData['jobTitle'],
			'salutation' => $applyData['salutation'],
			'firstname' => $applyData['firstName'],
			'lastname' => $applyData['lastName'],
			'street' => $applyData['street'],
			'city' => $applyData['city'],
			'country' => $applyData['country'],
			'phone' => $applyData['phone'],
			'mobile' => $applyData['mobile'],
			'email' => $applyData['email'],
			'message' => $applyData['message']
		];
	 * @param string $folder
	 * @return \TYPO3\CMS\Core\Resource\File[]
	 * @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
	 * @throws \Exception
	 * @throws \InvalidArgumentException
	private function getExistingFiles($folder): array {
		$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
		$resourceFactory = $objectManager->get(ResourceFactory::class);
		$storage = $resourceFactory->getStorageObject(1);
		$folderObject = $storage->getFolder('/Extension/' . $folder);
		return $storage->getFilesInFolder($folderObject);
	 * @param string $folder
	 * @throws \Exception
	private function getExistingApplicationFiles($folder): array {
		$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 string $folder
	 * @param JobApplication $applicationData
	 * @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
	private function submitApplicationFiles($folder, JobApplication $applicationData) {
		$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
		$resourceFactory = $objectManager->get(ResourceFactory::class);

		$newName = date('Ymd-His') . '_' . $applicationData->getFirstName();
		$sourceFolder = $storage->getFolder('/Extension/temp/' . $folder);
		$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);
		$sourceFolder = $storage->getFolder('/Extension/temp/' . $newName);
		if (!$storage->hasFolder('/Extension/JobApplication/')) {
			$storage->createFolder('/Extension/JobApplication/');
		$targetFolder = $storage->getFolder('/Extension/JobApplication/');
		$applicationFile = $storage->createFile($newName . '.csv', $sourceFolder);
		$applicationFilePath = str_replace('/', '', $storage->getConfiguration()['basePath']) .
			$applicationFile->getIdentifier();
		$this->writeApplicationFile($applicationData, $applicationFilePath, $fileNames);

	 * Writes the application files
	 *
	 * @param JobApplication $data
	 * @param string $filePath
	 * @param array $fileNames
	 * @throws \RuntimeException
	private function writeApplicationFile(JobApplication $data, $filePath, $fileNames) {
		$certificateNames = '';
		/** @var array[][] $fileNames */
		if (isset($fileNames['certificates'])) {
			foreach ($fileNames['certificates'] as $certificateName) {
				$certificatesArr[] = $certificateName;
			}
			$certificateNames = implode($certificatesArr, ', ');
			$data->getFirstName(),
			$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+');
			fputcsv($file, $dataToInsertArr);
			fclose($file);
		} catch (\RuntimeException $exception) {
			throw new \RuntimeException($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,
		];
	/**
	 * @param string $fieldName
	 * @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 = ''): array {
		$data = [];
		$namespace = key($_FILES);
		$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
		$resourceFactory = $objectManager->get(ResourceFactory::class);
		$storage = $resourceFactory->getStorageObject(1);
		if (!$storage->hasFolder('/Extension/temp/' . $applicationId . '/' . $fieldName)) {
			$storage->createFolder('/Extension/temp/' . $applicationId . '/' . $fieldName);
		$targetFalDirectory = '1:/Extension/temp/' . $applicationId . '/' . $fieldName;

		// 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->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();

		$uploadedFiles = [];
		foreach ((array) $result['upload'] as $files) {
			/** @var array $files */
			foreach ($files as $file) {
				$uploadedFiles[] = $file;
			}

		return $uploadedFiles;