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

LaravelReadQuery::getRelatedResourceReference()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 2
nop 4
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,
1 ignored issue
show
Unused Code introduced by
The parameter $targetResourceSet is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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,
1 ignored issue
show
Unused Code introduced by
The parameter $sourceResourceSet is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
209
        $sourceEntityInstance,
210
        ResourceSet $targetResourceSet,
1 ignored issue
show
Unused Code introduced by
The parameter $targetResourceSet is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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,
1 ignored issue
show
Unused Code introduced by
The parameter $sourceResourceSet is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
234
        $sourceEntityInstance,
235
        ResourceSet $targetResourceSet,
1 ignored issue
show
Unused Code introduced by
The parameter $targetResourceSet is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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