| @@ -0,0 +1,76 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| namespace App\Controllers; | |||||
| use App\Repositories\CustomerRepository; | |||||
| use App\Repositories\CustomerTypeRepository; | |||||
| use Core\Controller; | |||||
| use Core\Request; | |||||
| use Core\Response; | |||||
| class CustomerApiController extends Controller | |||||
| { | |||||
| public function customers(): Response | |||||
| { | |||||
| $request = Request::capture(); | |||||
| $customerTypeId = (int) ($request->input('customer_type_id') ?? 0); | |||||
| $repo = new CustomerRepository(database()); | |||||
| $rows = $customerTypeId > 0 | |||||
| ? $repo->allByTypeWithType($customerTypeId) | |||||
| : $repo->allWithType(); | |||||
| return $this->json(array_map([$this, 'formatCustomer'], $rows)); | |||||
| } | |||||
| public function customer(string $id): Response | |||||
| { | |||||
| $repo = new CustomerRepository(database()); | |||||
| $row = $repo->findWithType((int) $id); | |||||
| if ($row === null) { | |||||
| return Response::json(['error' => 'Not found'], 404); | |||||
| } | |||||
| return $this->json($this->formatCustomer($row)); | |||||
| } | |||||
| public function customerTypes(): Response | |||||
| { | |||||
| $repo = new CustomerTypeRepository(database()); | |||||
| $rows = $repo->allOrderedByName(); | |||||
| $data = array_map(static function (array $row): array { | |||||
| $attributes = []; | |||||
| if (!empty($row['attributes'])) { | |||||
| $attributes = json_decode((string) $row['attributes'], true) ?? []; | |||||
| } | |||||
| return [ | |||||
| 'id' => (int) $row['id'], | |||||
| 'name' => (string) $row['name'], | |||||
| 'api_match_field' => (string) ($row['api_match_field'] ?? ''), | |||||
| 'attributes' => $attributes, | |||||
| ]; | |||||
| }, $rows); | |||||
| return $this->json($data); | |||||
| } | |||||
| private function formatCustomer(array $row): array | |||||
| { | |||||
| $attributeValues = []; | |||||
| if (!empty($row['attribute_values'])) { | |||||
| $attributeValues = json_decode((string) $row['attribute_values'], true) ?? []; | |||||
| } | |||||
| return [ | |||||
| 'id' => (int) $row['id'], | |||||
| 'customer_type_id' => (int) $row['customer_type_id'], | |||||
| 'customer_type_name' => (string) ($row['customer_type_name'] ?? ''), | |||||
| 'attribute_values' => $attributeValues, | |||||
| ]; | |||||
| } | |||||
| } | |||||
| @@ -48,20 +48,39 @@ class CustomerRepository extends Repository | |||||
| 'SELECT c.id, c.customer_type_id, c.attribute_values, | 'SELECT c.id, c.customer_type_id, c.attribute_values, | ||||
| c.created_at, c.updated_at, | c.created_at, c.updated_at, | ||||
| ct.name AS customer_type_name, | ct.name AS customer_type_name, | ||||
| ct.attributes AS customer_type_attributes | |||||
| ct.attributes AS customer_type_attributes, | |||||
| ct.api_match_field | |||||
| FROM customer c | FROM customer c | ||||
| INNER JOIN customer_type ct ON c.customer_type_id = ct.id | INNER JOIN customer_type ct ON c.customer_type_id = ct.id | ||||
| ORDER BY c.id DESC' | ORDER BY c.id DESC' | ||||
| ); | ); | ||||
| } | } | ||||
| /** @return list<array<string, mixed>> */ | |||||
| public function allByTypeWithType(int $typeId): array | |||||
| { | |||||
| return $this->database->query( | |||||
| 'SELECT c.id, c.customer_type_id, c.attribute_values, | |||||
| c.created_at, c.updated_at, | |||||
| ct.name AS customer_type_name, | |||||
| ct.attributes AS customer_type_attributes, | |||||
| ct.api_match_field | |||||
| FROM customer c | |||||
| INNER JOIN customer_type ct ON c.customer_type_id = ct.id | |||||
| WHERE c.customer_type_id = :type_id | |||||
| ORDER BY c.id DESC', | |||||
| ['type_id' => $typeId] | |||||
| ); | |||||
| } | |||||
| public function findWithType(int $id): ?array | public function findWithType(int $id): ?array | ||||
| { | { | ||||
| return $this->database->first( | return $this->database->first( | ||||
| 'SELECT c.id, c.customer_type_id, c.attribute_values, | 'SELECT c.id, c.customer_type_id, c.attribute_values, | ||||
| c.created_at, c.updated_at, | c.created_at, c.updated_at, | ||||
| ct.name AS customer_type_name, | ct.name AS customer_type_name, | ||||
| ct.attributes AS customer_type_attributes | |||||
| ct.attributes AS customer_type_attributes, | |||||
| ct.api_match_field | |||||
| FROM customer c | FROM customer c | ||||
| INNER JOIN customer_type ct ON c.customer_type_id = ct.id | INNER JOIN customer_type ct ON c.customer_type_id = ct.id | ||||
| WHERE c.id = :id', | WHERE c.id = :id', | ||||
| @@ -0,0 +1,32 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| use Core\Database; | |||||
| use Core\Migration; | |||||
| return new class extends Migration | |||||
| { | |||||
| public function up(Database $database): void | |||||
| { | |||||
| $columnExists = $database->first( | |||||
| "SELECT 1 AS col FROM INFORMATION_SCHEMA.COLUMNS | |||||
| WHERE TABLE_NAME = 'customer_type' AND COLUMN_NAME = 'api_match_field'" | |||||
| ); | |||||
| if ($columnExists) { | |||||
| return; | |||||
| } | |||||
| $database->execute( | |||||
| "ALTER TABLE customer_type ADD api_match_field NVARCHAR(255) NULL" | |||||
| ); | |||||
| } | |||||
| public function down(Database $database): void | |||||
| { | |||||
| $database->execute( | |||||
| "ALTER TABLE customer_type DROP COLUMN api_match_field" | |||||
| ); | |||||
| } | |||||
| }; | |||||
| @@ -6,6 +6,7 @@ use App\Controllers\ApiProxyController; | |||||
| use App\Controllers\AuthController; | use App\Controllers\AuthController; | ||||
| use App\Controllers\CampaignController; | use App\Controllers\CampaignController; | ||||
| use App\Controllers\CampaignTypeController; | use App\Controllers\CampaignTypeController; | ||||
| use App\Controllers\CustomerApiController; | |||||
| use App\Controllers\CustomerController; | use App\Controllers\CustomerController; | ||||
| use App\Controllers\CustomerTypeController; | use App\Controllers\CustomerTypeController; | ||||
| use App\Controllers\HealthController; | use App\Controllers\HealthController; | ||||
| @@ -13,6 +14,11 @@ use App\Controllers\HomeController; | |||||
| use App\Controllers\JobController; | use App\Controllers\JobController; | ||||
| use App\Controllers\JobTypeController; | use App\Controllers\JobTypeController; | ||||
| // ── Customer API (public JSON endpoints) ────────────────────────────────────── | |||||
| $router->get('/api/customers', [CustomerApiController::class, 'customers']); | |||||
| $router->get('/api/customers/{id}', [CustomerApiController::class, 'customer']); | |||||
| $router->get('/api/customer-types', [CustomerApiController::class, 'customerTypes']); | |||||
| // ── API Proxy ───────────────────────────────────────────────────────────────── | // ── API Proxy ───────────────────────────────────────────────────────────────── | ||||
| $router->get('/api/proxy', [ApiProxyController::class, 'fetch'])->middleware('auth'); | $router->get('/api/proxy', [ApiProxyController::class, 'fetch'])->middleware('auth'); | ||||
Powered by TurnKey Linux.