src/App/Entity/RecurrentJob.php line 57

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use App\Command\ResetRecurrentJobsFreshnessDate;
  4. use App\Controller\ActivitytrackingController;
  5. use App\Entity\ContentDistribution\AgenturFuerArbeit\AfaProfession;
  6. use App\Entity\ContentDistribution\AgenturFuerArbeit\DestatisEconomicSector;
  7. use App\Entity\ContentDistribution\RecurrentJobContentDistributionValue;
  8. use App\Entity\ExternalPartner\ExternalPartner;
  9. use App\Entity\ExternalPartner\IntegratedExternalPartnerCustomer;
  10. use App\Entity\ExternalPartner\IntegratedExternalPartnerCustomerQuota;
  11. use App\Entity\ExternalPartner\RecurrentJobAdditionalInfo;
  12. use App\Entity\Membership\RecurrentJobBooking;
  13. use App\Entity\OccupationalFieldsAndProfessionsSearch\OccupationalFieldsAndProfessionsSearchMergedResultset;
  14. use App\Entity\OccupationalFieldsAndProfessionsSearch\OccupationalFieldsAndProfessionsSearchResultset;
  15. use App\Entity\Profile\JoboffererProfile;
  16. use App\Service\DestatisEconomicSectorService;
  17. use App\Service\MailService;
  18. use App\Service\OccupationalFieldCapabilitiesService;
  19. use App\Service\OccupationalFieldsAndProfessionsSearchService;
  20. use App\Utility\DateTimeUtility;
  21. use App\Utility\GenderNeutralizer;
  22. use App\Utility\GuidUtility;
  23. use App\Utility\ReflectionHelper;
  24. use App\Utility\TextCleaner;
  25. use App\Utility\UrlHelper;
  26. use App\Validator\Constraint as AppAssert;
  27. use App\Value\PossibleAvailabilitiesValue;
  28. use DateTime;
  29. use Doctrine\Common\Collections\ArrayCollection;
  30. use Doctrine\Common\Collections\Collection;
  31. use Doctrine\ORM\Mapping as ORM;
  32. use Exception;
  33. use InvalidArgumentException;
  34. use JanusHercules\ExtendedApplicationQuestionnaire\Domain\Entity\ExtendedApplicationQuestion;
  35. use JanusHercules\ExternalApplicationQuestions\Domain\Entity\SoftgardenApplicationJobInformation;
  36. use JanusHercules\IntegratedExternalPartnerCustomers\Domain\Entity\WeclappContractItem;
  37. use JanusHercules\Membership\Domain\Entity\FlexMembershipRecurrentJobSlot;
  38. use Symfony\Component\Validator\Constraints as Assert;
  39. use Symfony\Component\Validator\Constraints\Count;
  40. use Symfony\Component\Validator\Exception\ValidationFailedException;
  41. use Symfony\Component\Validator\Validation;
  42. /**
  43. * @ORM\Entity(repositoryClass="App\Repository\RecurrentJobRepository")
  44. *
  45. * @ORM\Table(
  46. * name="recurrent_jobs",
  47. * indexes={
  48. *
  49. * @ORM\Index(name="status_idx", columns={"status"}),
  50. * @ORM\Index(name="freshness_date_idx", columns={"freshness_date"})
  51. * }
  52. * )
  53. */
  54. class RecurrentJob extends AbstractJob
  55. {
  56. public const EMPLOYMENT_TYPE_ONCE = 0;
  57. public const EMPLOYMENT_TYPE_HELP = 1;
  58. public const EMPLOYMENT_TYPE_PART_TIME = 2;
  59. public const EMPLOYMENT_TYPE_FULL_TIME = 3;
  60. public const EMPLOYMENT_TYPE_UNDEFINED = 4;
  61. public const MAX_FRESHNESS_AGE_FOR_GOOGLE_JOBS = 60;
  62. public const DEFAULT_ADDITIONAL_SEARCHTERM_RANGE = 3;
  63. public const STARTOPTION_IMMEDIATELY = 0;
  64. public const STARTOPTION_DATE = 1;
  65. public const STARTOPTION_NOT_SPECIFIED = 2;
  66. public const STATUS_DRAFT = 0;
  67. public const STATUS_ACTIVE = 1;
  68. public const STATUS_INACTIVE = 2;
  69. // LEGACY STATUS_DEACTIVATED_BECAUSE_OF_QUOTA
  70. public const STATUS_DEACTIVATED_BECAUSE_OF_QUOTA = 3;
  71. public const CAREER_LEVEL_TRAINEE = 0;
  72. public const CAREER_LEVEL_ASSISTANT = 1;
  73. public const CAREER_LEVEL_EXPERT = 2;
  74. public const CAREER_LEVEL_EXECUTIVE = 3;
  75. public const EXPERIENCE_NONE = WantedJob::EXPERIENCE_NONE;
  76. public const EXPERIENCE_MORE_THAN_ONE_YEAR = WantedJob::EXPERIENCE_MORE_THAN_ONE_YEAR;
  77. public const EXPERIENCE_MORE_THAN_THREE_YEARS = WantedJob::EXPERIENCE_MORE_THAN_THREE_YEARS;
  78. public const EXPERIENCE_MORE_THAN_FIVE_YEARS = WantedJob::EXPERIENCE_MORE_THAN_FIVE_YEARS;
  79. public const APPLICATION_TYPE_CONVERSATION_MESSAGE = 0;
  80. public const APPLICATION_TYPE_FORWARDING = 1;
  81. public const APPLICATION_TYPE_EXTENDED_APPLICATION = 2;
  82. public const POSSIBLE_EMPLOYMENT_TYPES = [
  83. self::EMPLOYMENT_TYPE_ONCE,
  84. self::EMPLOYMENT_TYPE_HELP,
  85. self::EMPLOYMENT_TYPE_PART_TIME,
  86. self::EMPLOYMENT_TYPE_FULL_TIME
  87. ];
  88. public const POSSIBLE_CAREER_LEVELS = [
  89. self::CAREER_LEVEL_TRAINEE,
  90. self::CAREER_LEVEL_ASSISTANT,
  91. self::CAREER_LEVEL_EXPERT,
  92. self::CAREER_LEVEL_EXECUTIVE
  93. ];
  94. public const POSSIBLE_EXPERIENCE_VALUES_FOR_SELECTION = [
  95. self::EXPERIENCE_NONE,
  96. self::EXPERIENCE_MORE_THAN_ONE_YEAR,
  97. self::EXPERIENCE_MORE_THAN_THREE_YEARS
  98. ];
  99. public const POSSIBLE_APPLICATION_TYPES = [
  100. self::APPLICATION_TYPE_CONVERSATION_MESSAGE,
  101. self::APPLICATION_TYPE_FORWARDING,
  102. self::APPLICATION_TYPE_EXTENDED_APPLICATION
  103. ];
  104. public const POSSIBLE_EXPERIENCE_VALUES_FOR_SELECTION_WITH_TRANSLATION_MAPPING = [
  105. self::EXPERIENCE_NONE => 'recurrent_jobs.new_page.experience_none',
  106. self::EXPERIENCE_MORE_THAN_ONE_YEAR => 'recurrent_jobs.new_page.experience_more_than_one_year',
  107. self::EXPERIENCE_MORE_THAN_THREE_YEARS => 'recurrent_jobs.new_page.experience_more_than_three_years'
  108. ];
  109. public const POSSIBLE_EMPLOYMENT_TYPE_AVAILABLE_FOR_SELECTION_WITH_TRANSLATION_MAPPING = [
  110. 'recurrent_jobs.new_page.employment_types.once' => self::EMPLOYMENT_TYPE_ONCE,
  111. 'recurrent_jobs.new_page.employment_types.help' => self::EMPLOYMENT_TYPE_HELP,
  112. 'recurrent_jobs.new_page.employment_types.part_time' => self::EMPLOYMENT_TYPE_PART_TIME,
  113. 'recurrent_jobs.new_page.employment_types.full_time' => self::EMPLOYMENT_TYPE_FULL_TIME
  114. ];
  115. public const POSSIBLE_CAREER_LEVEL_AVAILABLE_FOR_SELECTION_WITH_TRANSLATION_MAPPING = [
  116. 'recurrent_jobs.new_page.career_level.trainee' => self::CAREER_LEVEL_TRAINEE,
  117. 'recurrent_jobs.new_page.career_level.assistant' => self::CAREER_LEVEL_ASSISTANT,
  118. 'recurrent_jobs.new_page.career_level.expert' => self::CAREER_LEVEL_EXPERT,
  119. 'recurrent_jobs.new_page.career_level.executive' => self::CAREER_LEVEL_EXECUTIVE
  120. ];
  121. public const POSSIBLE_APPLICATION_TYPE_AVAILABLE_FOR_SELECTION_WITH_TRANSLATION_MAPPING = [
  122. 'recurrent_jobs.new_page.application_type.conversation_message' => self::APPLICATION_TYPE_CONVERSATION_MESSAGE,
  123. 'recurrent_jobs.new_page.application_type.forwarding' => self::APPLICATION_TYPE_FORWARDING,
  124. 'recurrent_jobs.new_page.application_type.extended_application' => self::APPLICATION_TYPE_EXTENDED_APPLICATION
  125. ];
  126. /**
  127. * @throws Exception
  128. */
  129. public function __construct()
  130. {
  131. $this->joboffererProfile = null;
  132. $this->quota = null;
  133. $this->requiredExperience = RecurrentJob::EXPERIENCE_NONE;
  134. $this->occupationalFields = new ArrayCollection();
  135. $this->occupationalFieldCapabilityValues = new ArrayCollection();
  136. $this->additionalZipcodes = new ArrayCollection();
  137. $this->relevantOccupationalFields = new ArrayCollection();
  138. $this->relevantProfessions = new ArrayCollection();
  139. $this->title = '';
  140. $this->description = '';
  141. $this->createdAt = DateTimeUtility::createDateTimeUtc();
  142. $this->freshnessDate = DateTimeUtility::createDateTimeUtc();
  143. foreach (PossibleAvailabilitiesValue::WEEKDAYS as $weekday) {
  144. foreach (PossibleAvailabilitiesValue::TIMES_OF_DAY as $timeOfDay) {
  145. $attrName = 'isRequiredOn' . $weekday . $timeOfDay;
  146. $this->$attrName = false;
  147. }
  148. }
  149. $this->employmentTypes = [self::EMPLOYMENT_TYPE_PART_TIME, self::EMPLOYMENT_TYPE_FULL_TIME, self::EMPLOYMENT_TYPE_ONCE, self::EMPLOYMENT_TYPE_HELP];
  150. $this->additionalDescription = '';
  151. $this->careerLevels = [self::CAREER_LEVEL_ASSISTANT, self::CAREER_LEVEL_EXPERT];
  152. $this->isImmediateAppointment = true;
  153. $this->status = self::STATUS_DRAFT;
  154. $this->numberOfCreatedJobradarMatches = 0;
  155. $this->contentDistributionValues = new ArrayCollection();
  156. $this->externalPartnerRecurrentJobAdditionalInfos = new ArrayCollection();
  157. $this->numberOfFreshnessDateResets = 0;
  158. $this->automatedConversationMessagesMailings = new ArrayCollection();
  159. $this->additionalZipcodes = new ArrayCollection();
  160. $this->booking = null;
  161. $this->zipcode = null;
  162. $this->address = null;
  163. $this->city = null;
  164. $this->applicationType = null;
  165. $this->selfdescription = null;
  166. $this->profilePhoto = null;
  167. $this->headerImage = null;
  168. $this->isPlus = false;
  169. $this->afaProfessionId = null;
  170. $this->destatisEconomicSector = null;
  171. $this->superiorSalary = null;
  172. $this->concludisApplicationFormSetups = new ArrayCollection();
  173. $this->extendedApplicationQuestions = new ArrayCollection();
  174. $this->softgardenApplicationJobInformation = null;
  175. $this->selfServiceTrafficCampaigns = new ArrayCollection();
  176. $this->selfServiceTrafficCampaignBookings = new ArrayCollection();
  177. $this->slot = null;
  178. $this->duplicatedFromRecurrentJobId = null;
  179. }
  180. /**
  181. * @var string
  182. *
  183. * @ORM\GeneratedValue(strategy="CUSTOM")
  184. *
  185. * @ORM\CustomIdGenerator(class="App\Utility\DatabaseIdGenerator")
  186. *
  187. * @ORM\Column(name="id", type="guid")
  188. *
  189. * @ORM\Id
  190. */
  191. protected $id;
  192. public function setId(string $id): void
  193. {
  194. GuidUtility::validOrThrow($id);
  195. $this->id = $id;
  196. }
  197. /**
  198. * A callable for Elastica to decide if an object is to be indexed in ES.
  199. */
  200. public function isFindable()
  201. {
  202. return $this->isActive();
  203. }
  204. /**
  205. * @var ?DateTime
  206. *
  207. * @ORM\Column(name="created_at", type="datetime", nullable=true)
  208. */
  209. protected $createdAt;
  210. public function setCreatedAt(DateTime $createdAt): void
  211. {
  212. $this->createdAt = $createdAt;
  213. }
  214. public function getCreatedAt(): ?DateTime
  215. {
  216. return $this->createdAt;
  217. }
  218. /**
  219. * @var ?DateTime
  220. *
  221. * @ORM\Column(name="edited_at", type="datetime", nullable=true)
  222. */
  223. protected $editedAt;
  224. public function getEditedAt(): ?DateTime
  225. {
  226. return $this->editedAt;
  227. }
  228. public function setEditedAt(?DateTime $editedAt): void
  229. {
  230. $this->editedAt = $editedAt;
  231. }
  232. /**
  233. * The freshness date is used to influence the ranking of recurrent jobs in searches.
  234. *
  235. * The more recent the freshness date, the more likely it is that a recurrent job ends up at the beginning of a
  236. * result set. Freshness date is updated whenever the owning jobofferer uses the site
  237. * (@see ActivitytrackingController for more info), and through a cronjob that "boosts" recurrent jobs where the
  238. * freshness date is 30 days or older (@see ResetRecurrentJobsFreshnessDate for more info).
  239. *
  240. * @var DateTime
  241. *
  242. * @ORM\Column(name="freshness_date", type="datetime", nullable=false)
  243. */
  244. protected $freshnessDate;
  245. public function getFreshnessDate(): DateTime
  246. {
  247. return $this->freshnessDate;
  248. }
  249. public function setFreshnessDate(DateTime $freshnessDate)
  250. {
  251. $this->freshnessDate = $freshnessDate;
  252. }
  253. /**
  254. * @var int
  255. *
  256. * @ORM\Column(name="number_of_freshness_date_resets", type="integer", nullable=false)
  257. */
  258. protected $numberOfFreshnessDateResets;
  259. public function getNumberOfFreshnessDateResets(): int
  260. {
  261. return $this->numberOfFreshnessDateResets;
  262. }
  263. public function setNumberOfFreshnessDateResets(int $numberOfFreshnessDateResets)
  264. {
  265. $this->numberOfFreshnessDateResets = $numberOfFreshnessDateResets;
  266. }
  267. /**
  268. * @ORM\ManyToOne(targetEntity="App\Entity\Profile\JoboffererProfile", inversedBy="recurrentJobs", cascade={"persist"})
  269. *
  270. * @ORM\JoinColumn(name="jobofferer_profiles_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
  271. */
  272. protected ?JoboffererProfile $joboffererProfile;
  273. public function getJoboffererProfile(): ?JoboffererProfile
  274. {
  275. return $this->joboffererProfile;
  276. }
  277. public function setJoboffererProfile(JoboffererProfile $joboffererProfile): void
  278. {
  279. $this->joboffererProfile = $joboffererProfile;
  280. }
  281. /**
  282. * @var Collection|OccupationalField[]
  283. *
  284. * @ORM\ManyToMany(targetEntity="App\Entity\OccupationalField", inversedBy="recurrentJobs", cascade={"persist"})
  285. *
  286. * @ORM\JoinTable(
  287. * name="recurrent_jobs_occupational_fields",
  288. * joinColumns={
  289. *
  290. * @ORM\JoinColumn(name="recurrent_jobs_id", referencedColumnName="id", onDelete="CASCADE")
  291. * },
  292. * inverseJoinColumns={
  293. * @ORM\JoinColumn(name="occupational_field_id", referencedColumnName="id", onDelete="CASCADE")
  294. * }
  295. * )
  296. *
  297. * @Assert\Type("\Doctrine\Common\Collections\Collection")
  298. */
  299. protected $occupationalFields;
  300. /** @return Collection|OccupationalField[] */
  301. public function getOccupationalFields(): Collection
  302. {
  303. return $this->occupationalFields;
  304. }
  305. public function setOccupationalFields(Collection $occupationalFields): void
  306. {
  307. $this->occupationalFields = $occupationalFields;
  308. }
  309. /**
  310. * @return Collection|OccupationalField[]
  311. */
  312. public function getLegacyOccupationalFields(): Collection
  313. {
  314. $legacyOccupationalFields = [];
  315. foreach ($this->occupationalFields as $occupationalField) {
  316. if ($occupationalField->getId() <= OccupationalField::OCCUPATIONAL_FIELD_ID_REINIGUNGSKRAFT) {
  317. $legacyOccupationalFields[] = $occupationalField;
  318. }
  319. }
  320. return new ArrayCollection($legacyOccupationalFields);
  321. }
  322. /**
  323. * @var int
  324. *
  325. * @ORM\Column(name="required_experience", type="smallint", nullable=false)
  326. *
  327. * @Assert\Type("int")
  328. */
  329. protected $requiredExperience;
  330. /**
  331. * @var string|null
  332. *
  333. * @ORM\Column(name="title", type="string", length=128, nullable=true)
  334. *
  335. * @Assert\Type("string")
  336. *
  337. * @Assert\Length(
  338. * min = 0,
  339. * max = 128,
  340. * )
  341. */
  342. protected $title;
  343. public function setTitle(?string $title)
  344. {
  345. $this->title = mb_substr($title, 0, 128);
  346. }
  347. public function getTitle(): ?string
  348. {
  349. return $this->title;
  350. }
  351. public function getForDisplay(): string
  352. {
  353. if (is_null($this->getTitle()) || trim($this->getTitle()) === '') {
  354. return "Wir suchen #when einen {$this->getOccupationalFieldSearchterm()} (m/w/d)";
  355. } else {
  356. return $this->getTitle();
  357. }
  358. }
  359. /**
  360. * @var string
  361. *
  362. * @ORM\Column(name="description", type="text", length=10000, nullable=true)
  363. *
  364. * @Assert\Type("string")
  365. */
  366. protected $description;
  367. public function setDescription(?string $description)
  368. {
  369. if (is_null($description)) {
  370. $this->description = null;
  371. } else {
  372. $this->description = mb_substr($description, 0, 10000);
  373. }
  374. }
  375. public function getDescription(): ?string
  376. {
  377. return TextCleaner::removeSpecialCharacters($this->description);
  378. }
  379. /** @throws Exception */
  380. protected function setIsRequiredOnWeekday(string $weekday, bool $val)
  381. {
  382. if (!in_array($weekday, PossibleAvailabilitiesValue::WEEKDAYS)) {
  383. throw new Exception('Unknown availability weekday "' . $weekday . '"');
  384. }
  385. foreach (PossibleAvailabilitiesValue::TIMES_OF_DAY as $timeOfDay) {
  386. $attr = 'isRequiredOn' . $weekday . $timeOfDay;
  387. $this->$attr = $val;
  388. }
  389. }
  390. /** @throws Exception */
  391. protected function isRequiredOnWeekday(string $weekday): bool
  392. {
  393. if (!in_array($weekday, PossibleAvailabilitiesValue::WEEKDAYS)) {
  394. throw new Exception('Unknown availability weekday "' . $weekday . '"');
  395. }
  396. $result = false;
  397. foreach (PossibleAvailabilitiesValue::TIMES_OF_DAY as $timeOfDay) {
  398. $attr = 'isRequiredOn' . $weekday . $timeOfDay;
  399. if ($this->$attr === true) {
  400. $result = true;
  401. }
  402. }
  403. return $result;
  404. }
  405. /** @throws Exception */
  406. public function setIsRequiredOnMonday(bool $val)
  407. {
  408. $this->setIsRequiredOnWeekday('Monday', $val);
  409. }
  410. /** @throws Exception */
  411. public function isRequiredOnMonday(): bool
  412. {
  413. return $this->isRequiredOnWeekday('Monday');
  414. }
  415. /** @throws Exception */
  416. public function setIsRequiredOnTuesday(bool $val)
  417. {
  418. $this->setIsRequiredOnWeekday('Tuesday', $val);
  419. }
  420. /** @throws Exception */
  421. public function isRequiredOnTuesday(): bool
  422. {
  423. return $this->isRequiredOnWeekday('Tuesday');
  424. }
  425. /** @throws Exception */
  426. public function setIsRequiredOnWednesday(bool $val)
  427. {
  428. $this->setIsRequiredOnWeekday('Wednesday', $val);
  429. }
  430. /** @throws Exception */
  431. public function isRequiredOnWednesday(): bool
  432. {
  433. return $this->isRequiredOnWeekday('Wednesday');
  434. }
  435. /** @throws Exception */
  436. public function setIsRequiredOnThursday(bool $val)
  437. {
  438. $this->setIsRequiredOnWeekday('Thursday', $val);
  439. }
  440. /** @throws Exception */
  441. public function isRequiredOnThursday(): bool
  442. {
  443. return $this->isRequiredOnWeekday('Thursday');
  444. }
  445. /** @throws Exception */
  446. public function setIsRequiredOnFriday(bool $val)
  447. {
  448. $this->setIsRequiredOnWeekday('Friday', $val);
  449. }
  450. /** @throws Exception */
  451. public function isRequiredOnFriday(): bool
  452. {
  453. return $this->isRequiredOnWeekday('Friday');
  454. }
  455. /** @throws Exception */
  456. public function setIsRequiredOnSaturday(bool $val)
  457. {
  458. $this->setIsRequiredOnWeekday('Saturday', $val);
  459. }
  460. /** @throws Exception */
  461. public function isRequiredOnSaturday(): bool
  462. {
  463. return $this->isRequiredOnWeekday('Saturday');
  464. }
  465. /** @throws Exception */
  466. public function setIsRequiredOnSunday(bool $val)
  467. {
  468. $this->setIsRequiredOnWeekday('Sunday', $val);
  469. }
  470. /** @throws Exception */
  471. public function isRequiredOnSunday(): bool
  472. {
  473. return $this->isRequiredOnWeekday('Sunday');
  474. }
  475. /** @throws Exception */
  476. public function getRequiredWeekdays(): array
  477. {
  478. $result = [];
  479. foreach (PossibleAvailabilitiesValue::WEEKDAYS as $weekday) {
  480. if ($this->isRequiredOnWeekday($weekday)) {
  481. $result[] = $weekday;
  482. }
  483. }
  484. return $result;
  485. }
  486. /**
  487. * @var bool
  488. *
  489. * @ORM\Column(name="is_required_on_monday_morning", type="boolean", nullable=false)
  490. */
  491. protected $isRequiredOnMondayMorning;
  492. public function setIsRequiredOnMondayMorning(bool $isRequiredOnMondayMorning)
  493. {
  494. $this->isRequiredOnMondayMorning = $isRequiredOnMondayMorning;
  495. }
  496. public function isRequiredOnMondayMorning(): bool
  497. {
  498. return $this->isRequiredOnMondayMorning;
  499. }
  500. /**
  501. * @var bool
  502. *
  503. * @ORM\Column(name="is_required_on_monday_noon", type="boolean", nullable=false)
  504. */
  505. protected $isRequiredOnMondayNoon;
  506. public function setIsRequiredOnMondayNoon(bool $isRequiredOnMondayNoon)
  507. {
  508. $this->isRequiredOnMondayNoon = $isRequiredOnMondayNoon;
  509. }
  510. public function isRequiredOnMondayNoon(): bool
  511. {
  512. return $this->isRequiredOnMondayNoon;
  513. }
  514. /**
  515. * @var bool
  516. *
  517. * @ORM\Column(name="is_required_on_monday_evening", type="boolean", nullable=false)
  518. */
  519. protected $isRequiredOnMondayEvening;
  520. public function setIsRequiredOnMondayEvening(bool $isRequiredOnMondayEvening)
  521. {
  522. $this->isRequiredOnMondayEvening = $isRequiredOnMondayEvening;
  523. }
  524. public function isRequiredOnMondayEvening(): bool
  525. {
  526. return $this->isRequiredOnMondayEvening;
  527. }
  528. /**
  529. * @var bool
  530. *
  531. * @ORM\Column(name="is_required_on_monday_night", type="boolean", nullable=false)
  532. */
  533. protected $isRequiredOnMondayNight;
  534. public function setIsRequiredOnMondayNight(bool $isRequiredOnMondayNight)
  535. {
  536. $this->isRequiredOnMondayNight = $isRequiredOnMondayNight;
  537. }
  538. public function isRequiredOnMondayNight(): bool
  539. {
  540. return $this->isRequiredOnMondayNight;
  541. }
  542. /**
  543. * @var bool
  544. *
  545. * @ORM\Column(name="is_required_on_tuesday_morning", type="boolean", nullable=false)
  546. */
  547. protected $isRequiredOnTuesdayMorning;
  548. public function setIsRequiredOnTuesdayMorning(bool $isRequiredOnTuesdayMorning)
  549. {
  550. $this->isRequiredOnTuesdayMorning = $isRequiredOnTuesdayMorning;
  551. }
  552. public function isRequiredOnTuesdayMorning(): bool
  553. {
  554. return $this->isRequiredOnTuesdayMorning;
  555. }
  556. /**
  557. * @var bool
  558. *
  559. * @ORM\Column(name="is_required_on_tuesday_noon", type="boolean", nullable=false)
  560. */
  561. protected $isRequiredOnTuesdayNoon;
  562. public function setIsRequiredOnTuesdayNoon(bool $isRequiredOnTuesdayNoon)
  563. {
  564. $this->isRequiredOnTuesdayNoon = $isRequiredOnTuesdayNoon;
  565. }
  566. public function isRequiredOnTuesdayNoon(): bool
  567. {
  568. return $this->isRequiredOnTuesdayNoon;
  569. }
  570. /**
  571. * @var bool
  572. *
  573. * @ORM\Column(name="is_required_on_tuesday_evening", type="boolean", nullable=false)
  574. */
  575. protected $isRequiredOnTuesdayEvening;
  576. public function setIsRequiredOnTuesdayEvening(bool $isRequiredOnTuesdayEvening)
  577. {
  578. $this->isRequiredOnTuesdayEvening = $isRequiredOnTuesdayEvening;
  579. }
  580. public function isRequiredOnTuesdayEvening(): bool
  581. {
  582. return $this->isRequiredOnTuesdayEvening;
  583. }
  584. /**
  585. * @var bool
  586. *
  587. * @ORM\Column(name="is_required_on_tuesday_night", type="boolean", nullable=false)
  588. */
  589. protected $isRequiredOnTuesdayNight;
  590. public function setIsRequiredOnTuesdayNight(bool $isRequiredOnTuesdayNight)
  591. {
  592. $this->isRequiredOnTuesdayNight = $isRequiredOnTuesdayNight;
  593. }
  594. public function isRequiredOnTuesdayNight(): bool
  595. {
  596. return $this->isRequiredOnTuesdayNight;
  597. }
  598. /**
  599. * @var bool
  600. *
  601. * @ORM\Column(name="is_required_on_wednesday_morning", type="boolean", nullable=false)
  602. */
  603. protected $isRequiredOnWednesdayMorning;
  604. public function setIsRequiredOnWednesdayMorning(bool $isRequiredOnWednesdayMorning)
  605. {
  606. $this->isRequiredOnWednesdayMorning = $isRequiredOnWednesdayMorning;
  607. }
  608. public function isRequiredOnWednesdayMorning(): bool
  609. {
  610. return $this->isRequiredOnWednesdayMorning;
  611. }
  612. /**
  613. * @var bool
  614. *
  615. * @ORM\Column(name="is_required_on_wednesday_noon", type="boolean", nullable=false)
  616. */
  617. protected $isRequiredOnWednesdayNoon;
  618. public function setIsRequiredOnWednesdayNoon(bool $isRequiredOnWednesdayNoon)
  619. {
  620. $this->isRequiredOnWednesdayNoon = $isRequiredOnWednesdayNoon;
  621. }
  622. public function isRequiredOnWednesdayNoon(): bool
  623. {
  624. return $this->isRequiredOnWednesdayNoon;
  625. }
  626. /**
  627. * @var bool
  628. *
  629. * @ORM\Column(name="is_required_on_wednesday_evening", type="boolean", nullable=false)
  630. */
  631. protected $isRequiredOnWednesdayEvening;
  632. public function setIsRequiredOnWednesdayEvening(bool $isRequiredOnWednesdayEvening)
  633. {
  634. $this->isRequiredOnWednesdayEvening = $isRequiredOnWednesdayEvening;
  635. }
  636. public function isRequiredOnWednesdayEvening(): bool
  637. {
  638. return $this->isRequiredOnWednesdayEvening;
  639. }
  640. /**
  641. * @var bool
  642. *
  643. * @ORM\Column(name="is_required_on_wednesday_night", type="boolean", nullable=false)
  644. */
  645. protected $isRequiredOnWednesdayNight;
  646. public function setIsRequiredOnWednesdayNight(bool $isRequiredOnWednesdayNight)
  647. {
  648. $this->isRequiredOnWednesdayNight = $isRequiredOnWednesdayNight;
  649. }
  650. public function isRequiredOnWednesdayNight(): bool
  651. {
  652. return $this->isRequiredOnWednesdayNight;
  653. }
  654. /**
  655. * @var bool
  656. *
  657. * @ORM\Column(name="is_required_on_thursday_morning", type="boolean", nullable=false)
  658. */
  659. protected $isRequiredOnThursdayMorning;
  660. public function setIsRequiredOnThursdayMorning(bool $isRequiredOnThursdayMorning)
  661. {
  662. $this->isRequiredOnThursdayMorning = $isRequiredOnThursdayMorning;
  663. }
  664. public function isRequiredOnThursdayMorning(): bool
  665. {
  666. return $this->isRequiredOnThursdayMorning;
  667. }
  668. /**
  669. * @var bool
  670. *
  671. * @ORM\Column(name="is_required_on_thursday_noon", type="boolean", nullable=false)
  672. */
  673. protected $isRequiredOnThursdayNoon;
  674. public function setIsRequiredOnThursdayNoon(bool $isRequiredOnThursdayNoon)
  675. {
  676. $this->isRequiredOnThursdayNoon = $isRequiredOnThursdayNoon;
  677. }
  678. public function isRequiredOnThursdayNoon(): bool
  679. {
  680. return $this->isRequiredOnThursdayNoon;
  681. }
  682. /**
  683. * @var bool
  684. *
  685. * @ORM\Column(name="is_required_on_thursday_evening", type="boolean", nullable=false)
  686. */
  687. protected $isRequiredOnThursdayEvening;
  688. public function setIsRequiredOnThursdayEvening(bool $isRequiredOnThursdayEvening)
  689. {
  690. $this->isRequiredOnThursdayEvening = $isRequiredOnThursdayEvening;
  691. }
  692. public function isRequiredOnThursdayEvening(): bool
  693. {
  694. return $this->isRequiredOnThursdayEvening;
  695. }
  696. /**
  697. * @var bool
  698. *
  699. * @ORM\Column(name="is_required_on_thursday_night", type="boolean", nullable=false)
  700. */
  701. protected $isRequiredOnThursdayNight;
  702. public function setIsRequiredOnThursdayNight(bool $isRequiredOnThursdayNight)
  703. {
  704. $this->isRequiredOnThursdayNight = $isRequiredOnThursdayNight;
  705. }
  706. public function isRequiredOnThursdayNight(): bool
  707. {
  708. return $this->isRequiredOnThursdayNight;
  709. }
  710. /**
  711. * @var bool
  712. *
  713. * @ORM\Column(name="is_required_on_friday_morning", type="boolean", nullable=false)
  714. */
  715. protected $isRequiredOnFridayMorning;
  716. public function setIsRequiredOnFridayMorning(bool $isRequiredOnFridayMorning)
  717. {
  718. $this->isRequiredOnFridayMorning = $isRequiredOnFridayMorning;
  719. }
  720. public function isRequiredOnFridayMorning(): bool
  721. {
  722. return $this->isRequiredOnFridayMorning;
  723. }
  724. /**
  725. * @var bool
  726. *
  727. * @ORM\Column(name="is_required_on_friday_noon", type="boolean", nullable=false)
  728. */
  729. protected $isRequiredOnFridayNoon;
  730. public function setIsRequiredOnFridayNoon(bool $isRequiredOnFridayNoon)
  731. {
  732. $this->isRequiredOnFridayNoon = $isRequiredOnFridayNoon;
  733. }
  734. public function isRequiredOnFridayNoon(): bool
  735. {
  736. return $this->isRequiredOnFridayNoon;
  737. }
  738. /**
  739. * @var bool
  740. *
  741. * @ORM\Column(name="is_required_on_friday_evening", type="boolean", nullable=false)
  742. */
  743. protected $isRequiredOnFridayEvening;
  744. public function setIsRequiredOnFridayEvening(bool $isRequiredOnFridayEvening)
  745. {
  746. $this->isRequiredOnFridayEvening = $isRequiredOnFridayEvening;
  747. }
  748. public function isRequiredOnFridayEvening(): bool
  749. {
  750. return $this->isRequiredOnFridayEvening;
  751. }
  752. /**
  753. * @var bool
  754. *
  755. * @ORM\Column(name="is_required_on_friday_night", type="boolean", nullable=false)
  756. */
  757. protected $isRequiredOnFridayNight;
  758. public function setIsRequiredOnFridayNight(bool $isRequiredOnFridayNight)
  759. {
  760. $this->isRequiredOnFridayNight = $isRequiredOnFridayNight;
  761. }
  762. public function isRequiredOnFridayNight(): bool
  763. {
  764. return $this->isRequiredOnFridayNight;
  765. }
  766. /**
  767. * @var bool
  768. *
  769. * @ORM\Column(name="is_required_on_saturday_morning", type="boolean", nullable=false)
  770. */
  771. protected $isRequiredOnSaturdayMorning;
  772. public function setIsRequiredOnSaturdayMorning(bool $isRequiredOnSaturdayMorning)
  773. {
  774. $this->isRequiredOnSaturdayMorning = $isRequiredOnSaturdayMorning;
  775. }
  776. public function isRequiredOnSaturdayMorning(): bool
  777. {
  778. return $this->isRequiredOnSaturdayMorning;
  779. }
  780. /**
  781. * @var bool
  782. *
  783. * @ORM\Column(name="is_required_on_saturday_noon", type="boolean", nullable=false)
  784. */
  785. protected $isRequiredOnSaturdayNoon;
  786. public function setIsRequiredOnSaturdayNoon(bool $isRequiredOnSaturdayNoon)
  787. {
  788. $this->isRequiredOnSaturdayNoon = $isRequiredOnSaturdayNoon;
  789. }
  790. public function isRequiredOnSaturdayNoon(): bool
  791. {
  792. return $this->isRequiredOnSaturdayNoon;
  793. }
  794. /**
  795. * @var bool
  796. *
  797. * @ORM\Column(name="is_required_on_saturday_evening", type="boolean", nullable=false)
  798. */
  799. protected $isRequiredOnSaturdayEvening;
  800. public function setIsRequiredOnSaturdayEvening(bool $isRequiredOnSaturdayEvening)
  801. {
  802. $this->isRequiredOnSaturdayEvening = $isRequiredOnSaturdayEvening;
  803. }
  804. public function isRequiredOnSaturdayEvening(): bool
  805. {
  806. return $this->isRequiredOnSaturdayEvening;
  807. }
  808. /**
  809. * @var bool
  810. *
  811. * @ORM\Column(name="is_required_on_saturday_night", type="boolean", nullable=false)
  812. */
  813. protected $isRequiredOnSaturdayNight;
  814. public function setIsRequiredOnSaturdayNight(bool $isRequiredOnSaturdayNight)
  815. {
  816. $this->isRequiredOnSaturdayNight = $isRequiredOnSaturdayNight;
  817. }
  818. public function isRequiredOnSaturdayNight(): bool
  819. {
  820. return $this->isRequiredOnSaturdayNight;
  821. }
  822. /**
  823. * @var bool
  824. *
  825. * @ORM\Column(name="is_required_on_sunday_morning", type="boolean", nullable=false)
  826. */
  827. protected $isRequiredOnSundayMorning;
  828. public function setIsRequiredOnSundayMorning(bool $isRequiredOnSundayMorning)
  829. {
  830. $this->isRequiredOnSundayMorning = $isRequiredOnSundayMorning;
  831. }
  832. public function isRequiredOnSundayMorning(): bool
  833. {
  834. return $this->isRequiredOnSundayMorning;
  835. }
  836. /**
  837. * @var bool
  838. *
  839. * @ORM\Column(name="is_required_on_sunday_noon", type="boolean", nullable=false)
  840. */
  841. protected $isRequiredOnSundayNoon;
  842. public function setIsRequiredOnSundayNoon(bool $isRequiredOnSundayNoon)
  843. {
  844. $this->isRequiredOnSundayNoon = $isRequiredOnSundayNoon;
  845. }
  846. public function isRequiredOnSundayNoon(): bool
  847. {
  848. return $this->isRequiredOnSundayNoon;
  849. }
  850. /**
  851. * @var bool
  852. *
  853. * @ORM\Column(name="is_required_on_sunday_evening", type="boolean", nullable=false)
  854. */
  855. protected $isRequiredOnSundayEvening;
  856. public function setIsRequiredOnSundayEvening(bool $isRequiredOnSundayEvening)
  857. {
  858. $this->isRequiredOnSundayEvening = $isRequiredOnSundayEvening;
  859. }
  860. public function isRequiredOnSundayEvening(): bool
  861. {
  862. return $this->isRequiredOnSundayEvening;
  863. }
  864. /**
  865. * @var bool
  866. *
  867. * @ORM\Column(name="is_required_on_sunday_night", type="boolean", nullable=false)
  868. */
  869. protected $isRequiredOnSundayNight;
  870. public function setIsRequiredOnSundayNight(bool $isRequiredOnSundayNight)
  871. {
  872. $this->isRequiredOnSundayNight = $isRequiredOnSundayNight;
  873. }
  874. public function isRequiredOnSundayNight(): bool
  875. {
  876. return $this->isRequiredOnSundayNight;
  877. }
  878. public function getRequiredExperience(): int
  879. {
  880. return $this->requiredExperience;
  881. }
  882. public function setRequiredExperience(int $requiredExperience)
  883. {
  884. $this->requiredExperience = $requiredExperience;
  885. }
  886. public function getBusinessName(): string
  887. {
  888. return (string)$this->getJoboffererProfile()->getBusinessName();
  889. }
  890. public function hasNegativeReviews(): bool
  891. {
  892. return $this->getJoboffererProfile()->hasNegativeReviews();
  893. }
  894. public function numberOfNegativeReviews(): bool
  895. {
  896. return $this->getJoboffererProfile()->numberOfNegativeReviews();
  897. }
  898. /**
  899. * @var Collection|RecurrentJobAdditionalZipcode[]
  900. *
  901. * @ORM\OneToMany(targetEntity="\App\Entity\RecurrentJobAdditionalZipcode", mappedBy="recurrentJob", cascade={"persist", "remove"})
  902. */
  903. protected $additionalZipcodes;
  904. /* Note that if you add an additional zipcode here, only the
  905. * DB representation is changed; the additionalZipcodes field
  906. * in ES is not updated automatically, and must be updated
  907. * explicitly through a FOS\ElasticaBundle\Persister\ObjectPersister.
  908. */
  909. public function addAdditionalZipcode(string $zipcode): void
  910. {
  911. foreach ($this->additionalZipcodes as $additionalZipcode) {
  912. if ($additionalZipcode->getZipcode() === $zipcode) {
  913. return;
  914. }
  915. }
  916. $this->additionalZipcodes->add(new RecurrentJobAdditionalZipcode($this, $zipcode));
  917. }
  918. /** @return array|string[] */
  919. public function getAdditionalZipcodesAsStringArray(): array
  920. {
  921. $zipcodes = [];
  922. foreach ($this->additionalZipcodes as $additionalZipcode) {
  923. $zipcodes[] = $additionalZipcode->getZipcode();
  924. }
  925. return $zipcodes;
  926. }
  927. public function hasAdditionalZipcodes(): bool
  928. {
  929. return sizeof($this->additionalZipcodes) > 0;
  930. }
  931. public function isLocked(): bool
  932. {
  933. return $this->getJoboffererProfile()->isLocked();
  934. }
  935. // There would not really be a need for this method anymore, but we keep it because the ElasticSearch index is
  936. // configured to use the lastseenAt attribute; instead of switching ES to use freshnessDate, we keep the method and
  937. // thus avoid an ES reindex.
  938. public function getLastseenAt(): DateTime
  939. {
  940. return $this->getFreshnessDate();
  941. }
  942. // The following are helper functions for FOSElastica to get data in the format it needs
  943. public function getIndexableIsRequiredOnWeekdayTimeOfDay(): array
  944. {
  945. $result = [];
  946. foreach (PossibleAvailabilitiesValue::WEEKDAYS as $weekday) {
  947. foreach (PossibleAvailabilitiesValue::TIMES_OF_DAY as $timeOfDay) {
  948. $attrName = 'isRequiredOn' . $weekday . $timeOfDay;
  949. $result[$attrName] = $this->$attrName;
  950. }
  951. }
  952. return $result;
  953. }
  954. public function getIndexableNumberOfRequiredTimesForTimeOfDay(): array
  955. {
  956. $result = [];
  957. foreach (PossibleAvailabilitiesValue::TIMES_OF_DAY as $timeOfDay) {
  958. $result[$timeOfDay] = 0;
  959. }
  960. foreach (PossibleAvailabilitiesValue::WEEKDAYS as $weekday) {
  961. foreach (PossibleAvailabilitiesValue::TIMES_OF_DAY as $timeOfDay) {
  962. $attrName = 'isRequiredOn' . $weekday . $timeOfDay;
  963. if ($this->$attrName === true) {
  964. ++$result[$timeOfDay];
  965. }
  966. }
  967. }
  968. return $result;
  969. }
  970. public function __toString()
  971. {
  972. return (string)$this->getId();
  973. }
  974. public function getPausedSince(): ?DateTime
  975. {
  976. return $this->joboffererProfile->getPausedSince();
  977. }
  978. public function isPaused(): bool
  979. {
  980. return $this->joboffererProfile->isPaused();
  981. }
  982. /**
  983. * @var int|null
  984. *
  985. * @ORM\Column(name="employment_type", type="smallint", nullable=true)
  986. */
  987. protected $employmentType;
  988. public function getLegacyEmploymentType(): ?int
  989. {
  990. return $this->employmentType;
  991. }
  992. /**
  993. * @var array
  994. *
  995. * @ORM\Column(name="career_levels", type="array", nullable=false)
  996. *
  997. * @Count(min = 1, minMessage = "Mindestens eine Option muss gewählt werden")
  998. */
  999. protected $careerLevels;
  1000. /**
  1001. * @param array|int[] $careerLevels
  1002. *
  1003. * @throws Exception
  1004. */
  1005. public function setCareerLevels(array $careerLevels)
  1006. {
  1007. foreach ($careerLevels as $careerLevel) {
  1008. if (!is_int($careerLevel) || $careerLevel < self::CAREER_LEVEL_TRAINEE || $careerLevel > self::CAREER_LEVEL_EXECUTIVE) {
  1009. throw new Exception('Invalid value ' . $careerLevel . ' for careerLevel.');
  1010. }
  1011. }
  1012. $this->careerLevels = $careerLevels;
  1013. }
  1014. /**
  1015. * @return array|int[]
  1016. */
  1017. public function getCareerLevels(): array
  1018. {
  1019. if (!is_array($this->careerLevels)) {
  1020. return [];
  1021. }
  1022. return array_values($this->careerLevels);
  1023. }
  1024. /**
  1025. * @var array
  1026. *
  1027. * @ORM\Column(name="employment_types", type="array", nullable=false)
  1028. *
  1029. * @Count(min = 1, minMessage = "Mindestens eine Option muss gewählt werden")
  1030. */
  1031. protected $employmentTypes;
  1032. /** @throws Exception */
  1033. public function setEmploymentTypes(array $employmentTypes)
  1034. {
  1035. foreach ($employmentTypes as $employmentType) {
  1036. if (!is_int($employmentType) || $employmentType < self::EMPLOYMENT_TYPE_ONCE || $employmentType > self::EMPLOYMENT_TYPE_UNDEFINED) {
  1037. throw new Exception('Invalid value ' . $employmentType . ' for employmentType.');
  1038. }
  1039. }
  1040. $this->employmentTypes = array_values($employmentTypes);
  1041. }
  1042. public function getEmploymentTypes(): array
  1043. {
  1044. if (!is_array($this->employmentTypes)) {
  1045. return [];
  1046. }
  1047. return array_values($this->employmentTypes);
  1048. }
  1049. /**
  1050. * @var string|null
  1051. *
  1052. * @ORM\Column(name="additional_description", type="text", length=10000, nullable=true)
  1053. *
  1054. * @Assert\Type("string")
  1055. *
  1056. * @Assert\Length(
  1057. * min = 0,
  1058. * max = 3000,
  1059. * )
  1060. */
  1061. protected $additionalDescription;
  1062. public function setAdditionalDescription(?string $additionalDescription)
  1063. {
  1064. if (is_null($additionalDescription)) {
  1065. $this->additionalDescription = null;
  1066. } else {
  1067. $this->additionalDescription = mb_substr($additionalDescription, 0, 10000);
  1068. }
  1069. }
  1070. public function getAdditionalDescription(): ?string
  1071. {
  1072. return TextCleaner::removeSpecialCharacters($this->additionalDescription);
  1073. }
  1074. /**
  1075. * @var string|null
  1076. *
  1077. * @ORM\Column(name="occupational_field_capabilities_description", type="text", length=10000, nullable=true)
  1078. *
  1079. * @Assert\Type("string")
  1080. *
  1081. * @Assert\Length(
  1082. * min = 0,
  1083. * max = 3000,
  1084. * )
  1085. */
  1086. protected $occupationalFieldCapabilitiesDescription;
  1087. public function setOccupationalFieldCapabilitiesDescription(?string $occupationalFieldCapabilitiesDescription)
  1088. {
  1089. if (is_null($occupationalFieldCapabilitiesDescription)) {
  1090. $this->occupationalFieldCapabilitiesDescription = null;
  1091. } else {
  1092. $this->occupationalFieldCapabilitiesDescription = mb_substr($occupationalFieldCapabilitiesDescription, 0, 10000);
  1093. }
  1094. }
  1095. public function getOccupationalFieldCapabilitiesDescription(): ?string
  1096. {
  1097. return TextCleaner::removeSpecialCharacters($this->occupationalFieldCapabilitiesDescription);
  1098. }
  1099. /**
  1100. * @var string|null
  1101. *
  1102. * @ORM\Column(name="contact_name", type="string", length=128, nullable=true)
  1103. *
  1104. * @Assert\Length(
  1105. * min = 0,
  1106. * max = 50,
  1107. * )
  1108. */
  1109. protected $contactName;
  1110. public function setContactName(?string $contactName)
  1111. {
  1112. if (is_null($contactName)) {
  1113. $this->contactName = null;
  1114. } else {
  1115. $this->contactName = mb_substr($contactName, 0, 128);
  1116. }
  1117. }
  1118. public function getContactName(): ?string
  1119. {
  1120. return $this->contactName;
  1121. }
  1122. /**
  1123. * @var string|null
  1124. *
  1125. * @ORM\Column(name="contact_email", type="string", length=128, nullable=true)
  1126. *
  1127. * @Assert\Email(mode="strict")
  1128. */
  1129. protected $contactEmail;
  1130. public function setContactEmail(?string $contactEmail)
  1131. {
  1132. if (!is_null($contactEmail)) {
  1133. $contactEmail = mb_substr($contactEmail, 0, 128);
  1134. }
  1135. if (!is_null($contactEmail) && !MailService::emailAddressIsValidForMailer($contactEmail)) {
  1136. throw new InvalidArgumentException("E-mail $contactEmail is not valid for SwiftMailer.");
  1137. }
  1138. $this->contactEmail = $contactEmail;
  1139. }
  1140. public function getContactEmail(): ?string
  1141. {
  1142. if (is_null($this->contactEmail) && $this->getJoboffererProfile()) {
  1143. return $this->getJoboffererProfile()->getContactEmail();
  1144. } else {
  1145. return $this->contactEmail;
  1146. }
  1147. }
  1148. public function getContactEmailNonTransitive(): ?string
  1149. {
  1150. return $this->contactEmail;
  1151. }
  1152. /**
  1153. * @var string|null
  1154. *
  1155. * @ORM\Column(name="contact_phone", type="string", length=128, nullable=true)
  1156. *
  1157. * @Assert\Regex(pattern="/^[ +\-\/0-9]{6,30}$/")
  1158. */
  1159. protected $contactPhone;
  1160. public function setContactPhone(?string $contactPhone)
  1161. {
  1162. if (!is_null($contactPhone)) {
  1163. $contactPhone = mb_substr($contactPhone, 0, 128);
  1164. }
  1165. $this->contactPhone = $contactPhone;
  1166. }
  1167. public function getContactPhone(): ?string
  1168. {
  1169. return $this->contactPhone;
  1170. }
  1171. /**
  1172. * @var DateTime|null
  1173. *
  1174. * @ORM\Column(name="appointment_date", type="datetime", nullable=true)
  1175. */
  1176. protected $appointmentDate;
  1177. public function setAppointmentDate(?DateTime $appointmentDate)
  1178. {
  1179. $this->appointmentDate = $appointmentDate;
  1180. }
  1181. public function getAppointmentDate(): ?DateTime
  1182. {
  1183. return $this->appointmentDate;
  1184. }
  1185. /**
  1186. * @var bool
  1187. *
  1188. * @ORM\Column(name="is_immediate_appointment", type="boolean", nullable=false)
  1189. */
  1190. protected $isImmediateAppointment;
  1191. public function setIsImmediateAppointment(bool $isImmediateAppointment)
  1192. {
  1193. $this->isImmediateAppointment = $isImmediateAppointment;
  1194. }
  1195. public function isImmediateAppointment(): bool
  1196. {
  1197. return $this->isImmediateAppointment;
  1198. }
  1199. /**
  1200. * @var Collection|RecurrentJobOccupationalFieldCapabilityValue[]
  1201. *
  1202. * @ORM\OneToMany(targetEntity="\App\Entity\RecurrentJobOccupationalFieldCapabilityValue", mappedBy="recurrentJob", cascade={"persist", "remove"})
  1203. */
  1204. protected $occupationalFieldCapabilityValues;
  1205. public function getOccupationalFieldCapabilityValues(): Collection
  1206. {
  1207. return $this->occupationalFieldCapabilityValues;
  1208. }
  1209. public function setOccupationalFieldCapabilityValues(Collection $occupationalFieldCapabilityValues): void
  1210. {
  1211. $this->occupationalFieldCapabilityValues = $occupationalFieldCapabilityValues;
  1212. }
  1213. public function getAllOccupationalFieldIdsToCapabilityIdsToValuesSlim(): array
  1214. {
  1215. $result = [];
  1216. foreach (OccupationalFieldCapabilitiesService::CAPABILITY_IDS_BY_OCCUPATIONAL_FIELD_IDS as $occupationalFieldId => $capabilityIds) {
  1217. foreach ($capabilityIds as $capabilityId) {
  1218. $value = 0;
  1219. /** @var JobseekerOccupationalFieldCapabilityValue $occupationalFieldCapabilityValue */
  1220. foreach ($this->occupationalFieldCapabilityValues as $occupationalFieldCapabilityValue) {
  1221. if ($occupationalFieldCapabilityValue->getCapabilityId() === $capabilityId) {
  1222. $value = $occupationalFieldCapabilityValue->getValue();
  1223. }
  1224. }
  1225. $result[$capabilityId] = $value;
  1226. }
  1227. }
  1228. return $result;
  1229. }
  1230. public function getAllOccupationalFieldIdsToCapabilityIdsToValuesSlimIncludeLegacy(): array
  1231. {
  1232. $result = [];
  1233. $capabilities = OccupationalFieldCapabilitiesService::CAPABILITY_IDS_BY_OCCUPATIONAL_FIELD_IDS;
  1234. array_push($capabilities[0], OccupationalFieldCapabilitiesService::CAPABILITY_ID_GENERAL_LEGACY);
  1235. foreach ($capabilities as $occupationalFieldId => $capabilityIds) {
  1236. foreach ($capabilityIds as $capabilityId) {
  1237. $value = 0;
  1238. /** @var JobseekerOccupationalFieldCapabilityValue $occupationalFieldCapabilityValue */
  1239. foreach ($this->occupationalFieldCapabilityValues as $occupationalFieldCapabilityValue) {
  1240. if ($occupationalFieldCapabilityValue->getCapabilityId() === $capabilityId) {
  1241. $value = $occupationalFieldCapabilityValue->getValue();
  1242. }
  1243. }
  1244. $result[$capabilityId] = $value;
  1245. }
  1246. }
  1247. return $result;
  1248. }
  1249. /**
  1250. * @var int
  1251. *
  1252. * @ORM\Column(name="status", type="smallint", nullable=false)
  1253. */
  1254. protected $status;
  1255. public function setStatus(int $status)
  1256. {
  1257. $this->status = $status;
  1258. }
  1259. public function getStatus(): int
  1260. {
  1261. return $this->status;
  1262. }
  1263. public function isDraft(): bool
  1264. {
  1265. return $this->status === self::STATUS_DRAFT;
  1266. }
  1267. public function isActive(): bool
  1268. {
  1269. return $this->status === self::STATUS_ACTIVE;
  1270. }
  1271. public function isInactive(): bool
  1272. {
  1273. return $this->status === self::STATUS_INACTIVE;
  1274. }
  1275. /**
  1276. * @var int
  1277. *
  1278. * @ORM\Column(name="career_level", type="smallint", nullable=true)
  1279. */
  1280. protected $careerLevel;
  1281. public function getLegacyCareerLevel(): ?int
  1282. {
  1283. return $this->careerLevel;
  1284. }
  1285. /**
  1286. * @ORM\Column(name="number_of_created_jobradar_matches", type="integer", nullable=false)
  1287. *
  1288. * Note how having this attribute is different from simply counting how many jobradar matches
  1289. * currently exist for this recurrent job. We need to actively count how many jobradar matches we have
  1290. * ever CREATED for this recurrent job, and not just look up how many currently exist.
  1291. *
  1292. * This is because there is a business rule that says that for recurrent jobs
  1293. * of jobofferers without a membership, we only want to create a maximum of 8
  1294. * jobradar matches. See method recurrentJobCannotCreateAnyMoreJobradarMatches below.
  1295. *
  1296. * If we would simply use the CURRENT number of jobradar matches that exist for a given recurrent job,
  1297. * then we would not be able to enforce this rule properly, because we would ignore jobradar matches
  1298. * that subsequently got deleted (e.g. because a jobseeker removed his wanted job or his account).
  1299. */
  1300. protected int $numberOfCreatedJobradarMatches;
  1301. public function setNumberOfCreatedJobradarMatches(
  1302. int $numberOfCreatedJobradarMatches
  1303. ): void {
  1304. $this->numberOfCreatedJobradarMatches = $numberOfCreatedJobradarMatches;
  1305. }
  1306. public function getNumberOfCreatedJobradarMatches(): int
  1307. {
  1308. return $this->numberOfCreatedJobradarMatches;
  1309. }
  1310. /**
  1311. * @var Collection|OccupationalField[] Those occupational fields where the title matched the searchterm
  1312. *
  1313. * @ORM\ManyToMany(targetEntity="App\Entity\OccupationalField", inversedBy="recurrentJobsForWhichImRelevant", cascade={"persist"})
  1314. *
  1315. * @ORM\JoinTable(
  1316. * name="recurrent_jobs_relevant_occupational_fields",
  1317. * joinColumns={
  1318. *
  1319. * @ORM\JoinColumn(name="recurrent_jobs_id", referencedColumnName="id", onDelete="CASCADE")
  1320. * },
  1321. * inverseJoinColumns={
  1322. * @ORM\JoinColumn(name="occupational_field_id", referencedColumnName="id", onDelete="CASCADE")
  1323. * }
  1324. * )
  1325. *
  1326. * @Assert\Type("\Doctrine\Common\Collections\Collection")
  1327. */
  1328. protected $relevantOccupationalFields;
  1329. public function setRelevantOccupationalFields(Collection $occupationalFields): void
  1330. {
  1331. $this->relevantOccupationalFields = $occupationalFields;
  1332. }
  1333. /** @return Collection|OccupationalField[] */
  1334. public function getRelevantOccupationalFields(): Collection
  1335. {
  1336. return $this->relevantOccupationalFields;
  1337. }
  1338. /**
  1339. * @var Collection|Profession[] Those professions where the name matched the searchterm
  1340. *
  1341. * @ORM\ManyToMany(targetEntity="App\Entity\Profession", inversedBy="recurrentJobsForWhichImRelevant", cascade={"persist"})
  1342. *
  1343. * @ORM\JoinTable(
  1344. * name="recurrent_jobs_relevant_professions",
  1345. * joinColumns={
  1346. *
  1347. * @ORM\JoinColumn(name="recurrent_jobs_id", referencedColumnName="id", onDelete="CASCADE")
  1348. * },
  1349. * inverseJoinColumns={
  1350. * @ORM\JoinColumn(name="profession_id", referencedColumnName="id", onDelete="CASCADE")
  1351. * }
  1352. * )
  1353. *
  1354. * @Assert\Type("\Doctrine\Common\Collections\Collection")
  1355. */
  1356. protected $relevantProfessions;
  1357. public function setRelevantProfessions(Collection $professions): void
  1358. {
  1359. $this->relevantProfessions = $professions;
  1360. }
  1361. /**
  1362. * @return Profession[]|Collection
  1363. */
  1364. public function getRelevantProfessions(): Collection
  1365. {
  1366. return $this->relevantProfessions;
  1367. }
  1368. /**
  1369. * @return Profession[]|Collection
  1370. */
  1371. public function getProfessions(): Collection
  1372. {
  1373. $professions = [];
  1374. foreach ($this->occupationalFields as $occupationalField) {
  1375. foreach ($occupationalField->getProfessions() as $profession) {
  1376. $professions[] = $profession;
  1377. }
  1378. }
  1379. return new ArrayCollection($professions);
  1380. }
  1381. /**
  1382. * @var string|null
  1383. *
  1384. * @ORM\Column(name="occupational_field_searchterm", type="string", length=1024, nullable=true)
  1385. *
  1386. * @AppAssert\LatinWord
  1387. *
  1388. * @AppAssert\XssSafe
  1389. */
  1390. protected $occupationalFieldSearchterm;
  1391. public function setOccupationalFieldSearchterm(?string $occupationalFieldSearchterm): void
  1392. {
  1393. if (is_null($occupationalFieldSearchterm)) {
  1394. $this->occupationalFieldSearchterm = null;
  1395. } else {
  1396. $this->occupationalFieldSearchterm = mb_substr($occupationalFieldSearchterm, 0, 1024);
  1397. }
  1398. }
  1399. public function getOccupationalFieldSearchterm(): string
  1400. {
  1401. $term = trim((string)$this->occupationalFieldSearchterm);
  1402. if (trim($term) === '') {
  1403. if (sizeof($this->getRelevantOccupationalFields()) > 0) {
  1404. return $this->getRelevantOccupationalFields()->first()->getTitle();
  1405. }
  1406. if (sizeof($this->getOccupationalFields()) > 0) {
  1407. return $this->getOccupationalFields()->first()->getTitle();
  1408. }
  1409. return '';
  1410. }
  1411. return $term;
  1412. }
  1413. /**
  1414. * @var string[]|null
  1415. *
  1416. * @ORM\Column(name="additional_occupational_field_searchterms", type="array", length=65536, nullable=true)
  1417. */
  1418. protected $additionalOccupationalFieldSearchterms;
  1419. /**
  1420. * @param string[]|null $additionalOccupationalFieldSearchterms
  1421. */
  1422. public function setAdditionalOccupationalFieldSearchterms(
  1423. ?array $additionalOccupationalFieldSearchterms,
  1424. int $additionalSearchtermRange = self::DEFAULT_ADDITIONAL_SEARCHTERM_RANGE
  1425. ): void {
  1426. if (is_null($additionalOccupationalFieldSearchterms)) {
  1427. $this->additionalOccupationalFieldSearchterms = null;
  1428. return;
  1429. }
  1430. if (sizeof($additionalOccupationalFieldSearchterms) > $additionalSearchtermRange) {
  1431. throw new InvalidArgumentException('A maximum of ' . $additionalSearchtermRange . ' entries allowed for $additionalOccupationalFieldSearchterms array, but got ' . sizeof($additionalOccupationalFieldSearchterms) . '.');
  1432. }
  1433. $validator = Validation::createValidator();
  1434. foreach ($additionalOccupationalFieldSearchterms as $key => $additionalOccupationalFieldSearchterm) {
  1435. $violations = $validator->validate($additionalOccupationalFieldSearchterm, [new AppAssert\LatinWord(), new AppAssert\XssSafe()]);
  1436. if ($violations->count() > 0) {
  1437. throw new ValidationFailedException($additionalOccupationalFieldSearchterm, $violations);
  1438. }
  1439. if (!is_string($additionalOccupationalFieldSearchterm)) {
  1440. throw new InvalidArgumentException('$additionalOccupationalFieldSearchterms array must only contains strings, but contained value of type "' . gettype($additionalOccupationalFieldSearchterm) . '" at key "' . $key . '".');
  1441. }
  1442. }
  1443. $this->additionalOccupationalFieldSearchterms = $additionalOccupationalFieldSearchterms;
  1444. }
  1445. /** @return string[] */
  1446. public function getAdditionalOccupationalFieldSearchterms(): array
  1447. {
  1448. if (is_null($this->additionalOccupationalFieldSearchterms)) {
  1449. return [];
  1450. } else {
  1451. return $this->additionalOccupationalFieldSearchterms;
  1452. }
  1453. }
  1454. public function getAdditionalOccupationalFieldSearchtermsForDisplay(): string
  1455. {
  1456. if (is_null($this->additionalOccupationalFieldSearchterms)) {
  1457. return '';
  1458. } else {
  1459. $additionalSearchtermsForDisplay = '';
  1460. $counter = 1;
  1461. foreach ($this->additionalOccupationalFieldSearchterms as $additionalOccupationalFieldSearchterm) {
  1462. $additionalSearchtermsForDisplay = $additionalSearchtermsForDisplay . GenderNeutralizer::neutralize(ucfirst($additionalOccupationalFieldSearchterm));
  1463. if ($counter < sizeof($this->additionalOccupationalFieldSearchterms)) {
  1464. $additionalSearchtermsForDisplay = $additionalSearchtermsForDisplay . ', ';
  1465. }
  1466. ++$counter;
  1467. }
  1468. return $additionalSearchtermsForDisplay;
  1469. }
  1470. }
  1471. public function getAllOccupationalFieldSearchtermsAsString(): string
  1472. {
  1473. $string = $this->getOccupationalFieldSearchterm();
  1474. foreach ($this->getAdditionalOccupationalFieldSearchterms() as $additionalOccupationalFieldSearchterm) {
  1475. $string .= ' ' . $additionalOccupationalFieldSearchterm;
  1476. }
  1477. return $string;
  1478. }
  1479. // The following are helper functions for FOSElastica to get data in the format it needs
  1480. public function getOccupationalFieldSearchtermForFulltextsearch(): string
  1481. {
  1482. $normalizedAdditionalOccupationalFieldSearchterms = [];
  1483. foreach ($this->getAdditionalOccupationalFieldSearchterms() as $additionalOccupationalFieldSearchterm) {
  1484. $normalizedAdditionalOccupationalFieldSearchterms[] = OccupationalFieldsAndProfessionsSearchService::normalizeSearchterm($additionalOccupationalFieldSearchterm);
  1485. }
  1486. $normalizedAdditionalOccupationalFieldSearchtermsString = implode(' ', $normalizedAdditionalOccupationalFieldSearchterms);
  1487. return trim(
  1488. OccupationalFieldsAndProfessionsSearchService::normalizeSearchterm($this->getOccupationalFieldSearchterm())
  1489. . ' '
  1490. . $normalizedAdditionalOccupationalFieldSearchtermsString
  1491. );
  1492. }
  1493. /** @return string[] */
  1494. public function getAllOccupationalFieldsTitlesForFulltextsearch(): array
  1495. {
  1496. $result = [];
  1497. $occupationalFields = $this->occupationalFields;
  1498. /** @var OccupationalField $occupationalField */
  1499. foreach ($occupationalFields as $occupationalField) {
  1500. $result[] = OccupationalFieldsAndProfessionsSearchService::normalizeText($occupationalField->getTitle());
  1501. }
  1502. return $result;
  1503. }
  1504. /** @return string[] */
  1505. public function getRelevantOccupationalFieldsTitlesForFulltextsearch(): array
  1506. {
  1507. $result = [];
  1508. $occupationalFields = $this->relevantOccupationalFields;
  1509. /** @var OccupationalField $occupationalField */
  1510. foreach ($occupationalFields as $occupationalField) {
  1511. $result[] = OccupationalFieldsAndProfessionsSearchService::normalizeText($occupationalField->getTitle());
  1512. }
  1513. return $result;
  1514. }
  1515. /** @return string[] */
  1516. public function getAllProfessionsTitlesForFulltextsearch(): array
  1517. {
  1518. $result = [];
  1519. $professions = $this->getProfessions();
  1520. /** @var Profession $profession */
  1521. foreach ($professions as $profession) {
  1522. $result[] = OccupationalFieldsAndProfessionsSearchService::normalizeText($profession->getTitle());
  1523. }
  1524. return $result;
  1525. }
  1526. /** @return string[] */
  1527. public function getRelevantProfessionsTitlesForFulltextsearch(): array
  1528. {
  1529. $result = [];
  1530. $professions = $this->relevantProfessions;
  1531. /** @var Profession $profession */
  1532. foreach ($professions as $profession) {
  1533. $result[] = OccupationalFieldsAndProfessionsSearchService::normalizeText($profession->getTitle());
  1534. }
  1535. return $result;
  1536. }
  1537. /**
  1538. * @var RecurrentJobContentDistributionValue|Collection
  1539. *
  1540. * @ORM\OneToMany(targetEntity="App\Entity\ContentDistribution\RecurrentJobContentDistributionValue", mappedBy="recurrentJob", cascade={"persist", "remove"})
  1541. */
  1542. protected $contentDistributionValues;
  1543. /**
  1544. * @return RecurrentJobContentDistributionValue[]|Collection
  1545. */
  1546. public function getContentDistributionValues()
  1547. {
  1548. return $this->contentDistributionValues;
  1549. }
  1550. /** @throws Exception */
  1551. public function setContentDistributionStringValue(string $name, ?string $stringValue): void
  1552. {
  1553. /** @var RecurrentJobContentDistributionValue $contentDistributionValue */
  1554. foreach ($this->contentDistributionValues as $contentDistributionValue) {
  1555. if ($contentDistributionValue->getName() === $name) {
  1556. $contentDistributionValue->setStringValue($stringValue);
  1557. return;
  1558. }
  1559. }
  1560. if (!is_null($stringValue)) {
  1561. $this->contentDistributionValues->add(
  1562. RecurrentJobContentDistributionValue::createWithStringValue($this, $name, $stringValue)
  1563. );
  1564. }
  1565. }
  1566. /** @throws Exception */
  1567. public function setContentDistributionFloatValue(string $name, ?float $floatValue): void
  1568. {
  1569. /** @var RecurrentJobContentDistributionValue $contentDistributionValue */
  1570. foreach ($this->contentDistributionValues as $key => $contentDistributionValue) {
  1571. if ($contentDistributionValue->getName() === $name) {
  1572. $contentDistributionValue->setFloatValue($floatValue);
  1573. return;
  1574. }
  1575. }
  1576. if (!is_null($floatValue)) {
  1577. $this->contentDistributionValues->add(
  1578. RecurrentJobContentDistributionValue::createWithFloatValue($this, $name, $floatValue)
  1579. );
  1580. }
  1581. }
  1582. /** @throws Exception */
  1583. public function setContentDistributionBoolValue(string $name, ?bool $boolValue): void
  1584. {
  1585. /** @var RecurrentJobContentDistributionValue $contentDistributionValue */
  1586. foreach ($this->contentDistributionValues as $key => $contentDistributionValue) {
  1587. if ($contentDistributionValue->getName() === $name) {
  1588. $contentDistributionValue->setBoolValue($boolValue);
  1589. return;
  1590. }
  1591. }
  1592. if (!is_null($boolValue)) {
  1593. $this->contentDistributionValues->add(
  1594. RecurrentJobContentDistributionValue::createWithBoolValue($this, $name, $boolValue)
  1595. );
  1596. }
  1597. }
  1598. /** @throws Exception */
  1599. public function setContentDistributionDateTimeValue(string $name, ?DateTime $dateTimeValue): void
  1600. {
  1601. /** @var RecurrentJobContentDistributionValue $contentDistributionValue */
  1602. foreach ($this->contentDistributionValues as $key => $contentDistributionValue) {
  1603. if ($contentDistributionValue->getName() === $name) {
  1604. $contentDistributionValue->setDateTimeValue($dateTimeValue);
  1605. return;
  1606. }
  1607. }
  1608. if (!is_null($dateTimeValue)) {
  1609. $this->contentDistributionValues->add(
  1610. RecurrentJobContentDistributionValue::createWithDatetimeValue($this, $name, $dateTimeValue)
  1611. );
  1612. }
  1613. }
  1614. public function belongsToExternalPartner(): bool
  1615. {
  1616. return !is_null($this->getJoboffererProfile()->getUser()->getExternalPartner());
  1617. }
  1618. public function getExternalPartner(): ?ExternalPartner
  1619. {
  1620. return $this->getJoboffererProfile()->getUser()->getExternalPartner();
  1621. }
  1622. /**
  1623. * @var RecurrentJobAdditionalInfo|Collection
  1624. *
  1625. * @ORM\OneToMany(targetEntity="App\Entity\ExternalPartner\RecurrentJobAdditionalInfo", mappedBy="recurrentJob", cascade={"persist", "remove"})
  1626. */
  1627. protected $externalPartnerRecurrentJobAdditionalInfos;
  1628. public function getExternalPartnerRecurrentJobAdditionalInfos(): array
  1629. {
  1630. $externalPartnerRecurrentJobInfoArray = [];
  1631. /** @var RecurrentJobAdditionalInfo $externalPartnerRecurrentJobAdditionalInfo */
  1632. foreach ($this->externalPartnerRecurrentJobAdditionalInfos as $externalPartnerRecurrentJobAdditionalInfo) {
  1633. $externalPartnerRecurrentJobInfoArray[] = $externalPartnerRecurrentJobAdditionalInfo;
  1634. }
  1635. return $externalPartnerRecurrentJobInfoArray;
  1636. }
  1637. public function getExternalPartnerRecurrentJobAdditionalInfoStringValueByName(string $infoName): ?string
  1638. {
  1639. /** @var RecurrentJobAdditionalInfo $externalPartnerRecurrentJobAdditionalInfo */
  1640. foreach ($this->externalPartnerRecurrentJobAdditionalInfos as $externalPartnerRecurrentJobAdditionalInfo) {
  1641. if ($externalPartnerRecurrentJobAdditionalInfo->getInfoName() === $infoName) {
  1642. return $externalPartnerRecurrentJobAdditionalInfo->getInfoStringValue();
  1643. }
  1644. }
  1645. return null;
  1646. }
  1647. public function getExternalPartnerRecurrentJobAdditionalInfosAsKeyValue(): array
  1648. {
  1649. $additionalInfosAsKeyValue = [];
  1650. foreach ($this->externalPartnerRecurrentJobAdditionalInfos as $externalPartnerRecurrentJobAdditionalInfo) {
  1651. $additionalInfoKey = $externalPartnerRecurrentJobAdditionalInfo->getInfoName();
  1652. $additionalInfoValue = null;
  1653. if (!is_null($externalPartnerRecurrentJobAdditionalInfo->getInfoIntValue())) {
  1654. $additionalInfoValue = $externalPartnerRecurrentJobAdditionalInfo->getInfoIntValue();
  1655. }
  1656. if (!is_null($externalPartnerRecurrentJobAdditionalInfo->getInfoStringValue())) {
  1657. $additionalInfoValue = $externalPartnerRecurrentJobAdditionalInfo->getInfoStringValue();
  1658. }
  1659. if (is_null($additionalInfoValue)) {
  1660. continue;
  1661. }
  1662. $additionalInfosAsKeyValue[$additionalInfoKey] = $additionalInfoValue;
  1663. }
  1664. return $additionalInfosAsKeyValue;
  1665. }
  1666. /** @throws Exception */
  1667. public function setExternalPartnerRecurrentJobAdditionalInfoStringValueByName(string $infoName, ?string $stringValue): void
  1668. {
  1669. /** @var RecurrentJobAdditionalInfo $externalPartnerRecurrentJobAdditionalInfo */
  1670. foreach ($this->externalPartnerRecurrentJobAdditionalInfos as $externalPartnerRecurrentJobAdditionalInfo) {
  1671. if ($externalPartnerRecurrentJobAdditionalInfo->getInfoName() === $infoName) {
  1672. $externalPartnerRecurrentJobAdditionalInfo->setInfoStringValue($stringValue);
  1673. return;
  1674. }
  1675. }
  1676. $externalPartnerRecurrentJobAdditionalInfo = new RecurrentJobAdditionalInfo();
  1677. $externalPartnerRecurrentJobAdditionalInfo->setRecurrentJob($this);
  1678. $externalPartnerRecurrentJobAdditionalInfo->setInfoName($infoName);
  1679. $externalPartnerRecurrentJobAdditionalInfo->setInfoStringValue($stringValue);
  1680. $this->externalPartnerRecurrentJobAdditionalInfos->add($externalPartnerRecurrentJobAdditionalInfo);
  1681. }
  1682. public function getExternalPartnerRecurrentJobAdditionalInfoIntValueByName(string $infoName): ?int
  1683. {
  1684. /** @var RecurrentJobAdditionalInfo $externalPartnerRecurrentJobAdditionalInfo */
  1685. foreach ($this->externalPartnerRecurrentJobAdditionalInfos as $externalPartnerRecurrentJobAdditionalInfo) {
  1686. if ($externalPartnerRecurrentJobAdditionalInfo->getInfoName() === $infoName) {
  1687. return $externalPartnerRecurrentJobAdditionalInfo->getInfoIntValue();
  1688. }
  1689. }
  1690. return null;
  1691. }
  1692. /** @throws Exception */
  1693. public function setExternalPartnerRecurrentJobAdditionalInfoIntValueByName(string $infoName, int $intValue): void
  1694. {
  1695. /** @var RecurrentJobAdditionalInfo $externalPartnerRecurrentJobAdditionalInfo */
  1696. foreach ($this->externalPartnerRecurrentJobAdditionalInfos as $externalPartnerRecurrentJobAdditionalInfo) {
  1697. if ($externalPartnerRecurrentJobAdditionalInfo->getInfoName() === $infoName) {
  1698. $externalPartnerRecurrentJobAdditionalInfo->setInfoIntValue($intValue);
  1699. return;
  1700. }
  1701. }
  1702. $externalPartnerRecurrentJobAdditionalInfo = new RecurrentJobAdditionalInfo();
  1703. $externalPartnerRecurrentJobAdditionalInfo->setRecurrentJob($this);
  1704. $externalPartnerRecurrentJobAdditionalInfo->setInfoName($infoName);
  1705. $externalPartnerRecurrentJobAdditionalInfo->setInfoIntValue($intValue);
  1706. $this->externalPartnerRecurrentJobAdditionalInfos->add($externalPartnerRecurrentJobAdditionalInfo);
  1707. }
  1708. public function isLinkedToExternalPartner(): bool
  1709. {
  1710. if (is_null($this->getJoboffererProfile())) {
  1711. return false;
  1712. }
  1713. if (is_null($this->getJoboffererProfile()->getUser())) {
  1714. return false;
  1715. }
  1716. return $this->getJoboffererProfile()->getUser()->isLinkedToExternalPartner();
  1717. }
  1718. public function setRecurrentJobValuesAccordingToOccupationalFieldsAndProfessionsSearchResultset(
  1719. OccupationalFieldsAndProfessionsSearchResultset $resultset
  1720. ): void {
  1721. $this->setOccupationalFieldSearchterm($resultset->getOriginallyEnteredSearchterm());
  1722. $this->setAdditionalOccupationalFieldSearchterms([]);
  1723. $this->setOccupationalFields(new ArrayCollection($resultset->getOccupationalFields()));
  1724. $this->setRelevantOccupationalFields(new ArrayCollection($resultset->getRelevantOccupationalFields()));
  1725. $this->setRelevantProfessions(new ArrayCollection($resultset->getRelevantProfessions()));
  1726. }
  1727. public function setRecurrentJobValuesAccordingToOccupationalFieldsAndProfessionsSearchMergedResultset(
  1728. OccupationalFieldsAndProfessionsSearchMergedResultset $mergedResultset,
  1729. int $additionalSearchtermRange = self::DEFAULT_ADDITIONAL_SEARCHTERM_RANGE
  1730. ): void {
  1731. $this->setOccupationalFieldSearchterm($mergedResultset->getSearchterm());
  1732. $additionalSearchterms = array_slice($mergedResultset->getAdditionalSearchterms(), 0, $additionalSearchtermRange);
  1733. $this->setAdditionalOccupationalFieldSearchterms($additionalSearchterms, $additionalSearchtermRange);
  1734. $this->setOccupationalFields(new ArrayCollection($mergedResultset->getOccupationalFields()));
  1735. $this->setRelevantOccupationalFields(new ArrayCollection($mergedResultset->getRelevantOccupationalFields()));
  1736. $this->setRelevantProfessions(new ArrayCollection($mergedResultset->getRelevantProfessions()));
  1737. }
  1738. /**
  1739. * @ORM\ManyToOne(targetEntity="App\Entity\ExternalPartner\IntegratedExternalPartnerCustomerQuota", inversedBy="recurrentJobs", cascade={"persist"})
  1740. *
  1741. * @ORM\JoinColumn(name="quotas_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
  1742. */
  1743. protected ?IntegratedExternalPartnerCustomerQuota $quota;
  1744. public function getQuota(): ?IntegratedExternalPartnerCustomerQuota
  1745. {
  1746. return $this->quota;
  1747. }
  1748. /**
  1749. * @throws Exception
  1750. */
  1751. public function setQuota(?IntegratedExternalPartnerCustomerQuota $quota): void
  1752. {
  1753. if (is_null($this->getJoboffererProfile())) {
  1754. throw new Exception('Need an attached jobofferer profile to set quota, but it is null.');
  1755. }
  1756. if (is_null($this->getJoboffererProfile()->getUser())) {
  1757. throw new Exception('Need a user attached to the jobofferer profile to set quota, but it is null.');
  1758. }
  1759. if (!is_null($quota)
  1760. && !is_null($this->getJoboffererProfile()->getUser()->getExternalPartner())
  1761. && $this->getJoboffererProfile()->getUser()->getExternalPartner()->getId()
  1762. !== $quota->getIntegratedExternalPartnerCustomer()->getExternalPartner()->getId()
  1763. ) {
  1764. throw new InvalidArgumentException("Tried to set quota {$quota->getId()} of customer {$quota->getIntegratedExternalPartnerCustomer()->getId()} to recurrent job {$this->getId()}, but the recurrent job belongs to a user linked to external partner {$this->getJoboffererProfile()->getUser()->getExternalPartner()->getId()} and the quota is linked to external partner {$quota->getIntegratedExternalPartnerCustomer()->getExternalPartner()->getId()}.");
  1765. }
  1766. if (!is_null($quota)
  1767. && !is_null($this->getIntegratedExternalPartnerCustomer())
  1768. && $this->getIntegratedExternalPartnerCustomer()->getId()
  1769. !== $quota->getIntegratedExternalPartnerCustomer()->getId()
  1770. ) {
  1771. throw new InvalidArgumentException("Tried to set quota {$quota->getId()} of customer {$quota->getIntegratedExternalPartnerCustomer()->getInternalId()} to recurrent job {$this->getId()}, but the recurrent job belongs to a user linked to customer {$this->getIntegratedExternalPartnerCustomer()->getInternalId()}.");
  1772. }
  1773. $this->quota = $quota;
  1774. }
  1775. public function belongsToIntegratedExternalPartnerCustomer(): bool
  1776. {
  1777. return !is_null($this->getIntegratedExternalPartnerCustomer());
  1778. }
  1779. public function getIntegratedExternalPartnerCustomer(): ?IntegratedExternalPartnerCustomer
  1780. {
  1781. if (is_null($this->joboffererProfile)) {
  1782. return null;
  1783. }
  1784. if (is_null($this->joboffererProfile->getUser())) {
  1785. return null;
  1786. }
  1787. return $this->joboffererProfile->getUser()->getIntegratedExternalPartnerCustomer();
  1788. }
  1789. public function getIntegratedExternalPartnerCustomerId(): ?string
  1790. {
  1791. return (!is_null($this->getIntegratedExternalPartnerCustomer())) ? $this->joboffererProfile->getUser()->getIntegratedExternalPartnerCustomer()->getId() : null;
  1792. }
  1793. /**
  1794. * @ORM\Column(name="external_application_url", type="text", length=4096, nullable=true)
  1795. *
  1796. * @Assert\Length(
  1797. * min = 10,
  1798. * max = 4096,
  1799. * )
  1800. */
  1801. protected ?string $externalApplicationUrl = null;
  1802. public function getExternalApplicationUrl(): ?string
  1803. {
  1804. return $this->externalApplicationUrl;
  1805. }
  1806. /** @throws InvalidArgumentException */
  1807. public function setExternalApplicationUrl(?string $externalApplicationUrl): void
  1808. {
  1809. if (!is_null($externalApplicationUrl)) {
  1810. if (mb_strlen($externalApplicationUrl) > 4096) {
  1811. throw new InvalidArgumentException('Maximum of 4096 characters allowed!');
  1812. }
  1813. }
  1814. $this->externalApplicationUrl = $externalApplicationUrl;
  1815. }
  1816. public function getNormalizedExternalApplicationUrl(): ?string
  1817. {
  1818. return UrlHelper::getNormalizedUrl($this->getExternalApplicationUrl());
  1819. }
  1820. public function getNormalizedExternalApplicationUrlWithTrackingParameters(): ?string
  1821. {
  1822. return UrlHelper::getNormalizedUrlWithJobooUtmParameter($this->getExternalApplicationUrl(), $this);
  1823. }
  1824. /**
  1825. * @var string|null
  1826. *
  1827. * @ORM\Column(name="email_for_applications", type="string", length=128, nullable=true)
  1828. *
  1829. * @Assert\Email(mode="strict")
  1830. */
  1831. protected $emailForApplications;
  1832. public function setEmailForApplications(?string $emailForApplications): void
  1833. {
  1834. if (!is_null($emailForApplications)) {
  1835. $emailForApplications = mb_substr($emailForApplications, 0, 128);
  1836. if (!MailService::emailAddressIsValidForMailer($emailForApplications)) {
  1837. throw new InvalidArgumentException("E-mail '$emailForApplications' is not valid.");
  1838. }
  1839. }
  1840. $this->emailForApplications = $emailForApplications;
  1841. }
  1842. public function getEmailForApplications(): ?string
  1843. {
  1844. if (!is_null($this->emailForApplications)) {
  1845. return $this->emailForApplications;
  1846. } else {
  1847. return $this->getContactEmail();
  1848. }
  1849. }
  1850. /**
  1851. * @ORM\Column(name="zipcode", type="string", length=128, nullable=true)
  1852. *
  1853. * @Assert\Type("string")
  1854. *
  1855. * @AppAssert\KnownZipcode
  1856. */
  1857. protected ?string $zipcode;
  1858. public function setZipcode(?string $zipcode = null)
  1859. {
  1860. if (!is_null($zipcode)) {
  1861. $trimmedZipcode = trim($zipcode);
  1862. if (mb_strlen($trimmedZipcode) !== 5 || !is_numeric($trimmedZipcode)) {
  1863. throw new InvalidArgumentException("zipcode must either be null or a string with 5 digits, but got '$zipcode'");
  1864. }
  1865. $zipcode = $trimmedZipcode;
  1866. }
  1867. $this->zipcode = $zipcode;
  1868. }
  1869. public function setZipcodeHierarchically(string $zipcode): void
  1870. {
  1871. if (!is_null($this->zipcode)) {
  1872. $this->setZipcode($zipcode);
  1873. } else {
  1874. $this->getJoboffererProfile()->setZipcode($zipcode);
  1875. }
  1876. }
  1877. public function getZipcode(): ?string
  1878. {
  1879. if (is_null($this->zipcode)) {
  1880. return $this->getJoboffererProfile()->getZipcode();
  1881. }
  1882. return $this->zipcode;
  1883. }
  1884. /**
  1885. * @ORM\Column(name="address", type="string", length=128, nullable=true)
  1886. */
  1887. protected ?string $address;
  1888. public function setAddress(?string $address = null)
  1889. {
  1890. if (!is_null($address)) {
  1891. $address = mb_substr($address, 0, 128);
  1892. }
  1893. $this->address = $address;
  1894. }
  1895. public function getAddress(): ?string
  1896. {
  1897. if (is_null($this->address)) {
  1898. return $this->getJoboffererProfile()->getAddress();
  1899. }
  1900. return $this->address;
  1901. }
  1902. /**
  1903. * @ORM\Column(name="city", type="string", length=128, nullable=true)
  1904. */
  1905. protected ?string $city;
  1906. public function setCity(?string $city)
  1907. {
  1908. if (is_null($city)) {
  1909. $this->city = null;
  1910. } else {
  1911. $this->city = mb_substr($city, 0, 128);
  1912. }
  1913. }
  1914. public function getCity(): ?string
  1915. {
  1916. if (is_null($this->city) || $this->city === '') {
  1917. return $this->getJoboffererProfile()->getCity();
  1918. }
  1919. return $this->city;
  1920. }
  1921. /**
  1922. * @ORM\OneToOne(targetEntity="App\Entity\Membership\RecurrentJobBooking", mappedBy="recurrentJob", cascade={"persist", "remove"})
  1923. */
  1924. protected ?RecurrentJobBooking $booking;
  1925. public function getBooking(): ?RecurrentJobBooking
  1926. {
  1927. return $this->booking;
  1928. }
  1929. public function setBooking(?RecurrentJobBooking $booking): void
  1930. {
  1931. $this->booking = $booking;
  1932. }
  1933. /**
  1934. * @ORM\Column(name="application_type", type="smallint", nullable=true)
  1935. *
  1936. * @Assert\Type("int")
  1937. */
  1938. protected ?int $applicationType;
  1939. public function getApplicationType(): ?int
  1940. {
  1941. return $this->applicationType;
  1942. }
  1943. /** @throws Exception */
  1944. public function setApplicationType(?int $applicationType): void
  1945. {
  1946. if (!is_null($applicationType) && !in_array($applicationType, self::POSSIBLE_APPLICATION_TYPES)) {
  1947. throw new Exception('Unknown application type "' . $applicationType . '"');
  1948. }
  1949. $this->applicationType = $applicationType;
  1950. }
  1951. /**
  1952. * @var string
  1953. *
  1954. * @ORM\Column(name="selfdescription", type="text", length=10000, nullable=true)
  1955. */
  1956. protected $selfdescription;
  1957. public function setSelfdescription(?string $selfdescription = null)
  1958. {
  1959. if (!is_null($selfdescription)) {
  1960. $selfdescription = mb_substr($selfdescription, 0, 10000);
  1961. }
  1962. $this->selfdescription = $selfdescription;
  1963. }
  1964. public function getSelfdescription(): ?string
  1965. {
  1966. if (is_null($this->selfdescription)) {
  1967. return $this->joboffererProfile->getSelfdescription();
  1968. }
  1969. return TextCleaner::removeSpecialCharacters($this->selfdescription);
  1970. }
  1971. /**
  1972. * @ORM\OneToOne(targetEntity="App\Entity\RecurrentJobProfilePhoto", mappedBy="recurrentJob", cascade={"persist", "remove"})
  1973. */
  1974. protected ?RecurrentJobProfilePhoto $profilePhoto;
  1975. public function getProfilePhoto(): ?RecurrentJobProfilePhoto
  1976. {
  1977. return $this->profilePhoto;
  1978. }
  1979. public function setProfilePhoto(?RecurrentJobProfilePhoto $profilePhoto): void
  1980. {
  1981. $this->profilePhoto = $profilePhoto;
  1982. }
  1983. public function getProfilePhotoFileName(): ?string
  1984. {
  1985. if (!is_null($this->profilePhoto)) {
  1986. return $this->profilePhoto->getFileName();
  1987. } else {
  1988. return $this->getJoboffererProfile()->getPhotoFileName();
  1989. }
  1990. }
  1991. public function hasProfilePhoto(): bool
  1992. {
  1993. return !is_null($this->getProfilePhotoFileName());
  1994. }
  1995. public function getImagineFilterNameForMaximizedProfilePhoto(): string
  1996. {
  1997. if (!is_null($this->profilePhoto)) {
  1998. return 'recurrent_job_profile_photos_maximized';
  1999. } else {
  2000. return 'profile_photos_maximized';
  2001. }
  2002. }
  2003. public function isJoboffererProfilePhoto(): ?string
  2004. {
  2005. if (!is_null($this->profilePhoto)) {
  2006. return false;
  2007. }
  2008. return true;
  2009. }
  2010. /**
  2011. * @ORM\OneToOne(targetEntity="App\Entity\RecurrentJobHeaderImage", mappedBy="recurrentJob", cascade={"persist", "remove"})
  2012. */
  2013. protected ?RecurrentJobHeaderImage $headerImage;
  2014. public function getHeaderImage(): ?RecurrentJobHeaderImage
  2015. {
  2016. return $this->headerImage;
  2017. }
  2018. public function setHeaderImage(?RecurrentJobHeaderImage $headerImage): void
  2019. {
  2020. $this->headerImage = $headerImage;
  2021. }
  2022. public function getHeaderImageFileName(): ?string
  2023. {
  2024. if (!is_null($this->headerImage)) {
  2025. return $this->headerImage->getFileName();
  2026. }
  2027. return null;
  2028. }
  2029. public function hasHeaderImage(): bool
  2030. {
  2031. return !is_null($this->getHeaderImageFileName());
  2032. }
  2033. public function getImagineFilterNameForMaximizedHeaderImage(): string
  2034. {
  2035. if (!is_null($this->headerImage)) {
  2036. return 'recurrent_job_header_image_maximized';
  2037. } else {
  2038. return 'header_image_maximized';
  2039. }
  2040. }
  2041. /**
  2042. * @ORM\Column(name="is_plus", type="boolean", nullable=false)
  2043. */
  2044. protected bool $isPlus;
  2045. public function setIsPlus(bool $isPlus): void
  2046. {
  2047. if (!is_null($this->slot) && $isPlus) {
  2048. throw new InvalidArgumentException("Cannot set isPlus to true for rj '$this->id' if rj is already inside of a flex membership slot.");
  2049. }
  2050. $this->isPlus = $isPlus;
  2051. }
  2052. public function isPlus(): bool
  2053. {
  2054. return $this->isPlus;
  2055. }
  2056. /**
  2057. * @var AutomatedConversationMessagesMailing[]|Collection
  2058. *
  2059. * @ORM\OneToMany(targetEntity="App\Entity\AutomatedConversationMessagesMailing", mappedBy="recurrentJob", cascade={"persist", "remove"})
  2060. */
  2061. protected $automatedConversationMessagesMailings;
  2062. public function getAutomatedConversationMessagesMailings(): Collection
  2063. {
  2064. return $this->automatedConversationMessagesMailings;
  2065. }
  2066. /**
  2067. * @ORM\ManyToOne(targetEntity="App\Entity\ContentDistribution\AgenturFuerArbeit\DestatisEconomicSector", cascade={"persist"})
  2068. *
  2069. * @ORM\JoinColumn(name="destatis_economic_sectors_running_number", referencedColumnName="running_number", nullable=true, onDelete="SET NULL")
  2070. */
  2071. protected ?DestatisEconomicSector $destatisEconomicSector = null;
  2072. public function getDestatisEconomicSector(): ?DestatisEconomicSector
  2073. {
  2074. if (is_null($this->destatisEconomicSector)
  2075. && !is_null($this->joboffererProfile)
  2076. ) {
  2077. return $this->joboffererProfile->getDestatisEconomicSector();
  2078. }
  2079. return $this->destatisEconomicSector;
  2080. }
  2081. public function setDestatisEconomicSector(?DestatisEconomicSector $destatisEconomicSector): void
  2082. {
  2083. $this->destatisEconomicSector = $destatisEconomicSector;
  2084. }
  2085. /**
  2086. * @ORM\Column(name="destatis_economic_sector_decision", type="smallint", nullable=true, options={"unsigned": true})
  2087. */
  2088. protected ?int $destatisEconomicSectorDecision;
  2089. public function setDestatisEconomicSectorDecision(?int $destatisEconomicSectorDecision): void
  2090. {
  2091. if (!is_null($destatisEconomicSectorDecision)) {
  2092. if (!ReflectionHelper::hasConstWithValue(
  2093. DestatisEconomicSectorService::class,
  2094. 'SECTOR_DECISION_',
  2095. $destatisEconomicSectorDecision
  2096. )
  2097. ) {
  2098. throw new InvalidArgumentException("Value '$destatisEconomicSectorDecision' not allowed for destatisEconomicSectorDecision.");
  2099. }
  2100. }
  2101. $this->destatisEconomicSectorDecision = $destatisEconomicSectorDecision;
  2102. }
  2103. public function getDestatisEconomicSectorDecision(): ?int
  2104. {
  2105. if (is_null($this->destatisEconomicSectorDecision)
  2106. && !is_null($this->joboffererProfile)
  2107. ) {
  2108. return $this->joboffererProfile->getDestatisEconomicSectorDecision();
  2109. }
  2110. return $this->destatisEconomicSectorDecision;
  2111. }
  2112. public function getDestatisEconomicSectorOrigin(): ?int
  2113. {
  2114. if (!is_null($this->destatisEconomicSector)) {
  2115. return DestatisEconomicSectorService::SECTOR_ORIGIN_RECURRENT_JOB;
  2116. }
  2117. if (!is_null($this->joboffererProfile)) {
  2118. return $this->joboffererProfile->getDestatisEconomicSectorOrigin();
  2119. }
  2120. return null;
  2121. }
  2122. /**
  2123. * @ORM\Column(name="afa_professions_filename_prefix", type="string", length=16, nullable=true)
  2124. */
  2125. protected ?string $afaProfessionFilenamePrefix;
  2126. public function getAfaProfessionFilenamePrefix(): ?string
  2127. {
  2128. return $this->afaProfessionFilenamePrefix;
  2129. }
  2130. /**
  2131. * @ORM\Column(name="afa_professions_id", type="integer", nullable=true, options={"unsigned": true})
  2132. */
  2133. protected ?int $afaProfessionId;
  2134. public function getAfaProfessionId(): ?int
  2135. {
  2136. return $this->afaProfessionId;
  2137. }
  2138. public function setAfaProfession(
  2139. ?AfaProfession $afaProfession
  2140. ): void {
  2141. if (is_null($afaProfession)) {
  2142. $this->afaProfessionFilenamePrefix = null;
  2143. $this->afaProfessionId = null;
  2144. } else {
  2145. $this->afaProfessionFilenamePrefix = mb_substr($afaProfession->getFilenamePrefix(), 0, 16);
  2146. $this->afaProfessionId = $afaProfession->getId();
  2147. }
  2148. }
  2149. /**
  2150. * @var RecurrentJobStatusChangeLogEntry[]|Collection
  2151. *
  2152. * @ORM\OneToMany(targetEntity="App\Entity\RecurrentJobStatusChangeLogEntry", mappedBy="recurrentJob", cascade={"persist", "remove"})
  2153. */
  2154. private $statusChangeLogEntries;
  2155. /**
  2156. * @return RecurrentJobStatusChangeLogEntry[]|Collection
  2157. */
  2158. public function getStatusChangeLogEntries(): Collection
  2159. {
  2160. return $this->statusChangeLogEntries;
  2161. }
  2162. public function addStatusChangeLogEntry(RecurrentJobStatusChangeLogEntry $statusChangeLogEntry): void
  2163. {
  2164. $this->statusChangeLogEntries[] = $statusChangeLogEntry;
  2165. }
  2166. public function hasClickBasedBilling(): bool
  2167. {
  2168. if (is_null($this->getIntegratedExternalPartnerCustomer())) {
  2169. return false;
  2170. }
  2171. return $this->getIntegratedExternalPartnerCustomer()->hasClickBasedBilling();
  2172. }
  2173. /**
  2174. * @ORM\Column(name="superior_salary", type="boolean", nullable=true)
  2175. */
  2176. protected ?bool $superiorSalary;
  2177. public function setSuperiorSalary(?bool $superiorSalary): void
  2178. {
  2179. $this->superiorSalary = $superiorSalary;
  2180. }
  2181. public function getSuperiorSalary(): bool
  2182. {
  2183. if ($this->belongsToIntegratedExternalPartnerCustomer() && $this->getIntegratedExternalPartnerCustomer()->hasClickBasedBilling()) {
  2184. return false;
  2185. }
  2186. if ($this->belongsToIntegratedExternalPartnerCustomer()) {
  2187. return true;
  2188. }
  2189. if ($this->isLinkedToExternalPartner()) {
  2190. return true;
  2191. }
  2192. return (bool)$this->superiorSalary;
  2193. }
  2194. /**
  2195. * @throws Exception
  2196. */
  2197. public function getLatestSyncToSearchIndexAt(): DateTime
  2198. {
  2199. return DateTimeUtility::createDateTimeUtc();
  2200. }
  2201. /**
  2202. * @ORM\OneToMany(targetEntity="JanusHercules\ExternalApplicationQuestions\Domain\Entity\ConcludisApplicationFormSetup", mappedBy="recurrentJob", cascade={"persist", "remove"})
  2203. */
  2204. private Collection $concludisApplicationFormSetups;
  2205. /**
  2206. * @ORM\ManyToMany(targetEntity="JanusHercules\ExtendedApplicationQuestionnaire\Domain\Entity\ExtendedApplicationQuestion")
  2207. *
  2208. * @ORM\JoinTable(name="recurrent_jobs_extended_application_questions",
  2209. * joinColumns={@ORM\JoinColumn(name="recurrent_jobs_id", referencedColumnName="id", onDelete="CASCADE")},
  2210. * inverseJoinColumns={@ORM\JoinColumn(name="extended_application_questions_id", referencedColumnName="id", onDelete="CASCADE")}
  2211. * )
  2212. *
  2213. * Note: The naming here is potentially misleading.
  2214. * An extended application question can only be linked to exactly zero or exactly one recurrent jobs,
  2215. * but not to multiple recurrent jobs!
  2216. *
  2217. * The reason that $extendedApplicationQuestions is a "plural" collection is only
  2218. * due to the fact that upon implementation of this relationship, we wanted to avoid extending
  2219. * the large recurrent jobs table with another column, and instead use a separate table.
  2220. */
  2221. protected Collection $extendedApplicationQuestions;
  2222. public function getExtendedApplicationQuestions(): Collection
  2223. {
  2224. return $this->extendedApplicationQuestions;
  2225. }
  2226. public function setExtendedApplicationQuestions(Collection $extendedApplicationQuestions): void
  2227. {
  2228. $this->extendedApplicationQuestions = $extendedApplicationQuestions;
  2229. }
  2230. public function addExtendedApplicationQuestion(ExtendedApplicationQuestion $extendedApplicationQuestion): void
  2231. {
  2232. $this->extendedApplicationQuestions[] = $extendedApplicationQuestion;
  2233. }
  2234. public function removeExtendedApplicationQuestionIfExists(ExtendedApplicationQuestion $extendedApplicationQuestionToRemove): bool
  2235. {
  2236. foreach ($this->extendedApplicationQuestions as $key => $extendedApplicationQuestion) {
  2237. if ($extendedApplicationQuestion->getId() === $extendedApplicationQuestionToRemove->getId()) {
  2238. $this->extendedApplicationQuestions->remove($key);
  2239. return true;
  2240. }
  2241. }
  2242. return false;
  2243. }
  2244. /**
  2245. * @ORM\OneToMany(targetEntity="App\Entity\ExtendedApplication\ExtendedApplication", mappedBy="recurrentJob", cascade={"persist"})
  2246. */
  2247. protected Collection $extendedApplications;
  2248. public function getExtendedApplications(): Collection
  2249. {
  2250. return $this->extendedApplications;
  2251. }
  2252. /**
  2253. * @ORM\ManyToOne(targetEntity="JanusHercules\IntegratedExternalPartnerCustomers\Domain\Entity\WeclappContractItem", cascade={"persist"})
  2254. *
  2255. * @ORM\JoinColumn(name="weclapp_contract_items_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
  2256. */
  2257. protected ?WeclappContractItem $weclappContractItem = null;
  2258. public function getWeclappContractItem(): ?WeclappContractItem
  2259. {
  2260. return $this->weclappContractItem;
  2261. }
  2262. /**
  2263. * @ORM\OneToOne(targetEntity="JanusHercules\ExternalApplicationQuestions\Domain\Entity\SoftgardenApplicationJobInformation", mappedBy="recurrentJob", cascade={"persist", "remove"})
  2264. */
  2265. private ?SoftgardenApplicationJobInformation $softgardenApplicationJobInformation;
  2266. /**
  2267. * @ORM\OneToMany(targetEntity="JanusHercules\SelfServiceTrafficCampaign\Domain\Entity\SelfServiceTrafficCampaign", mappedBy="recurrentJob"))
  2268. */
  2269. private ?Collection $selfServiceTrafficCampaigns;
  2270. public function getSelfServiceTrafficCampaigns(): Collection
  2271. {
  2272. return $this->selfServiceTrafficCampaigns;
  2273. }
  2274. /**
  2275. * @ORM\OneToMany(targetEntity="JanusHercules\SelfServiceTrafficCampaign\Domain\Entity\SelfServiceTrafficCampaignBooking", mappedBy="recurrentJob"))
  2276. */
  2277. private ?Collection $selfServiceTrafficCampaignBookings;
  2278. public function getSelfServiceTrafficCampaignBookings(): Collection
  2279. {
  2280. return $this->selfServiceTrafficCampaignBookings;
  2281. }
  2282. /**
  2283. * @ORM\OneToOne(targetEntity="JanusHercules\Membership\Domain\Entity\FlexMembershipRecurrentJobSlot", mappedBy="recurrentJob", cascade={"persist", "remove"})
  2284. */
  2285. protected ?FlexMembershipRecurrentJobSlot $slot;
  2286. public function getSlot(): ?FlexMembershipRecurrentJobSlot
  2287. {
  2288. return $this->slot;
  2289. }
  2290. public function setSlot(?FlexMembershipRecurrentJobSlot $slot): void
  2291. {
  2292. if ($this->isPlus) {
  2293. throw new InvalidArgumentException("Was asked to set flex membership slot for rj '$this->id' but rj is already plus.");
  2294. }
  2295. $this->slot = $slot;
  2296. }
  2297. /**
  2298. * @ORM\Column(name="duplicated_from_recurrent_job_id", type="string", length=48, nullable=true)
  2299. */
  2300. protected ?string $duplicatedFromRecurrentJobId;
  2301. public function getDuplicatedFromRecurrentJobId(): ?string
  2302. {
  2303. return $this->duplicatedFromRecurrentJobId;
  2304. }
  2305. public function setDuplicatedFromRecurrentJobId(?string $duplicatedFromRecurrentJobId): void
  2306. {
  2307. $this->duplicatedFromRecurrentJobId = $duplicatedFromRecurrentJobId;
  2308. }
  2309. public function getBusinessnameSearchtermZipcodeAsHash(): string
  2310. {
  2311. return hash('xxh3', $this->getBusinessName() . $this->getOccupationalFieldSearchterm() . $this->getZipcode());
  2312. }
  2313. }