Conditions | 34 |
Paths | > 20000 |
Total Lines | 164 |
Code Lines | 108 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
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 |
||
50 | public function getResourceSet( |
||
51 | QueryType $queryType, |
||
52 | ResourceSet $resourceSet, |
||
53 | $filterInfo = null, |
||
54 | $orderBy = null, |
||
55 | $top = null, |
||
56 | $skip = null, |
||
57 | $skipToken = null, |
||
58 | $sourceEntityInstance = null |
||
59 | ) { |
||
60 | if (null != $filterInfo && !($filterInfo instanceof FilterInfo)) { |
||
61 | throw new InvalidArgumentException('Filter info must be either null or instance of FilterInfo.'); |
||
62 | } |
||
63 | if (null != $skipToken && !($skipToken instanceof SkipTokenInfo)) { |
||
64 | throw new InvalidArgumentException('Skip token must be either null or instance of SkipTokenInfo.'); |
||
65 | } |
||
66 | |||
67 | $eagerLoad = []; |
||
68 | |||
69 | $this->checkSourceInstance($sourceEntityInstance); |
||
70 | if (null == $sourceEntityInstance) { |
||
71 | $sourceEntityInstance = $this->getSourceEntityInstance($resourceSet); |
||
72 | } |
||
73 | |||
74 | $keyName = null; |
||
75 | if ($sourceEntityInstance instanceof Model) { |
||
76 | $eagerLoad = $sourceEntityInstance->getEagerLoad(); |
||
77 | $keyName = $sourceEntityInstance->getKeyName(); |
||
78 | } elseif ($sourceEntityInstance instanceof Relation) { |
||
79 | $eagerLoad = $sourceEntityInstance->getRelated()->getEagerLoad(); |
||
80 | $keyName = $sourceEntityInstance->getRelated()->getKeyName(); |
||
81 | } |
||
82 | assert(isset($keyName)); |
||
83 | |||
84 | $checkInstance = $sourceEntityInstance instanceof Model ? $sourceEntityInstance : null; |
||
85 | $this->checkAuth($sourceEntityInstance, $checkInstance); |
||
86 | |||
87 | $result = new QueryResult(); |
||
88 | $result->results = null; |
||
89 | $result->count = null; |
||
90 | |||
91 | if (null != $orderBy) { |
||
92 | foreach ($orderBy->getOrderByInfo()->getOrderByPathSegments() as $order) { |
||
93 | foreach ($order->getSubPathSegments() as $subOrder) { |
||
94 | $subName = $subOrder->getName(); |
||
95 | $subName = (self::PK == $subName) ? $sourceEntityInstance->getKeyName() : $subName; |
||
96 | $sourceEntityInstance = $sourceEntityInstance->orderBy( |
||
97 | $subName, |
||
98 | $order->isAscending() ? 'asc' : 'desc' |
||
99 | ); |
||
100 | } |
||
101 | } |
||
102 | } |
||
103 | |||
104 | // throttle up for trench run |
||
105 | if (null != $skipToken) { |
||
106 | $parameters = []; |
||
107 | $processed = []; |
||
108 | $segments = $skipToken->getOrderByInfo()->getOrderByPathSegments(); |
||
109 | $values = $skipToken->getOrderByKeysInToken(); |
||
110 | $numValues = count($values); |
||
111 | assert($numValues == count($segments)); |
||
112 | |||
113 | for ($i = 0; $i < $numValues; $i++) { |
||
114 | $relation = $segments[$i]->isAscending() ? '>' : '<'; |
||
115 | $name = $segments[$i]->getSubPathSegments()[0]->getName(); |
||
116 | $parameters[$name] = ['direction' => $relation, 'value' => trim($values[$i][0], '\'')]; |
||
117 | } |
||
118 | |||
119 | foreach ($parameters as $name => $line) { |
||
120 | $processed[$name] = ['direction' => $line['direction'], 'value' => $line['value']]; |
||
121 | $sourceEntityInstance = $sourceEntityInstance |
||
122 | ->orWhere(function ($query) use ($processed) { |
||
123 | foreach ($processed as $key => $proc) { |
||
124 | $query->where($key, $proc['direction'], $proc['value']); |
||
125 | } |
||
126 | }); |
||
127 | // now we've handled the later-in-order segment for this key, drop it back to equality in prep |
||
128 | // for next key - same-in-order for processed keys and later-in-order for next |
||
129 | $processed[$name]['direction'] = '='; |
||
130 | } |
||
131 | } |
||
132 | |||
133 | if (!isset($skip)) { |
||
134 | $skip = 0; |
||
135 | } |
||
136 | if (!isset($top)) { |
||
137 | $top = PHP_INT_MAX; |
||
138 | } |
||
139 | |||
140 | $nullFilter = true; |
||
141 | $isvalid = null; |
||
142 | if (isset($filterInfo)) { |
||
143 | $method = 'return '.$filterInfo->getExpressionAsString().';'; |
||
144 | $clln = '$'.$resourceSet->getResourceType()->getName(); |
||
145 | $isvalid = create_function($clln, $method); |
||
|
|||
146 | $nullFilter = false; |
||
147 | } |
||
148 | |||
149 | $bulkSetCount = $sourceEntityInstance->count(); |
||
150 | $bigSet = 20000 < $bulkSetCount; |
||
151 | |||
152 | if ($nullFilter) { |
||
153 | // default no-filter case, palm processing off to database engine - is a lot faster |
||
154 | $resultSet = $sourceEntityInstance->skip($skip)->take($top)->with($eagerLoad)->get(); |
||
155 | $resultCount = $bulkSetCount; |
||
156 | } elseif ($bigSet) { |
||
157 | assert(isset($isvalid), 'Filter closure not set'); |
||
158 | $resultSet = collect([]); |
||
159 | $rawCount = 0; |
||
160 | $rawTop = null === $top ? $bulkSetCount : $top; |
||
161 | |||
162 | // loop thru, chunk by chunk, to reduce chances of exhausting memory |
||
163 | $sourceEntityInstance->chunk( |
||
164 | 5000, |
||
165 | function ($results) use ($isvalid, &$skip, &$resultSet, &$rawCount, $rawTop) { |
||
166 | // apply filter |
||
167 | $results = $results->filter($isvalid); |
||
168 | // need to iterate through full result set to find count of items matching filter, |
||
169 | // so we can't bail out early |
||
170 | $rawCount += $results->count(); |
||
171 | // now bolt on filtrate to accumulating result set if we haven't accumulated enough bitz |
||
172 | if ($rawTop > $resultSet->count() + $skip) { |
||
173 | $resultSet = collect(array_merge($resultSet->all(), $results->all())); |
||
174 | $sliceAmount = min($skip, $resultSet->count()); |
||
175 | $resultSet = $resultSet->slice($sliceAmount); |
||
176 | $skip -= $sliceAmount; |
||
177 | } |
||
178 | } |
||
179 | ); |
||
180 | |||
181 | // clean up residual to-be-skipped records |
||
182 | $resultSet = $resultSet->slice($skip); |
||
183 | $resultCount = $rawCount; |
||
184 | } else { |
||
185 | if ($sourceEntityInstance instanceof Model) { |
||
186 | $sourceEntityInstance = $sourceEntityInstance->getQuery(); |
||
187 | } |
||
188 | $resultSet = $sourceEntityInstance->with($eagerLoad)->get(); |
||
189 | $resultSet = $resultSet->filter($isvalid); |
||
190 | $resultCount = $resultSet->count(); |
||
191 | |||
192 | if (isset($skip)) { |
||
193 | $resultSet = $resultSet->slice($skip); |
||
194 | } |
||
195 | } |
||
196 | |||
197 | if (isset($top)) { |
||
198 | $resultSet = $resultSet->take($top); |
||
199 | } |
||
200 | |||
201 | if (QueryType::ENTITIES() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) { |
||
202 | $result->results = []; |
||
203 | foreach ($resultSet as $res) { |
||
204 | $result->results[] = $res; |
||
205 | } |
||
206 | } |
||
207 | if (QueryType::COUNT() == $queryType || QueryType::ENTITIES_WITH_COUNT() == $queryType) { |
||
208 | $result->count = $resultCount; |
||
209 | } |
||
210 | $hazMore = $bulkSetCount > $skip + count($resultSet); |
||
211 | $result->hasMore = $hazMore; |
||
212 | return $result; |
||
213 | } |
||
214 | |||
442 |
create_function
can pose a great security vulnerability as it is similar toeval
, and could be used for arbitrary code execution. We highly recommend to use a closure instead.