Completed
Pull Request — master (#11)
by Alex
07:24 queued 02:44
created

LaravelQuery   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 309
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 10

Test Coverage

Coverage 43.14%

Importance

Changes 0
Metric Value
wmc 38
c 0
b 0
f 0
lcom 0
cbo 10
dl 0
loc 309
ccs 44
cts 102
cp 0.4314
rs 8.3999

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A handlesOrderedPaging() 0 4 1
A getExpressionProvider() 0 4 1
C getResourceSet() 0 61 18
A getResourceFromResourceSet() 0 6 1
C getResource() 0 27 8
B getRelatedResourceSet() 0 25 1
A getResourceFromRelatedResourceSet() 0 10 1
A getRelatedResourceReference() 0 9 1
A getSourceEntityInstance() 0 6 1
A updateResource() 0 9 1
A deleteResource() 0 6 1
A createResourceforResourceSet() 0 7 1
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