• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CPS-IT / personio-jobs / 15388375997

02 Jun 2025 09:09AM UTC coverage: 3.654% (+0.04%) from 3.61%
15388375997

push

github

web-flow
Merge pull request #228 from CPS-IT/task/drop-v11

[!!!][TASK] Drop support for TYPO3 v11.5

0 of 8 new or added lines in 5 files covered. (0.0%)

6 existing lines in 5 files now uncovered.

27 of 739 relevant lines covered (3.65%)

0.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Classes/Domain/Factory/SchemaFactory.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the TYPO3 CMS extension "personio_jobs".
7
 *
8
 * Copyright (C) 2023 Elias Häußler <e.haeussler@familie-redlich.de>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace CPSIT\Typo3PersonioJobs\Domain\Factory;
25

26
use Brotkrueml\Schema\Model\Type\JobPosting;
27
use Brotkrueml\Schema\Model\Type\Organization;
28
use Brotkrueml\Schema\Model\Type\Place;
29
use Brotkrueml\Schema\Type\TypeFactory;
30
use CPSIT\Typo3PersonioJobs\Domain\Model\Job;
31
use CPSIT\Typo3PersonioJobs\Enums\Job\EmploymentType;
32
use CPSIT\Typo3PersonioJobs\Enums\Job\Schedule;
33
use CPSIT\Typo3PersonioJobs\Enums\Schema\EmploymentType as EmploymentTypeSchema;
34
use CPSIT\Typo3PersonioJobs\Event\EnrichJobPostingSchemaEvent;
35
use CPSIT\Typo3PersonioJobs\Exception\ExtensionNotLoadedException;
36
use CPSIT\Typo3PersonioJobs\Service\PersonioApiService;
37
use CPSIT\Typo3PersonioJobs\Utility\FrontendUtility;
38
use Psr\EventDispatcher\EventDispatcherInterface;
39
use TYPO3\CMS\Core\Information\Typo3Version;
40
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
41
use TYPO3\CMS\Core\Utility\GeneralUtility;
42
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
43

44
/**
45
 * SchemaFactory
46
 *
47
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
48
 * @license GPL-2.0-or-later
49
 */
50
final readonly class SchemaFactory
51
{
52
    public function __construct(
×
53
        private PersonioApiService $personioApiService,
54
        private ContentObjectRenderer $contentObjectRenderer,
55
        private EventDispatcherInterface $eventDispatcher,
UNCOV
56
    ) {}
×
57

58
    /**
59
     * @throws ExtensionNotLoadedException
60
     */
61
    public function createJobPosting(Job $job): JobPosting
×
62
    {
63
        // Throw exception if schema extension is not installed
64
        if (!ExtensionManagementUtility::isLoaded('schema')) {
×
65
            throw ExtensionNotLoadedException::create('schema');
×
66
        }
67

68
        $serverRequest = FrontendUtility::getServerRequest();
×
69
        $organizationType = $this->createOrganization($job);
×
70
        $placeType = $this->createPlace($job);
×
71

72
        // Create job posting
NEW
73
        $jobPosting = GeneralUtility::makeInstance(TypeFactory::class)->create('JobPosting');
×
UNCOV
74
        \assert($jobPosting instanceof JobPosting);
×
75

76
        $jobPosting
×
77
            ->setProperty('datePosted', ($job->getCreateDate() ?? new \DateTime())->format('Y-m-d'))
×
78
            ->setProperty('employmentType', $this->decorateEmploymentType($job))
×
79
            ->setProperty('hiringOrganization', $organizationType)
×
80
            ->setProperty('jobLocation', $placeType)
×
81
            ->setProperty('occupationalCategory', $job->getOccupationCategory())
×
82
            ->setProperty('title', $job->getName())
×
83
            ->setProperty('description', $this->decorateDescription($job))
×
84
            ->setProperty('url', (string)$serverRequest->getUri())
×
85
            ->setProperty('sameAs', (string)$this->personioApiService->getJobUrl($job))
×
86
        ;
×
87

88
        $this->eventDispatcher->dispatch(new EnrichJobPostingSchemaEvent($job, $jobPosting));
×
89

90
        return $jobPosting;
×
91
    }
92

93
    private function createOrganization(Job $job): Organization
×
94
    {
95
        /** @var Organization $organization */
96
        $organization = TypeFactory::createType('Organization')
×
97
            ->setProperty('name', $job->getSubcompany())
×
98
            ->setProperty('address', $job->getOffice())
×
99
        ;
×
100

101
        return $organization;
×
102
    }
103

104
    private function createPlace(Job $job): Place
×
105
    {
106
        /** @var Place $place */
107
        $place = TypeFactory::createType('Place')
×
108
            ->setProperty('address', $job->getOffice())
×
109
        ;
×
110

111
        return $place;
×
112
    }
113

114
    /**
115
     * @return value-of<EmploymentTypeSchema>|list<value-of<EmploymentTypeSchema>>
116
     * @see https://developers.google.com/search/docs/appearance/structured-data/job-posting#job-posting-definition
117
     */
118
    private function decorateEmploymentType(Job $job): string|array
×
119
    {
120
        $employmentType = EmploymentType::tryFrom($job->getEmploymentType());
×
121
        $schedule = Schedule::tryFrom($job->getSchedule());
×
122

123
        if ($employmentType === null && $schedule === null) {
×
124
            return EmploymentTypeSchema::Other->value;
×
125
        }
126

127
        if ($employmentType === EmploymentType::Intern) {
×
128
            return EmploymentTypeSchema::Intern->value;
×
129
        }
130

131
        return match ($schedule) {
×
132
            Schedule::FullTime => EmploymentTypeSchema::FullTime->value,
×
133
            Schedule::PartTime => EmploymentTypeSchema::PartTime->value,
×
134
            Schedule::FullOrPartTime => [EmploymentTypeSchema::FullTime->value, EmploymentTypeSchema::PartTime->value],
×
135
            null => EmploymentTypeSchema::Other->value,
×
136
        };
×
137
    }
138

139
    private function decorateDescription(Job $job): string
×
140
    {
141
        $description = '';
×
142

143
        foreach ($job->getJobDescriptions() as $jobDescription) {
×
144
            $rawJobDescription = $jobDescription->getBodytext();
×
145
            $description .= $rawJobDescription . ' ';
×
146
        }
147

148
        if ((new Typo3Version())->getMajorVersion() >= 12) {
×
149
            // https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/12.0/Breaking-96520-EnforceNon-emptyConfigurationInCObjparseFunc.html
150
            $parsedDescription = $this->contentObjectRenderer->parseFunc($description, null, '< lib.parseFunc_RTE');
×
151
        } else {
152
            /* @phpstan-ignore-next-line argument.type (Only relevant for legacy TYPO3 versions) */
153
            $parsedDescription = $this->contentObjectRenderer->parseFunc($description, [], '< lib.parseFunc_RTE');
×
154
        }
155

156
        return $parsedDescription;
×
157
    }
158
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc