Test Failed
Pull Request — master (#38)
by Alex
03:12
created

LaravelReadQuery::getRelatedResourceSet()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 30
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 24
nc 2
nop 9

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace AlgoWeb\PODataLaravel\Query;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Support\Facades\App;
7
use Symfony\Component\Process\Exception\InvalidArgumentException;
8
use POData\Providers\Metadata\ResourceProperty;
9
use POData\Providers\Metadata\ResourceSet;
10
use POData\Providers\Query\QueryResult;
11
use POData\Providers\Query\QueryType;
12
use POData\UriProcessor\QueryProcessor\ExpressionParser\FilterInfo;
13
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\KeyDescriptor;
14
15
class LaravelReadQuery
16
{
17
18
    /**
19
     * Gets collection of entities belongs to an entity set
20
     * IE: http://host/EntitySet
21
     *  http://host/EntitySet?$skip=10&$top=5&filter=Prop gt Value
22
     *
23
     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
24
     * @param ResourceSet $resourceSet The entity set containing the entities to fetch
25
     * @param FilterInfo $filterInfo represents the $filter parameter of the OData query.  NULL if no $filter specified
26
     * @param mixed $orderBy sorted order if we want to get the data in some specific order
27
     * @param int $top number of records which  need to be skip
28
     * @param String $skipToken value indicating what records to skip
29
     *
30
     * @return QueryResult
31
     */
32
    public function getResourceSet(
33
        QueryType $queryType,
34
        ResourceSet $resourceSet,
35
        $filterInfo = null,
36
        $orderBy = null,
37
        $top = null,
38
        $skipToken = null,
39
        Model $sourceEntityInstance = null
40
    ) {
41
        if (null != $filterInfo && !($filterInfo instanceof FilterInfo)) {
42
            throw new InvalidArgumentException('Filter info must be either null or instance of FilterInfo.');
43
        }
44
45
        if (null == $sourceEntityInstance) {
46
            $sourceEntityInstance = $this->getSourceEntityInstance($resourceSet);
47
        }
48
49
        $result          = new QueryResult();
50
        $result->results = null;
51
        $result->count   = null;
52
53
        if (null != $orderBy) {
54
            foreach ($orderBy->getOrderByInfo()->getOrderByPathSegments() as $order) {
55
                foreach ($order->getSubPathSegments() as $subOrder) {
56
                    $sourceEntityInstance = $sourceEntityInstance->orderBy(
57
                        $subOrder->getName(),
58
                        $order->isAscending() ? 'asc' : 'desc'
59
                    );
60
                }
61
            }
62
        }
63
64
        $resultSet = $sourceEntityInstance->get();
65
66
        if (isset($filterInfo)) {
67
            $method = "return ".$filterInfo->getExpressionAsString().";";
68
            $clln = "$".$resourceSet->getResourceType()->getName();
69
            $isvalid = create_function($clln, $method);
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
70
            $resultSet = $resultSet->filter($isvalid);
71
        }
72
73
        $resultCount = $resultSet->count();
74
75
        if (isset($skipToken)) {
76
            $resultSet = $resultSet->slice($skipToken);
77
        }
78
        if (isset($top)) {
79
            $resultSet = $resultSet->take($top);
80
        }
81
82
83
        if (QueryType::ENTITIES() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) {
84
            $result->results = array();
85
            foreach ($resultSet as $res) {
86
                $result->results[] = $res;
87
            }
88
        }
89
        if (QueryType::COUNT() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) {
90
            $result->count = $resultCount;
91
        }
92
        return $result;
93
    }
94
95
    /**
96
     * Get related resource set for a resource
97
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection
98
     * http://host/EntitySet?$expand=NavigationPropertyToCollection
99
     *
100
     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
101
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
102
     * @param object $sourceEntityInstance The source entity instance.
103
     * @param ResourceSet $targetResourceSet The resource set of containing the target of the navigation property
104
     * @param ResourceProperty $targetProperty The navigation property to retrieve
105
     * @param FilterInfo $filter represents the $filter parameter of the OData query.  NULL if no $filter specified
106
     * @param mixed $orderBy sorted order if we want to get the data in some specific order
107
     * @param int $top number of records which  need to be skip
108
     * @param String $skip value indicating what records to skip
109
     *
110
     * @return QueryResult
111
     *
112
     */
113
    public function getRelatedResourceSet(
114
        QueryType $queryType,
115
        ResourceSet $sourceResourceSet,
116
        $sourceEntityInstance,
117
        ResourceSet $targetResourceSet,
118
        ResourceProperty $targetProperty,
119
        $filter = null,
120
        $orderBy = null,
121
        $top = null,
122
        $skip = null
123
    ) {
124
        if (!($sourceEntityInstance instanceof Model)) {
125
            throw new InvalidArgumentException('Source entity must be an Eloquent model.');
126
        }
127
128
        $propertyName = $targetProperty->getName();
129
        $results = $sourceEntityInstance->$propertyName();
130
        $relatedClass = $results->getRelated();
131
        $sourceEntityInstance = new $relatedClass();
132
133
        return $this->getResourceSet(
134
            $queryType,
135
            $sourceResourceSet,
136
            $filter,
137
            $orderBy,
138
            $top,
139
            $skip,
140
            $sourceEntityInstance
141
        );
142
    }
143
144
    /**
145
     * Gets an entity instance from an entity set identified by a key
146
     * IE: http://host/EntitySet(1L)
147
     * http://host/EntitySet(KeyA=2L,KeyB='someValue')
148
     *
149
     * @param ResourceSet $resourceSet The entity set containing the entity to fetch
150
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
151
     *
152
     * @return object|null Returns entity instance if found else null
153
     */
154
    public function getResourceFromResourceSet(
155
        ResourceSet $resourceSet,
156
        KeyDescriptor $keyDescriptor = null
157
    ) {
158
        return $this->getResource($resourceSet, $keyDescriptor);
159
    }
160
161
162
    /**
163
     * Common method for getResourceFromRelatedResourceSet() and getResourceFromResourceSet()
164
     * @param ResourceSet|null $resourceSet
165
     * @param KeyDescriptor|null $keyDescriptor
166
     */
167
    public function getResource(
168
        ResourceSet $resourceSet = null,
169
        KeyDescriptor $keyDescriptor = null,
170
        array $whereCondition = [],
171
        Model $sourceEntityInstance = null
172
    ) {
173
        if (null == $resourceSet && null == $sourceEntityInstance) {
174
            throw new \Exception('Must supply at least one of a resource set and source entity.');
175
        }
176
177
        if (null == $sourceEntityInstance) {
178
            assert(null != $resourceSet);
179
            $sourceEntityInstance = $this->getSourceEntityInstance($resourceSet);
180
        }
181
182
        if ($keyDescriptor) {
183
            foreach ($keyDescriptor->getValidatedNamedValues() as $key => $value) {
184
                $trimValue = trim($value[0], "\"'");
185
                $sourceEntityInstance = $sourceEntityInstance->where($key, $trimValue);
186
            }
187
        }
188
        foreach ($whereCondition as $fieldName => $fieldValue) {
189
            $sourceEntityInstance = $sourceEntityInstance->where($fieldName, $fieldValue);
190
        }
191
        $sourceEntityInstance = $sourceEntityInstance->get();
192
        return (0 == $sourceEntityInstance->count()) ? null : $sourceEntityInstance->first();
193
    }
194
195
    /**
196
     * Get related resource for a resource
197
     * IE: http://host/EntitySet(1L)/NavigationPropertyToSingleEntity
198
     * http://host/EntitySet?$expand=NavigationPropertyToSingleEntity
199
     *
200
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
201
     * @param object $sourceEntityInstance The source entity instance.
202
     * @param ResourceSet $targetResourceSet The entity set containing the entity pointed to by the navigation property
203
     * @param ResourceProperty $targetProperty The navigation property to fetch
204
     *
205
     * @return object|null The related resource if found else null
206
     */
207
    public function getRelatedResourceReference(
208
        ResourceSet $sourceResourceSet,
209
        $sourceEntityInstance,
210
        ResourceSet $targetResourceSet,
211
        ResourceProperty $targetProperty
212
    ) {
213
        if (!($sourceEntityInstance instanceof Model)) {
214
            throw new InvalidArgumentException('Source entity must be an Eloquent model.');
215
        }
216
        $propertyName = $targetProperty->getName();
217
        return $sourceEntityInstance->$propertyName;
218
    }
219
220
    /**
221
     * Gets a related entity instance from an entity set identified by a key
222
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection(33)
223
     *
224
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
225
     * @param object $sourceEntityInstance The source entity instance.
226
     * @param ResourceSet $targetResourceSet The entity set containing the entity to fetch
227
     * @param ResourceProperty $targetProperty The metadata of the target property.
228
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
229
     *
230
     * @return object|null Returns entity instance if found else null
231
     */
232
    public function getResourceFromRelatedResourceSet(
233
        ResourceSet $sourceResourceSet,
234
        $sourceEntityInstance,
235
        ResourceSet $targetResourceSet,
236
        ResourceProperty $targetProperty,
237
        KeyDescriptor $keyDescriptor
238
    ) {
239
        if (!($sourceEntityInstance instanceof Model)) {
240
            throw new InvalidArgumentException('Source entity must be an Eloquent model.');
241
        }
242
        $propertyName = $targetProperty->getName();
243
        return $this->getResource(null, $keyDescriptor, [], $sourceEntityInstance->$propertyName);
244
    }
245
246
247
    /**
248
     * @param ResourceSet $resourceSet
249
     * @return mixed
250
     */
251
    protected function getSourceEntityInstance(ResourceSet $resourceSet)
252
    {
253
        $entityClassName = $resourceSet->getResourceType()->getInstanceType()->name;
254
        return App::make($entityClassName);
255
    }
256
}
257