RestObject::skipUniqueFieldsValidationCreation()   B
last analyzed

Complexity

Conditions 7
Paths 12

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 17
c 2
b 0
f 0
ccs 0
cts 12
cp 0
rs 8.2222
cc 7
eloc 12
nc 12
nop 1
crap 56
1
<?php
2
namespace Fathomminds\Rest\Database\Clusterpoint;
3
4
use Fathomminds\Rest\Exceptions\RestException;
5
use Fathomminds\Rest\Objects\RestObject as CoreRestObject;
6
7
class RestObject extends CoreRestObject
8
{
9
    protected $primaryKey = '_id';
10
    protected $databaseClass = Database::class;
11
12
    public function find($client = null)
13
    {
14
        if ($client === null) {
15
            $client = $this->getClient();
16
        }
17
        return (new Finder($client))
18
            ->database($this->getDatabaseName())
19
            ->from($this->getResourceName());
20
    }
21
22
    public function validateUniqueFields()
23
    {
24
        $uniqueFields = $this->getUniqueFields();
25
        if ($this->skipUniqueFieldsValidation($uniqueFields, $this->isModification())) {
26
            return;
27
        }
28
        $query = $this->getUniqueFieldQuery($uniqueFields);
29
        $res = $query->get();
30
        if ((int)$res->hits() > 0) {
31
            $results = json_decode($res->rawResponse())->results;
32
            $message = $results[0]->{$this->primaryKey} === $this->getPrimaryKeyValue() ?
33
                'Primary key collision' : 'Unique constraint violation';
34
            throw new RestException(
35
                $message,
36
                ['resourceName' => $this->resourceName, 'confilct' => $results[0]]
37
            );
38
        }
39
    }
40
41
    private function skipUniqueFieldsValidation($uniqueFields, $isModification)
42
    {
43
        if ($isModification) {
44
            return $this->skipUniqueFieldsValidationModification($uniqueFields);
45
        }
46
        return $this->skipUniqueFieldsValidationCreation($uniqueFields);
47
    }
48
49
    private function skipUniqueFieldsValidationModification($uniqueFields)
50
    {
51
        $resource = $this->resource();
52
        $filteredUniqueFields = array_diff($uniqueFields, [$this->primaryKey]);
53
        foreach ($filteredUniqueFields as $uniqueField) {
54
            $UFisSet = (property_exists($resource, $uniqueField) && $resource->{$uniqueField} !== null);
55
            if ($UFisSet) {
56
                return false;
57
            }
58
        }
59
        return true;
60
    }
61
62
    private function skipUniqueFieldsValidationCreation($uniqueFields)
63
    {
64
        $resource = $this->resource();
65
        $PKisInUniqueFields = in_array($this->primaryKey, $uniqueFields);
66
        $PKisSet = (property_exists($resource, $this->primaryKey) && $resource->{$this->primaryKey} !== null);
67
        if ($PKisInUniqueFields && $PKisSet) {
68
            return false;
69
        }
70
        $filteredUniqueFields = array_diff($uniqueFields, [$this->primaryKey]);
71
        foreach ($filteredUniqueFields as $uniqueField) {
72
            $UFisSet = (property_exists($resource, $uniqueField) && $resource->{$uniqueField} !== null);
73
            if ($UFisSet) {
74
                return false;
75
            }
76
        }
77
        return true;
78
    }
79
80
    private function getUniqueFieldQuery($uniqueFields)
81
    {
82
        $query = $this->getClient()->database($this->getDatabaseName() . '.' . $this->resourceName);
83
        if ($this->isModification()) {
84
            $uniqueFields = array_diff($uniqueFields, [$this->primaryKey]);
85
            $query->where($this->primaryKey, '!=', $this->getPrimaryKeyValue(), false);
86
        }
87
        // @codeCoverageIgnoreStart
88
        $query->where(function($query) use ($uniqueFields) {
89
            foreach ($uniqueFields as $fieldName) {
90
                list($propertyExists, $propertyValue) = $this->getProperty($fieldName);
91
                if ($propertyExists && $propertyValue !== null) {
92
                    $this->validateUniqueFieldDataType($fieldName, $propertyValue);
93
                    $query->orWhere($fieldName, '==', $propertyValue, false);
94
                }
95
            }
96
        });
97
        // @codeCoverageIgnoreEnd
98
        return $query->limit(1);
99
    }
100
101
    private function getProperty($fieldNameDotted, $resource = null)
102
    {
103
        if ($resource === null) {
104
            $resource = $this->resource;
105
        }
106
        $fieldNameArr = explode('.', $fieldNameDotted);
107
        $fieldName = array_shift($fieldNameArr);
108
        if (!property_exists($resource, $fieldName)) {
109
            return [
110
                false,
111
                null
112
            ];
113
        }
114
        if (count($fieldNameArr) === 0) {
115
            return [
116
                true,
117
                $resource->{$fieldName}
118
            ];
119
        }
120
        return $this->getProperty(implode('.', $fieldNameArr), $resource->{$fieldName});
121
    }
122
123
    private function validateUniqueFieldDataType($fieldName, $propertyValue)
124
    {
125
        $dataType = gettype($propertyValue);
126
        if (in_array($dataType, $this->validUniqueFieldTypes)) {
127
            return;
128
        }
129
        throw new RestException(
130
            'Data type is invalid for unique field',
131
            [
132
                'resourceName' => $this->resourceName,
133
                'fieldName' => $fieldName,
134
                'data' => $propertyValue,
135
                'dataType' => $dataType,
136
                'validDataTypes' => $this->validUniqueFieldTypes
137
            ]
138
        );
139
    }
140
141
    private function isModification()
142
    {
143
        if ($this->updateMode() || $this->replaceMode()) {
144
            return true;
145
        }
146
        return false;
147
    }
148
149
    public function query()
150
    {
151
        $query = $this->getClient()->database($this->getDatabaseName() . '.' . $this->resourceName);
152
        return $query;
153
    }
154
}
155