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