FieldTypeConverter.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.2.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Database;
  16. use Cake\Database\Type;
  17. use Cake\Database\Type\BatchCastingInterface;
  18. use Cake\Database\Type\OptionalConvertInterface;
  19. /**
  20. * A callable class to be used for processing each of the rows in a statement
  21. * result, so that the values are converted to the right PHP types.
  22. */
  23. class FieldTypeConverter
  24. {
  25. /**
  26. * An array containing the name of the fields and the Type objects
  27. * each should use when converting them.
  28. *
  29. * @var array
  30. */
  31. protected $_typeMap;
  32. /**
  33. * An array containing the name of the fields and the Type objects
  34. * each should use when converting them using batching.
  35. *
  36. * @var array
  37. */
  38. protected $batchingTypeMap;
  39. /**
  40. * An array containing all the types registered in the Type system
  41. * at the moment this object is created. Used so that the types list
  42. * is not fetched on each single row of the results.
  43. *
  44. * @var array
  45. */
  46. protected $types;
  47. /**
  48. * The driver object to be used in the type conversion
  49. *
  50. * @var \Cake\Database\Driver
  51. */
  52. protected $_driver;
  53. /**
  54. * Builds the type map
  55. *
  56. * @param \Cake\Database\TypeMap $typeMap Contains the types to use for converting results
  57. * @param \Cake\Database\Driver $driver The driver to use for the type conversion
  58. */
  59. public function __construct(TypeMap $typeMap, Driver $driver)
  60. {
  61. $this->_driver = $driver;
  62. $map = $typeMap->toArray();
  63. $types = Type::buildAll();
  64. $simpleMap = $batchingMap = [];
  65. $simpleResult = $batchingResult = [];
  66. foreach ($types as $k => $type) {
  67. if ($type instanceof OptionalConvertInterface && !$type->requiresToPhpCast()) {
  68. continue;
  69. }
  70. // Because of backwards compatibility reasons, we won't allow classes
  71. // inheriting Type in userland code to be batchable, even if they implement
  72. // the interface. Users can implement the TypeInterface instead to have
  73. // access to this feature.
  74. $batchingType = $type instanceof BatchCastingInterface &&
  75. $type instanceof Type &&
  76. strpos(get_class($type), 'Cake\Database\Type') === false;
  77. if ($batchingType) {
  78. $batchingMap[$k] = $type;
  79. continue;
  80. }
  81. $simpleMap[$k] = $type;
  82. }
  83. foreach ($map as $field => $type) {
  84. if (isset($simpleMap[$type])) {
  85. $simpleResult[$field] = $simpleMap[$type];
  86. continue;
  87. }
  88. if (isset($batchingMap[$type])) {
  89. $batchingResult[$type][] = $field;
  90. }
  91. }
  92. // Using batching when there is onl a couple for the type is actually slower,
  93. // so, let's check for that case here.
  94. foreach ($batchingResult as $type => $fields) {
  95. if (count($fields) > 2) {
  96. continue;
  97. }
  98. foreach ($fields as $f) {
  99. $simpleResult[$f] = $batchingMap[$type];
  100. }
  101. unset($batchingResult[$type]);
  102. }
  103. $this->types = $types;
  104. $this->_typeMap = $simpleResult;
  105. $this->batchingTypeMap = $batchingResult;
  106. }
  107. /**
  108. * Converts each of the fields in the array that are present in the type map
  109. * using the corresponding Type class.
  110. *
  111. * @param array $row The array with the fields to be casted
  112. * @return array
  113. */
  114. public function __invoke($row)
  115. {
  116. if (!empty($this->_typeMap)) {
  117. foreach ($this->_typeMap as $field => $type) {
  118. $row[$field] = $type->toPHP($row[$field], $this->_driver);
  119. }
  120. }
  121. if (!empty($this->batchingTypeMap)) {
  122. foreach ($this->batchingTypeMap as $t => $fields) {
  123. $row = $this->types[$t]->manyToPHP($row, $fields, $this->_driver);
  124. }
  125. }
  126. return $row;
  127. }
  128. }