<?php declare(strict_types=1); namespace MySQLReplication\Config; use JsonSerializable; readonly class Config implements JsonSerializable { public function __construct( public string $user, public string $host, public int $port, public string $password, public string $charset, public string $gtid, public string $mariaDbGtid, public int $slaveId, public string $binLogFileName, public string $binLogPosition, public array $eventsOnly, public array $eventsIgnore, public array $tablesOnly, public array $databasesOnly, public int $tableCacheSize, public array $custom, public float $heartbeatPeriod, public string $slaveUuid, private array $tablesRegex = [], private array $databasesRegex = [], ) { } public function validate(): void { if (!empty($this->host)) { $ip = gethostbyname($this->host); if (filter_var($ip, FILTER_VALIDATE_IP) === false) { throw new ConfigException(ConfigException::IP_ERROR_MESSAGE, ConfigException::IP_ERROR_CODE); } } if (!empty($this->port) && filter_var( $this->port, FILTER_VALIDATE_INT, [ 'options' => [ 'min_range' => 0, ], ] ) === false) { throw new ConfigException(ConfigException::PORT_ERROR_MESSAGE, ConfigException::PORT_ERROR_CODE); } if (!empty($this->gtid)) { foreach (explode(',', $this->gtid) as $gtid) { if (!(bool)preg_match( '/^([0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})((?::[0-9-]+)+)$/', $gtid, $matches )) { throw new ConfigException(ConfigException::GTID_ERROR_MESSAGE, ConfigException::GTID_ERROR_CODE); } } } if (!empty($this->slaveId) && filter_var( $this->slaveId, FILTER_VALIDATE_INT, [ 'options' => [ 'min_range' => 0, ], ] ) === false) { throw new ConfigException( ConfigException::SLAVE_ID_ERROR_MESSAGE, ConfigException::SLAVE_ID_ERROR_CODE ); } if (bccomp($this->binLogPosition, '0') === -1) { throw new ConfigException( ConfigException::BIN_LOG_FILE_POSITION_ERROR_MESSAGE, ConfigException::BIN_LOG_FILE_POSITION_ERROR_CODE ); } if (filter_var($this->tableCacheSize, FILTER_VALIDATE_INT, [ 'options' => [ 'min_range' => 0, ], ]) === false) { throw new ConfigException( ConfigException::TABLE_CACHE_SIZE_ERROR_MESSAGE, ConfigException::TABLE_CACHE_SIZE_ERROR_CODE ); } if ($this->heartbeatPeriod !== 0.0 && false === ( $this->heartbeatPeriod >= 0.001 && $this->heartbeatPeriod <= 4294967.0 )) { throw new ConfigException( ConfigException::HEARTBEAT_PERIOD_ERROR_MESSAGE, ConfigException::HEARTBEAT_PERIOD_ERROR_CODE ); } } public function checkDataBasesOnly(string $database): bool { return ($this->databasesOnly !== [] && !in_array($database, $this->databasesOnly, true)) || ($this->databasesRegex !== [] && !self::matchNames($database, $this->databasesRegex)); } public function checkTablesOnly(string $table): bool { return ($this->tablesOnly !== [] && !in_array($table, $this->tablesOnly, true)) || ($this->tablesRegex !== [] && !self::matchNames($table, $this->tablesRegex)); } public function checkEvent(int $type): bool { if ($this->eventsOnly !== [] && !in_array($type, $this->eventsOnly, true)) { return false; } if (in_array($type, $this->eventsIgnore, true)) { return false; } return true; } public function jsonSerialize(): array { return get_class_vars(self::class); } private static function matchNames(string $name, array $patterns): bool { foreach ($patterns as $pattern) { if (preg_match($pattern, $name)) { return true; } } return false; } } |