Test Failed
Push — master ( 1e7eb6...0a8a93 )
by Andreas
02:24
created

driver::loadMetadataForClass()   C

Complexity

Conditions 14
Paths 116

Size

Total Lines 94
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 58
CRAP Score 14.0072

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 14
eloc 54
c 2
b 0
f 0
nc 116
nop 2
dl 0
loc 94
ccs 58
cts 60
cp 0.9667
crap 14.0072
rs 6.1333

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
4
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
6
 */
7
8
namespace midgard\portable;
9
10
use midgard\portable\mgdschema\manager;
11
use midgard\portable\mgdschema\translator;
12
use midgard\portable\mgdschema\property;
13
use midgard\portable\storage\type\datetime;
14
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver as driver_interface;
15
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
16
use Doctrine\ORM\Mapping\MappingException;
17
use Doctrine\ORM\Mapping\ClassMetadata as CM;
18
use Doctrine\DBAL\Types\Type;
19
20
class driver implements driver_interface
0 ignored issues
show
Deprecated Code introduced by
The interface Doctrine\Common\Persiste...ng\Driver\MappingDriver has been deprecated: 1.3 Use Doctrine\Persistence\Mapping\Driver\MappingDriver ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

20
class driver implements /** @scrutinizer ignore-deprecated */ driver_interface

This interface has been deprecated. The supplier of the interface has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.

Loading history...
21
{
22
    private $dbtypemap = [
23
        'unsigned integer' => ['type' => Type::INTEGER, 'default' => 0], // <== UNSIGNED in Doctrine\DBAL\Schema\Column
24
        'integer' => ['type' => Type::INTEGER, 'default' => 0],
25
        'boolean' => ['type' => Type::BOOLEAN, 'default' => false],
26
        'bool' => ['type' => Type::BOOLEAN, 'default' => false],
27
        'guid' => ['type' => Type::STRING, 'length' => 80, 'default' => ''],
28
        'varchar(80)' => ['type' => Type::STRING, 'length' => 80, 'default' => ''],
29
        'string' => ['type' => Type::STRING, 'length' => 255, 'default' => ''],
30
        'datetime' => ['type' => datetime::TYPE, 'default' => '0001-01-01 00:00:00'],
31
        'text' => ['type' => Type::TEXT],
32
        'longtext' => ['type' => Type::TEXT],
33
        'float' => ['type' => Type::FLOAT, 'default' => 0.0],
34
        'double' => ['type' => Type::FLOAT, 'default' => 0.0]
35
    ];
36
37
    private $vardir;
38
39
    private $types;
40
41
    private $namespace;
42
43
    private $manager;
44
45
    /**
46
     * keep track of the namespaces already in use and
47
     * remember the used manager instance for resolving types
48
     *
49
     * @var array
50
     */
51
    private static $processed_namespaces = [];
52
53
    /**
54
     * indicates whether the current namespace has been used before
55
     *
56
     * @var boolean
57
     */
58
    private $is_fresh_namespace;
59
60 14
    public function __construct(array $schemadirs, $vardir, $namespace = 'midgard\\portable\\entities')
61
    {
62 14
        $this->vardir = $vardir . '/';
63 14
        $this->namespace = $namespace;
64
65 14
        $this->is_fresh_namespace = !isset(self::$processed_namespaces[$this->namespace]);
66 14
        if ($this->is_fresh_namespace) {
67 14
            $this->manager = new manager($schemadirs, $this->namespace);
68 14
            self::$processed_namespaces[$this->namespace] = ["manager" => $this->manager];
69 14
        } else {
70
            // reuse manager instance
71
            $this->manager = self::$processed_namespaces[$this->namespace]["manager"];
72
        }
73 14
    }
74
75 10
    public function is_fresh_namespace()
76
    {
77 10
        return $this->is_fresh_namespace;
78
    }
79
80 10
    public function get_namespace()
81
    {
82 10
        return $this->namespace;
83
    }
84
85 11
    public function get_manager()
86
    {
87 11
        return $this->manager;
88
    }
89
90 10
    public function get_vardir()
91
    {
92 10
        return rtrim($this->vardir, '/');
93
    }
94
95 12
    private function initialize()
96
    {
97 12
        $this->types = $this->manager->get_types();
98 12
    }
99
100
    /**
101
     * {@inheritDoc}
102
     */
103 2
    public function getAllClassNames()
104
    {
105 2
        if ($this->types === null) {
106 1
            $this->initialize();
107 1
        }
108
109 2
        return array_keys($this->types);
110
    }
111
112
    /**
113
     * {@inheritDoc}
114
     */
115 11
    public function isTransient($classname)
116
    {
117 11
        if ($this->types === null) {
118 8
            $this->initialize();
119 8
        }
120 11
        return !isset($this->types[$classname]);
121
    }
122
123
    /**
124
     * {@inheritDoc}
125
     */
126 14
    public function loadMetadataForClass($classname, ClassMetadata $metadata)
127
    {
128 14
        if ($this->types === null) {
129 3
            $this->initialize();
130 3
        }
131 14
        if (!isset($this->types[$classname])) {
132 3
            throw MappingException::classIsNotAValidEntityOrMappedSuperClass($classname);
133
        }
134
135 14
        $type = $this->types[$classname];
136
137
        // TODO: extends
138
139
        $table = [
140 14
            'name' => '`' . $type->table . '`',
141
            'options' => [
142
                //Doctrine's default on MySQL is InnoDB, and the foreign keys don't play well with Midgard logic
143
                //TODO: Maybe at some point we could try to figure out how to explicitly disable foreign key constraint creation instead
144
                'engine' => 'MyISAM'
145 14
            ]
146 14
        ];
147
148 14
        $metadata->setPrimaryTable($table);
149
150 14
        $metadata->midgard['parent'] = $type->parent;
0 ignored issues
show
Bug introduced by
Accessing midgard on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
151 14
        $metadata->midgard['parentfield'] = $type->parentfield;
152 14
        $metadata->midgard['upfield'] = $type->upfield;
153 14
        $metadata->midgard['childtypes'] = $this->manager->get_child_classes($type->name);
154 14
        $metadata->midgard['field_aliases'] = $type->field_aliases;
155
156 14
        foreach ($type->get_properties() as $name => $property) {
157
            // doctrine can handle id links only
158 14
            if (   $property->link
159 14
                && $target_class = $this->manager->resolve_targetclass($property)) {
160
                $link_mapping = [
161 10
                    'fieldName' => $property->name,
162 10
                    'targetEntity' => $target_class,
163
                    'joinColumns' => [
164
                        [
165 10
                            'name' => $property->field,
166 10
                            'referencedColumnName' => $property->link['field']
167 10
                        ]
168 10
                    ],
169 10
                    'midgard:link_target' => $property->link['field'],
170 10
                    'midgard:link_name' => $property->link['target'],
171 10
                ];
172
173 10
                if ($link_mapping['fieldName'] == 'id') {
174
                    $link_mapping['id'] = true;
175
                }
176
177 10
                $metadata->mapManyToOne($link_mapping);
178 10
                continue;
179
            }
180
181 14
            $mapping = $this->dbtypemap[$property->dbtype] ?? $this->parse_dbtype($property);
182 5
183 5
            if ($property->unique) {
184 14
                if ($property->name == 'guid') {
185
                    $mapping['unique'] = true;
186
                } else {
187 14
                    //we can't set this as a real DB constraint because of softdelete and tree hierarchies
188 14
                    $metadata->midgard['unique_fields'][] = $property->name;
189 14
                }
190 14
            }
191
192 4
            $mapping['columnName'] = $property->field;
193
            $mapping['midgard:midgard_type'] = translator::to_constant($property->type);
194 14
            $mapping['midgard:description'] = $property->description;
195
196 14
            // its some other link (like guid link)
197 14
            if ($property->noidlink) {
198 14
                $mapping['noidlink'] = $property->noidlink;
199
            }
200
201 14
            if ($property->name == $type->primaryfield) {
202 4
                $mapping['id'] = true;
203 4
                unset($mapping['default']);
204
                if ($mapping['type'] == Type::INTEGER) {
0 ignored issues
show
Deprecated Code introduced by
The constant Doctrine\DBAL\Types\Type::INTEGER has been deprecated: Use {@see DefaultTypes::INTEGER} instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

204
                if ($mapping['type'] == /** @scrutinizer ignore-deprecated */ Type::INTEGER) {

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
205 14
                    $metadata->setIdGeneratorType(CM::GENERATOR_TYPE_AUTO);
206 14
                } else {
207 14
                    $metadata->setIdGeneratorType(CM::GENERATOR_TYPE_NONE);
208 14
                }
209 14
            }
210 14
211 3
            $mapping['fieldName'] = $name;
212
213 14
            $metadata->mapField($mapping);
214
215 14
            if ($property->index) {
216
                if (empty($metadata->table['indexes'])) {
0 ignored issues
show
Bug introduced by
Accessing table on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
217 14
                    $metadata->table['indexes'] = [];
218
                }
219 14
                $metadata->table['indexes'][$type->name . '_' . $property->name . '_idx'] = ['columns' => [$property->field]];
220 13
            }
221 13
        }
222 13
    }
223 13
224 13
    private function parse_dbtype(property $property)
225 14
    {
226 14
        if (strpos($property->dbtype, 'varchar') === 0) {
227
            $mapping = [
228 5
                'type' => Type::STRING,
0 ignored issues
show
Deprecated Code introduced by
The constant Doctrine\DBAL\Types\Type::STRING has been deprecated: Use {@see DefaultTypes::STRING} instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

228
                'type' => /** @scrutinizer ignore-deprecated */ Type::STRING,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
229
            ];
230 5
231
            if (substr($property->dbtype, -1) == ')') {
232 5
                $mapping['length'] = (int) substr($property->dbtype, 8, -1);
233 5
                return $mapping;
234
            }
235 5
236 4
            if (substr($property->dbtype, -8) == ') binary') {
237 4
                // see http://www.doctrine-project.org/jira/browse/DDC-1817
238
                $mapping['length'] = (int) substr($property->dbtype, 8, -1);
239
                $mapping['comment'] = 'BINARY';
240 2
                return $mapping;
241
            }
242 2
        } elseif (strpos($property->dbtype, 'set') === 0) {
243 2
            // see http://docs.doctrine-project.org/en/latest/cookbook/mysql-enums.html
244 2
            if (!empty($this->dbtypemap[$property->type])) {
245
                $mapping = $this->dbtypemap[$property->type];
246 2
                $mapping['comment'] = $property->dbtype;
247
                return $mapping;
248 2
            }
249 2
        } elseif (strpos(strtolower($property->dbtype), 'decimal') === 0) {
250 2
            $matches = [];
251 2
            preg_match('/DECIMAL\((\d+),(\d+)\)/i', $property->dbtype, $matches);
252
            $mapping = [
253
                'type' => Type::DECIMAL,
0 ignored issues
show
Deprecated Code introduced by
The constant Doctrine\DBAL\Types\Type::DECIMAL has been deprecated: Use {@see DefaultTypes::DECIMAL} instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

253
                'type' => /** @scrutinizer ignore-deprecated */ Type::DECIMAL,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
254
                'precision' => $matches[1],
255
                'scale' => $matches[2]
256
            ];
257
            return $mapping;
258
        }
259
260
        throw new \Exception($property->get_parent()->name . ': ' . $property->name . ' ' . $property->dbtype . ' not implemented yet');
261
    }
262
}
263