1<?php
2
3namespace Doctrine\DBAL\Types;
4
5use Doctrine\DBAL\DBALException;
6use Throwable;
7
8use function get_class;
9use function gettype;
10use function implode;
11use function is_object;
12use function is_scalar;
13use function sprintf;
14use function strlen;
15use function substr;
16
17/**
18 * Conversion Exception is thrown when the database to PHP conversion fails.
19 *
20 * @psalm-immutable
21 */
22class ConversionException extends DBALException
23{
24    /**
25     * Thrown when a Database to Doctrine Type Conversion fails.
26     *
27     * @param string $value
28     * @param string $toType
29     *
30     * @return ConversionException
31     */
32    public static function conversionFailed($value, $toType, ?Throwable $previous = null)
33    {
34        $value = strlen($value) > 32 ? substr($value, 0, 20) . '...' : $value;
35
36        return new self('Could not convert database value "' . $value . '" to Doctrine Type ' . $toType, 0, $previous);
37    }
38
39    /**
40     * Thrown when a Database to Doctrine Type Conversion fails and we can make a statement
41     * about the expected format.
42     *
43     * @param string $value
44     * @param string $toType
45     * @param string $expectedFormat
46     *
47     * @return ConversionException
48     */
49    public static function conversionFailedFormat($value, $toType, $expectedFormat, ?Throwable $previous = null)
50    {
51        $value = strlen($value) > 32 ? substr($value, 0, 20) . '...' : $value;
52
53        return new self(
54            'Could not convert database value "' . $value . '" to Doctrine Type ' .
55            $toType . '. Expected format: ' . $expectedFormat,
56            0,
57            $previous
58        );
59    }
60
61    /**
62     * Thrown when the PHP value passed to the converter was not of the expected type.
63     *
64     * @param mixed    $value
65     * @param string   $toType
66     * @param string[] $possibleTypes
67     *
68     * @return ConversionException
69     */
70    public static function conversionFailedInvalidType(
71        $value,
72        $toType,
73        array $possibleTypes,
74        ?Throwable $previous = null
75    ) {
76        $actualType = is_object($value) ? get_class($value) : gettype($value);
77
78        if (is_scalar($value)) {
79            return new self(sprintf(
80                "Could not convert PHP value '%s' of type '%s' to type '%s'. Expected one of the following types: %s",
81                $value,
82                $actualType,
83                $toType,
84                implode(', ', $possibleTypes)
85            ), 0, $previous);
86        }
87
88        return new self(sprintf(
89            "Could not convert PHP value of type '%s' to type '%s'. Expected one of the following types: %s",
90            $actualType,
91            $toType,
92            implode(', ', $possibleTypes)
93        ), 0, $previous);
94    }
95
96    /**
97     * @param mixed  $value
98     * @param string $format
99     * @param string $error
100     *
101     * @return ConversionException
102     */
103    public static function conversionFailedSerialization($value, $format, $error)
104    {
105        $actualType = is_object($value) ? get_class($value) : gettype($value);
106
107        return new self(sprintf(
108            "Could not convert PHP type '%s' to '%s', as an '%s' error was triggered by the serialization",
109            $actualType,
110            $format,
111            $error
112        ));
113    }
114
115    public static function conversionFailedUnserialization(string $format, string $error): self
116    {
117        return new self(sprintf(
118            "Could not convert database value to '%s' as an error was triggered by the unserialization: '%s'",
119            $format,
120            $error
121        ));
122    }
123}
124