Total Complexity | 44 |
Total Lines | 188 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like Pagination often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Pagination, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
24 | final class Pagination |
||
25 | { |
||
26 | private $options; |
||
27 | private $resourceMetadataFactory; |
||
28 | |||
29 | public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, array $options = []) |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * Gets the current page. |
||
50 | * |
||
51 | * @throws InvalidArgumentException |
||
52 | */ |
||
53 | public function getPage(array $context = []): int |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * Gets the current offset. |
||
70 | */ |
||
71 | public function getOffset(string $resourceClass = null, string $operationName = null, array $context = []): int |
||
72 | { |
||
73 | $graphql = $context['graphql'] ?? false; |
||
74 | |||
75 | $limit = $this->getLimit($resourceClass, $operationName, $context); |
||
76 | |||
77 | if ($graphql && null !== ($after = $this->getParameterFromContext($context, 'after'))) { |
||
78 | return false === ($after = base64_decode($after, true)) ? 0 : (int) $after + 1; // break for UUID? |
||
|
|||
79 | } |
||
80 | |||
81 | if ($graphql && null !== ($before = $this->getParameterFromContext($context, 'before'))) { |
||
82 | return ($offset = (false === ($before = base64_decode($before, true)) ? 0 : (int) $before - $limit)) < 0 ? 0 : $offset; // break for UUID? |
||
83 | } |
||
84 | |||
85 | if ($graphql && null !== ($last = $this->getParameterFromContext($context, 'last'))) { |
||
86 | return ($offset = ($context['count'] ?? 0) - $last) < 0 ? 0 : $offset; |
||
87 | } |
||
88 | |||
89 | return ($this->getPage($context) - 1) * $limit; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Gets the current limit. |
||
94 | * |
||
95 | * @throws InvalidArgumentException |
||
96 | */ |
||
97 | public function getLimit(string $resourceClass = null, string $operationName = null, array $context = []): int |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Gets info about the pagination. |
||
146 | * |
||
147 | * Returns an array with the following info as values: |
||
148 | * - the page {@see Pagination::getPage()} |
||
149 | * - the offset {@see Pagination::getOffset()} |
||
150 | * - the limit {@see Pagination::getLimit()} |
||
151 | * |
||
152 | * @throws InvalidArgumentException |
||
153 | */ |
||
154 | public function getPagination(string $resourceClass = null, string $operationName = null, array $context = []): array |
||
155 | { |
||
156 | $page = $this->getPage($context); |
||
157 | $limit = $this->getLimit($resourceClass, $operationName, $context); |
||
158 | |||
159 | if (0 === $limit && 1 < $page) { |
||
160 | throw new InvalidArgumentException('Page should not be greater than 1 if limit is equal to 0'); |
||
161 | } |
||
162 | |||
163 | return [$page, $this->getOffset($resourceClass, $operationName, $context), $limit]; |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * Is the pagination enabled? |
||
168 | */ |
||
169 | public function isEnabled(string $resourceClass = null, string $operationName = null, array $context = []): bool |
||
170 | { |
||
171 | return $this->getEnabled($context, $resourceClass, $operationName); |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * Is the partial pagination enabled? |
||
176 | */ |
||
177 | public function isPartialEnabled(string $resourceClass = null, string $operationName = null, array $context = []): bool |
||
178 | { |
||
179 | return $this->getEnabled($context, $resourceClass, $operationName, true); |
||
180 | } |
||
181 | |||
182 | /** |
||
183 | * Is the classic or partial pagination enabled? |
||
184 | */ |
||
185 | private function getEnabled(array $context, string $resourceClass = null, string $operationName = null, bool $partial = false): bool |
||
186 | { |
||
187 | $enabled = $this->options[$partial ? 'partial' : 'enabled']; |
||
188 | $clientEnabled = $this->options[$partial ? 'client_partial' : 'client_enabled']; |
||
189 | |||
190 | if (null !== $resourceClass) { |
||
191 | $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); |
||
192 | $enabled = $resourceMetadata->getCollectionOperationAttribute($operationName, $partial ? 'pagination_partial' : 'pagination_enabled', $enabled, true); |
||
193 | |||
194 | $clientEnabled = $resourceMetadata->getCollectionOperationAttribute($operationName, $partial ? 'pagination_client_partial' : 'pagination_client_enabled', $clientEnabled, true); |
||
195 | } |
||
196 | |||
197 | if ($clientEnabled) { |
||
198 | return filter_var($this->getParameterFromContext($context, $this->options[$partial ? 'partial_parameter_name' : 'enabled_parameter_name'], $enabled), FILTER_VALIDATE_BOOLEAN); |
||
199 | } |
||
200 | |||
201 | return $enabled; |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Gets the given pagination parameter name from the given context. |
||
206 | */ |
||
207 | private function getParameterFromContext(array $context, string $parameterName, $default = null) |
||
212 | } |
||
213 | } |
||
214 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.