$answers question_id => answer value * @param list $acceptedVersionIds Accepted policy version IDs */ public function validate( int $offeringId, array $answers, array $acceptedVersionIds ): ?\WP_Error { foreach ( $this->questions->findByOffering( $offeringId, true ) as $question ) { if ( $question->isRequired && '' === trim( (string) ( $answers[ (int) $question->id ] ?? '' ) ) ) { return new \WP_Error( 'missing_answer', __( 'Please answer all required questions.', 'unsupervised-schedular' ), [ 'status' => 400 ] ); } } foreach ( $this->requiredPolicyVersionIds() as $versionId ) { if ( ! in_array( $versionId, $acceptedVersionIds, true ) ) { return new \WP_Error( 'policy_required', __( 'You must accept all required policies.', 'unsupervised-schedular' ), [ 'status' => 400 ] ); } } return null; } /** * Persist answers and policy acceptances for a created registration. * * `$acceptedBy` is who actually agreed, when that is not the student — a * guardian booking for a child. It defaults to 0, read back as "the student * agreed for themselves". * * @param array $answers question_id => answer value * @param list $acceptedVersionIds Accepted policy version IDs */ public function record( string $registrationType, int $registrationId, int $studentId, int $offeringId, array $answers, array $acceptedVersionIds, ?string $ipAddress = null, int $acceptedBy = 0 ): void { foreach ( $this->questions->findByOffering( $offeringId, true ) as $question ) { $value = (string) ( $answers[ (int) $question->id ] ?? '' ); if ( '' === $value ) { continue; } $this->answers->insert( new Answer( questionId: (int) $question->id, registrationType: $registrationType, registrationId: $registrationId, studentId: $studentId, answerValue: $value, ) ); } foreach ( $this->requiredPolicyVersionIds() as $versionId ) { if ( ! in_array( $versionId, $acceptedVersionIds, true ) ) { continue; } $this->acceptances->insert( new PolicyAcceptance( policyVersionId: $versionId, studentId: $studentId, registrationType: $registrationType, registrationId: $registrationId, acceptedBy: $acceptedBy > 0 ? $acceptedBy : $studentId, ipAddress: $ipAddress, ) ); } } /** * Current published version IDs of every booking-scoped policy. * * @return list */ private function requiredPolicyVersionIds(): array { $ids = []; foreach ( $this->policies->findForScope( Policy::SCOPE_BOOKING ) as $policy ) { if ( null === $policy->currentVersionId ) { continue; } $version = $this->versions->findById( $policy->currentVersionId ); if ( null !== $version && $version->isPublished() ) { $ids[] = (int) $version->id; } } return $ids; } }