Completed
Push — master ( 4f5d93...61da31 )
by Dmitry
03:01 queued 13s
created

Type::isReference()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Tarantool\Mapper\Schema;
4
5
use Tarantool\Mapper\Contracts;
6
use LogicException;
7
8
class Type implements Contracts\Type
9
{
10
    private $convention;
11
    private $properties = [];
12
    private $indexes = [];
13
    private $types = [];
14
15
    private $manager;
16
    private $space;
17
    private $spaceId;
18
    private $name;
19
20 26
    public function __construct(Contracts\Manager $manager, $name, array $properties, array $types, array $indexes)
21
    {
22 26
        $this->manager = $manager;
23 26
        $this->name = $name;
24 26
        $this->convention = $manager->getMeta()->getConvention();
25 26
        $this->spaceId = $manager->getSchema()->getSpaceId($name);
26
27 26
        $this->properties = $properties;
28 26
        $this->indexes = $indexes;
29 26
        $this->types = $types;
30 26
    }
31
32 26
    public function getSpace()
33
    {
34 26
        if (!$this->space) {
35 26
            $this->space = $this->getManager()->getClient()->getSpace($this->spaceId);
36
        }
37
38 26
        return $this->space;
39
    }
40
41 26
    public function getSpaceId()
42
    {
43 26
        return $this->spaceId;
44
    }
45
46 26
    public function getManager()
47
    {
48 26
        return $this->manager;
49
    }
50
51 26
    public function getName()
52
    {
53 26
        return $this->name;
54
    }
55
56 26
    public function addIndex($properties, array $arguments = null)
57
    {
58 26
        $properties = (array) $properties;
59 26
        foreach ($properties as $property) {
60 26
            if (!$this->hasProperty($property)) {
61 26
                throw new LogicException("Unknown property $property for ".$this->name);
62
            }
63
        }
64
65 26
        $schema = $this->manager->getSchema();
66
67 26
        $indexName = implode('_', $properties);
68
69 26
        if ($schema->hasIndex($this->getName(), $indexName)) {
70 1
            throw new LogicException("Index $indexName already exists!");
71
        }
72
73 26
        if (!$arguments) {
74 26
            $arguments = [];
75
        }
76
77 26
        if (!array_key_exists('parts', $arguments) || !count($arguments['parts'])) {
78 26
            $arguments['parts'] = [];
79 26
            foreach ($properties as $property) {
80 26
                $arguments['parts'][] = array_search($property, $this->properties) + 1;
81 26
                $arguments['parts'][] = $this->convention->getTarantoolType($this->types[$property]);
82
            }
83
        }
84
85 26
        $num = $schema->createIndex($this->getName(), $indexName, $arguments);
86 26
        $this->indexes[$num] = $properties;
87
88 26
        return $this;
89
    }
90
91
    /**
92
     * @param $property name
93
     *
94
     * @return Type
95
     */
96 26
    public function addProperty($name, $type = null)
97
    {
98 26
        if ($this->hasProperty($name)) {
99 1
            throw new LogicException("Duplicate property $name");
100
        }
101 26
        if (!$type) {
102 26
            $type = $this->manager->getMeta()->getConvention()->getType($name);
103
        }
104 26
        $this->types[$name] = $type;
105 26
        $this->manager->create('property', [
106 26
            'space' => $this->spaceId,
107 26
            'index' => count($this->properties),
108 26
            'name' => $name,
109 26
            'type' => $this->types[$name],
110
        ]);
111
112 26
        $this->properties[] = $name;
113
114 26
        return $this;
115
    }
116
117 26
    public function hasProperty($name)
118
    {
119 26
        return in_array($name, $this->properties);
120
    }
121
122 26
    public function getProperties()
123
    {
124 26
        return $this->properties;
125
    }
126
127 1
    public function getPropertyType($property)
128
    {
129 1
        return $this->types[$property];
130
    }
131
132 4
    public function setPropertyType($property, $type)
133
    {
134 4
        $this->types[$property] = $type;
135
136
        // update entity
137 4
        $row = $this->getManager()->get('property')->findOne([
0 ignored issues
show
Bug introduced by
The method findOne does only exist in Tarantool\Mapper\Contracts\Repository, but not in Tarantool\Mapper\Contracts\Entity.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
138 4
            'space' => $this->spaceId,
139 4
            'index' => array_search($property, $this->properties),
140
        ]);
141 4
        $row->type = $type;
142 4
        $this->getManager()->save($row);
143
144 4
        return $this;
145
    }
146
147 3
    public function reference(Contracts\Type $foreign, $property = null)
148
    {
149 3
        if (!$property) {
150 2
            $property = $foreign->getName();
151
        }
152
153 3
        $this->addProperty($property);
154 3
        $this->setPropertyType($property, $foreign->getName());
155 3
        $this->addIndex($property, ['unique' => false]);
156
157 3
        return $this;
158
    }
159
160 1
    public function isReference($property)
161
    {
162 1
        return !$this->convention->isPrimitive($this->types[$property]);
163
    }
164
165 3
    public function getReferenceProperty(Contracts\Type $type)
166
    {
167 3
        $properties = [];
168 3
        foreach ($this->types as $property => $propertyType) {
169 3
            if ($type->getName() == $propertyType) {
170 3
                $properties[] = $property;
171
            }
172
        }
173 3
        if (!count($properties)) {
174 1
            throw new LogicException('Type '.$this->getName().' is not related with '.$type->getName());
175
        }
176 2
        if (count($properties) > 1) {
177 1
            throw new LogicException('Multiple type reference found');
178
        }
179
180 1
        return $properties[0];
181
    }
182
183 1
    public function getReferences()
184
    {
185 1
        $references = [];
186 1
        $convention = $this->manager->getMeta()->getConvention();
187 1
        foreach ($this->types as $property => $type) {
188 1
            if (!$convention->isPrimitive($type)) {
189 1
                $references[$property] = $type;
190
            }
191
        }
192
193 1
        return $references;
194
    }
195
196 26
    public function getRequiredProperties()
197
    {
198 26
        if (!isset($this->requiredProperties)) {
199 26
            $this->requiredProperties = ['id' => 1];
0 ignored issues
show
Bug introduced by
The property requiredProperties does not seem to exist. Did you mean properties?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
200 26
            $indexList = $this->manager->getSchema()->listIndexes($this->getName());
201 26
            foreach ($indexList as $name => $fields) {
202 26
                foreach ($fields as $num) {
203 26
                    $this->requiredProperties[$this->properties[$num]] = true;
0 ignored issues
show
Bug introduced by
The property requiredProperties does not seem to exist. Did you mean properties?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
204
                }
205
            }
206 26
            $this->requiredProperties = array_keys($this->requiredProperties);
0 ignored issues
show
Bug introduced by
The property requiredProperties does not seem to exist. Did you mean properties?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
207
        }
208
209 26
        return $this->requiredProperties;
0 ignored issues
show
Bug introduced by
The property requiredProperties does not seem to exist. Did you mean properties?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
210
    }
211
212 1
    public function getIndex($num)
213
    {
214 1
        return $this->indexes[$num];
215
    }
216
217 26
    public function findIndex($query)
218
    {
219 26
        if (!count($query)) {
220 2
            return 0;
221
        }
222
223 26
        sort($query);
224 26
        foreach ($this->indexes as $name => $fields) {
225 26
            if ($fields == $query) {
226 26
                return $name;
227
            }
228
        }
229
230
        // cast partial index
231 2
        $casting = [];
232
233 2
        foreach ($this->indexes as $name => $fields) {
234 2
            if (!count(array_diff($query, $fields))) {
235 2
                $casting[count(array_diff($fields, $query))] = $name;
236
            }
237
        }
238 2
        ksort($casting);
239
240 2
        return array_shift($casting);
241
    }
242
243 26
    public function getIndexTuple($index, $params)
244
    {
245 26
        $tuple = [];
246 26
        foreach ($this->indexes[$index] as $property) {
247 26
            $value = array_key_exists($property, $params) ? $params[$property] : null;
248 26
            if ($value) {
249 26
                $tuple[array_search($property, $this->indexes[$index])] = $value;
250
            }
251
        }
252
253 26
        return $tuple;
254
    }
255
256 26 View Code Duplication
    public function getTuple($input)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
257
    {
258 26
        $output = [];
259 26
        foreach ($this->getProperties() as $index => $name) {
260 26
            if (array_key_exists($name, $input)) {
261 26
                $output[$index] = $this->encodeProperty($name, $input[$name]);
262
            }
263
        }
264
265 26
        return $output;
266
    }
267
268 26 View Code Duplication
    public function fromTuple($input)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
269
    {
270 26
        $output = [];
271 26
        foreach ($this->getProperties() as $index => $name) {
272 26
            if (array_key_exists($index, $input)) {
273 26
                $output[$name] = $this->decodeProperty($name, $input[$index]);
274
            }
275
        }
276
277 26
        return $output;
278
    }
279
280 26
    public function encodeProperty($name, $value)
281
    {
282 26
        return $this->convention->encode($this->types[$name], $value);
283
    }
284
285 26
    public function decodeProperty($name, $value)
286
    {
287 26
        return $this->convention->decode($this->types[$name], $value);
288
    }
289
}
290