1<?php
2
3namespace Doctrine\DBAL\Types;
4
5use Doctrine\DBAL\DBALException;
6use Doctrine\DBAL\ParameterType;
7use Doctrine\DBAL\Platforms\AbstractPlatform;
8
9use function array_map;
10use function get_class;
11use function str_replace;
12use function strrpos;
13use function substr;
14
15/**
16 * The base class for so-called Doctrine mapping types.
17 *
18 * A Type object is obtained by calling the static {@link getType()} method.
19 */
20abstract class Type
21{
22    /** @deprecated Use {@see Types::BIGINT} instead. */
23    public const BIGINT = Types::BIGINT;
24
25    /** @deprecated Use {@see Types::BINARY} instead. */
26    public const BINARY = Types::BINARY;
27
28    /** @deprecated Use {@see Types::BLOB} instead. */
29    public const BLOB = Types::BLOB;
30
31    /** @deprecated Use {@see Types::BOOLEAN} instead. */
32    public const BOOLEAN = Types::BOOLEAN;
33
34    /** @deprecated Use {@see Types::DATE_MUTABLE} instead. */
35    public const DATE = Types::DATE_MUTABLE;
36
37    /** @deprecated Use {@see Types::DATE_IMMUTABLE} instead. */
38    public const DATE_IMMUTABLE = Types::DATE_IMMUTABLE;
39
40    /** @deprecated Use {@see Types::DATEINTERVAL} instead. */
41    public const DATEINTERVAL = Types::DATEINTERVAL;
42
43    /** @deprecated Use {@see Types::DATETIME_MUTABLE} instead. */
44    public const DATETIME = Types::DATETIME_MUTABLE;
45
46    /** @deprecated Use {@see Types::DATETIME_IMMUTABLE} instead. */
47    public const DATETIME_IMMUTABLE = Types::DATETIME_IMMUTABLE;
48
49    /** @deprecated Use {@see Types::DATETIMETZ_MUTABLE} instead. */
50    public const DATETIMETZ = Types::DATETIMETZ_MUTABLE;
51
52    /** @deprecated Use {@see Types::DATETIMETZ_IMMUTABLE} instead. */
53    public const DATETIMETZ_IMMUTABLE = Types::DATETIMETZ_IMMUTABLE;
54
55    /** @deprecated Use {@see Types::DECIMAL} instead. */
56    public const DECIMAL = Types::DECIMAL;
57
58    /** @deprecated Use {@see Types::FLOAT} instead. */
59    public const FLOAT = Types::FLOAT;
60
61    /** @deprecated Use {@see Types::GUID} instead. */
62    public const GUID = Types::GUID;
63
64    /** @deprecated Use {@see Types::INTEGER} instead. */
65    public const INTEGER = Types::INTEGER;
66
67    /** @deprecated Use {@see Types::JSON} instead. */
68    public const JSON = Types::JSON;
69
70    /** @deprecated Use {@see Types::JSON_ARRAY} instead. */
71    public const JSON_ARRAY = Types::JSON_ARRAY;
72
73    /** @deprecated Use {@see Types::OBJECT} instead. */
74    public const OBJECT = Types::OBJECT;
75
76    /** @deprecated Use {@see Types::SIMPLE_ARRAY} instead. */
77    public const SIMPLE_ARRAY = Types::SIMPLE_ARRAY;
78
79    /** @deprecated Use {@see Types::SMALLINT} instead. */
80    public const SMALLINT = Types::SMALLINT;
81
82    /** @deprecated Use {@see Types::STRING} instead. */
83    public const STRING = Types::STRING;
84
85    /** @deprecated Use {@see Types::ARRAY} instead. */
86    public const TARRAY = Types::ARRAY;
87
88    /** @deprecated Use {@see Types::TEXT} instead. */
89    public const TEXT = Types::TEXT;
90
91    /** @deprecated Use {@see Types::TIME_MUTABLE} instead. */
92    public const TIME = Types::TIME_MUTABLE;
93
94    /** @deprecated Use {@see Types::TIME_IMMUTABLE} instead. */
95    public const TIME_IMMUTABLE = Types::TIME_IMMUTABLE;
96
97    /**
98     * The map of supported doctrine mapping types.
99     */
100    private const BUILTIN_TYPES_MAP = [
101        Types::ARRAY                => ArrayType::class,
102        Types::BIGINT               => BigIntType::class,
103        Types::BINARY               => BinaryType::class,
104        Types::BLOB                 => BlobType::class,
105        Types::BOOLEAN              => BooleanType::class,
106        Types::DATE_MUTABLE         => DateType::class,
107        Types::DATE_IMMUTABLE       => DateImmutableType::class,
108        Types::DATEINTERVAL         => DateIntervalType::class,
109        Types::DATETIME_MUTABLE     => DateTimeType::class,
110        Types::DATETIME_IMMUTABLE   => DateTimeImmutableType::class,
111        Types::DATETIMETZ_MUTABLE   => DateTimeTzType::class,
112        Types::DATETIMETZ_IMMUTABLE => DateTimeTzImmutableType::class,
113        Types::DECIMAL              => DecimalType::class,
114        Types::FLOAT                => FloatType::class,
115        Types::GUID                 => GuidType::class,
116        Types::INTEGER              => IntegerType::class,
117        Types::JSON                 => JsonType::class,
118        Types::JSON_ARRAY           => JsonArrayType::class,
119        Types::OBJECT               => ObjectType::class,
120        Types::SIMPLE_ARRAY         => SimpleArrayType::class,
121        Types::SMALLINT             => SmallIntType::class,
122        Types::STRING               => StringType::class,
123        Types::TEXT                 => TextType::class,
124        Types::TIME_MUTABLE         => TimeType::class,
125        Types::TIME_IMMUTABLE       => TimeImmutableType::class,
126    ];
127
128    /** @var TypeRegistry|null */
129    private static $typeRegistry;
130
131    /**
132     * @internal Do not instantiate directly - use {@see Type::addType()} method instead.
133     */
134    final public function __construct()
135    {
136    }
137
138    /**
139     * Converts a value from its PHP representation to its database representation
140     * of this type.
141     *
142     * @param mixed            $value    The value to convert.
143     * @param AbstractPlatform $platform The currently used database platform.
144     *
145     * @return mixed The database representation of the value.
146     */
147    public function convertToDatabaseValue($value, AbstractPlatform $platform)
148    {
149        return $value;
150    }
151
152    /**
153     * Converts a value from its database representation to its PHP representation
154     * of this type.
155     *
156     * @param mixed            $value    The value to convert.
157     * @param AbstractPlatform $platform The currently used database platform.
158     *
159     * @return mixed The PHP representation of the value.
160     */
161    public function convertToPHPValue($value, AbstractPlatform $platform)
162    {
163        return $value;
164    }
165
166    /**
167     * Gets the default length of this type.
168     *
169     * @deprecated Rely on information provided by the platform instead.
170     *
171     * @return int|null
172     */
173    public function getDefaultLength(AbstractPlatform $platform)
174    {
175        return null;
176    }
177
178    /**
179     * Gets the SQL declaration snippet for a column of this type.
180     *
181     * @param mixed[]          $column   The column definition
182     * @param AbstractPlatform $platform The currently used database platform.
183     *
184     * @return string
185     */
186    abstract public function getSQLDeclaration(array $column, AbstractPlatform $platform);
187
188    /**
189     * Gets the name of this type.
190     *
191     * @return string
192     *
193     * @todo Needed?
194     */
195    abstract public function getName();
196
197    /**
198     * @internal This method is only to be used within DBAL for forward compatibility purposes. Do not use directly.
199     */
200    final public static function getTypeRegistry(): TypeRegistry
201    {
202        if (self::$typeRegistry === null) {
203            self::$typeRegistry = self::createTypeRegistry();
204        }
205
206        return self::$typeRegistry;
207    }
208
209    private static function createTypeRegistry(): TypeRegistry
210    {
211        $registry = new TypeRegistry();
212
213        foreach (self::BUILTIN_TYPES_MAP as $name => $class) {
214            $registry->register($name, new $class());
215        }
216
217        return $registry;
218    }
219
220    /**
221     * Factory method to create type instances.
222     * Type instances are implemented as flyweights.
223     *
224     * @param string $name The name of the type (as returned by getName()).
225     *
226     * @return Type
227     *
228     * @throws DBALException
229     */
230    public static function getType($name)
231    {
232        return self::getTypeRegistry()->get($name);
233    }
234
235    /**
236     * Adds a custom type to the type map.
237     *
238     * @param string $name      The name of the type. This should correspond to what getName() returns.
239     * @param string $className The class name of the custom type.
240     *
241     * @return void
242     *
243     * @throws DBALException
244     */
245    public static function addType($name, $className)
246    {
247        self::getTypeRegistry()->register($name, new $className());
248    }
249
250    /**
251     * Checks if exists support for a type.
252     *
253     * @param string $name The name of the type.
254     *
255     * @return bool TRUE if type is supported; FALSE otherwise.
256     */
257    public static function hasType($name)
258    {
259        return self::getTypeRegistry()->has($name);
260    }
261
262    /**
263     * Overrides an already defined type to use a different implementation.
264     *
265     * @param string $name
266     * @param string $className
267     *
268     * @return void
269     *
270     * @throws DBALException
271     */
272    public static function overrideType($name, $className)
273    {
274        self::getTypeRegistry()->override($name, new $className());
275    }
276
277    /**
278     * Gets the (preferred) binding type for values of this type that
279     * can be used when binding parameters to prepared statements.
280     *
281     * This method should return one of the {@link ParameterType} constants.
282     *
283     * @return int
284     */
285    public function getBindingType()
286    {
287        return ParameterType::STRING;
288    }
289
290    /**
291     * Gets the types array map which holds all registered types and the corresponding
292     * type class
293     *
294     * @return string[]
295     */
296    public static function getTypesMap()
297    {
298        return array_map(
299            static function (Type $type): string {
300                return get_class($type);
301            },
302            self::getTypeRegistry()->getMap()
303        );
304    }
305
306    /**
307     * @deprecated Relying on string representation is discouraged and will be removed in DBAL 3.0.
308     *
309     * @return string
310     */
311    public function __toString()
312    {
313        $type     = static::class;
314        $position = strrpos($type, '\\');
315
316        if ($position !== false) {
317            $type = substr($type, $position);
318        }
319
320        return str_replace('Type', '', $type);
321    }
322
323    /**
324     * Does working with this column require SQL conversion functions?
325     *
326     * This is a metadata function that is required for example in the ORM.
327     * Usage of {@link convertToDatabaseValueSQL} and
328     * {@link convertToPHPValueSQL} works for any type and mostly
329     * does nothing. This method can additionally be used for optimization purposes.
330     *
331     * @return bool
332     */
333    public function canRequireSQLConversion()
334    {
335        return false;
336    }
337
338    /**
339     * Modifies the SQL expression (identifier, parameter) to convert to a database value.
340     *
341     * @param string $sqlExpr
342     *
343     * @return string
344     */
345    public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
346    {
347        return $sqlExpr;
348    }
349
350    /**
351     * Modifies the SQL expression (identifier, parameter) to convert to a PHP value.
352     *
353     * @param string           $sqlExpr
354     * @param AbstractPlatform $platform
355     *
356     * @return string
357     */
358    public function convertToPHPValueSQL($sqlExpr, $platform)
359    {
360        return $sqlExpr;
361    }
362
363    /**
364     * Gets an array of database types that map to this Doctrine type.
365     *
366     * @return string[]
367     */
368    public function getMappedDatabaseTypes(AbstractPlatform $platform)
369    {
370        return [];
371    }
372
373    /**
374     * If this Doctrine Type maps to an already mapped database type,
375     * reverse schema engineering can't tell them apart. You need to mark
376     * one of those types as commented, which will have Doctrine use an SQL
377     * comment to typehint the actual Doctrine Type.
378     *
379     * @return bool
380     */
381    public function requiresSQLCommentHint(AbstractPlatform $platform)
382    {
383        return false;
384    }
385}
386