Completed
Push — master ( addaf0...c57d80 )
by Dmitry
03:20
created

Repository::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Tarantool\Mapper;
4
5
use Tarantool\Mapper\Contracts;
6
use BadMethodCallException;
7
use LogicException;
8
9
class Repository implements Contracts\Repository
10
{
11
    protected $type;
12
    protected $entities = [];
13
    protected $keyMap = [];
14
15
    protected $magicMethodRules = [
16
        'by' => false,
17
        'firstBy' => true,
18
        'oneBy' => true
19
    ];
20
21
    public function __construct(Contracts\Type $type)
22
    {
23
        $this->type = $type;
24
    }
25
26
    public function make(array $data = null)
27
    {
28
        return $this->register(new Entity($data));
29
    }
30
31
    public function __call($method, $arguments)
32
    {
33
        foreach ($this->magicMethodRules as $prefix => $oneItem) {
34
            if (substr($method, 0, strlen($prefix)) == $prefix) {
35
                $tail = substr($method, strlen($prefix));
36
                $fields = array_map('strtolower', explode('And', $tail));
37
                return $this->find(array_combine($fields, $arguments), $oneItem);
38
            }
39
        }
40
41
        throw new BadMethodCallException("Method $method not found");
42
    }
43
44
    public function find($params, $oneItem = false)
45
    {
46
        $fields = array_keys($params);
47
        sort($fields);
48
        $index = implode('_', $fields);
49
50
        $space = $this->type->getManager()->getClient()->getSpace($this->type->getName());
51
        $data = $space->select(array_values($params), $index);
52
53
        $result = [];
54
        if (!empty($data->getData())) {
55
            foreach ($data->getData() as $tuple) {
56
                $data = $this->type->decode($tuple);
57
                if (isset($data['id']) && array_key_exists($data['id'], $this->keyMap)) {
58
                    $entity = $this->entities[$this->keyMap[$data['id']]];
59
                    $entity->update($data);
60
                } else {
61
                    $entity = new Entity($data);
62
                    $this->register($entity);
63
                }
64
                if ($oneItem) {
65
                    return $entity;
66
                }
67
                $result[] = $entity;
68
            }
69
        }
70
        if (!$oneItem) {
71
            return $result;
72
        }
73
    }
74
75
    /**
76
     * @return Entity
77
     */
78
    public function knows(Contracts\Entity $entity)
79
    {
80
        return in_array($entity, $this->entities);
81
    }
82
83
    public function save(Contracts\Entity $entity)
84
    {
85
        if (!$this->knows($entity)) {
86
            throw new LogicException("Entity is not related with this repository");
87
        }
88
89
        if (!$entity->getId()) {
90
            $this->generateId($entity);
91
            $tuple = $this->type->encode($entity->toArray());
92
            $this->type->getSpace()->insert($tuple);
93
        } else {
94
            $changes = $entity->pullChanges();
95
            if (count($changes)) {
96
                $operations = [];
97
                foreach ($this->type->encode($changes) as $key => $value) {
98
                    $operations[] = ['=', $key + 1, $value];
99
                }
100
                $this->type->getSpace()->update($entity->getId(), $operations);
101
            }
102
        }
103
104
        return $entity;
105
    }
106
107
    protected function register(Contracts\Entity $entity)
108
    {
109
        if (!$this->knows($entity)) {
110
            $this->entities[] = $entity;
111
        }
112
        if ($entity->getId() && !array_key_exists($entity->getId(), $this->keyMap)) {
113
            $this->keyMap[$entity->getId()] = array_search($entity, $this->entities);
114
        }
115
        return $entity;
116
    }
117
118
    protected function generateId(Contracts\Entity $entity)
119
    {
120
        $manager = $this->type->getManager();
121
        $name = $this->type->getName();
122
123
        $sequence = $manager->get('sequences')->oneByName($name);
124
        if (!$sequence) {
125
            $sequence = $manager->get('sequences')->make([
126
                'name' => $name,
127
                'value' => 0,
128
            ]);
129
            $manager->save($sequence);
130
        }
131
132
        $nextValue = $manager->getClient()
133
            ->getSpace('sequences')
134
            ->update($sequence->id, [['+', 2, 1]])
135
            ->getData()[0][2];
136
137
        $entity->setId($nextValue);
138
139
        $this->register($entity);
140
141
        return $entity;
142
    }
143
}
144