> */ private array $fields; /** @var list */ private array $builtInSources; /** @param array> $fields @param list $additionalBuiltInSources */ public function __construct(array $fields, array $additionalBuiltInSources = []) { $this->fields = $fields; $this->builtInSources = array_values(array_unique(array_merge( array_values(array_filter(array_keys($fields), static fn(string $source): bool => !str_contains($source, '.'))), $additionalBuiltInSources ))); } public function sourceExists(string $source): bool { return isset($this->fields[$source]); } public function isBuiltInSource(string $source): bool { return in_array($source, $this->builtInSources, true); } public function sourceFields(string $source): array { return $this->fields[$source] ?? []; } public function hasEmailField(string $source): bool { return in_array('Email', $this->fields[$source] ?? [], true) || in_array('email', $this->fields[$source] ?? [], true); } public function joinPath(string $left, string $right): ?array { $pairs = [ 'contacts|accounts' => ['left' => 'contacts.Accountid', 'right' => 'accounts.ID'], 'accounts|contacts' => ['left' => 'accounts.ID', 'right' => 'contacts.Accountid'], 'renewals|accounts' => ['left' => 'renewals.account_id', 'right' => 'accounts.ID'], 'accounts|renewals' => ['left' => 'accounts.ID', 'right' => 'renewals.account_id'], 'renewals|contacts' => ['left' => 'renewals.account_id', 'right' => 'contacts.Accountid'], 'contacts|renewals' => ['left' => 'contacts.Accountid', 'right' => 'renewals.account_id'], 'articles|pages' => ['left' => 'articles.PageID', 'right' => 'pages.ID'], 'pages|articles' => ['left' => 'pages.ID', 'right' => 'articles.PageID'], 'pages|issues' => ['left' => 'pages.Issue', 'right' => 'issues.ID'], 'issues|pages' => ['left' => 'issues.ID', 'right' => 'pages.Issue'], 'ads|pages' => ['left' => 'ads.PageID', 'right' => 'pages.ID'], 'pages|ads' => ['left' => 'pages.ID', 'right' => 'ads.PageID'], 'ads|advertisers' => ['left' => 'ads.Advertiser', 'right' => 'advertisers.AdvertiserName'], 'advertisers|ads' => ['left' => 'advertisers.AdvertiserName', 'right' => 'ads.Advertiser'], 'invoices|ads' => ['left' => 'invoices.ad_id', 'right' => 'ads.ID'], 'ads|invoices' => ['left' => 'ads.ID', 'right' => 'invoices.ad_id'], 'invoices|issues' => ['left' => 'invoices.issue_id', 'right' => 'issues.ID'], 'issues|invoices' => ['left' => 'issues.ID', 'right' => 'invoices.issue_id'], 'invoices|pages' => ['left' => 'invoices.issue_id', 'right' => 'pages.Issue'], 'pages|invoices' => ['left' => 'pages.Issue', 'right' => 'invoices.issue_id'], ]; if (isset($this->fields['ad_sizes'])) { $pairs['ads|ad_sizes'] = ['left' => 'ads.AdSize', 'right' => 'ad_sizes.SizeName']; $pairs['ad_sizes|ads'] = ['left' => 'ad_sizes.SizeName', 'right' => 'ads.AdSize']; } return $pairs[$left . '|' . $right] ?? null; } public function allKnownSources(): array { return array_keys($this->fields); } public function sourceTable(string $source): ?string { return $source; } public function fieldSql(string $source, string $field, string $alias): ?string { if (!isset($this->fields[$source]) || !in_array($field, $this->fields[$source], true)) { return null; } return $alias . '.`' . str_replace('`', '``', $field) . '`'; } }