Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php |
||
| 47 | class CursorPaginationProfile extends ProfileAliasManager implements ProfileInterface { |
||
| 48 | /** |
||
| 49 | * human api |
||
| 50 | */ |
||
| 51 | |||
| 52 | /** |
||
| 53 | * set links to paginate the data using cursors of the paginated data |
||
| 54 | * |
||
| 55 | * @param PaginableInterface $paginable a CollectionDocument or RelationshipObject |
||
| 56 | * @param string $baseOrCurrentUrl |
||
| 57 | * @param string $firstCursor |
||
| 58 | * @param string $lastCursor |
||
| 59 | */ |
||
| 60 | public function setLinks(PaginableInterface $paginable, $baseOrCurrentUrl, $firstCursor, $lastCursor) { |
||
| 66 | |||
| 67 | /** |
||
| 68 | * @param PaginableInterface $paginable a CollectionDocument or RelationshipObject |
||
| 69 | * @param string $baseOrCurrentUrl |
||
| 70 | * @param string $lastCursor |
||
| 71 | */ |
||
| 72 | public function setLinksFirstPage(PaginableInterface $paginable, $baseOrCurrentUrl, $lastCursor) { |
||
| 75 | |||
| 76 | /** |
||
| 77 | * @param PaginableInterface $paginable a CollectionDocument or RelationshipObject |
||
| 78 | * @param string $baseOrCurrentUrl |
||
| 79 | * @param string $firstCursor |
||
| 80 | */ |
||
| 81 | public function setLinksLastPage(PaginableInterface $paginable, $baseOrCurrentUrl, $firstCursor) { |
||
| 84 | |||
| 85 | /** |
||
| 86 | * set the cursor of a specific resource to allow pagination after or before this resource |
||
| 87 | * |
||
| 88 | * @param ResourceInterface $resource |
||
| 89 | * @param string $cursor |
||
| 90 | */ |
||
| 91 | public function setCursor(ResourceInterface $resource, $cursor) { |
||
| 94 | |||
| 95 | /** |
||
| 96 | * set count(s) to tell about the (estimated) total size |
||
| 97 | * |
||
| 98 | * @param PaginableInterface $paginable a CollectionDocument or RelationshipObject |
||
| 99 | * @param int $exactTotal optional |
||
| 100 | * @param int $bestGuessTotal optional |
||
| 101 | */ |
||
| 102 | public function setCount(PaginableInterface $paginable, $exactTotal=null, $bestGuessTotal=null) { |
||
| 105 | |||
| 106 | /** |
||
| 107 | * spec api |
||
| 108 | */ |
||
| 109 | |||
| 110 | /** |
||
| 111 | * helper to get generate a correct page[before] link, use to apply manually |
||
| 112 | * |
||
| 113 | * @param string $baseOrCurrentUrl |
||
| 114 | * @param string $beforeCursor |
||
| 115 | * @return string |
||
| 116 | */ |
||
| 117 | public function generatePreviousLink($baseOrCurrentUrl, $beforeCursor) { |
||
| 120 | |||
| 121 | /** |
||
| 122 | * helper to get generate a correct page[after] link, use to apply manually |
||
| 123 | * |
||
| 124 | * @param string $baseOrCurrentUrl |
||
| 125 | * @param string $afterCursor |
||
| 126 | * @return string |
||
| 127 | */ |
||
| 128 | public function generateNextLink($baseOrCurrentUrl, $afterCursor) { |
||
| 131 | |||
| 132 | /** |
||
| 133 | * pagination links are inside the links object that is a sibling of the paginated data |
||
| 134 | * |
||
| 135 | * ends up at one of: |
||
| 136 | * - /links/prev & /links/next |
||
| 137 | * - /data/relationships/foo/links/prev & /data/relationships/foo/links/next |
||
| 138 | * - /data/0/relationships/foo/links/prev & /data/0/relationships/foo/links/next |
||
| 139 | * |
||
| 140 | * @see https://jsonapi.org/profiles/ethanresnick/cursor-pagination/#terms-pagination-links |
||
| 141 | * |
||
| 142 | * @param PaginableInterface $paginable |
||
| 143 | * @param LinkObject $previousLinkObject |
||
| 144 | * @param LinkObject $nextLinkObject |
||
| 145 | */ |
||
| 146 | public function setPaginationLinkObjects(PaginableInterface $paginable, LinkObject $previousLinkObject, LinkObject $nextLinkObject) { |
||
| 150 | |||
| 151 | /** |
||
| 152 | * @param PaginableInterface $paginable |
||
| 153 | * @param string $baseOrCurrentUrl |
||
| 154 | * @param string $firstCursor |
||
| 155 | */ |
||
| 156 | public function setPaginationLinkObjectsWithoutNext(PaginableInterface $paginable, $baseOrCurrentUrl, $firstCursor) { |
||
| 159 | |||
| 160 | /** |
||
| 161 | * @param PaginableInterface $paginable |
||
| 162 | * @param string $baseOrCurrentUrl |
||
| 163 | * @param string $lastCursor |
||
| 164 | */ |
||
| 165 | public function setPaginationLinkObjectsWithoutPrevious(PaginableInterface $paginable, $baseOrCurrentUrl, $lastCursor) { |
||
| 168 | |||
| 169 | /** |
||
| 170 | * @param PaginableInterface $paginable |
||
| 171 | */ |
||
| 172 | public function setPaginationLinkObjectsExplicitlyEmpty(PaginableInterface $paginable) { |
||
| 175 | |||
| 176 | /** |
||
| 177 | * pagination item metadata is the page meta at the top-level of a paginated item |
||
| 178 | * |
||
| 179 | * ends up at one of: |
||
| 180 | * - /data/meta/page |
||
| 181 | * - /data/relationships/foo/meta/page |
||
| 182 | * - /data/0/relationships/foo/meta/page |
||
| 183 | * |
||
| 184 | * @see https://jsonapi.org/profiles/ethanresnick/cursor-pagination/#terms-pagination-item-metadata |
||
| 185 | * |
||
| 186 | * @param ResourceInterface $resource |
||
| 187 | * @param string $cursor |
||
| 188 | */ |
||
| 189 | public function setItemMeta(ResourceInterface $resource, $cursor) { |
||
| 201 | |||
| 202 | /** |
||
| 203 | * pagination metadata is the page meta that is a sibling of the paginated data (and pagination links) |
||
| 204 | * |
||
| 205 | * ends up at one of: |
||
| 206 | * - /meta/page/total & /meta/page/estimatedTotal/bestGuess & /meta/page/rangeTruncated |
||
| 207 | * - /data/relationships/foo/meta/page/total & /data/relationships/foo/meta/page/estimatedTotal/bestGuess & /data/relationships/foo/meta/page/rangeTruncated |
||
| 208 | * - /data/0/relationships/foo/meta/page/total & /data/0/relationships/foo/meta/page/estimatedTotal/bestGuess & /data/0/relationships/foo/meta/page/rangeTruncated |
||
| 209 | * |
||
| 210 | * @see https://jsonapi.org/profiles/ethanresnick/cursor-pagination/#terms-pagination-metadata |
||
| 211 | * |
||
| 212 | * @param PaginableInterface $paginable |
||
| 213 | * @param int $exactTotal optional |
||
| 214 | * @param int $bestGuessTotal optional |
||
| 215 | * @param boolean $rangeIsTruncated optional, if both after and before are supplied but the items exceed requested or max size |
||
| 216 | */ |
||
| 217 | public function setPaginationMeta(PaginableInterface $paginable, $exactTotal=null, $bestGuessTotal=null, $rangeIsTruncated=null) { |
||
| 234 | |||
| 235 | /** |
||
| 236 | * get an ErrorObject for when the requested sorting cannot efficiently be paginated |
||
| 237 | * |
||
| 238 | * ends up at: |
||
| 239 | * - /errors/0/code |
||
| 240 | * - /errors/0/status |
||
| 241 | * - /errors/0/source/parameter |
||
| 242 | * - /errors/0/links/type/0 |
||
| 243 | * - /errors/0/title optional |
||
| 244 | * - /errors/0/detail optional |
||
| 245 | * |
||
| 246 | * @param string $genericTitle optional |
||
| 247 | * @param string $specificDetails optional |
||
| 248 | * @return ErrorObject |
||
| 249 | */ |
||
| 250 | View Code Duplication | public function getUnsupportedSortErrorObject($genericTitle=null, $specificDetails=null) { |
|
| 262 | |||
| 263 | /** |
||
| 264 | * get an ErrorObject for when the requested page size exceeds the server-defined max page size |
||
| 265 | * |
||
| 266 | * ends up at: |
||
| 267 | * - /errors/0/code |
||
| 268 | * - /errors/0/status |
||
| 269 | * - /errors/0/source/parameter |
||
| 270 | * - /errors/0/links/type/0 |
||
| 271 | * - /errors/0/meta/page/maxSize |
||
| 272 | * - /errors/0/title optional |
||
| 273 | * - /errors/0/detail optional |
||
| 274 | * |
||
| 275 | * @param int $maxSize |
||
| 276 | * @param string $genericTitle optional, e.g. 'Page size requested is too large.' |
||
| 277 | * @param string $specificDetails optional, e.g. 'You requested a size of 200, but 100 is the maximum.' |
||
| 278 | * @return ErrorObject |
||
| 279 | */ |
||
| 280 | public function getMaxPageSizeExceededErrorObject($maxSize, $genericTitle=null, $specificDetails=null) { |
||
| 293 | |||
| 294 | /** |
||
| 295 | * get an ErrorObject for when the requested page size is not a positive integer, or when the requested page after/before is not a valid cursor |
||
| 296 | * |
||
| 297 | * ends up at: |
||
| 298 | * - /errors/0/code |
||
| 299 | * - /errors/0/status |
||
| 300 | * - /errors/0/source/parameter |
||
| 301 | * - /errors/0/links/type/0 optional |
||
| 302 | * - /errors/0/title optional |
||
| 303 | * - /errors/0/detail optional |
||
| 304 | * |
||
| 305 | * @param int $queryParameter e.g. 'sort' or 'page[size]', aliasing should already be done using {@see getKeyword} |
||
| 306 | * @param string $typeLink optional |
||
| 307 | * @param string $genericTitle optional, e.g. 'Invalid Parameter.' |
||
| 308 | * @param string $specificDetails optional, e.g. 'page[size] must be a positive integer; got 0' |
||
| 309 | * @return ErrorObject |
||
| 310 | */ |
||
| 311 | public function getInvalidParameterValueErrorObject($queryParameter, $typeLink=null, $genericTitle=null, $specificDetails=null) { |
||
| 326 | |||
| 327 | /** |
||
| 328 | * get an ErrorObject for when range pagination requests (when both 'page[after]' and 'page[before]' are requested) are not supported |
||
| 329 | * |
||
| 330 | * ends up at: |
||
| 331 | * - /errors/0/code |
||
| 332 | * - /errors/0/status |
||
| 333 | * - /errors/0/links/type/0 |
||
| 334 | * |
||
| 335 | * @param string $genericTitle optional |
||
| 336 | * @param string $specificDetails optional |
||
| 337 | * @return ErrorObject |
||
| 338 | */ |
||
| 339 | View Code Duplication | public function getRangePaginationNotSupportedErrorObject($genericTitle=null, $specificDetails=null) { |
|
| 350 | |||
| 351 | /** |
||
| 352 | * internal api |
||
| 353 | */ |
||
| 354 | |||
| 355 | /** |
||
| 356 | * add or adjust a key in the query string of a url |
||
| 357 | * |
||
| 358 | * @param string $url |
||
| 359 | * @param string $key |
||
| 360 | * @param string $value |
||
| 361 | */ |
||
| 362 | private function setQueryParameter($url, $key, $value) { |
||
| 384 | |||
| 385 | /** |
||
| 386 | * ProfileInterface |
||
| 387 | */ |
||
| 388 | |||
| 389 | /** |
||
| 390 | * @inheritDoc |
||
| 391 | */ |
||
| 392 | public function getOfficialLink() { |
||
| 395 | |||
| 396 | /** |
||
| 397 | * @inheritDoc |
||
| 398 | */ |
||
| 399 | public function getOfficialKeywords() { |
||
| 402 | } |
||
| 403 |