Completed
Pull Request — master (#132)
by Mathias
01:41
created

TypesDumper::dumpToFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
/*
4
 * This file is part of the "elao/enum" package.
5
 *
6
 * Copyright (C) Elao
7
 *
8
 * @author Elao <[email protected]>
9
 */
10
11
namespace Elao\Enum\Bridge\Doctrine\DBAL\Types;
12
13
use Elao\Enum\Exception\LogicException;
14
15
/**
16
 * @internal
17
 */
18
class TypesDumper
19
{
20
    public const TYPE_INT = 'int';
21
    public const TYPE_STRING = 'string';
22
    public const TYPE_ENUM = 'enum';
23
    public const TYPE_JSON_COLLECTION = 'json_collection';
24
    public const TYPE_CSV_COLLECTION = 'csv_collection';
25
    public const TYPES = [
26
        self::TYPE_INT,
27
        self::TYPE_STRING,
28
        self::TYPE_ENUM,
29
        self::TYPE_JSON_COLLECTION,
30
        self::TYPE_CSV_COLLECTION,
31
    ];
32
33
    public const TYPES_SUFFIXES = [
34
        self::TYPE_INT => 'Type',
35
        self::TYPE_STRING => 'Type',
36
        self::TYPE_ENUM => 'Type',
37
        self::TYPE_JSON_COLLECTION => 'JsonCollectionType',
38
        self::TYPE_CSV_COLLECTION => 'CsvCollectionType',
39
    ];
40
41
    public const MARKER = 'ELAO_ENUM_DT';
42
43
    public function dumpToFile(string $file, array $types)
44
    {
45
        file_put_contents($file, $this->dump($types));
46
    }
47
48
    private function dump(array $types): string
49
    {
50
        $namespaces = [];
51
        foreach ($types as [$enumClass, $type, $name, $default]) {
52
            $fqcn = self::getTypeClassname($enumClass, $type);
0 ignored issues
show
Bug introduced by
The variable $enumClass does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $type does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
53
            $classname = basename(str_replace('\\', '/', $fqcn));
54
            $ns = substr($fqcn, 0, -\strlen($classname) - 1);
55
56
            if (!isset($namespaces[$ns])) {
57
                $namespaces[$ns] = '';
58
            }
59
60
            $namespaces[$ns] .= $this->getTypeCode(
61
                $classname,
62
                $enumClass,
63
                $type,
64
                $name,
0 ignored issues
show
Bug introduced by
The variable $name does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
65
                $default
0 ignored issues
show
Bug introduced by
The variable $default does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
66
            );
67
        }
68
69
        $code = "<?php\n";
70
        foreach ($namespaces as $namespace => $typeCode) {
71
            $code .= <<<PHP
72
73
namespace $namespace {
74
$typeCode
75
}
76
77
PHP;
78
        }
79
80
        return $code;
81
    }
82
83
    private function getTypeCode(
84
        string $classname,
85
        string $enumClass,
86
        string $type,
87
        string $name,
88
        $defaultOnNull
89
    ): string {
90
        $code = <<<PHP
91
            public const NAME = '$name';
92
93
            protected function getEnumClass(): string
94
            {
95
                return \\{$enumClass}::class;
96
            }
97
98
            public function getName(): string
99
            {
100
                return static::NAME;
101
            }
102
PHP;
103
        switch ($type) {
104
            case self::TYPE_INT:
105
                $baseClass = AbstractIntegerEnumType::class;
106
                break;
107
            case self::TYPE_STRING:
108
                $baseClass = AbstractEnumType::class;
109
110
                if ($defaultOnNull !== null) {
111
                    $defaultOnNullCode = $this->valueAsCode($defaultOnNull);
112
                    $code .= <<<PHP
113
114
            protected function onNullFromDatabase()
115
            {
116
                return \\{$enumClass}::get({$defaultOnNullCode});
117
            }
118
119
            protected function onNullFromPhp()
120
            {
121
                return {$defaultOnNullCode};
122
            }
123
PHP;
124
                }
125
                break;
126
            case self::TYPE_ENUM:
127
                $baseClass = AbstractEnumSQLDeclarationType::class;
128
                break;
129
            case self::TYPE_JSON_COLLECTION:
130
                $baseClass = AbstractJsonCollectionEnumType::class;
131
                break;
132
            case self::TYPE_CSV_COLLECTION:
133
                $baseClass = AbstractCsvCollectionEnumType::class;
134
                break;
135
            default:
136
                throw new LogicException(sprintf('Unexpected type "%s"', $type));
137
        }
138
139
        return <<<PHP
140
141
    if (!\class_exists($classname::class)) {
142
        class $classname extends \\{$baseClass}
143
        {
144
$code
145
        }
146
    }
147
148
PHP;
149
    }
150
151
    private function valueAsCode($value): string
152
    {
153
        if (is_string($value)) {
154
            if (strpos($value, '::') !== false) { // Constant name
155
                return sprintf('\\%s', ltrim($value, '\\'));
156
            }
157
158
            return sprintf('\'%s\'', $value); // plain string
159
        }
160
161
        if (is_bool($value)) {
162
            return $value ? 'true': 'false';
163
        }
164
165
        return (string)$value;
166
    }
167
168
    public static function getTypeClassname(string $class, string $type): string
169
    {
170
        $suffix = self::TYPES_SUFFIXES[$type];
171
172
        return self::MARKER . "\\{$class}{$suffix}";
173
    }
174
}
175