PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.4
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.4
4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 4.2.1 All 138 releases
learnpress / inc / MCP / Support / Validator.php

Validator.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.4, at inc/MCP/Support/Validator.php

320 lines 7.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace LearnPress\MCP\Support;
4
5 use LearnPress\Models\CourseModel;
6 use LearnPress\Models\CoursePostModel;
7 use LearnPress\Models\CourseSectionModel;
8 use LearnPress\Models\LessonPostModel;
9 use LearnPress\Models\QuizPostModel;
10 use LearnPress\Models\Question\QuestionPostModel;
11 use LearnPress\Models\Quiz\QuizQuestionModel;
12 use LearnPress\Models\UserItems\UserItemModel;
13 use LearnPress\Models\UserModel;
14 use WP_Error;
15
16 defined( 'ABSPATH' ) || exit;
17
18 /**
19 * Shared validation + entity-resolution helpers for Phase 2 MCP tools.
20 *
21 * Validates IDs, allowlists, and target existence consistently so domain
22 * executors do not reimplement the same checks.
23 */
24 class Validator {
25
26 /**
27 * Read a required positive integer ID from input.
28 *
29 * @param array $args Input args.
30 * @param string $key Field name.
31 *
32 * @return int|WP_Error
33 */
34 public static function require_id( array $args, string $key ) {
35 $id = absint( $args[ $key ] ?? 0 );
36 if ( $id <= 0 ) {
37 /* translators: %s: field name. */
38 return Errors::invalid( sprintf( __( '%s is required and must be a positive integer.', 'learnpress' ), $key ) );
39 }
40
41 return $id;
42 }
43
44 /**
45 * Validate an optional post status against the Phase 2 allowlist.
46 *
47 * @param mixed $value Raw status value.
48 *
49 * @return string|WP_Error Empty string when not provided.
50 */
51 public static function status( $value ) {
52 if ( null === $value || '' === $value ) {
53 return '';
54 }
55
56 $status = sanitize_key( (string) $value );
57 if ( ! in_array( $status, Schemas::allowed_statuses(), true ) ) {
58 return Errors::invalid(
59 sprintf(
60 /* translators: 1: provided status, 2: allowed statuses. */
61 __( 'Invalid status "%1$s". Allowed: %2$s.', 'learnpress' ),
62 $status,
63 implode( ', ', Schemas::allowed_statuses() )
64 )
65 );
66 }
67
68 return $status;
69 }
70
71 /**
72 * Allowed enrollment statuses.
73 *
74 * @return string[]
75 */
76 public static function enrollment_statuses(): array {
77 return array(
78 UserItemModel::STATUS_ENROLLED,
79 UserItemModel::STATUS_FINISHED,
80 UserItemModel::STATUS_PURCHASED,
81 UserItemModel::STATUS_COMPLETED,
82 UserItemModel::STATUS_CANCEL,
83 );
84 }
85
86 /**
87 * Statuses allowed when creating a manual enrollment (active states only).
88 *
89 * Finished/completed/cancel are reached via update-enrollment, not creation,
90 * to avoid inconsistent records (e.g. finished with no end_time/result).
91 *
92 * @return string[]
93 */
94 public static function enroll_create_statuses(): array {
95 return array(
96 UserItemModel::STATUS_ENROLLED,
97 UserItemModel::STATUS_PURCHASED,
98 );
99 }
100
101 /**
102 * Allowed graduation values.
103 *
104 * @return string[]
105 */
106 public static function graduations(): array {
107 return array(
108 UserItemModel::GRADUATION_IN_PROGRESS,
109 UserItemModel::GRADUATION_PASSED,
110 UserItemModel::GRADUATION_FAILED,
111 );
112 }
113
114 /**
115 * Validate an optional enrollment status.
116 *
117 * @param mixed $value Raw value.
118 *
119 * @return string|WP_Error Empty string when not provided.
120 */
121 public static function enrollment_status( $value ) {
122 if ( null === $value || '' === $value ) {
123 return '';
124 }
125
126 $status = sanitize_key( (string) $value );
127 if ( ! in_array( $status, self::enrollment_statuses(), true ) ) {
128 return Errors::invalid(
129 sprintf(
130 /* translators: 1: status, 2: allowed list. */
131 __( 'Invalid enrollment status "%1$s". Allowed: %2$s.', 'learnpress' ),
132 $status,
133 implode( ', ', self::enrollment_statuses() )
134 )
135 );
136 }
137
138 return $status;
139 }
140
141 /**
142 * Validate an optional graduation value.
143 *
144 * @param mixed $value Raw value.
145 *
146 * @return string|WP_Error Empty string when not provided.
147 */
148 public static function graduation( $value ) {
149 if ( null === $value || '' === $value ) {
150 return '';
151 }
152
153 $graduation = sanitize_key( (string) $value );
154 if ( ! in_array( $graduation, self::graduations(), true ) ) {
155 return Errors::invalid(
156 sprintf(
157 /* translators: 1: graduation, 2: allowed list. */
158 __( 'Invalid graduation "%1$s". Allowed: %2$s.', 'learnpress' ),
159 $graduation,
160 implode( ', ', self::graduations() )
161 )
162 );
163 }
164
165 return $graduation;
166 }
167
168 /**
169 * Validate a question type against LearnPress registered types.
170 *
171 * @param mixed $value Raw type.
172 *
173 * @return string|WP_Error
174 */
175 public static function question_type( $value ) {
176 $type = sanitize_key( (string) $value );
177 if ( '' === $type || ! QuestionPostModel::check_type_valid( $type ) ) {
178 return Errors::invalid(
179 sprintf(
180 /* translators: %s: provided type. */
181 __( 'Invalid question type "%s".', 'learnpress' ),
182 $type
183 )
184 );
185 }
186
187 return $type;
188 }
189
190 /**
191 * Resolve a course or return a 404.
192 *
193 * @param int $course_id Course ID.
194 *
195 * @return CourseModel|WP_Error
196 */
197 public static function find_course( int $course_id ) {
198 $course = CourseModel::find( $course_id, true );
199 if ( ! $course instanceof CourseModel ) {
200 return Errors::not_found( __( 'Course not found.', 'learnpress' ) );
201 }
202
203 return $course;
204 }
205
206 /**
207 * Resolve a course post model or return a 404.
208 *
209 * @param int $course_id Course ID.
210 *
211 * @return CoursePostModel|WP_Error
212 */
213 public static function find_course_post( int $course_id ) {
214 $course = CoursePostModel::find( $course_id, true );
215 if ( ! $course instanceof CoursePostModel ) {
216 return Errors::not_found( __( 'Course not found.', 'learnpress' ) );
217 }
218
219 return $course;
220 }
221
222 /**
223 * Resolve a section that belongs to a course, or return a 404.
224 *
225 * @param int $section_id Section ID.
226 * @param int $course_id Course ID.
227 *
228 * @return CourseSectionModel|WP_Error
229 */
230 public static function find_section( int $section_id, int $course_id ) {
231 $section = CourseSectionModel::find( $section_id, $course_id, true );
232 if ( ! $section instanceof CourseSectionModel ) {
233 return Errors::not_found( __( 'Section not found in this course.', 'learnpress' ) );
234 }
235
236 return $section;
237 }
238
239 /**
240 * Resolve a lesson or return a 404.
241 *
242 * @param int $lesson_id Lesson ID.
243 *
244 * @return LessonPostModel|WP_Error
245 */
246 public static function find_lesson( int $lesson_id ) {
247 $lesson = LessonPostModel::find( $lesson_id, true );
248 if ( ! $lesson instanceof LessonPostModel ) {
249 return Errors::not_found( __( 'Lesson not found.', 'learnpress' ) );
250 }
251
252 return $lesson;
253 }
254
255 /**
256 * Resolve a quiz or return a 404.
257 *
258 * @param int $quiz_id Quiz ID.
259 *
260 * @return QuizPostModel|WP_Error
261 */
262 public static function find_quiz( int $quiz_id ) {
263 $quiz = QuizPostModel::find( $quiz_id, true );
264 if ( ! $quiz instanceof QuizPostModel ) {
265 return Errors::not_found( __( 'Quiz not found.', 'learnpress' ) );
266 }
267
268 return $quiz;
269 }
270
271 /**
272 * Resolve a question or return a 404.
273 *
274 * @param int $question_id Question ID.
275 *
276 * @return QuestionPostModel|WP_Error
277 */
278 public static function find_question( int $question_id ) {
279 $question = QuestionPostModel::find( $question_id, true );
280 if ( ! $question instanceof QuestionPostModel ) {
281 return Errors::not_found( __( 'Question not found.', 'learnpress' ) );
282 }
283
284 return $question;
285 }
286
287 /**
288 * Resolve a quiz-question relationship or return a 404.
289 *
290 * @param int $quiz_id Quiz ID.
291 * @param int $question_id Question ID.
292 *
293 * @return QuizQuestionModel|WP_Error
294 */
295 public static function find_quiz_question( int $quiz_id, int $question_id ) {
296 $relation = QuizQuestionModel::find( $quiz_id, $question_id, true );
297 if ( ! $relation instanceof QuizQuestionModel ) {
298 return Errors::not_found( __( 'Question is not assigned to this quiz.', 'learnpress' ) );
299 }
300
301 return $relation;
302 }
303
304 /**
305 * Resolve a user or return a 404.
306 *
307 * @param int $user_id User ID.
308 *
309 * @return UserModel|WP_Error
310 */
311 public static function find_user( int $user_id ) {
312 $user = UserModel::find( $user_id, true );
313 if ( ! $user instanceof UserModel ) {
314 return Errors::not_found( __( 'User not found.', 'learnpress' ) );
315 }
316
317 return $user;
318 }
319 }
320