Passed
Push — master ( e755f8...88fee8 )
by Andreas
05:04
created

driver::getAllClassNames()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
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\type;
13
use midgard\portable\mgdschema\property;
14
use midgard\portable\storage\type\datetime;
15
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver as driver_interface;
16
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
17
use Doctrine\ORM\Mapping\MappingException;
18
use Doctrine\ORM\Mapping\ClassMetadata as CM;
19
use Doctrine\DBAL\Types\Type as dtype;
20
21
class driver implements driver_interface
22
{
23
    private $dbtypemap = array(
24
        'unsigned integer' => array('type' => dtype::INTEGER, 'default' => 0), // <== UNSIGNED in Doctrine\DBAL\Schema\Column
25
        'integer' => array('type' => dtype::INTEGER, 'default' => 0),
26
        'boolean' => array('type' => dtype::BOOLEAN, 'default' => false),
27
        'bool' => array('type' => dtype::BOOLEAN, 'default' => false),
28
        'guid' => array('type' => dtype::STRING, 'length' => 80, 'default' => ''),
29
        'varchar(80)' => array('type' => dtype::STRING, 'length' => 80, 'default' => ''),
30
        'string' => array('type' => dtype::STRING, 'length' => 255, 'default' => ''),
31
        'datetime' => array('type' => datetime::TYPE, 'default' => '0001-01-01 00:00:00'),
32
        'text' => array('type' => dtype::TEXT),
33
        'longtext' => array('type' => dtype::TEXT),
34
        'float' => array('type' => dtype::FLOAT, 'default' => 0.0),
35
        'double' => array('type' => dtype::FLOAT, 'default' => 0.0)
36
    );
37
38
    private $vardir;
39
40
    private $types;
41
42
    private $namespace;
43
44
    private $manager;
45
46
    /**
47
     * keep track of the namespaces already in use and
48
     * remember the used manager instance for resolving types
49
     *
50
     * @var array
51
     */
52
    private static $processed_namespaces = array();
53
54
    /**
55
     * indicates whether the current namespace has been used before
56
     *
57
     * @var boolean
58
     */
59
    private $is_fresh_namespace;
60
61 14
    public function __construct(array $schemadirs, $vardir, $namespace = 'midgard\\portable\\entities')
62
    {
63 14
        $this->vardir = $vardir . '/';
64 14
        $this->namespace = $namespace;
65
66 14
        $this->is_fresh_namespace = !array_key_exists($this->namespace, self::$processed_namespaces);
67 14
        if ($this->is_fresh_namespace) {
68 14
            $this->manager = new manager($schemadirs, $this->namespace);
69 14
            self::$processed_namespaces[$this->namespace] = array("manager" => $this->manager);
70 14
        } else {
71
            // reuse manager instance
72
            $this->manager = self::$processed_namespaces[$this->namespace]["manager"];
73
        }
74 14
    }
75
76 10
    public function is_fresh_namespace()
77
    {
78 10
        return $this->is_fresh_namespace;
79
    }
80
81 10
    public function get_namespace()
82
    {
83 10
        return $this->namespace;
84
    }
85
86 11
    public function get_manager()
87
    {
88 11
        return $this->manager;
89
    }
90
91 10
    public function get_vardir()
92
    {
93 10
        return rtrim($this->vardir, '/');
94
    }
95
96 12
    private function initialize()
97
    {
98 12
        $this->types = $this->manager->get_types();
99 12
    }
100
101
    /**
102
     * {@inheritDoc}
103
     */
104 2
    public function getAllClassNames()
105
    {
106 2
        if ($this->types === null) {
107 1
            $this->initialize();
108 1
        }
109
110 2
        return array_keys($this->types);
111
    }
112
113
    /**
114
     * {@inheritDoc}
115
     */
116 11
    public function isTransient($classname)
117
    {
118 11
        if ($this->types === null) {
119 8
            $this->initialize();
120 8
        }
121 11
        return !array_key_exists($classname, $this->types);
122
    }
123
124
    /**
125
     * {@inheritDoc}
126
     */
127 14
    public function loadMetadataForClass($classname, ClassMetadata $metadata)
128
    {
129 14
        if ($this->types === null) {
130 3
            $this->initialize();
131 3
        }
132 14
        if (!array_key_exists($classname, $this->types)) {
133 3
            throw MappingException::classIsNotAValidEntityOrMappedSuperClass($classname);
134
        }
135
136 14
        $type = $this->types[$classname];
137
138
        // TODO: extends
139
140
        $table = array(
141 14
            'name' => $type->table,
142
            'options' => array(
143
                //Doctrine's default on MySQL is InnoDB, and the foreign keys don't play well with Midgard logic
144
                //TODO: Maybe at some point we could try to figure out how to explicitly disable foreign key constraint creation instead
145
                'engine' => 'MyISAM'
146 14
            )
147 14
        );
148
149 14
        $metadata->setPrimaryTable($table);
150
151 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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
152 14
        $metadata->midgard['parentfield'] = $type->parentfield;
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
153 14
        $metadata->midgard['upfield'] = $type->upfield;
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
154 14
        $metadata->midgard['childtypes'] = $this->manager->get_child_classes($type->name);
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
155 14
        $metadata->midgard['field_aliases'] = $type->field_aliases;
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
156
157 14
        foreach ($type->get_properties() as $name => $property) {
158
            // doctrine can handle id links only
159 14
            if (   $property->link
160 14
                && $target_class = $this->manager->resolve_targetclass($property)) {
161
                $link_mapping = array(
162 10
                    'fieldName' => $property->name,
163 10
                    'targetEntity' => $target_class,
164
                    'joinColumns' => array(
165
                        array(
166 10
                            'name' => $property->field,
167 10
                            'referencedColumnName' => $property->link['field']
168 10
                        )
169 10
                    ),
170 10
                    'midgard:link_target' => $property->link['field'],
171 10
                    'midgard:link_name' => $property->link['target'],
172 10
                );
173
174 10
                if ($link_mapping['fieldName'] == 'id') {
175
                    $link_mapping['id'] = true;
176
                }
177
178 10
                $metadata->mapManyToOne($link_mapping);
179 10
                continue;
180
            }
181
182 14 View Code Duplication
            if (empty($this->dbtypemap[$property->dbtype])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
183 5
                $mapping = $this->parse_dbtype($property);
184 5
            } else {
185 14
                $mapping = $this->dbtypemap[$property->dbtype];
186
            }
187
188 14
            if ($property->unique) {
189 14
                if ($property->name == 'guid') {
190 14
                    $mapping['unique'] = true;
191 14
                } else {
192
                    //we can't set this as a real DB constraint because of softdelete and tree hierarchies
193 4
                    $metadata->midgard['unique_fields'][] = $property->name;
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
194
                }
195 14
            }
196
197 14
            $mapping['columnName'] = $property->field;
198 14
            $mapping['midgard:midgard_type'] = translator::to_constant($property->type);
199 14
            $mapping['midgard:description'] = $property->description;
200
201
            // its some other link (like guid link)
202 14
            if ($property->noidlink) {
203 4
                $mapping['noidlink'] = $property->noidlink;
204 4
            }
205
206 14
            if ($property->name == $type->primaryfield) {
207 14
                $mapping['id'] = true;
208 14
                unset($mapping['default']);
209 14
                if ($mapping['type'] == dtype::INTEGER) {
210 14
                    $metadata->setIdGeneratorType(CM::GENERATOR_TYPE_AUTO);
211 14
                } else {
212 3
                    $metadata->setIdGeneratorType(CM::GENERATOR_TYPE_NONE);
213
                }
214 14
            }
215
216 14
            $mapping['fieldName'] = $name;
217
218 14
            $metadata->mapField($mapping);
219
220 14
            if ($property->index) {
221 13
                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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
222 13
                    $metadata->table['indexes'] = array();
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
223 13
                }
224 13
                $metadata->table['indexes'][$type->name . '_' . $property->name . '_idx'] = array('columns' => array($property->field));
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
225 13
            }
226 14
        }
227 14
    }
228
229 5
    private function parse_dbtype(property $property)
230
    {
231 5
        if (strpos($property->dbtype, 'varchar') === 0) {
232
            $mapping = array(
233 5
                'type' => dtype::STRING,
234 5
            );
235
236 5 View Code Duplication
            if (substr($property->dbtype, -1) == ')') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
237 4
                $mapping['length'] = (int) substr($property->dbtype, 8, -1);
238 4
                return $mapping;
239
            }
240
241 2 View Code Duplication
            if (substr($property->dbtype, -8) == ') binary') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
242
                // see http://www.doctrine-project.org/jira/browse/DDC-1817
243 2
                $mapping['length'] = (int) substr($property->dbtype, 8, -1);
244 2
                $mapping['comment'] = 'BINARY';
245 2
                return $mapping;
246
            }
247 2
        } elseif (strpos($property->dbtype, 'set') === 0) {
248
            // see http://docs.doctrine-project.org/en/latest/cookbook/mysql-enums.html
249 2 View Code Duplication
            if (!empty($this->dbtypemap[$property->type])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
250 2
                $mapping = $this->dbtypemap[$property->type];
251 2
                $mapping['comment'] = $property->dbtype;
252 2
                return $mapping;
253
            }
254
        } elseif (strpos(strtolower($property->dbtype), 'decimal') === 0) {
255
            $matches = array();
256
            preg_match('/DECIMAL\((\d+),(\d+)\)/i', $property->dbtype, $matches);
257
            $mapping = array(
258
                'type' => dtype::DECIMAL,
259
                'precision' => $matches[1],
260
                'scale' => $matches[2]
261
            );
262
            return $mapping;
263
        }
264
265
        throw new \Exception($property->get_parent()->name . ': ' . $property->name . ' ' . $property->dbtype . ' not implemented yet');
266
    }
267
}
268