phase 1 and 2

This commit is contained in:
Doar Mihai
2026-04-03 00:23:01 +03:00
parent 4976742c29
commit 9dcf3c36d7
33 changed files with 2563 additions and 5 deletions
@@ -0,0 +1,176 @@
<?php
namespace App\Services\JobApi\Clients;
use App\Services\JobApi\DTO\JobData;
use App\Services\JobApi\Exceptions\ApiException;
use App\Services\JobApi\Transformers\AdzunaTransformer;
use App\Services\JobApi\Transformers\JobTransformer;
use Illuminate\Http\Client\PendingRequest;
class AdzunaClient extends JobApiClient
{
private string $appId;
private string $appKey;
private string $country = 'us'; // Default to US
protected function getTransformer(): JobTransformer
{
return new AdzunaTransformer();
}
protected function attachAuthentication(PendingRequest $client): PendingRequest
{
// Parse API key as "app_id:app_key"
if ($this->source->api_key && str_contains($this->source->api_key, ':')) {
[$this->appId, $this->appKey] = explode(':', $this->source->api_key, 2);
} else {
throw new ApiException(
'Adzuna API key must be in format "app_id:app_key"',
$this->source->name
);
}
// Extract country from configuration if set
if (!empty($this->source->configuration['country'])) {
$this->country = $this->source->configuration['country'];
}
return $client;
}
/**
* Fetch jobs from Adzuna API
*
* @param array $params [
* 'what' => string, // Job title or keywords
* 'where' => string, // Location
* 'results_per_page' => int,
* 'page' => int,
* 'category' => string,
* 'full_time' => int, // 1 for full-time only
* 'part_time' => int, // 1 for part-time only
* 'contract' => int, // 1 for contract only
* 'max_days_old' => int, // Jobs posted within last N days
* ]
* @return array<JobData>
*/
public function fetchJobs(array $params = []): array
{
try {
$queryParams = $this->buildQueryParams($params);
// Adzuna API endpoint structure: /v1/api/jobs/{country}/search/{page}
$page = $queryParams['page'] ?? 1;
unset($queryParams['page']);
$endpoint = "search/{$page}";
$response = $this->makeRequest('GET', $endpoint, $queryParams);
$data = $response->json();
if (!isset($data['results']) || !is_array($data['results'])) {
throw new ApiException(
'Invalid response structure from Adzuna API',
$this->source->name,
['response' => $data]
);
}
$this->updateLastFetched();
return $this->transformer->transformMany($data['results']);
} catch (ApiException $e) {
throw $e;
} catch (\Throwable $e) {
throw new ApiException(
'Failed to fetch jobs from Adzuna',
$this->source->name,
['error' => $e->getMessage()],
0,
$e
);
}
}
/**
* Build query parameters for the API request
*/
private function buildQueryParams(array $params): array
{
$queryParams = [
'app_id' => $this->appId,
'app_key' => $this->appKey,
'results_per_page' => min($params['results_per_page'] ?? 20, 50),
'page' => $params['page'] ?? 1,
];
if (!empty($params['what'])) {
$queryParams['what'] = $params['what'];
}
if (!empty($params['where'])) {
$queryParams['where'] = $params['where'];
}
if (isset($params['category'])) {
$queryParams['category'] = $params['category'];
}
if (isset($params['full_time'])) {
$queryParams['full_time'] = (int) $params['full_time'];
}
if (isset($params['part_time'])) {
$queryParams['part_time'] = (int) $params['part_time'];
}
if (isset($params['contract'])) {
$queryParams['contract'] = (int) $params['contract'];
}
if (isset($params['max_days_old'])) {
$queryParams['max_days_old'] = (int) $params['max_days_old'];
}
return $queryParams;
}
/**
* Override buildUrl to include country in path
*/
protected function buildUrl(string $endpoint): string
{
$baseUrl = rtrim($this->source->api_url, '/');
$endpoint = ltrim($endpoint, '/');
return "{$baseUrl}/{$this->country}/{$endpoint}";
}
/**
* Get supported countries
*/
public function getSupportedCountries(): array
{
return [
'au' => 'Australia',
'at' => 'Austria',
'br' => 'Brazil',
'ca' => 'Canada',
'fr' => 'France',
'de' => 'Germany',
'in' => 'India',
'it' => 'Italy',
'nl' => 'Netherlands',
'nz' => 'New Zealand',
'pl' => 'Poland',
'ru' => 'Russia',
'sg' => 'Singapore',
'za' => 'South Africa',
'ch' => 'Switzerland',
'gb' => 'United Kingdom',
'us' => 'United States',
];
}
}