1<?php 2 3namespace Doctrine\DBAL\ForwardCompatibility; 4 5use Doctrine\DBAL\Driver; 6use Doctrine\DBAL\Exception; 7use Doctrine\DBAL\Exception\NoKeyValue; 8use Doctrine\DBAL\ParameterType; 9use Doctrine\Deprecations\Deprecation; 10use IteratorAggregate; 11use PDO; 12use ReturnTypeWillChange; 13use Traversable; 14 15use function array_shift; 16use function func_get_args; 17use function method_exists; 18 19/** 20 * A wrapper around a Doctrine\DBAL\Driver\ResultStatement that adds 3.0 features 21 * defined in Result interface 22 */ 23class Result implements IteratorAggregate, DriverStatement, DriverResultStatement 24{ 25 /** @var Driver\ResultStatement */ 26 private $stmt; 27 28 public static function ensure(Driver\ResultStatement $stmt): Result 29 { 30 if ($stmt instanceof Result) { 31 return $stmt; 32 } 33 34 return new Result($stmt); 35 } 36 37 public function __construct(Driver\ResultStatement $stmt) 38 { 39 $this->stmt = $stmt; 40 } 41 42 /** 43 * @return Driver\ResultStatement 44 */ 45 #[ReturnTypeWillChange] 46 public function getIterator() 47 { 48 return $this->stmt; 49 } 50 51 /** 52 * {@inheritDoc} 53 * 54 * @deprecated Use Result::free() instead. 55 */ 56 public function closeCursor() 57 { 58 return $this->stmt->closeCursor(); 59 } 60 61 /** 62 * {@inheritDoc} 63 */ 64 public function columnCount() 65 { 66 return $this->stmt->columnCount(); 67 } 68 69 /** 70 * {@inheritDoc} 71 * 72 * @deprecated Use one of the fetch- or iterate-related methods. 73 */ 74 public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) 75 { 76 return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3); 77 } 78 79 /** 80 * {@inheritDoc} 81 * 82 * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead. 83 */ 84 public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) 85 { 86 Deprecation::triggerIfCalledFromOutside( 87 'doctrine/dbal', 88 'https://github.com/doctrine/dbal/pull/4019', 89 'Result::fetch() is deprecated, use Result::fetchNumeric(), fetchAssociative() or fetchOne() instead.' 90 ); 91 92 return $this->stmt->fetch(...func_get_args()); 93 } 94 95 /** 96 * {@inheritDoc} 97 * 98 * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead. 99 */ 100 public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) 101 { 102 Deprecation::triggerIfCalledFromOutside( 103 'doctrine/dbal', 104 'https://github.com/doctrine/dbal/pull/4019', 105 'Result::fetchAll() is deprecated, use Result::fetchAllNumeric(), fetchAllAssociative() or ' . 106 'fetchFirstColumn() instead.' 107 ); 108 109 return $this->stmt->fetchAll($fetchMode, $fetchArgument, $ctorArgs); 110 } 111 112 /** 113 * {@inheritDoc} 114 * 115 * @deprecated Use fetchOne() instead. 116 */ 117 public function fetchColumn($columnIndex = 0) 118 { 119 Deprecation::triggerIfCalledFromOutside( 120 'doctrine/dbal', 121 'https://github.com/doctrine/dbal/pull/4019', 122 'Result::fetchColumn() is deprecated, use Result::fetchOne() instead.' 123 ); 124 125 return $this->stmt->fetchColumn($columnIndex); 126 } 127 128 /** 129 * {@inheritDoc} 130 */ 131 public function fetchNumeric() 132 { 133 return $this->stmt->fetch(PDO::FETCH_NUM); 134 } 135 136 /** 137 * {@inheritDoc} 138 */ 139 public function fetchAssociative() 140 { 141 return $this->stmt->fetch(PDO::FETCH_ASSOC); 142 } 143 144 /** 145 * {@inheritDoc} 146 */ 147 public function fetchOne() 148 { 149 $row = $this->fetchNumeric(); 150 151 if ($row === false) { 152 return false; 153 } 154 155 return $row[0]; 156 } 157 158 /** 159 * {@inheritDoc} 160 */ 161 public function fetchAllNumeric(): array 162 { 163 $rows = []; 164 165 while (($row = $this->fetchNumeric()) !== false) { 166 $rows[] = $row; 167 } 168 169 return $rows; 170 } 171 172 /** 173 * {@inheritDoc} 174 */ 175 public function fetchAllAssociative(): array 176 { 177 $rows = []; 178 179 while (($row = $this->fetchAssociative()) !== false) { 180 $rows[] = $row; 181 } 182 183 return $rows; 184 } 185 186 /** 187 * {@inheritDoc} 188 */ 189 public function fetchAllKeyValue(): array 190 { 191 $this->ensureHasKeyValue(); 192 $data = []; 193 194 foreach ($this->fetchAllNumeric() as [$key, $value]) { 195 $data[$key] = $value; 196 } 197 198 return $data; 199 } 200 201 /** 202 * {@inheritDoc} 203 */ 204 public function fetchAllAssociativeIndexed(): array 205 { 206 $data = []; 207 208 foreach ($this->fetchAllAssociative() as $row) { 209 $data[array_shift($row)] = $row; 210 } 211 212 return $data; 213 } 214 215 /** 216 * {@inheritDoc} 217 */ 218 public function fetchFirstColumn(): array 219 { 220 $rows = []; 221 222 while (($row = $this->fetchOne()) !== false) { 223 $rows[] = $row; 224 } 225 226 return $rows; 227 } 228 229 /** 230 * {@inheritdoc} 231 * 232 * @return Traversable<int,array<int,mixed>> 233 */ 234 public function iterateNumeric(): Traversable 235 { 236 while (($row = $this->fetchNumeric()) !== false) { 237 yield $row; 238 } 239 } 240 241 /** 242 * {@inheritDoc} 243 * 244 * @return Traversable<int,array<string,mixed>> 245 */ 246 public function iterateAssociative(): Traversable 247 { 248 while (($row = $this->fetchAssociative()) !== false) { 249 yield $row; 250 } 251 } 252 253 /** 254 * {@inheritDoc} 255 * 256 * @return Traversable<mixed,mixed> 257 */ 258 public function iterateKeyValue(): Traversable 259 { 260 $this->ensureHasKeyValue(); 261 262 foreach ($this->iterateNumeric() as [$key, $value]) { 263 yield $key => $value; 264 } 265 } 266 267 /** 268 * {@inheritDoc} 269 * 270 * @return Traversable<mixed,array<string,mixed>> 271 */ 272 public function iterateAssociativeIndexed(): Traversable 273 { 274 foreach ($this->iterateAssociative() as $row) { 275 yield array_shift($row) => $row; 276 } 277 } 278 279 /** 280 * {@inheritDoc} 281 * 282 * @return Traversable<int,mixed> 283 */ 284 public function iterateColumn(): Traversable 285 { 286 while (($value = $this->fetchOne()) !== false) { 287 yield $value; 288 } 289 } 290 291 /** 292 * {@inheritDoc} 293 */ 294 public function rowCount() 295 { 296 if (method_exists($this->stmt, 'rowCount')) { 297 return $this->stmt->rowCount(); 298 } 299 300 throw Exception::notSupported('rowCount'); 301 } 302 303 public function free(): void 304 { 305 $this->closeCursor(); 306 } 307 308 private function ensureHasKeyValue(): void 309 { 310 $columnCount = $this->columnCount(); 311 312 if ($columnCount < 2) { 313 throw NoKeyValue::fromColumnCount($columnCount); 314 } 315 } 316 317 /** 318 * {@inheritDoc} 319 * 320 * @deprecated This feature will no longer be available on Result object in 3.0.x version. 321 */ 322 public function bindValue($param, $value, $type = ParameterType::STRING) 323 { 324 Deprecation::triggerIfCalledFromOutside( 325 'doctrine/dbal', 326 'https://github.com/doctrine/dbal/pull/4019', 327 'Result::bindValue() is deprecated, no replacement.' 328 ); 329 330 if ($this->stmt instanceof Driver\Statement) { 331 return $this->stmt->bindValue($param, $value, $type); 332 } 333 334 throw Exception::notSupported('bindValue'); 335 } 336 337 /** 338 * {@inheritDoc} 339 * 340 * @deprecated This feature will no longer be available on Result object in 3.0.x version. 341 */ 342 public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) 343 { 344 Deprecation::triggerIfCalledFromOutside( 345 'doctrine/dbal', 346 'https://github.com/doctrine/dbal/pull/4019', 347 'Result::bindParam() is deprecated, no replacement.' 348 ); 349 350 if ($this->stmt instanceof Driver\Statement) { 351 return $this->stmt->bindParam($param, $variable, $type, $length); 352 } 353 354 throw Exception::notSupported('bindParam'); 355 } 356 357 /** 358 * {@inheritDoc} 359 * 360 * @deprecated The error information is available via exceptions. 361 */ 362 public function errorCode() 363 { 364 Deprecation::triggerIfCalledFromOutside( 365 'doctrine/dbal', 366 'https://github.com/doctrine/dbal/pull/4019', 367 'Result::errorCode() is deprecated, the error information is available via exceptions.' 368 ); 369 370 if ($this->stmt instanceof Driver\Statement) { 371 return $this->stmt->errorCode(); 372 } 373 374 throw Exception::notSupported('errorCode'); 375 } 376 377 /** 378 * {@inheritDoc} 379 * 380 * @deprecated The error information is available via exceptions. 381 */ 382 public function errorInfo() 383 { 384 Deprecation::triggerIfCalledFromOutside( 385 'doctrine/dbal', 386 'https://github.com/doctrine/dbal/pull/4019', 387 'Result::errorInfo() is deprecated, the error information is available via exceptions.' 388 ); 389 390 if ($this->stmt instanceof Driver\Statement) { 391 return $this->stmt->errorInfo(); 392 } 393 394 throw Exception::notSupported('errorInfo'); 395 } 396 397 /** 398 * {@inheritDoc} 399 * 400 * @deprecated This feature will no longer be available on Result object in 3.0.x version. 401 */ 402 public function execute($params = null) 403 { 404 Deprecation::triggerIfCalledFromOutside( 405 'doctrine/dbal', 406 'https://github.com/doctrine/dbal/pull/4019', 407 'Result::execute() is deprecated, no replacement.' 408 ); 409 410 if ($this->stmt instanceof Driver\Statement) { 411 return $this->stmt->execute($params); 412 } 413 414 throw Exception::notSupported('execute'); 415 } 416} 417