Completed
Pull Request — master (#11)
by Alex
13:27
created

LaravelQuery::getRelatedResourceSet()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 11
cts 11
cp 1
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 20
nc 1
nop 9
crap 1

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 POData\Providers\Metadata\ResourceProperty;
6
use POData\Providers\Metadata\ResourceSet;
7
use POData\UriProcessor\QueryProcessor\Expression\Parser\IExpressionProvider;
8
use POData\UriProcessor\QueryProcessor\ExpressionParser\FilterInfo;
9
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\KeyDescriptor;
10
use POData\Providers\Query\IQueryProvider;
11
use POData\Providers\Expression\MySQLExpressionProvider;
12
use POData\Providers\Query\QueryType;
13
use POData\Providers\Query\QueryResult;
14
use POData\Providers\Expression\PHPExpressionProvider;
15
use AlgoWeb\PODataLaravel\Interfaces\AuthInterface;
16
use AlgoWeb\PODataLaravel\Auth\NullAuthProvider;
17
use Illuminate\Support\Facades\DB;
18
19
class LaravelQuery implements IQueryProvider
20
{
21
    protected $expression;
22
    protected $auth;
23
    public $queryProviderClassName;
24
25 2
    public function __construct(AuthInterface $auth = null)
26
    {
27
        /* MySQLExpressionProvider();*/
28 2
        $this->expression = new LaravelExpressionProvider(); //PHPExpressionProvider('expression');
29 2
        $this->queryProviderClassName = get_class($this);
30 2
        $this->auth = isset($auth) ? $auth : new NullAuthProvider();
31 2
    }
32
33
    /**
34
     * Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters
35
     * If the query provider can not handle ordered paging, it must return the entire result set and POData will
36
     * perform the ordering and paging
37
     *
38
     * @return Boolean True if the query provider can handle ordered paging, false if POData should perform the paging
39
     */
40
    public function handlesOrderedPaging()
41
    {
42
        return true;
43
    }
44
45
    /**
46
     * Gets the expression provider used by to compile OData expressions into expression used by this query provider.
47
     *
48
     * @return \POData\Providers\Expression\IExpressionProvider
49
     */
50
    public function getExpressionProvider()
51
    {
52
        return $this->expression;
53
    }
54
55
    /**
56
     * Gets collection of entities belongs to an entity set
57
     * IE: http://host/EntitySet
58
     *  http://host/EntitySet?$skip=10&$top=5&filter=Prop gt Value
59
     *
60
     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
61
     * @param ResourceSet $resourceSet The entity set containing the entities to fetch
62
     * @param FilterInfo $filterInfo represents the $filter parameter of the OData query.  NULL if no $filter specified
63
     * @param mixed $orderBy sorted order if we want to get the data in some specific order
64
     * @param int $top number of records which  need to be skip
65
     * @param String $skipToken value indicating what records to skip
66
     *
67
     * @return QueryResult
68
     */
69 3
    public function getResourceSet(
70
        QueryType $queryType,
71
        ResourceSet $resourceSet,
72
        $filterInfo = null,
73
        $orderBy = null,
74
        $top = null,
75
        $skipToken = null,
76
        $sourceEntityInstance = null
77
    ) {
78 3
        if ($resourceSet == null && $sourceEntityInstance == null) {
79
            throw new \Exception('Must supply at least one of a resource set and source entity');
80
        }
81 3
        if ($sourceEntityInstance == null) {
82 1
            $sourceEntityInstance = $this->getSourceEntityInstance($resourceSet);
83 1
        }
84
85 3
        $result          = new QueryResult();
86 3
        $result->results = null;
87 3
        $result->count   = null;
88
89 3
        if (isset($orderBy) && null != $orderBy) {
90
            foreach ($orderBy->getOrderByInfo()->getOrderByPathSegments() as $order) {
91
                foreach ($order->getSubPathSegments() as $subOrder) {
92
                    $sourceEntityInstance = $sourceEntityInstance->orderBy(
93
                        $subOrder->getName(),
94
                        $order->isAscending() ? 'asc' : 'desc'
95
                    );
96
                }
97
            }
98
        }
99 3
        if (isset($skipToken)) {
100 1
            $sourceEntityInstance = $sourceEntityInstance->skip($skipToken);
101 1
        }
102 3
        if (isset($top)) {
103 1
            $sourceEntityInstance = $sourceEntityInstance->take($top);
104 1
        }
105
106 3
        $resultSet = $sourceEntityInstance->get();
107
108 3
        if (isset($filterInfo)) {
109
            $method = "return ".$filterInfo->getExpressionAsString().";";
110
            $clln = "$".$resourceSet->getResourceType()->getName();
111
            $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...
112
            $resultSet = $resultSet->filter($isvalid);
113
        }
114
115
116 3
        if (QueryType::ENTITIES() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) {
117 1
            $result->results = array();
118 1
            foreach ($resultSet as $res) {
119 1
                $result->results[] = $res;
120 1
            }
121 1
        }
122 3
        if (QueryType::COUNT() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) {
123 3
            if (is_array($resultSet)) {
124
                $resultSet = collect($resultSet);
125
            }
126 3
            $result->count = $resultSet->count();
127 3
        }
128 3
        return $result;
129
    }
130
    /**
131
     * Gets an entity instance from an entity set identified by a key
132
     * IE: http://host/EntitySet(1L)
133
     * http://host/EntitySet(KeyA=2L,KeyB='someValue')
134
     *
135
     * @param ResourceSet $resourceSet The entity set containing the entity to fetch
136
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
137
     *
138
     * @return object|null Returns entity instance if found else null
139
     */
140
    public function getResourceFromResourceSet(
141
        ResourceSet $resourceSet,
142
        KeyDescriptor $keyDescriptor = null
143
    ) {
144
        return $this->getResource($resourceSet, $keyDescriptor);
145
    }
146
147
    /**
148
     * Common method for getResourceFromRelatedResourceSet() and getResourceFromResourceSet()
149
     * @param ResourceSet|null $resourceSet
150
     * @param null|KeyDescriptor $keyDescriptor
151
     */
152
    protected function getResource(
153
        $resourceSet,
154
        $keyDescriptor,
155
        array $whereCondition = [],
156
        $sourceEntityInstance = null
157
    ) {
158
        if ($resourceSet == null && $sourceEntityInstance == null) {
159
            throw new \Exception('Must supply at least one of a resource set and source entity');
160
        }
161
        if ($sourceEntityInstance == null) {
162
            $entityClassName = $resourceSet->getResourceType()->getInstanceType()->name;
0 ignored issues
show
Bug introduced by
It seems like $resourceSet is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
163
            $sourceEntityInstance = new $entityClassName();
164
        }
165
        if ($keyDescriptor) {
166
            foreach ($keyDescriptor->getValidatedNamedValues() as $key => $value) {
167
                $sourceEntityInstance = $sourceEntityInstance->where($key, $value[0]);
168
            }
169
        }
170
        foreach ($whereCondition as $fieldName => $fieldValue) {
171
            $sourceEntityInstance = $sourceEntityInstance->where($fieldName, $fieldValue);
172
        }
173
        $sourceEntityInstance = $sourceEntityInstance->get();
174
        if (0 == $sourceEntityInstance->count()) {
175
            return null;
176
        }
177
        return $sourceEntityInstance->first();
178
    }
179
180
    /**
181
     * Get related resource set for a resource
182
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection
183
     * http://host/EntitySet?$expand=NavigationPropertyToCollection
184
     *
185
     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
186
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
187
     * @param object $sourceEntityInstance The source entity instance.
188
     * @param ResourceSet $targetResourceSet The resource set of containing the target of the navigation property
189
     * @param ResourceProperty $targetProperty The navigation property to retrieve
190
     * @param FilterInfo $filter represents the $filter parameter of the OData query.  NULL if no $filter specified
191
     * @param mixed $orderBy sorted order if we want to get the data in some specific order
192
     * @param int $top number of records which  need to be skip
193
     * @param String $skip value indicating what records to skip
194
     *
195
     * @return QueryResult
196
     *
197
     */
198 3
    public function getRelatedResourceSet(
199
        QueryType $queryType,
200
        ResourceSet $sourceResourceSet,
201
        $sourceEntityInstance,
202
        ResourceSet $targetResourceSet,
203
        ResourceProperty $targetProperty,
204
        $filter = null,
205
        $orderBy = null,
206
        $top = null,
207
        $skip = null
208
    ) {
209 3
        $propertyName = $targetProperty->getName();
210 3
        $results = $sourceEntityInstance->$propertyName();
211
212 3
        return $this->getResourceSet(
213 3
            $queryType,
214 3
            $sourceResourceSet,
215 3
            $filter,
216 3
            $orderBy,
217 3
            $top,
218 3
            $skip,
219
            $results
220 3
        );
221
222
    }
223
224
    /**
225
     * Gets a related entity instance from an entity set identified by a key
226
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection(33)
227
     *
228
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
229
     * @param object $sourceEntityInstance The source entity instance.
230
     * @param ResourceSet $targetResourceSet The entity set containing the entity to fetch
231
     * @param ResourceProperty $targetProperty The metadata of the target property.
232
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
233
     *
234
     * @return object|null Returns entity instance if found else null
235
     */
236
    public function getResourceFromRelatedResourceSet(
237
        ResourceSet $sourceResourceSet,
238
        $sourceEntityInstance,
239
        ResourceSet $targetResourceSet,
240
        ResourceProperty $targetProperty,
241
        KeyDescriptor $keyDescriptor
242
    ) {
243
        $propertyName = $targetProperty->getName();
244
        return $this->getResource(null, $keyDescriptor, [], $sourceEntityInstance->$propertyName);
245
    }
246
247
    /**
248
     * Get related resource for a resource
249
     * IE: http://host/EntitySet(1L)/NavigationPropertyToSingleEntity
250
     * http://host/EntitySet?$expand=NavigationPropertyToSingleEntity
251
     *
252
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
253
     * @param object $sourceEntityInstance The source entity instance.
254
     * @param ResourceSet $targetResourceSet The entity set containing the entity pointed to by the navigation property
255
     * @param ResourceProperty $targetProperty The navigation property to fetch
256
     *
257
     * @return object|null The related resource if found else null
258
     */
259
    public function getRelatedResourceReference(
260
        ResourceSet $sourceResourceSet,
261
        $sourceEntityInstance,
262
        ResourceSet $targetResourceSet,
263
        ResourceProperty $targetProperty
264
    ) {
265
        $propertyName = $targetProperty->getName();
266
        return $sourceEntityInstance->$propertyName;
267
    }
268
269
    /**
270
     * @param ResourceSet $resourceSet
271
     * @return mixed
272
     */
273
    protected function getSourceEntityInstance(ResourceSet $resourceSet)
274
    {
275
        $entityClassName = $resourceSet->getResourceType()->getInstanceType()->name;
276
        $sourceEntityInstance = new $entityClassName();
277
        return $sourceEntityInstance = $sourceEntityInstance->newQuery();
0 ignored issues
show
Unused Code introduced by
$sourceEntityInstance is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
278
    }
279
    
280
    /**
281
     * Updates a resource 
282
     *
283
     * @param ResourceSet      $sourceResourceSet    The entity set containing the source entity
284
     * @param object           $sourceEntityInstance The source entity instance
285
     * @param KeyDescriptor    $keyDescriptor        The key identifying the entity to fetch
286
     * @param object           $data                 The New data for the entity instance.
287
     * @param bool             $shouldUpdate        Should undefined values be updated or reset to default
288
     *
289
     * @return object|null The new resource value if it is assignable or throw exception for null.
290
     */
291
    public function updateResource(
292
        ResourceSet $sourceResourceSet,
293
        $sourceEntityInstance,
294
        KeyDescriptor $keyDescriptor,
295
        $data,
296
        $shouldUpdate = false
297
    ) {
298
        throw new \POData\Common\NotImplementedException();
299
    }
300
    /**
301
     * Delete resource from a resource set.
302
     * @param ResourceSet|null $resourceSet
0 ignored issues
show
Documentation introduced by
There is no parameter named $resourceSet. Did you maybe mean $sourceResourceSet?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
303
     * @param object           $sourceEntityInstance
304
     *
305
     * return bool true if resources sucessfully deteled, otherwise false.
306
     */
307
    public function deleteResource(
308
        ResourceSet $sourceResourceSet,
309
        $sourceEntityInstance
310
    ) {
311
        throw new \POData\Common\NotImplementedException();
312
    }
313
    /**
314
     * @param ResourceSet      $resourceSet   The entity set containing the entity to fetch
315
     * @param object           $sourceEntityInstance The source entity instance
316
     * @param object           $data                 The New data for the entity instance.
317
     *
318
     * returns object|null returns the newly created model if sucessful or null if model creation failed.
319
     */
320
    public function createResourceforResourceSet(
321
        ResourceSet $resourceSet,
322
        $sourceEntityInstance,
323
        $data
324
    ) {
325
        throw new \POData\Common\NotImplementedException();
326
    }
327
}
328