Completed
Pull Request — master (#8)
by Alex
03:06 queued 10s
created

LaravelQuery::getSourceEntityInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 4
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
crap 2
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
        $table = DB::table('dummy');
26 2
        $this->expression = new LaravelExpressionProvider($table); //PHPExpressionProvider('expression');
0 ignored issues
show
Unused Code introduced by
The call to LaravelExpressionProvider::__construct() has too many arguments starting with $table.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
27 2
        $this->queryProviderClassName = get_class($this);
28 2
    }
29
30
    /**
31
     * Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters
32
     * If the query provider can not handle ordered paging, it must return the entire result set and POData will
33
     * perform the ordering and paging
34
     *
35
     * @return Boolean True if the query provider can handle ordered paging, false if POData should perform the paging
36
     */
37
    public function handlesOrderedPaging()
38
    {
39
        return true;
40
    }
41
42
    /**
43
     * Gets the expression provider used by to compile OData expressions into expression used by this query provider.
44
     *
45
     * @return \POData\Providers\Expression\IExpressionProvider
46
     */
47
    public function getExpressionProvider()
48
    {
49
        return $this->expression;
50
    }
51
52
    /**
53
     * Gets collection of entities belongs to an entity set
54
     * IE: http://host/EntitySet
55
     *  http://host/EntitySet?$skip=10&$top=5&filter=Prop gt Value
56
     *
57
     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
58
     * @param ResourceSet $resourceSet The entity set containing the entities to fetch
59
     * @param FilterInfo $filterInfo represents the $filter parameter of the OData query.  NULL if no $filter specified
60
     * @param mixed $orderBy sorted order if we want to get the data in some specific order
61
     * @param int $top number of records which  need to be skip
62
     * @param String $skipToken value indicating what records to skip
63
     *
64
     * @return QueryResult
65
     */
66 3
    public function getResourceSet(
67
        QueryType $queryType,
68
        ResourceSet $resourceSet,
69
        $filterInfo = null,
70
        $orderBy = null,
71
        $top = null,
72
        $skipToken = null,
73
        $sourceEntityInstance = null
74
    ) {
75 3
        if ($resourceSet == null && $sourceEntityInstance == null) {
76
            throw new \Exception('Must supply at least one of a resource set and source entity');
77
        }
78 3
        if ($sourceEntityInstance == null) {
79 1
            $sourceEntityInstance = $this->getSourceEntityInstance($resourceSet);
80 1
        }
81
82 3
        $result          = new QueryResult();
83 3
        $result->results = null;
84 3
        $result->count   = null;
85
86 3
        if (isset($orderBy) && null != $orderBy) {
87
            foreach ($orderBy->getOrderByInfo()->getOrderByPathSegments() as $order) {
88
                foreach ($order->getSubPathSegments() as $subOrder) {
89
                    $sourceEntityInstance = $sourceEntityInstance->orderBy(
90
                        $subOrder->getName(),
91
                        $order->isAscending() ? 'asc' : 'desc'
92
                    );
93
                }
94
            }
95
        }
96 3
        if (isset($skipToken)) {
97 1
            $sourceEntityInstance = $sourceEntityInstance->skip($skipToken);
98 1
        }
99 3
        if (isset($top)) {
100 1
            $sourceEntityInstance = $sourceEntityInstance->take($top);
101 1
        }
102
103 3
        $resultSet = $sourceEntityInstance->get();
104
105 3
        if (isset($filterInfo)) {
106
            $method = "return ".$filterInfo->getExpressionAsString().";";
107
            $clln = "$".$resourceSet->getResourceType()->getName();
108
            $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...
109
            $resultSet = $resultSet->filter($isvalid);
110
        }
111
112
113 3
        if (QueryType::ENTITIES() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) {
114 1
            $result->results = array();
115 1
            foreach ($resultSet as $res) {
116 1
                $result->results[] = $res;
117 1
            }
118 1
        }
119 3
        if (QueryType::COUNT() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) {
120 3
            if (is_array($resultSet)) {
121
                $resultSet = collect($resultSet);
122
            }
123 3
            $result->count = $resultSet->count();
124 3
        }
125 3
        return $result;
126
    }
127
    /**
128
     * Gets an entity instance from an entity set identified by a key
129
     * IE: http://host/EntitySet(1L)
130
     * http://host/EntitySet(KeyA=2L,KeyB='someValue')
131
     *
132
     * @param ResourceSet $resourceSet The entity set containing the entity to fetch
133
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
134
     *
135
     * @return object|null Returns entity instance if found else null
136
     */
137
    public function getResourceFromResourceSet(
138
        ResourceSet $resourceSet,
139
        KeyDescriptor $keyDescriptor = null
140
    ) {
141
        return $this->getResource($resourceSet, $keyDescriptor);
142
    }
143
144
    /**
145
     * Common method for getResourceFromRelatedResourceSet() and getResourceFromResourceSet()
146
     * @param ResourceSet|null $resourceSet
147
     * @param null|KeyDescriptor $keyDescriptor
148
     */
149
    protected function getResource(
150
        $resourceSet,
151
        $keyDescriptor,
152
        array $whereCondition = [],
153
        $sourceEntityInstance = null
154
    ) {
155
        if ($resourceSet == null && $sourceEntityInstance == null) {
156
            throw new \Exception('Must supply at least one of a resource set and source entity');
157
        }
158
        if ($sourceEntityInstance == null) {
159
            $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...
160
            $sourceEntityInstance = new $entityClassName();
161
        }
162
        if ($keyDescriptor) {
163
            foreach ($keyDescriptor->getValidatedNamedValues() as $key => $value) {
164
                $sourceEntityInstance = $sourceEntityInstance->where($key, $value[0]);
165
            }
166
        }
167
        foreach ($whereCondition as $fieldName => $fieldValue) {
168
            $sourceEntityInstance = $sourceEntityInstance->where($fieldName, $fieldValue);
169
        }
170
        $sourceEntityInstance = $sourceEntityInstance->get();
171
        if (0 == $sourceEntityInstance->count()) {
172
            return null;
173
        }
174
        return $sourceEntityInstance->first();
175
    }
176
177
    /**
178
     * Get related resource set for a resource
179
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection
180
     * http://host/EntitySet?$expand=NavigationPropertyToCollection
181
     *
182
     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
183
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
184
     * @param object $sourceEntityInstance The source entity instance.
185
     * @param ResourceSet $targetResourceSet The resource set of containing the target of the navigation property
186
     * @param ResourceProperty $targetProperty The navigation property to retrieve
187
     * @param FilterInfo $filter represents the $filter parameter of the OData query.  NULL if no $filter specified
188
     * @param mixed $orderBy sorted order if we want to get the data in some specific order
189
     * @param int $top number of records which  need to be skip
190
     * @param String $skip value indicating what records to skip
191
     *
192
     * @return QueryResult
193
     *
194
     */
195 3
    public function getRelatedResourceSet(
196
        QueryType $queryType,
197
        ResourceSet $sourceResourceSet,
198
        $sourceEntityInstance,
199
        ResourceSet $targetResourceSet,
200
        ResourceProperty $targetProperty,
201
        $filter = null,
202
        $orderBy = null,
203
        $top = null,
204
        $skip = null
205
    ) {
206 3
        $propertyName = $targetProperty->getName();
207 3
        $results = $sourceEntityInstance->$propertyName();
208
209 3
        return $this->getResourceSet(
210 3
            $queryType,
211 3
            $sourceResourceSet,
212 3
            $filter,
213 3
            $orderBy,
214 3
            $top,
215 3
            $skip,
216
            $results
217 3
        );
218
219
    }
220
221
    /**
222
     * Gets a related entity instance from an entity set identified by a key
223
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection(33)
224
     *
225
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
226
     * @param object $sourceEntityInstance The source entity instance.
227
     * @param ResourceSet $targetResourceSet The entity set containing the entity to fetch
228
     * @param ResourceProperty $targetProperty The metadata of the target property.
229
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
230
     *
231
     * @return object|null Returns entity instance if found else null
232
     */
233
    public function getResourceFromRelatedResourceSet(
234
        ResourceSet $sourceResourceSet,
235
        $sourceEntityInstance,
236
        ResourceSet $targetResourceSet,
237
        ResourceProperty $targetProperty,
238
        KeyDescriptor $keyDescriptor
239
    ) {
240
        $propertyName = $targetProperty->getName();
241
        return $this->getResource(null, $keyDescriptor, [], $sourceEntityInstance->$propertyName);
242
    }
243
244
    /**
245
     * Get related resource for a resource
246
     * IE: http://host/EntitySet(1L)/NavigationPropertyToSingleEntity
247
     * http://host/EntitySet?$expand=NavigationPropertyToSingleEntity
248
     *
249
     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
250
     * @param object $sourceEntityInstance The source entity instance.
251
     * @param ResourceSet $targetResourceSet The entity set containing the entity pointed to by the navigation property
252
     * @param ResourceProperty $targetProperty The navigation property to fetch
253
     *
254
     * @return object|null The related resource if found else null
255
     */
256
    public function getRelatedResourceReference(
257
        ResourceSet $sourceResourceSet,
258
        $sourceEntityInstance,
259
        ResourceSet $targetResourceSet,
260
        ResourceProperty $targetProperty
261
    ) {
262
        $propertyName = $targetProperty->getName();
263
        return $sourceEntityInstance->$propertyName;
264
    }
265
266
    /**
267
     * @param ResourceSet $resourceSet
268
     * @return mixed
269
     */
270
    protected function getSourceEntityInstance(ResourceSet $resourceSet)
271
    {
272
        $entityClassName = $resourceSet->getResourceType()->getInstanceType()->name;
273
        $sourceEntityInstance = new $entityClassName();
274
        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...
275
    }
276
}
277