4b2c79a88c8c38c25914470de7e5d0f105ccb9a7
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Utility / TypeHandlingUtility.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Extbase\Utility;
5
6 /* *
7 * This script belongs to the TYPO3 Flow framework. *
8 * *
9 * It is free software; you can redistribute it and/or modify it under *
10 * the terms of the GNU Lesser General Public License, either version 3 *
11 * of the License, or (at your option) any later version. *
12 * *
13 * The TYPO3 project - inspiring people to share! *
14 * */
15
16 /**
17 * PHP type handling functions
18 * @internal only to be used within Extbase, not part of TYPO3 Core API.
19 */
20 class TypeHandlingUtility
21 {
22 /**
23 * A property type parse pattern.
24 */
25 const PARSE_TYPE_PATTERN = '/^\\\\?(?P<type>integer|int|float|double|boolean|bool|string|DateTimeImmutable|DateTime|[A-Z][a-zA-Z0-9\\\\]+|object|resource|array|ArrayObject|SplObjectStorage|TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\ObjectStorage)(?:<\\\\?(?P<elementType>[a-zA-Z0-9\\\\]+)>)?/';
26
27 /**
28 * A type pattern to detect literal types.
29 */
30 const LITERAL_TYPE_PATTERN = '/^(?:integer|int|float|double|boolean|bool|string)$/';
31
32 /**
33 * @var array
34 */
35 protected static $collectionTypes = ['array', 'ArrayObject', 'SplObjectStorage', \TYPO3\CMS\Extbase\Persistence\ObjectStorage::class];
36
37 /**
38 * Returns an array with type information, including element type for
39 * collection types (array, SplObjectStorage, ...)
40 *
41 * @param string $type Type of the property (see PARSE_TYPE_PATTERN)
42 * @return array An array with information about the type
43 * @throws \TYPO3\CMS\Extbase\Utility\Exception\InvalidTypeException
44 */
45 public static function parseType(string $type): array
46 {
47 $matches = [];
48 if (preg_match(self::PARSE_TYPE_PATTERN, $type, $matches)) {
49 $type = self::normalizeType($matches['type']);
50 $elementType = isset($matches['elementType']) ? self::normalizeType($matches['elementType']) : null;
51
52 if ($elementType !== null && !self::isCollectionType($type)) {
53 throw new \TYPO3\CMS\Extbase\Utility\Exception\InvalidTypeException('Found an invalid element type declaration in %s. Type "' . $type . '" must not have an element type hint (' . $elementType . ').', 1264093642);
54 }
55
56 return [
57 'type' => $type,
58 'elementType' => $elementType
59 ];
60 }
61 throw new \TYPO3\CMS\Extbase\Utility\Exception\InvalidTypeException('Found an invalid element type declaration in %s. A type "' . var_export($type, true) . '" does not exist.', 1264093630);
62 }
63
64 /**
65 * Normalize data types so they match the PHP type names:
66 * int -> integer
67 * double -> float
68 * bool -> boolean
69 *
70 * @param string $type Data type to unify
71 * @return string unified data type
72 */
73 public static function normalizeType(string $type): string
74 {
75 switch ($type) {
76 case 'int':
77 $type = 'integer';
78 break;
79 case 'bool':
80 $type = 'boolean';
81 break;
82 case 'double':
83 $type = 'float';
84 break;
85 }
86 return $type;
87 }
88
89 /**
90 * Returns TRUE if the $type is a literal.
91 *
92 * @param string $type
93 * @return bool
94 */
95 public static function isLiteral(string $type): bool
96 {
97 return preg_match(self::LITERAL_TYPE_PATTERN, $type) === 1;
98 }
99
100 /**
101 * Returns TRUE if the $type is a simple type.
102 *
103 * @param string $type
104 * @return bool
105 */
106 public static function isSimpleType(string $type): bool
107 {
108 return in_array(self::normalizeType($type), ['array', 'string', 'float', 'integer', 'boolean'], true);
109 }
110
111 /**
112 * Returns TRUE if the $type is a CMS core type object.
113 *
114 * @param string|object $type
115 * @return bool
116 */
117 public static function isCoreType($type): bool
118 {
119 return is_subclass_of($type, \TYPO3\CMS\Core\Type\TypeInterface::class);
120 }
121
122 /**
123 * Returns TRUE if the $type is a collection type.
124 *
125 * @param string $type
126 * @return bool
127 */
128 public static function isCollectionType(string $type): bool
129 {
130 if (in_array($type, self::$collectionTypes, true)) {
131 return true;
132 }
133
134 if (class_exists($type) === true || interface_exists($type) === true) {
135 foreach (self::$collectionTypes as $collectionType) {
136 if (is_subclass_of($type, $collectionType) === true) {
137 return true;
138 }
139 }
140 }
141
142 return false;
143 }
144
145 /**
146 * Returns TRUE when the given value can be used in an "in" comparison in a query.
147 *
148 * @param mixed $value
149 * @return bool
150 */
151 public static function isValidTypeForMultiValueComparison($value): bool
152 {
153 return is_array($value) || $value instanceof \Traversable;
154 }
155
156 /**
157 * Converts a hex encoded string into binary data
158 *
159 * @param string $hexadecimalData A hex encoded string of data
160 * @return string A binary string decoded from the input
161 */
162 public static function hex2bin(string $hexadecimalData): string
163 {
164 $binaryData = '';
165 $length = strlen($hexadecimalData);
166 for ($i = 0; $i < $length; $i += 2) {
167 $binaryData .= pack('C', hexdec(substr($hexadecimalData, $i, 2)));
168 }
169 return $binaryData;
170 }
171 }