src/ApiBundle/Controller/JobOfferController.php line 20

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace ApiBundle\Controller;
  4. use AppBundle\MobileJobOffer\DTO\MobileJobOfferDetailsDTO;
  5. use AppBundle\MobileJobOffer\Request\MobileJobOfferSearchRequest;
  6. use AppBundle\MobileJobOffer\Service\InterestSubmissionService;
  7. use AppBundle\MobileJobOffer\Service\MobileJobOfferSearchService;
  8. use AppBundle\Repository\MobileJobOfferRepository;
  9. use Exception;
  10. use OpenApi\Attributes as OA;
  11. use Pimcore\Model\DataObject\MobileJobOffer;
  12. use Symfony\Component\HttpFoundation\JsonResponse;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\HttpFoundation\Response;
  15. use Symfony\Component\Routing\Annotation\Route;
  16. class JobOfferController extends ApiController
  17. {
  18.     private MobileJobOfferSearchService $mobileJobOfferSearchService;
  19.     private MobileJobOfferRepository $mobileJobOfferRepository;
  20.     private InterestSubmissionService $interestSubmissionService;
  21.     public function __construct(MobileJobOfferSearchService $mobileJobOfferSearchServiceMobileJobOfferRepository $mobileJobOfferRepositoryInterestSubmissionService $interestSubmissionServicestring $apiKey)
  22.     {
  23.         $this->mobileJobOfferSearchService $mobileJobOfferSearchService;
  24.         $this->mobileJobOfferRepository $mobileJobOfferRepository;
  25.         $this->interestSubmissionService $interestSubmissionService;
  26.         parent::__construct($apiKey);
  27.     }
  28.     #[Route('/api/job-offers'name'api_job_offers_list'methods: ['GET'])]
  29.     #[OA\Get(path'/api/job-offers'description'Zwraca listę ofert pracy z możliwością filtrowania po mieście, stanowisku, rodzaju umowy, lokalizacji GPS, dacie oraz stronnicowaniem.'summary'Lista ofert pracy z filtrami i paginacją'tags: ['Job Offers'])]
  30.     #[OA\Parameter(name'X-API-KEY'description'Klucz API wymagany do autoryzacji'in'header'requiredtrueschema: new OA\Schema(type'string'example'your-api-key'))]
  31.     #[OA\Parameter(name'cityIds'description'Lista ID miast, oddzielone przecinkami (np. 1,2,3)'in'query'requiredfalseschema: new OA\Schema(type'string'example'1,2,3'))]
  32.     #[OA\Parameter(name'positionIds'description'Lista ID stanowisk, oddzielone przecinkami (np. 1,2,3)'in'query'requiredfalseschema: new OA\Schema(type'string'example'1,2,5'))]
  33.     #[OA\Parameter(name'contractTypeIds'description'Lista ID rodzajów umów, oddzielone przecinkami (np. 1,3)'in'query'requiredfalseschema: new OA\Schema(type'string'example'1,3'))]
  34.     #[OA\Parameter(name'gpsPoints'description"Tablica punktów GPS w formacie 'lat,lon'. Użyj gpsPoints[]=52.2297,21.0122&gpsPoints[]=50.06143,19.93658"in'query'requiredfalseschema: new OA\Schema(
  35.         type'array',
  36.         items: new OA\Items(description'Format: latitude,longitude'type'string'example'52.2297,21.0122'),
  37.     ), example: ['52.2297,21.0122''50.06143,19.93658'], style'form'explodetrue)]
  38.     #[OA\Parameter(name'gpsRadius'description'Promień w kilometrach wokół punktu GPS do filtrowania ofert'in'query'requiredfalseschema: new OA\Schema(type'number'format'float'example10))]
  39.     #[OA\Parameter(name'dateFrom'description'Początkowa data zakresu w formacie YYYY-MM-DD'in'query'requiredfalseschema: new OA\Schema(type'string'format'date'example'2025-09-01'))]
  40.     #[OA\Parameter(name'dateTo'description'Końcowa data zakresu w formacie YYYY-MM-DD'in'query'requiredfalseschema: new OA\Schema(type'string'format'date'example'2025-09-30'))]
  41.     #[OA\Parameter(name'limit'description'Ilość ofert do zwrócenia na stronie (stronnicowanie)'in'query'requiredfalseschema: new OA\Schema(type'integer', default: 20example20))]
  42.     #[OA\Parameter(name'offset'description'Przesunięcie wyników (ilość ofert do pominięcia) dla stronnicowania'in'query'requiredfalseschema: new OA\Schema(type'integer', default: 0example0))]
  43.     #[OA\Response(
  44.         response200,
  45.         description'Lista ofert pracy',
  46.         content: new OA\JsonContent(
  47.             properties: [
  48.                 new OA\Property(property'success'type'boolean'exampletrue),
  49.                 new OA\Property(
  50.                     property'data',
  51.                     properties: [
  52.                         new OA\Property(property'hasMore'description'Czy są kolejne strony wyników'type'boolean'exampletrue),
  53.                         new OA\Property(property'totalCount'description'Całkowita liczba ofert spełniających kryteria'type'integer'example42),
  54.                         new OA\Property(
  55.                             property'offers',
  56.                             type'array',
  57.                             items: new OA\Items(
  58.                                 properties: [
  59.                                     new OA\Property(property'id'type'integer'example7423),
  60.                                     new OA\Property(property'nameFirstLine'type'string'example'Magisterka farmacji'),
  61.                                     new OA\Property(property'nameSecondLine'type'string'example'Magister farmacji'),
  62.                                     new OA\Property(property'cityId'type'integer'example1),
  63.                                     new OA\Property(property'cityName'type'string'example'Kraków'),
  64.                                     new OA\Property(property'hourlyRateSummary'type'string'example'25-30 zł/h'),
  65.                                     new OA\Property(property'publicationDate'type'string'format'date-time'example'2025-09-10T12:00:00Z'),
  66.                                 ],
  67.                                 type'object',
  68.                             ),
  69.                         ),
  70.                     ],
  71.                     type'object',
  72.                 ),
  73.             ],
  74.             type'object',
  75.         ),
  76.     )]
  77.     public function list(Request $request): JsonResponse
  78.     {
  79.         if (!$this->validateApiKey($request)) {
  80.             return $this->returnInvalidApiKeyError();
  81.         }
  82.         try {
  83.             $searchRequest MobileJobOfferSearchRequest::fromRequest($request);
  84.             $offer $this->mobileJobOfferSearchService->searchOffer($searchRequest);
  85.             return new JsonResponse([
  86.                 'success' => true,
  87.                 'data' => $offer,
  88.             ]);
  89.         } catch (Exception $e) {
  90.             return new JsonResponse([
  91.                 'success' => false,
  92.                 'error' => $e->getMessage(),
  93.             ], Response::HTTP_BAD_REQUEST);
  94.         }
  95.     }
  96.     #[Route('/api/job-offers/{id}'name'api_job_offers_details'methods: ['GET'])]
  97.     #[OA\Get(path'/api/job-offers/{id}'description'Endpoint zwraca szczegółowe informacje o konkretnej ofercie pracy na podstawie jej ID.'summary'Szczegóły oferty pracy'tags: ['Job Offers'])]
  98.     #[OA\Parameter(name'X-API-KEY'description'Klucz API wymagany do autoryzacji'in'header'requiredtrueschema: new OA\Schema(type'string'example'your-api-key'))]
  99.     #[OA\Parameter(name'id'description'ID oferty pracy'in'path'requiredtrueschema: new OA\Schema(type'integer'example7423))]
  100.     #[OA\Response(
  101.         response200,
  102.         description'Szczegóły oferty pracy',
  103.         content: new OA\JsonContent(
  104.             properties: [
  105.                 new OA\Property(property'success'type'boolean'exampletrue),
  106.                 new OA\Property(
  107.                     property'data',
  108.                     properties: [
  109.                         new OA\Property(property'id'type'integer'example7423),
  110.                         new OA\Property(property'nameFirstLine'type'string'example'Magisterka farmacji'),
  111.                         new OA\Property(property'nameSecondLine'type'string'example'Magister farmacji'),
  112.                         new OA\Property(property'cityId'type'integer'example1),
  113.                         new OA\Property(property'cityName'type'string'example'Kraków'),
  114.                         new OA\Property(property'hourlyRateSummary'type'string'example'25-30 zł/h'),
  115.                         new OA\Property(
  116.                             property'gpsPoint',
  117.                             properties: [
  118.                                 new OA\Property(property'lat'type'number'format'float'example50.0514238),
  119.                                 new OA\Property(property'lng'type'number'format'float'example19.9415525),
  120.                             ],
  121.                             type'object',
  122.                         ),
  123.                         new OA\Property(
  124.                             property'sections',
  125.                             description'Sekcje opisu oferty, każda z tytułem i treścią',
  126.                             type'array',
  127.                             items: new OA\Items(
  128.                                 properties: [
  129.                                     new OA\Property(property'title'type'string'example'Opis stanowiska'),
  130.                                     new OA\Property(property'descriptions'type'string'example'Opis szczegółowy stanowiska pracy...'),
  131.                                 ],
  132.                                 type'object',
  133.                             ),
  134.                         ),
  135.                     ],
  136.                     type'object',
  137.                 ),
  138.             ],
  139.             type'object',
  140.         ),
  141.     )]
  142.     public function details(Request $requestint $id): JsonResponse
  143.     {
  144.         if (!$this->validateApiKey($request)) {
  145.             return $this->returnInvalidApiKeyError();
  146.         }
  147.         $mobile $this->mobileJobOfferRepository->find($id);
  148.         if (!$mobile instanceof MobileJobOffer) {
  149.             return new JsonResponse([
  150.                 'success' => false,
  151.                 'message' => 'Offer not found',
  152.             ], Response::HTTP_NOT_FOUND);
  153.         }
  154.         $data MobileJobOfferDetailsDTO::createFromMobileJobOffer($mobile);
  155.         return new JsonResponse([
  156.             'success' => true,
  157.             'data' => $data,
  158.         ]);
  159.     }
  160.     #[Route('/api/job-offers/interest'name'api_job_offers_interest'methods: ['POST'])]
  161.     #[OA\Post(path'/api/job-offers/interest'description'Przyjmuje zgłoszenie zainteresowania ofertą pracy z wybranymi terminami oraz danymi kontaktowymi użytkownika.'summary'Zgłoś zainteresowanie ofertą pracy na wybrane terminy'tags: ['Job Offers'])]
  162.     #[OA\Parameter(name'X-API-KEY'description'Klucz API wymagany do autoryzacji'in'header'requiredtrueschema: new OA\Schema(type'string'example'your-api-key'))]
  163.     #[OA\RequestBody(
  164.         requiredtrue,
  165.         content: new OA\JsonContent(
  166.             required: ['offerId''selectedDateIds''phone'],
  167.             properties: [
  168.                 new OA\Property(property'offerId'description'ID oferty pracy'type'integer'example7423nullablefalse),
  169.                 new OA\Property(
  170.                     property'selectedDateIds',
  171.                     description'Tablica ID terminów, którymi użytkownik jest zainteresowany',
  172.                     type'array',
  173.                     items: new OA\Items(type'integer'),
  174.                     minItems1,
  175.                     example: [02],
  176.                 ),
  177.                 new OA\Property(property'phone'description'Numer telefonu kontaktowego'type'string'example'+48123456789'nullablefalse),
  178.                 new OA\Property(property'futureContactConsent'description'Zgoda na przyszły kontakt'type'boolean'exampletruenullablefalse),
  179.             ],
  180.             type'object',
  181.         ),
  182.     )]
  183.     #[OA\Response(
  184.         response200,
  185.         description'Potwierdzenie przyjęcia zgłoszenia zainteresowania',
  186.         content: new OA\JsonContent(
  187.             properties: [
  188.                 new OA\Property(property'success'type'boolean'exampletrue),
  189.                 new OA\Property(property'message'type'string'example'The submission has been accepted.'),
  190.             ],
  191.             type'object',
  192.         ),
  193.     )]
  194.     #[OA\Response(
  195.         response404,
  196.         description'Błąd walidacji danych wejściowych',
  197.         content: new OA\JsonContent(
  198.             properties: [
  199.                 new OA\Property(property'success'type'boolean'examplefalse),
  200.                 new OA\Property(property'message'type'string'example'Selected offer does not exist.'),
  201.             ],
  202.             type'object',
  203.         ),
  204.     )]
  205.     public function submitInterest(Request $request): JsonResponse
  206.     {
  207.         if (!$this->validateApiKey($request)) {
  208.             return $this->returnInvalidApiKeyError();
  209.         }
  210.         $data json_decode($request->getContent(), true);
  211.         $offer $this->mobileJobOfferSearchService->offerExists($data['offerId']);
  212.         if (!$offer) {
  213.             return new JsonResponse([
  214.                 'success' => false,
  215.                 'message' => 'Selected offer does not exist.',
  216.             ], Response::HTTP_NOT_FOUND);
  217.         }
  218.         if (isset($data['selectedDateIds']) && !$this->mobileJobOfferSearchService->datesExist($data['offerId'], $data['selectedDateIds'])) {
  219.             return new JsonResponse([
  220.                 'success' => false,
  221.                 'message' => 'At least one of the selected dates does not exist.',
  222.             ], Response::HTTP_NOT_FOUND);
  223.         }
  224.         $this->interestSubmissionService->submitInterest($data);
  225.         return new JsonResponse([
  226.             'success' => true,
  227.             'message' => 'The submission has been accepted.',
  228.         ]);
  229.     }
  230. }