pdo = $GLOBALS['pdo']; return; } throw new \RuntimeException('Global PDO connection not initialized'); } /** * @return array */ private function getColumnsMeta(): array { if (self::$columnsMeta !== null) { return self::$columnsMeta; } $stmt = $this->pdo->prepare( 'SELECT column_name, is_nullable, data_type FROM information_schema.columns WHERE table_schema = current_schema() AND table_name = :table ORDER BY ordinal_position' ); $stmt->execute(['table' => 'cpr']); $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC); if (!$rows) { throw new \RuntimeException('Unable to load CPR table metadata'); } $meta = []; foreach ($rows as $row) { $meta[$row['column_name']] = [ 'nullable' => strtoupper((string)$row['is_nullable']) === 'YES', 'data_type' => (string)$row['data_type'], ]; } self::$columnsMeta = $meta; return self::$columnsMeta; } /** * @return array */ public function getUserColumns(): array { $meta = $this->getColumnsMeta(); unset($meta['cpr_id']); return array_diff_key($meta, ['status_id' => true, 'payment_id' => true]); } public function create(array $data, int $statusId, int $paymentId): array { $meta = $this->getColumnsMeta(); $columns = []; $placeholders = []; $params = []; foreach ($meta as $column => $info) { if ($column === 'cpr_id') { continue; } if ($column === 'status_id') { $columns[] = '"status_id"'; $placeholders[] = ':status_id'; $params['status_id'] = $statusId; continue; } if ($column === 'payment_id') { $columns[] = '"payment_id"'; $placeholders[] = ':payment_id'; $params['payment_id'] = $paymentId; continue; } if (!array_key_exists($column, $data)) { if ($info['nullable']) { $columns[] = '"' . $column . '"'; $placeholders[] = ':' . $column; $params[$column] = null; continue; } throw new \InvalidArgumentException("Missing field: {$column}"); } $value = $data[$column]; if ($column === 'cpr_children_codes') { $value = $this->normalizeChildrenCodes($value); } $columns[] = '"' . $column . '"'; $placeholders[] = ':' . $column; $params[$column] = $value; } $sql = 'INSERT INTO "cpr" (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $placeholders) . ') RETURNING cpr_id'; $stmt = $this->pdo->prepare($sql); $stmt->execute($params); $cprId = (int)$stmt->fetchColumn(); $record = $this->fetchById($cprId); if (!$record) { throw new \RuntimeException('Failed to load created CPR record'); } if (isset($record['cpr_children_codes'])) { $record['cpr_children_codes'] = $this->decodeChildrenCodes((string)$record['cpr_children_codes']); } $record['cpr_id'] = (int)$record['cpr_id']; if (isset($record['status_id'])) { $record['status_id'] = (int)$record['status_id']; } if (isset($record['payment_id'])) { $record['payment_id'] = (int)$record['payment_id']; } return $record; } private function normalizeChildrenCodes($value): string { if (is_array($value)) { $value = array_map('strval', array_values($value)); if (!$value) { throw new \InvalidArgumentException('cpr_children_codes must not be empty'); } $encoded = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); if ($encoded === false) { throw new \InvalidArgumentException('Invalid cpr_children_codes payload'); } return $encoded; } if (is_string($value) && trim($value) !== '') { return $value; } throw new \InvalidArgumentException('cpr_children_codes must be a non-empty string or array of strings'); } /** * @return array|string */ private function decodeChildrenCodes(string $stored) { $decoded = json_decode($stored, true); if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { return $decoded; } return $stored; } private function fetchById(int $id): ?array { $stmt = $this->pdo->prepare('SELECT * FROM "cpr" WHERE cpr_id = :id'); $stmt->execute(['id' => $id]); $record = $stmt->fetch(\PDO::FETCH_ASSOC); return $record ?: null; } }