src/App/Entity/Profile/JoboffererProfile.php line 37

Open in your IDE?
  1. <?php
  2. namespace App\Entity\Profile;
  3. use App\Entity\ContentDistribution\AgenturFuerArbeit\DestatisEconomicSector;
  4. use App\Entity\ConversationMessage\ConversationMessage;
  5. use App\Entity\EconomicSector;
  6. use App\Entity\ExternalPartner\JoboffererProfileAdditionalInfo;
  7. use App\Entity\JoboffererProfileAdditionalFile;
  8. use App\Entity\Profile;
  9. use App\Entity\ProfileBlock;
  10. use App\Entity\ProfileFavorization;
  11. use App\Entity\ProfileReview;
  12. use App\Entity\RecurrentJob;
  13. use App\Entity\User;
  14. use App\Exception\InvalidEmailException;
  15. use App\Service\DestatisEconomicSectorService;
  16. use App\Service\MailService;
  17. use App\Service\XmlFormattingService;
  18. use App\Utility\ReflectionHelper;
  19. use App\Utility\TextCleaner;
  20. use App\Validator\Constraint as AppAssert;
  21. use DateTime;
  22. use Doctrine\Common\Collections\ArrayCollection;
  23. use Doctrine\Common\Collections\Collection;
  24. use Doctrine\ORM\Mapping as ORM;
  25. use Exception;
  26. use InvalidArgumentException;
  27. use Symfony\Component\Validator\Constraints as Assert;
  28. use Symfony\Component\Validator\Context\ExecutionContextInterface;
  29. /**
  30. * @ORM\Entity
  31. *
  32. * @ORM\Table(name="jobofferer_profiles")
  33. */
  34. class JoboffererProfile extends Profile
  35. {
  36. public const LIMITED_IN_SEARCH_VALUE_FALSE = 0;
  37. public const LIMITED_IN_SEARCH_VALUE_TRUE = 1;
  38. public const LIMITED_IN_SEARCH_VALUE_FALSE_BY_HAND = 2;
  39. public const LIMITED_IN_SEARCH_VALUE_TRUE_BY_HAND = 3;
  40. public function __construct()
  41. {
  42. parent::__construct();
  43. $this->recurrentJobs = new ArrayCollection();
  44. $this->additionalFiles = new ArrayCollection();
  45. $this->selfdescription = '';
  46. $this->identifiedAsRecruitmentAgency = false;
  47. $this->limitedInSearch = self::LIMITED_IN_SEARCH_VALUE_TRUE;
  48. }
  49. /**
  50. * @var User
  51. *
  52. * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="joboffererProfiles", cascade={"persist"})
  53. *
  54. * @ORM\JoinColumn(name="users_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
  55. */
  56. protected $user;
  57. /**
  58. * @ORM\Column(name="selfdescription", type="text", length=10000, nullable=true)
  59. *
  60. * @Assert\Type("string")
  61. */
  62. protected ?string $selfdescription;
  63. public function setSelfdescription(
  64. ?string $selfdescription = null,
  65. ?bool $formatHeadings = true
  66. ): void {
  67. if ($formatHeadings) {
  68. // Headings that are greater than h4 should not exist in the description text and should be replaced with h4 headings
  69. $selfdescription = XmlFormattingService::formatHeadingsForDescriptionTexts($selfdescription);
  70. }
  71. $this->selfdescription = $selfdescription;
  72. }
  73. public function getSelfdescription(): ?string
  74. {
  75. return TextCleaner::removeSpecialCharacters($this->selfdescription);
  76. }
  77. /**
  78. * @ORM\Column(name="firstname", type="string", length=128, nullable=true)
  79. *
  80. * @Assert\Type("string")
  81. *
  82. * @Assert\Length(
  83. * min = 0,
  84. * max = 50,
  85. * )
  86. */
  87. protected ?string $firstname;
  88. public function setFirstname(?string $firstname = null): void
  89. {
  90. $this->firstname = $firstname;
  91. }
  92. public function getFirstname(): ?string
  93. {
  94. return $this->firstname;
  95. }
  96. /**
  97. * @ORM\Column(name="lastname", type="string", length=128, nullable=true)
  98. *
  99. * @Assert\Type("string")
  100. *
  101. * @Assert\Length(
  102. * min = 0,
  103. * max = 50,
  104. * )
  105. */
  106. protected ?string $lastname;
  107. public function setLastname(?string $lastname = null): void
  108. {
  109. $this->lastname = $lastname;
  110. }
  111. public function getLastname(): ?string
  112. {
  113. return $this->lastname;
  114. }
  115. /**
  116. * @ORM\Column(name="address", type="string", length=128, nullable=true)
  117. *
  118. * @Assert\Type("string")
  119. *
  120. * @Assert\NotBlank()
  121. *
  122. * @Assert\Length(
  123. * min = 5,
  124. * max = 128,
  125. * )
  126. */
  127. protected ?string $address;
  128. public function setAddress(?string $address = null): void
  129. {
  130. $this->address = $address;
  131. }
  132. public function getAddress(): ?string
  133. {
  134. return $this->address;
  135. }
  136. /**
  137. * @ORM\Column(name="zipcode", type="string", length=128, nullable=true)
  138. *
  139. * @Assert\Type("string")
  140. *
  141. * @Assert\NotNull()
  142. *
  143. * @Assert\NotBlank()
  144. *
  145. * @AppAssert\KnownZipcode
  146. */
  147. protected ?string $zipcode = null;
  148. public function setZipcode(
  149. ?string $zipcode = null
  150. ): void {
  151. if (!is_null($zipcode)) {
  152. $trimmedZipcode = trim($zipcode);
  153. if (mb_strlen($trimmedZipcode) !== 5 || !is_numeric($trimmedZipcode)) {
  154. throw new InvalidArgumentException("zipcode must either be null or a string with 5 digits, but got '$zipcode'");
  155. }
  156. $zipcode = $trimmedZipcode;
  157. }
  158. $this->zipcode = $zipcode;
  159. }
  160. public function getZipcode(): ?string
  161. {
  162. return $this->zipcode;
  163. }
  164. /**
  165. * @ORM\Column(name="city", type="string", length=128, nullable=true)
  166. *
  167. * @Assert\Type("string")
  168. *
  169. * @Assert\NotBlank()
  170. *
  171. * @Assert\Length(
  172. * min = 2,
  173. * max = 128,
  174. * )
  175. */
  176. protected ?string $city;
  177. public function setCity(?string $city): void
  178. {
  179. $this->city = mb_substr($city, 0, 128);
  180. }
  181. public function getCity(): ?string
  182. {
  183. return $this->city;
  184. }
  185. /**
  186. * @var ConversationMessage[]|Collection|array
  187. *
  188. * @ORM\OneToMany(targetEntity="\App\Entity\ConversationMessage\ConversationMessage", mappedBy="joboffererProfile", cascade={"persist", "remove"})
  189. */
  190. protected array|Collection $conversationMessages;
  191. public function addConversationMessage(ConversationMessage $conversationMessage): void
  192. {
  193. $this->conversationMessages[] = $conversationMessage;
  194. }
  195. public function getConversationMessages(): Collection
  196. {
  197. return $this->conversationMessages;
  198. }
  199. /**
  200. * @var ProfileReview|Collection
  201. *
  202. * @ORM\OneToMany(targetEntity="\App\Entity\ProfileReview", mappedBy="joboffererProfile", cascade={"persist", "remove"})
  203. */
  204. protected $profileReviews;
  205. public function addProfileReview(ProfileReview $profileReview): void
  206. {
  207. $this->profileReviews[] = $profileReview;
  208. }
  209. public function getProfileReviews(): ProfileReview|Collection
  210. {
  211. return $this->profileReviews;
  212. }
  213. /**
  214. * @var ProfileBlock|Collection
  215. *
  216. * @ORM\OneToMany(targetEntity="\App\Entity\ProfileBlock", mappedBy="joboffererProfile", cascade={"persist", "remove"})
  217. */
  218. protected $profileBlocks;
  219. public function addProfileBlock(ProfileBlock $profileBlock): void
  220. {
  221. $this->profileBlocks[] = $profileBlock;
  222. }
  223. public function getProfileBlocks(): Collection|ProfileBlock
  224. {
  225. return $this->profileBlocks;
  226. }
  227. public function getProfileBlockForBlockOfJobseekerProfile(JobseekerProfile $jobseekerProfile): ProfileBlock
  228. {
  229. /** @var ProfileBlock $profileBlock */
  230. foreach ($this->profileBlocks as $profileBlock) {
  231. if ($profileBlock->isBlocker($this) && $profileBlock->getJobseekerProfile()->getId() === $jobseekerProfile->getId()) {
  232. return $profileBlock;
  233. }
  234. }
  235. throw new Exception('Jobofferer profile ' . $this->getId() . ' has not blocked jobseeker profile ' . $jobseekerProfile->getId());
  236. }
  237. /**
  238. * @var ProfileFavorization|Collection
  239. *
  240. * @ORM\OneToMany(targetEntity="\App\Entity\ProfileFavorization", mappedBy="joboffererProfile", cascade={"persist", "remove"})
  241. */
  242. protected $profileFavorizations;
  243. public function addProfileFavorization(ProfileFavorization $profileFavorization): void
  244. {
  245. $this->profileFavorizations[] = $profileFavorization;
  246. }
  247. public function getProfileFavorizations(): Collection|ProfileFavorization
  248. {
  249. return $this->profileFavorizations;
  250. }
  251. public function getProfileFavorizationForFavorizationOfJobseekerProfile(JobseekerProfile $jobseekerProfile): ProfileFavorization
  252. {
  253. /** @var ProfileFavorization $profileFavorization */
  254. foreach ($this->profileFavorizations as $profileFavorization) {
  255. if ($profileFavorization->isFavorer($this) && $profileFavorization->getJobseekerProfile()->getId() === $jobseekerProfile->getId()) {
  256. return $profileFavorization;
  257. }
  258. }
  259. throw new Exception('Jobofferer profile ' . $this->getId() . ' has not favored jobseeker profile ' . $jobseekerProfile->getId());
  260. }
  261. /**
  262. * @var RecurrentJob[]|Collection
  263. *
  264. * @ORM\OneToMany(targetEntity="\App\Entity\RecurrentJob", mappedBy="joboffererProfile", cascade={"persist", "remove"})
  265. */
  266. protected array|Collection|ArrayCollection $recurrentJobs;
  267. public function addRecurrentJob(RecurrentJob $recurrentJobs): void
  268. {
  269. $this->recurrentJobs[] = $recurrentJobs;
  270. }
  271. public function removeRecurrentJob(RecurrentJob $recurrentJobToRemove): void
  272. {
  273. foreach ($this->recurrentJobs as $key => $recurrentJob) {
  274. if ($recurrentJob->getId() === $recurrentJobToRemove->getId()) {
  275. $this->recurrentJobs->remove($key);
  276. }
  277. }
  278. }
  279. /**
  280. * @return RecurrentJob[]|Collection
  281. */
  282. public function getRecurrentJobs(): array|ArrayCollection|Collection
  283. {
  284. return $this->recurrentJobs;
  285. }
  286. /**
  287. * @var JoboffererProfileAdditionalFile|Collection
  288. *
  289. * @ORM\OneToMany(targetEntity="\App\Entity\JoboffererProfileAdditionalFile", mappedBy="joboffererProfile", cascade={"persist", "remove"})
  290. */
  291. protected Collection|ArrayCollection|JoboffererProfileAdditionalFile $additionalFiles;
  292. public function getAdditionalFiles(): JoboffererProfileAdditionalFile|ArrayCollection|Collection
  293. {
  294. return $this->additionalFiles;
  295. }
  296. /**
  297. * @ORM\Column(name="businessName", type="string", length=128, nullable=true)
  298. *
  299. * @Assert\Type("string")
  300. *
  301. * @Assert\NotBlank()
  302. *
  303. * @Assert\Length(
  304. * min = 2,
  305. * max = 100,
  306. * )
  307. */
  308. protected ?string $businessName;
  309. public function setBusinessName(?string $businessName = null): void
  310. {
  311. if (!is_null($businessName)) {
  312. $this->businessName = mb_substr($businessName, 0, 128);
  313. } else {
  314. $this->businessName = null;
  315. }
  316. }
  317. public function getBusinessName(): ?string
  318. {
  319. return $this->businessName;
  320. }
  321. /**
  322. * @ORM\ManyToOne(targetEntity="App\Entity\EconomicSector", cascade={"persist"})
  323. *
  324. * @ORM\JoinColumn(name="economic_sectors_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
  325. */
  326. protected ?EconomicSector $economicSector;
  327. public function getEconomicSector(): ?EconomicSector
  328. {
  329. return $this->economicSector;
  330. }
  331. public function setEconomicSector(EconomicSector $economicSector): void
  332. {
  333. $this->economicSector = $economicSector;
  334. }
  335. /**
  336. * @Assert\Callback
  337. */
  338. public function validate(ExecutionContextInterface $context, $payload): void
  339. {
  340. parent::validate($context, $payload);
  341. }
  342. /**
  343. * @ORM\Column(name="paused_since", type="datetime", nullable=true)
  344. *
  345. * @Assert\Type("datetime")
  346. */
  347. private $pausedSince;
  348. public function getPausedSince(): ?DateTime
  349. {
  350. return $this->pausedSince;
  351. }
  352. public function setPausedSince(?DateTime $pausedSince = null): void
  353. {
  354. $this->pausedSince = $pausedSince;
  355. }
  356. public function isPaused(): bool
  357. {
  358. return $this->pausedSince !== null;
  359. }
  360. public function getStarsScoreRating(): float
  361. {
  362. $score = 2.5;
  363. $step = 0.5;
  364. $score += $this->getSelfdescription() ? $step : 0;
  365. $score += $this->getMobilenumber() ? $step : 0;
  366. $score += $this->getPhotoFileName() ? $step : 0;
  367. return $score;
  368. }
  369. /**
  370. * @ORM\OneToMany(targetEntity="App\Entity\ExternalPartner\JoboffererProfileAdditionalInfo", mappedBy="joboffererProfile", cascade={"persist", "remove"})
  371. */
  372. protected $externalPartnerJoboffererProfileAdditionalInfos;
  373. public function getExternalPartnerJoboffererProfileAdditionalInfos(): array
  374. {
  375. $externalPartnerJoboffererProfileInfoArray = [];
  376. /* @var JoboffererProfileAdditionalInfo $externalPartnerJoboffererProfileAdditionalInfo */
  377. if (!is_null($this->externalPartnerJoboffererProfileAdditionalInfos)) {
  378. foreach ($this->externalPartnerJoboffererProfileAdditionalInfos as $externalPartnerJoboffererProfileAdditionalInfo) {
  379. $externalPartnerJoboffererProfileInfoArray[] = $externalPartnerJoboffererProfileAdditionalInfo;
  380. }
  381. }
  382. return $externalPartnerJoboffererProfileInfoArray;
  383. }
  384. public function getExternalPartnerJoboffererProfileAdditionalInfoStringValueByName(string $infoName): ?string
  385. {
  386. /* @var JoboffererProfileAdditionalInfo $externalPartnerJoboffererProfileAdditionalInfo */
  387. if (!is_null($this->externalPartnerJoboffererProfileAdditionalInfos)) {
  388. foreach ($this->externalPartnerJoboffererProfileAdditionalInfos as $externalPartnerJoboffererProfileAdditionalInfo) {
  389. if ($externalPartnerJoboffererProfileAdditionalInfo->getInfoName() === $infoName) {
  390. return $externalPartnerJoboffererProfileAdditionalInfo->getInfoStringValue();
  391. }
  392. }
  393. }
  394. return null;
  395. }
  396. /** @throws Exception */
  397. public function setExternalPartnerJoboffererProfileAdditionalInfoStringValueByName(string $infoName, ?string $stringValue): void
  398. {
  399. if (!is_null($this->externalPartnerJoboffererProfileAdditionalInfos)) {
  400. /** @var JoboffererProfileAdditionalInfo $externalPartnerJoboffererProfileAdditionalInfo */
  401. foreach ($this->externalPartnerJoboffererProfileAdditionalInfos as $externalPartnerJoboffererProfileAdditionalInfo) {
  402. if ($externalPartnerJoboffererProfileAdditionalInfo->getInfoName() === $infoName) {
  403. $externalPartnerJoboffererProfileAdditionalInfo->setInfoStringValue($stringValue);
  404. return;
  405. }
  406. }
  407. } else {
  408. $this->externalPartnerJoboffererProfileAdditionalInfos = new ArrayCollection();
  409. }
  410. $externalPartnerJoboffererProfileAdditionalInfo = new JoboffererProfileAdditionalInfo();
  411. $externalPartnerJoboffererProfileAdditionalInfo->setJoboffererProfile($this);
  412. $externalPartnerJoboffererProfileAdditionalInfo->setInfoName($infoName);
  413. $externalPartnerJoboffererProfileAdditionalInfo->setInfoStringValue($stringValue);
  414. $this->externalPartnerJoboffererProfileAdditionalInfos->add($externalPartnerJoboffererProfileAdditionalInfo);
  415. }
  416. public function getExternalPartnerJoboffererProfileAdditionalInfoIntValueByName(string $infoName): ?int
  417. {
  418. if (!is_null($this->externalPartnerJoboffererProfileAdditionalInfos)) {
  419. /** @var JoboffererProfileAdditionalInfo $externalPartnerJoboffererProfileAdditionalInfo */
  420. foreach ($this->externalPartnerJoboffererProfileAdditionalInfos as $externalPartnerJoboffererProfileAdditionalInfo) {
  421. if ($externalPartnerJoboffererProfileAdditionalInfo->getInfoName() === $infoName) {
  422. return $externalPartnerJoboffererProfileAdditionalInfo->getInfoIntValue();
  423. }
  424. }
  425. }
  426. return null;
  427. }
  428. /** @throws Exception */
  429. public function setExternalPartnerJoboffererProfileAdditionalInfoIntValueByName(string $infoName, int $intValue): void
  430. {
  431. if (!is_null($this->externalPartnerJoboffererProfileAdditionalInfos)) {
  432. /** @var JoboffererProfileAdditionalInfo $externalPartnerJoboffererProfileAdditionalInfo */
  433. foreach ($this->externalPartnerJoboffererProfileAdditionalInfos as $externalPartnerJoboffererProfileAdditionalInfo) {
  434. if ($externalPartnerJoboffererProfileAdditionalInfo->getInfoName() === $infoName) {
  435. $externalPartnerJoboffererProfileAdditionalInfo->setInfoIntValue($intValue);
  436. return;
  437. }
  438. }
  439. } else {
  440. $this->externalPartnerJoboffererProfileAdditionalInfos = new ArrayCollection();
  441. }
  442. $externalPartnerJoboffererProfileAdditionalInfo = new JoboffererProfileAdditionalInfo();
  443. $externalPartnerJoboffererProfileAdditionalInfo->setJoboffererProfile($this);
  444. $externalPartnerJoboffererProfileAdditionalInfo->setInfoName($infoName);
  445. $externalPartnerJoboffererProfileAdditionalInfo->setInfoIntValue($intValue);
  446. $this->externalPartnerJoboffererProfileAdditionalInfos->add($externalPartnerJoboffererProfileAdditionalInfo);
  447. }
  448. /**
  449. * @ORM\ManyToOne(targetEntity="App\Entity\ContentDistribution\AgenturFuerArbeit\DestatisEconomicSector", cascade={"persist"})
  450. *
  451. * @ORM\JoinColumn(name="destatis_economic_sectors_running_number", referencedColumnName="running_number", nullable=true, onDelete="SET NULL")
  452. */
  453. protected ?DestatisEconomicSector $destatisEconomicSector = null;
  454. public function getDestatisEconomicSector(): ?DestatisEconomicSector
  455. {
  456. if (is_null($this->destatisEconomicSector)
  457. && !is_null($this->getUser()->getIntegratedExternalPartnerCustomer())
  458. ) {
  459. return $this
  460. ->getUser()
  461. ->getIntegratedExternalPartnerCustomer()
  462. ->getDestatisEconomicSector();
  463. }
  464. return $this->destatisEconomicSector;
  465. }
  466. public function setDestatisEconomicSector(?DestatisEconomicSector $destatisEconomicSector): void
  467. {
  468. $this->destatisEconomicSector = $destatisEconomicSector;
  469. }
  470. /**
  471. * @ORM\Column(name="destatis_economic_sector_decision", type="smallint", nullable=true, options={"unsigned": true})
  472. */
  473. protected ?int $destatisEconomicSectorDecision;
  474. public function setDestatisEconomicSectorDecision(?int $destatisEconomicSectorDecision): void
  475. {
  476. if (!is_null($destatisEconomicSectorDecision)) {
  477. if (!ReflectionHelper::hasConstWithValue(
  478. DestatisEconomicSectorService::class,
  479. 'SECTOR_DECISION_',
  480. $destatisEconomicSectorDecision)
  481. ) {
  482. throw new InvalidArgumentException("Value '$destatisEconomicSectorDecision' not allowed for destatisEconomicSectorDecision.");
  483. }
  484. }
  485. $this->destatisEconomicSectorDecision = $destatisEconomicSectorDecision;
  486. }
  487. public function getDestatisEconomicSectorDecision(): ?int
  488. {
  489. if (is_null($this->destatisEconomicSectorDecision)
  490. && !is_null($this->getUser()->getIntegratedExternalPartnerCustomer())
  491. ) {
  492. return $this
  493. ->getUser()
  494. ->getIntegratedExternalPartnerCustomer()
  495. ->getDestatisEconomicSectorDecision();
  496. }
  497. return $this->destatisEconomicSectorDecision;
  498. }
  499. public function getDestatisEconomicSectorOrigin(): ?int
  500. {
  501. if (!is_null($this->destatisEconomicSector)) {
  502. return DestatisEconomicSectorService::SECTOR_ORIGIN_JOBOFFERER_PROFILE;
  503. }
  504. if (!is_null($this->getUser()->getIntegratedExternalPartnerCustomer())) {
  505. return $this
  506. ->getUser()
  507. ->getIntegratedExternalPartnerCustomer()
  508. ->getDestatisEconomicSectorOrigin();
  509. }
  510. return null;
  511. }
  512. /**
  513. * @ORM\Column(name="identified_as_recruitment_agency", type="boolean", nullable=false)
  514. */
  515. private bool $identifiedAsRecruitmentAgency;
  516. public function isIdentifiedAsRecruitmentAgency(): bool
  517. {
  518. return $this->identifiedAsRecruitmentAgency;
  519. }
  520. // please consider using the method markAsRecruitmentAgency() instead of the direct setter
  521. public function setIdentifiedAsRecruitmentAgency(bool $identifiedAsRecruitmentAgency): void
  522. {
  523. $this->identifiedAsRecruitmentAgency = $identifiedAsRecruitmentAgency;
  524. }
  525. /**
  526. * @ORM\Column(name="limited_in_search", type="smallint", nullable=false)
  527. */
  528. private int $limitedInSearch;
  529. public function getLimitedInSearch(): int
  530. {
  531. return $this->limitedInSearch;
  532. }
  533. public function isLimitedInSearch(): int
  534. {
  535. return $this->limitedInSearch === self::LIMITED_IN_SEARCH_VALUE_TRUE || $this->limitedInSearch === self::LIMITED_IN_SEARCH_VALUE_TRUE_BY_HAND;
  536. }
  537. public function setLimitedInSearch(int $limitedInSearch): void
  538. {
  539. if (!ReflectionHelper::hasConstWithValue(
  540. self::class,
  541. 'LIMITED_IN_SEARCH_VALUE_',
  542. $limitedInSearch)
  543. ) {
  544. throw new InvalidArgumentException("Value '$limitedInSearch' not allowed for limitedInSearch.");
  545. }
  546. $this->limitedInSearch = $limitedInSearch;
  547. }
  548. /**
  549. * @ORM\Column(name="email_for_invoice", type="string", nullable=true)
  550. */
  551. protected ?string $emailForInvoice;
  552. public function setEmailForInvoice(
  553. ?string $emailForInvoice = null
  554. ): void {
  555. if (!is_null($emailForInvoice) && $emailForInvoice !== '' && !MailService::emailAddressIsValidForMailer($emailForInvoice)) {
  556. throw new InvalidEmailException("E-mail {$emailForInvoice} is not valid for SwiftMailer.");
  557. }
  558. $this->emailForInvoice = $emailForInvoice;
  559. }
  560. public function getEmailForInvoice(): ?string
  561. {
  562. return $this->emailForInvoice;
  563. }
  564. }