PluginProbe
404 Solution / 4.2.0
404 Solution v4.2.0
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / PublishedPostsProvider.php

PublishedPostsProvider.php in 404 Solution 4.2.0, at includes/PublishedPostsProvider.php

156 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 if (!defined('ABSPATH')) {
5 exit;
6 }
7
8 /** Return some of the published pages when requested. */
9 class ABJ_404_Solution_PublishedPostsProvider {
10
11 /** Track which rows to get from the database using limit.
12 * @var integer */
13 private $currentLowRowNumber = 0;
14
15 /** When not null then use this data instead of querying the database.
16 * @var array<int, mixed>|null
17 */
18 private $dataToUse = null;
19
20 /** Tracks whether we're using user supplied data or not.
21 * @var bool */
22 private $useDataMode = false;
23
24 /** When set, only return posts with these IDs (whitelist mode).
25 * @var array<int, int>|null */
26 private $restrictedIds = null;
27
28 /** @var self|null */
29 private static $instance = null;
30
31 /** @var ABJ_404_Solution_ContentRepository */
32 private $contentRepository;
33
34 /**
35 * @param ABJ_404_Solution_ContentRepository|null $contentRepository Content repository
36 */
37 public function __construct($contentRepository = null) {
38 $this->contentRepository = $contentRepository !== null ? $contentRepository : abj_service('content_repository');
39 }
40
41 public static function resetForTests(?self $replacement = null): void {
42 self::$instance = $replacement;
43 }
44
45 /** @return self */
46 public static function getInstance() {
47 if (self::$instance == null) {
48 self::$instance = new ABJ_404_Solution_PublishedPostsProvider();
49 }
50
51 return self::$instance;
52 }
53
54 /** Use this data instead of querying the database.
55 * @param array<int, mixed> $data
56 * @return void
57 */
58 function useThisData(array $data): void {
59 $this->dataToUse = $data;
60 $this->useDataMode = true;
61 }
62
63 /**
64 * Restrict results to only posts with the given IDs (whitelist mode).
65 * This enables N-gram prefiltering to limit the dataset before expensive processing.
66 *
67 * @param array<int, int|string> $ids Array of post IDs to include
68 * @return void
69 */
70 function restrictToIds(array $ids): void {
71 if (!empty($ids) && is_array($ids)) {
72 $this->restrictedIds = array_map('intval', $ids);
73 }
74 }
75
76 /**
77 * Check if we're in restricted ID mode.
78 * @return bool
79 */
80 function hasRestrictedIds() {
81 return !empty($this->restrictedIds);
82 }
83
84 /**
85 * @param int $permalinkLength Order by prioritizing things with a permalink
86 * close to this length.
87 * @param int $batchSize The number of results to return. e.g. 100.
88 * @param int|null $maxAcceptableDistance
89 * @return array<int, mixed>
90 */
91 function getNextBatch(int $permalinkLength, int $batchSize = 1000, $maxAcceptableDistance = null): array {
92 if ($this->useDataMode) {
93 return $this->getNextBatchFromLocalData($permalinkLength, $batchSize, $maxAcceptableDistance);
94 }
95
96 return $this->getNextBatchFromTheDatabase($permalinkLength, $batchSize, $maxAcceptableDistance);
97 }
98
99 /**
100 * @param int $permalinkLength
101 * @param int $batchSize
102 * @param int|null $maxAcceptableDistance
103 * @return array<int, mixed>
104 */
105 private function getNextBatchFromLocalData(int $permalinkLength, int $batchSize, $maxAcceptableDistance): array {
106 $data = $this->dataToUse ?? array();
107 // get the rows to return.
108 $rows = array_slice($data, 0, $batchSize);
109
110 // remove the rows we'll return.
111 $this->dataToUse = array_slice($data, $batchSize);
112
113 return $rows;
114 }
115
116 /**
117 * @param int $permalinkLength
118 * @param int $batchSize
119 * @param int|null $maxAcceptableDistance
120 * @return array<int, mixed>
121 */
122 private function getNextBatchFromTheDatabase(int $permalinkLength, int $batchSize, $maxAcceptableDistance): array {
123 $orderBy = "abs(plc.url_length - " . $permalinkLength . "), wp_posts.id";
124 $limit = $this->currentLowRowNumber . ", " . $batchSize;
125 $extraWhereClause = '';
126
127 if ($maxAcceptableDistance != null) {
128 $extraWhereClause = "and abs(plc.url_length - " . $permalinkLength .
129 ") <= " . $maxAcceptableDistance;
130 }
131
132 // N-gram prefiltering: restrict to specific IDs if whitelist is set
133 if (!empty($this->restrictedIds)) {
134 $idList = implode(',', $this->restrictedIds);
135 $extraWhereClause .= " and wp_posts.id IN (" . $idList . ")";
136 }
137
138 $rows = $this->contentRepository->getPublishedPagesAndPostsIDs('', '', $limit, $orderBy, $extraWhereClause);
139
140 $this->currentLowRowNumber += $batchSize;
141
142 return $rows;
143 }
144
145 /** Start over at 0 when getting the next batch.
146 * @return void
147 */
148 function resetBatch(): void {
149 $this->currentLowRowNumber = 0;
150 $this->dataToUse = null;
151 $this->useDataMode = false;
152 $this->restrictedIds = null;
153 }
154
155 }
156