LaravelReadQueryUtilityTrait   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 23
eloc 56
c 4
b 0
f 0
dl 0
loc 134
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A processKeyDescriptor() 0 7 4
A getLaravelRelationName() 0 8 2
A processEagerLoadList() 0 16 4
A getSourceEntityInstance() 0 4 1
A checkSourceInstance() 0 12 5
B processSkipToken() 0 39 7
1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * Created by PhpStorm.
6
 * User: alex
7
 * Date: 14/02/20
8
 * Time: 10:54 PM.
9
 */
10
namespace AlgoWeb\PODataLaravel\Query;
11
12
use Illuminate\Database\Eloquent\Builder;
13
use Illuminate\Database\Eloquent\Collection;
14
use Illuminate\Database\Eloquent\Model;
15
use Illuminate\Database\Eloquent\Relations\Relation;
16
use Illuminate\Support\Facades\App;
17
use POData\Common\InvalidOperationException;
18
use POData\Common\ODataException;
19
use POData\Providers\Metadata\ResourceSet;
20
use POData\UriProcessor\QueryProcessor\SkipTokenParser\SkipTokenInfo;
21
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\KeyDescriptor;
22
use Symfony\Component\Process\Exception\InvalidArgumentException;
23
24
trait LaravelReadQueryUtilityTrait
25
{
26
    /** @var string|null */
27
    protected $name;
28
29
    /**
30
     * @param  SkipTokenInfo             $skipToken
31
     * @param  Model|Builder             $sourceEntityInstance
32
     * @throws InvalidOperationException
33
     * @return mixed
34
     */
35
    protected function processSkipToken(SkipTokenInfo $skipToken, $sourceEntityInstance)
36
    {
37
        $parameters = [];
38
        $processed  = [];
39
        $segments   = $skipToken->getOrderByInfo()->getOrderByPathSegments();
40
        $values     = $skipToken->getOrderByKeysInToken();
41
        $numValues  = count($values);
42
        if ($numValues != count($segments)) {
43
            $msg = 'Expected ' . count($segments) . ', got ' . $numValues;
44
            throw new InvalidOperationException($msg);
45
        }
46
47
        for ($i = 0; $i < $numValues; $i++) {
48
            $relation          = $segments[$i]->isAscending() ? '>' : '<';
49
            $name              = $segments[$i]->getSubPathSegments()[0]->getName();
50
            $baseVal           = $values[$i][0];
51
            /** @var string $rawValue */
52
            $rawValue          = is_string($baseVal) ? $baseVal : $baseVal->/** @scrutinizer ignore-call */toString();
53
            $parameters[$name] = [
54
                'direction' => $relation,
55
                'value' => trim(/** @scrutinizer ignore-type */$rawValue, '\'')
56
            ];
57
        }
58
59
        foreach ($parameters as $name => $line) {
60
            $processed[$name]     = ['direction' => $line['direction'], 'value' => $line['value']];
61
            $sourceEntityInstance = $sourceEntityInstance
62
                ->orWhere(
63
                    function (Builder $query) use ($processed) {
64
                        foreach ($processed as $key => $proc) {
65
                            $query->where($key, $proc['direction'], $proc['value']);
66
                        }
67
                    }
68
                );
69
            // now we've handled the later-in-order segment for this key, drop it back to equality in prep
70
            // for next key - same-in-order for processed keys and later-in-order for next
71
            $processed[$name]['direction'] = '=';
72
        }
73
        return $sourceEntityInstance;
74
    }
75
76
    /**
77
     * @param  ResourceSet          $resourceSet
78
     * @throws \ReflectionException
79
     * @return mixed
80
     */
81
    protected function getSourceEntityInstance(ResourceSet $resourceSet)
82
    {
83
        $entityClassName = $resourceSet->getResourceType()->getInstanceType()->name;
84
        return App::make($entityClassName);
85
    }
86
87
    /**
88
     * @param  Model|Relation|null       $source
89
     * @param  ResourceSet               $resourceSet
90
     * @throws \ReflectionException
91
     * @return Model|Relation|mixed|null
92
     */
93
    protected function checkSourceInstance($source, ResourceSet $resourceSet)
94
    {
95
        if (!(null == $source || $source instanceof Model || $source instanceof Relation)) {
0 ignored issues
show
introduced by
$source is always a sub-type of Illuminate\Database\Eloquent\Relations\Relation.
Loading history...
96
            $msg = 'Source entity instance must be null, a model, or a relation.';
97
            throw new InvalidArgumentException($msg);
98
        }
99
100
        if (null == $source) {
101
            $source = $this->getSourceEntityInstance(/* @scrutinizer ignore-type */$resourceSet);
102
        }
103
104
        return $source;
105
    }
106
107
    /**
108
     * @param  Model|Relation|Builder    $sourceEntityInstance
109
     * @param  KeyDescriptor|null        $keyDescriptor
110
     * @throws InvalidOperationException
111
     */
112
    protected function processKeyDescriptor(&$sourceEntityInstance, KeyDescriptor $keyDescriptor = null): void
113
    {
114
        if ($keyDescriptor) {
115
            $table = ($sourceEntityInstance instanceof Model) ? $sourceEntityInstance->getTable() . '.' : '';
116
            foreach ($keyDescriptor->getValidatedNamedValues() as $key => $value) {
117
                $trimValue            = trim($value[0], '\'');
118
                $sourceEntityInstance = $sourceEntityInstance->where($table . $key, $trimValue);
119
            }
120
        }
121
    }
122
123
    /**
124
     * @param  string[]                  $eagerLoad
125
     * @throws InvalidOperationException
126
     * @return string[]
127
     */
128
    protected function processEagerLoadList(array $eagerLoad = []): array
129
    {
130
        $rawLoad = [];
131
        foreach ($eagerLoad as $line) {
132
            if (!is_string($line)) {
133
                throw new InvalidOperationException('Eager-load elements must be non-empty strings');
134
            }
135
            $lineParts     = explode('/', $line);
136
            $numberOfParts = count($lineParts);
137
            for ($i = 0; $i < $numberOfParts; $i++) {
138
                $lineParts[$i] = $this->getLaravelRelationName($lineParts[$i]);
139
            }
140
            $remixLine = implode('.', $lineParts);
141
            $rawLoad[] = $remixLine;
142
        }
143
        return $rawLoad;
144
    }
145
146
    /**
147
     * @param  string $odataProperty
148
     * @return string
149
     */
150
    protected function getLaravelRelationName(string $odataProperty)
151
    {
152
        $laravelProperty = $odataProperty;
153
        $pos             = strrpos($laravelProperty, '_');
154
        if ($pos !== false) {
155
            $laravelProperty = substr($laravelProperty, 0, $pos);
156
        }
157
        return $laravelProperty;
158
    }
159
}
160