1<?php 2/* 3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14 */ 15 16namespace Alcaeus\MongoDbAdapter; 17 18use MongoDB\BSON; 19use MongoDB\Model; 20 21/** 22 * @internal 23 */ 24class TypeConverter 25{ 26 /** 27 * Converts a legacy type to the new BSON type 28 * 29 * This method handles type conversion from ext-mongo to ext-mongodb: 30 * - For all types (MongoId, MongoDate, etc.) it returns the correct BSON 31 * object instance 32 * - For arrays and objects it iterates over properties and converts each 33 * item individually 34 * - For other types it returns the value unconverted 35 * 36 * @param mixed $value 37 * @return mixed 38 */ 39 public static function fromLegacy($value) 40 { 41 switch (true) { 42 case $value instanceof TypeInterface: 43 return $value->toBSONType(); 44 case is_array($value): 45 case is_object($value); 46 $result = []; 47 48 foreach ($value as $key => $item) { 49 $result[$key] = self::fromLegacy($item); 50 } 51 52 return self::ensureCorrectType($result, is_object($value)); 53 default: 54 return $value; 55 } 56 } 57 58 /** 59 * Converts a BSON type to the legacy types 60 * 61 * This method handles type conversion from ext-mongodb to ext-mongo: 62 * - For all instances of BSON\Type it returns an object of the 63 * corresponding legacy type (MongoId, MongoDate, etc.) 64 * - For arrays and objects it iterates over properties and converts each 65 * item individually 66 * - For other types it returns the value unconverted 67 * 68 * @param mixed $value 69 * @return mixed 70 */ 71 public static function toLegacy($value) 72 { 73 switch (true) { 74 case $value instanceof BSON\Type: 75 return self::convertBSONObjectToLegacy($value); 76 case is_array($value): 77 case is_object($value): 78 $result = []; 79 80 foreach ($value as $key => $item) { 81 $result[$key] = self::toLegacy($item); 82 } 83 84 return $result; 85 default: 86 return $value; 87 } 88 } 89 90 /** 91 * Helper method to find out if an array has numerical indexes 92 * 93 * For performance reason, this method checks the first array index only. 94 * More thorough inspection of the array might be needed. 95 * Note: Returns true for empty arrays to preserve compatibility with empty 96 * lists. 97 * 98 * @param array $array 99 * @return bool 100 */ 101 public static function isNumericArray(array $array) 102 { 103 return $array === [] || is_numeric(array_keys($array)[0]); 104 } 105 106 /** 107 * Converter method to convert a BSON object to its legacy type 108 * 109 * @param BSON\Type $value 110 * @return mixed 111 */ 112 private static function convertBSONObjectToLegacy(BSON\Type $value) 113 { 114 switch (true) { 115 case $value instanceof BSON\ObjectID: 116 return new \MongoId($value); 117 case $value instanceof BSON\Binary: 118 return new \MongoBinData($value); 119 case $value instanceof BSON\Javascript: 120 return new \MongoCode($value); 121 case $value instanceof BSON\MaxKey: 122 return new \MongoMaxKey(); 123 case $value instanceof BSON\MinKey: 124 return new \MongoMinKey(); 125 case $value instanceof BSON\Regex: 126 return new \MongoRegex($value); 127 case $value instanceof BSON\Timestamp: 128 return new \MongoTimestamp($value); 129 case $value instanceof BSON\UTCDatetime: 130 return new \MongoDate($value); 131 case $value instanceof Model\BSONDocument: 132 case $value instanceof Model\BSONArray: 133 return array_map( 134 ['self', 'toLegacy'], 135 $value->getArrayCopy() 136 ); 137 default: 138 return $value; 139 } 140 } 141 142 /** 143 * Converts all arrays with non-numeric keys to stdClass 144 * 145 * @param array $array 146 * @param bool $wasObject 147 * @return array|Model\BSONArray|Model\BSONDocument 148 */ 149 private static function ensureCorrectType(array $array, $wasObject = false) 150 { 151 if ($wasObject || ! static::isNumericArray($array)) { 152 return new Model\BSONDocument($array); 153 } 154 155 return $array; 156 } 157} 158