1<?php 2 3namespace Elastica; 4 5use Elastica\Exception\InvalidException; 6use Nyholm\Dsn\Configuration\Url; 7use Nyholm\Dsn\DsnParser; 8use Nyholm\Dsn\Exception\ExceptionInterface as DsnException; 9use Nyholm\Dsn\Exception\FunctionNotSupportedException; 10 11/** 12 * Elastica client configuration. 13 * 14 * @author Antoine Lamirault <lamiraultantoine@gmail.com> 15 */ 16class ClientConfiguration 17{ 18 /** 19 * Config with defaults. 20 * 21 * retryOnConflict: Use in \Elastica\Client::updateDocument 22 * bigintConversion: Set to true to enable the JSON bigint to string conversion option (see issue #717) 23 * 24 * @var array 25 */ 26 protected $configuration = [ 27 'host' => null, 28 'port' => null, 29 'path' => null, 30 'url' => null, 31 'proxy' => null, 32 'transport' => null, 33 'persistent' => true, 34 'timeout' => null, 35 'connections' => [], // host, port, path, transport, compression, persistent, timeout, username, password, auth_type, config -> (curl, headers, url) 36 'roundRobin' => false, 37 'retryOnConflict' => 0, 38 'bigintConversion' => false, 39 'username' => null, 40 'password' => null, 41 'auth_type' => null, // basic, digest, gssnegotiate, ntlm 42 ]; 43 44 /** 45 * Create configuration. 46 * 47 * @param array $config Additional config 48 * 49 * @return ClientConfiguration 50 */ 51 public static function fromArray(array $config): self 52 { 53 $clientConfiguration = new static(); 54 foreach ($config as $key => $value) { 55 $clientConfiguration->set($key, $value); 56 } 57 58 return $clientConfiguration; 59 } 60 61 /** 62 * Create configuration from Dsn string. Example of valid DSN strings: 63 * - http://localhost 64 * - http://foo:bar@localhost:1234?timeout=4&persistant=false 65 * - pool(http://127.0.0.1 http://127.0.0.2/bar?timeout=4). 66 * 67 * @return ClientConfiguration 68 */ 69 public static function fromDsn(string $dsnString): self 70 { 71 try { 72 $func = DsnParser::parseFunc($dsnString); 73 } catch (DsnException $e) { 74 throw new InvalidException(\sprintf('DSN "%s" is invalid.', $dsnString), 0, $e); 75 } 76 77 if ('dsn' === $func->getName()) { 78 /** @var Url $dsn */ 79 $dsn = $func->first(); 80 $clientConfiguration = self::fromArray(self::parseDsn($dsn)); 81 } elseif ('pool' === $func->getName()) { 82 $connections = []; 83 $clientConfiguration = new static(); 84 /** @var Url $arg */ 85 foreach ($func->getArguments() as $arg) { 86 $connections[] = self::parseDsn($arg); 87 } 88 $clientConfiguration->set('connections', $connections); 89 } else { 90 throw new FunctionNotSupportedException($dsnString, $func->getName()); 91 } 92 93 foreach ($func->getParameters() as $optionName => $optionValue) { 94 if ('false' === $optionValue) { 95 $optionValue = false; 96 } elseif ('true' === $optionValue) { 97 $optionValue = true; 98 } elseif (\is_numeric($optionValue)) { 99 $optionValue = (int) $optionValue; 100 } 101 102 $clientConfiguration->set($optionName, $optionValue); 103 } 104 105 return $clientConfiguration; 106 } 107 108 /** 109 * Returns a specific config key or the whole config array if not set. 110 * 111 * @throws InvalidException if the given key is not found in the configuration 112 * 113 * @return mixed Config value 114 */ 115 public function get(string $key) 116 { 117 if ('' === $key) { 118 return $this->configuration; 119 } 120 121 if (!$this->has($key)) { 122 throw new InvalidException('Config key is not set: '.$key); 123 } 124 125 return $this->configuration[$key]; 126 } 127 128 /** 129 * Returns boolean indicates if configuration has key. 130 */ 131 public function has(string $key): bool 132 { 133 return \array_key_exists($key, $this->configuration); 134 } 135 136 /** 137 * Return all configuration. 138 */ 139 public function getAll(): array 140 { 141 return $this->configuration; 142 } 143 144 /** 145 * @param string $key Key to set 146 * @param mixed $value Value 147 */ 148 public function set(string $key, $value): void 149 { 150 $this->configuration[$key] = $value; 151 } 152 153 /** 154 * Add value to a key. If original value is not an array, value is wrapped. 155 * 156 * @param string $key Key to add 157 * @param mixed $value Value 158 */ 159 public function add(string $key, $value): void 160 { 161 if (!\array_key_exists($key, $this->configuration)) { 162 $this->configuration[$key] = [$value]; 163 } else { 164 if (\is_array($this->configuration[$key])) { 165 $this->configuration[$key][] = $value; 166 } else { 167 $this->configuration[$key] = [$this->configuration[$key], $value]; 168 } 169 } 170 } 171 172 private static function parseDsn(Url $dsn): array 173 { 174 $data = ['host' => $dsn->getHost()]; 175 176 if (null !== $dsn->getScheme()) { 177 $data['transport'] = $dsn->getScheme(); 178 } 179 180 if (null !== $dsn->getUser()) { 181 $data['username'] = $dsn->getUser(); 182 } 183 184 if (null !== $dsn->getPassword()) { 185 $data['password'] = $dsn->getPassword(); 186 } 187 188 if (null !== $dsn->getUser() && null !== $dsn->getPassword()) { 189 $data['auth_type'] = 'basic'; 190 } 191 192 if (null !== $dsn->getPort()) { 193 $data['port'] = $dsn->getPort(); 194 } 195 196 if (null !== $dsn->getPath()) { 197 $data['path'] = $dsn->getPath(); 198 } 199 200 foreach ($dsn->getParameters() as $optionName => $optionValue) { 201 if ('false' === $optionValue) { 202 $optionValue = false; 203 } elseif ('true' === $optionValue) { 204 $optionValue = true; 205 } elseif (\is_numeric($optionValue)) { 206 $optionValue = (int) $optionValue; 207 } 208 209 $data[$optionName] = $optionValue; 210 } 211 212 return $data; 213 } 214} 215