Completed
Push — master ( 1af4f5...caaac4 )
by Andreas
03:43
created

driver::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2.004

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 3
dl 0
loc 14
ccs 9
cts 10
cp 0.9
crap 2.004
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 11
    private function initialize()
97
    {
98 11
        $this->types = $this->manager->get_types();
99 11
    }
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 8
    public function isTransient($classname)
117
    {
118 8
        if ($this->types === null) {
119 7
            $this->initialize();
120 7
        }
121 8
        return !array_key_exists($classname, $this->types);
122
    }
123
124
    /**
125
     * {@inheritDoc}
126
     */
127 11
    public function loadMetadataForClass($classname, ClassMetadata $metadata)
128
    {
129 11
        if ($this->types === null) {
130 3
            $this->initialize();
131 3
        }
132 11
        if (!array_key_exists($classname, $this->types)) {
133 3
            throw MappingException::classIsNotAValidEntityOrMappedSuperClass($classname);
134
        }
135
136 11
        $type = $this->types[$classname];
137
138
        // TODO: extends
139
140
        $table = array(
141 11
            '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 11
            )
147 11
        );
148
149 11
        $metadata->setPrimaryTable($table);
150
151 11
        $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 11
        $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 11
        $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 11
        $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 11
        $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 11
        foreach ($type->get_properties() as $name => $property) {
158
            // doctrine can handle id links only
159 11
            if (   $property->link
160 11
                && $target_class = $this->manager->resolve_targetclass($property)) {
161
                $link_mapping = array(
162 8
                    'fieldName' => $property->name,
163 8
                    'targetEntity' => $target_class,
164
                    'joinColumns' => array(
165
                        array(
166 8
                            'name' => $property->field,
167 8
                            'referencedColumnName' => $property->link['field']
168 8
                        )
169 8
                    ),
170 8
                    'midgard:link_target' => $property->link['field'],
171 8
                    'midgard:link_name' => $property->link['target'],
172 8
                );
173
174 8
                if ($link_mapping['fieldName'] == 'id') {
175
                    $link_mapping['id'] = true;
176
                }
177
178 8
                $metadata->mapManyToOne($link_mapping);
179 8
                continue;
180
            }
181
182 11 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 4
                $mapping = $this->parse_dbtype($property);
184 4
            } else {
185 11
                $mapping = $this->dbtypemap[$property->dbtype];
186
            }
187
188 11
            if ($property->unique) {
189 11
                if ($property->name == 'guid') {
190 11
                    $mapping['unique'] = true;
191 11
                } else {
192
                    //we can't set this as a real DB constraint because of softdelete and tree hierarchies
193 3
                    $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 11
            }
196
197 11
            $mapping['columnName'] = $property->field;
198 11
            $mapping['midgard:midgard_type'] = translator::to_constant($property->type);
199 11
            $mapping['midgard:description'] = $property->description;
200
201
            // its some other link (like guid link)
202 11
            if ($property->noidlink) {
203 3
                $mapping['noidlink'] = $property->noidlink;
204 3
            }
205
206 11
            if ($property->name == $type->primaryfield) {
207 11
                $mapping['id'] = true;
208 11
                unset($mapping['default']);
209 11
                if ($mapping['type'] == dtype::INTEGER) {
210 11
                    $metadata->setIdGeneratorType(CM::GENERATOR_TYPE_AUTO);
211 11
                } else {
212 3
                    $metadata->setIdGeneratorType(CM::GENERATOR_TYPE_NONE);
213
                }
214 11
            }
215
216 11
            $mapping['fieldName'] = $name;
217
218 11
            $metadata->mapField($mapping);
219
220 11
            if ($property->index) {
221 10
                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 10
                    $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 10
                }
224 10
                $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 10
            }
226 11
        }
227 11
    }
228
229 4
    private function parse_dbtype(property $property)
230
    {
231 4
        if (strpos($property->dbtype, 'varchar') === 0) {
232
            $mapping = array(
233 4
                'type' => dtype::STRING,
234 4
            );
235
236 4 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 3
                $mapping['length'] = (int) substr($property->dbtype, 8, -1);
238 3
                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
        }
255
256
        throw new \Exception($property->get_parent()->name . ': ' . $property->name . ' ' . $property->dbtype . ' not implemented yet');
257
    }
258
}
259