Completed
Push — master ( 2077d1...b6c184 )
by Christopher
03:32
created

LaravelQuery   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 301
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 9

Test Coverage

Coverage 42.57%

Importance

Changes 0
Metric Value
wmc 37
lcom 0
cbo 9
dl 0
loc 301
ccs 43
cts 101
cp 0.4257
rs 8.6
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A handlesOrderedPaging() 0 4 1
A getExpressionProvider() 0 4 1
A __construct() 0 6 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 3 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 Illuminate\Support\Facades\DB;
16
17
class LaravelQuery implements IQueryProvider
18
{
19
    protected $expression;
20
    public $queryProviderClassName;
21
22 2
    public function __construct()
23
    {
24
        /* MySQLExpressionProvider();*/
25 2
        $this->expression = new LaravelExpressionProvider(); //PHPExpressionProvider('expression');
26 2
        $this->queryProviderClassName = get_class($this);
27 2
    }
28
29
    /**
30
     * Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters
31
     * If the query provider can not handle ordered paging, it must return the entire result set and POData will
32
     * perform the ordering and paging
33
     *
34
     * @return Boolean True if the query provider can handle ordered paging, false if POData should perform the paging
35
     */
36
    public function handlesOrderedPaging()
37
    {
38
        return true;
39
    }
40
41
    /**
42
     * Gets the expression provider used by to compile OData expressions into expression used by this query provider.
43
     *
44
     * @return \POData\Providers\Expression\IExpressionProvider
45
     */
46
    public function getExpressionProvider()
47
    {
48
        return $this->expression;
49
    }
50
51
    /**
52
     * Gets collection of entities belongs to an entity set
53
     * IE: http://host/EntitySet
54
     *  http://host/EntitySet?$skip=10&$top=5&filter=Prop gt Value
55
     *
56
     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
57
     * @param ResourceSet $resourceSet The entity set containing the entities to fetch
58
     * @param FilterInfo $filterInfo represents the $filter parameter of the OData query.  NULL if no $filter specified
59
     * @param mixed $orderBy sorted order if we want to get the data in some specific order
60
     * @param int $top number of records which  need to be skip
61
     * @param String $skipToken value indicating what records to skip
62
     *
63
     * @return QueryResult
64
     */
65 3
    public function getResourceSet(
66
        QueryType $queryType,
67
        ResourceSet $resourceSet,
68
        $filterInfo = null,
69
        $orderBy = null,
70
        $top = null,
71
        $skipToken = null,
72
        $sourceEntityInstance = null
73
    ) {
74 3
        if ($resourceSet == null && $sourceEntityInstance == null) {
75
            throw new \Exception('Must supply at least one of a resource set and source entity');
76
        }
77 3
        if ($sourceEntityInstance == null) {
78 1
            $sourceEntityInstance = $this->getSourceEntityInstance($resourceSet);
79 1
        }
80
81 3
        $result          = new QueryResult();
82 3
        $result->results = null;
83 3
        $result->count   = null;
84
85 3
        if (isset($orderBy) && null != $orderBy) {
86
            foreach ($orderBy->getOrderByInfo()->getOrderByPathSegments() as $order) {
87
                foreach ($order->getSubPathSegments() as $subOrder) {
88
                    $sourceEntityInstance = $sourceEntityInstance->orderBy(
89
                        $subOrder->getName(),
90
                        $order->isAscending() ? 'asc' : 'desc'
91
                    );
92
                }
93
            }
94
        }
95 3
        if (isset($skipToken)) {
96 1
            $sourceEntityInstance = $sourceEntityInstance->skip($skipToken);
97 1
        }
98 3
        if (isset($top)) {
99 1
            $sourceEntityInstance = $sourceEntityInstance->take($top);
100 1
        }
101
102 3
        $resultSet = $sourceEntityInstance->get();
103
104 3
        if (isset($filterInfo)) {
105
            $method = "return ".$filterInfo->getExpressionAsString().";";
106
            $clln = "$".$resourceSet->getResourceType()->getName();
107
            $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...
108
            $resultSet = $resultSet->filter($isvalid);
109
        }
110
111
112 3
        if (QueryType::ENTITIES() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) {
113 1
            $result->results = array();
114 1
            foreach ($resultSet as $res) {
115 1
                $result->results[] = $res;
116 1
            }
117 1
        }
118 3
        if (QueryType::COUNT() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) {
119 3
            if (is_array($resultSet)) {
120
                $resultSet = collect($resultSet);
121
            }
122 3
            $result->count = $resultSet->count();
123 3
        }
124 3
        return $result;
125
    }
126
    /**
127
     * Gets an entity instance from an entity set identified by a key
128
     * IE: http://host/EntitySet(1L)
129
     * http://host/EntitySet(KeyA=2L,KeyB='someValue')
130
     *
131
     * @param ResourceSet $resourceSet The entity set containing the entity to fetch
132
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
133
     *
134
     * @return object|null Returns entity instance if found else null
135
     */
136
    public function getResourceFromResourceSet(
137
        ResourceSet $resourceSet,
138
        KeyDescriptor $keyDescriptor = null
139
    ) {
140
        return $this->getResource($resourceSet, $keyDescriptor);
141
    }
142
143
    /**
144
     * Common method for getResourceFromRelatedResourceSet() and getResourceFromResourceSet()
145
     * @param ResourceSet|null $resourceSet
146
     * @param null|KeyDescriptor $keyDescriptor
147
     */
148
    protected function getResource(
149
        $resourceSet,
150
        $keyDescriptor,
151
        array $whereCondition = [],
152
        $sourceEntityInstance = null
153
    ) {
154
        if ($resourceSet == null && $sourceEntityInstance == null) {
155
            throw new \Exception('Must supply at least one of a resource set and source entity');
156
        }
157
        if ($sourceEntityInstance == null) {
158
            $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...
159
            $sourceEntityInstance = new $entityClassName();
160
        }
161
        if ($keyDescriptor) {
162
            foreach ($keyDescriptor->getValidatedNamedValues() as $key => $value) {
163
                $sourceEntityInstance = $sourceEntityInstance->where($key, $value[0]);
164
            }
165
        }
166
        foreach ($whereCondition as $fieldName => $fieldValue) {
167
            $sourceEntityInstance = $sourceEntityInstance->where($fieldName, $fieldValue);
168
        }
169
        $sourceEntityInstance = $sourceEntityInstance->get();
170
        if (0 == $sourceEntityInstance->count()) {
171
            return null;
172
        }
173
        return $sourceEntityInstance->first();
174
    }
175
176
    /**
177
     * Get related resource set for a resource
178
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection
179
     * http://host/EntitySet?$expand=NavigationPropertyToCollection
180
     *
181
     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
182
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
183
     * @param object $sourceEntityInstance The source entity instance.
184
     * @param ResourceSet $targetResourceSet The resource set of containing the target of the navigation property
185
     * @param ResourceProperty $targetProperty The navigation property to retrieve
186
     * @param FilterInfo $filter represents the $filter parameter of the OData query.  NULL if no $filter specified
187
     * @param mixed $orderBy sorted order if we want to get the data in some specific order
188
     * @param int $top number of records which  need to be skip
189
     * @param String $skip value indicating what records to skip
190
     *
191
     * @return QueryResult
192
     *
193
     */
194 3
    public function getRelatedResourceSet(
195
        QueryType $queryType,
196
        ResourceSet $sourceResourceSet,
197
        $sourceEntityInstance,
198
        ResourceSet $targetResourceSet,
199
        ResourceProperty $targetProperty,
200
        $filter = null,
201
        $orderBy = null,
202
        $top = null,
203
        $skip = null
204
    ) {
205 3
        $propertyName = $targetProperty->getName();
206 3
        $results = $sourceEntityInstance->$propertyName();
207
208 3
        return $this->getResourceSet(
209 3
            $queryType,
210 3
            $sourceResourceSet,
211 3
            $filter,
212 3
            $orderBy,
213 3
            $top,
214 3
            $skip,
215
            $results
216 3
        );
217
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
        $propertyName = $targetProperty->getName();
240
        return $this->getResource(null, $keyDescriptor, [], $sourceEntityInstance->$propertyName);
241
    }
242
243
    /**
244
     * Get related resource for a resource
245
     * IE: http://host/EntitySet(1L)/NavigationPropertyToSingleEntity
246
     * http://host/EntitySet?$expand=NavigationPropertyToSingleEntity
247
     *
248
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
249
     * @param object $sourceEntityInstance The source entity instance.
250
     * @param ResourceSet $targetResourceSet The entity set containing the entity pointed to by the navigation property
251
     * @param ResourceProperty $targetProperty The navigation property to fetch
252
     *
253
     * @return object|null The related resource if found else null
254
     */
255
    public function getRelatedResourceReference(
256
        ResourceSet $sourceResourceSet,
257
        $sourceEntityInstance,
258
        ResourceSet $targetResourceSet,
259
        ResourceProperty $targetProperty
260
    ) {
261
        $propertyName = $targetProperty->getName();
262
        return $sourceEntityInstance->$propertyName;
263
    }
264
265
    /**
266
     * @param ResourceSet $resourceSet
267
     * @return mixed
268
     */
269
    protected function getSourceEntityInstance(ResourceSet $resourceSet)
270
    {
271
        $entityClassName = $resourceSet->getResourceType()->getInstanceType()->name;
272
        $sourceEntityInstance = new $entityClassName();
273
        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...
274
    }
275
    
276
    /**
277
     * Updates a resource 
278
     *
279
     * @param ResourceSet      $sourceResourceSet    The entity set containing the source entity
280
     * @param object           $sourceEntityInstance The source entity instance
281
     * @param KeyDescriptor    $keyDescriptor        The key identifying the entity to fetch
282
     * @param object           $data                 The New data for the entity instance.
283
     * @param bool             $shouldUpdate        Should undefined values be updated or reset to default
284
     *
285
     * @return object|null The new resource value if it is assignable or throw exception for null.
286
     */
287
    public function updateResource(ResourceSet $sourceResourceSet,$sourceEntityInstance, KeyDescriptor $keyDescriptor,$data, $shouldUpdate = false){
288
        throw new \POData\Common\NotImplementedException();
289
    }
290
    /**
291
     * Delete resource from a resource set.
292
     * @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...
293
     * @param object           $sourceEntityInstance
294
     *
295
     * return bool true if resources sucessfully deteled, otherwise false.
296
     */
297
    public function deleteResource(
298
        ResourceSet $sourceResourceSet,
299
        $sourceEntityInstance
300
    ){
301
        throw new \POData\Common\NotImplementedException();
302
    }
303
    /**
304
     * @param ResourceSet      $resourceSet   The entity set containing the entity to fetch
305
     * @param object           $sourceEntityInstance The source entity instance
306
     * @param object           $data                 The New data for the entity instance.
307
     * 
308
     * returns object|null returns the newly created model if sucessful or null if model creation failed.
309
     */
310
    public function createResourceforResourceSet(
311
        ResourceSet $resourceSet,
312
        $sourceEntityInstance,
313
        $data
314
    ){
315
        throw new \POData\Common\NotImplementedException();
316
    }
317
}
318