@@ -934,6 +934,125 @@ public function reorderQuestions(int $formId, array $newOrder): DataResponse {
934934 return new DataResponse ($ response );
935935 }
936936
937+ /**
938+ * Updates the Order of all Questions in a Branch of a conditional
939+ *
940+ * @param int $formId Id of the form to reorder
941+ * @param string $branchId Id of the branch.
942+ * @param int $parentQuestionId Id of the parent trigger question.
943+ * @param list<int> $newOrder Array of Question-Ids in new order.
944+ * @return DataResponse<Http::STATUS_OK, array<string, FormsOrder>, array{}>
945+ * @throws OCSBadRequestException The given array contains duplicates
946+ * @throws OCSBadRequestException The length of the given array does not match the number of stored questions
947+ * @throws OCSBadRequestException Question doesn't belong to given Form
948+ * @throws OCSBadRequestException One question has already been marked as deleted
949+ * @throws OCSForbiddenException This form is archived and can not be modified
950+ * @throws OCSForbiddenException User has no permissions to get this form
951+ * @throws OCSNotFoundException Could not find form
952+ * @throws OCSNotFoundException Could not find question
953+ *
954+ * 200: the question ids of the given form in the new order
955+ */
956+ #[CORS ()]
957+ #[NoAdminRequired()]
958+ #[BruteForceProtection(action: 'form ' )]
959+ #[ApiRoute(verb: 'PATCH ' , url: '/api/v3/forms/{formId}/subquestions ' )]
960+ public function reorderSubQuestions (int $ formId , string $ branchId , int $ parentQuestionId , array $ newOrder ): DataResponse {
961+ $ this ->logger ->debug ('Reordering Sub-Questions on Form {formId}, Parent-Question {parentQuestionId}, Branch {branchId} as Question-Ids {newOrder} ' , [
962+ 'formId ' => $ formId ,
963+ 'parentQuestionId ' => $ parentQuestionId ,
964+ 'branchId ' => $ branchId ,
965+ 'newOrder ' => $ newOrder
966+ ]);
967+
968+ $ form = $ this ->formsService ->getFormIfAllowed ($ formId , Constants::PERMISSION_EDIT );
969+ $ this ->formsService ->obtainFormLock ($ form );
970+
971+ if ($ this ->formsService ->isFormArchived ($ form )) {
972+ $ this ->logger ->debug ('This form is archived and can not be modified ' );
973+ throw new OCSForbiddenException ('This form is archived and can not be modified ' );
974+ }
975+
976+ // Check if array contains duplicates
977+ if (array_unique ($ newOrder ) !== $ newOrder ) {
978+ $ this ->logger ->debug ('The given array contains duplicates ' );
979+ throw new OCSBadRequestException ('The given array contains duplicates ' );
980+ }
981+
982+ // Check if all questions are given in Array.
983+ $ questions = $ this ->questionMapper ->findByBranch ($ parentQuestionId , $ branchId );
984+ if (sizeof ($ questions ) !== sizeof ($ newOrder )) {
985+ $ this ->logger ->debug ('The length of the given array does not match the number of stored questions ' );
986+ throw new OCSBadRequestException ('The length of the given array does not match the number of stored questions ' );
987+ }
988+
989+ $ questions = []; // Clear Array of Entities
990+ $ response = []; // Array of ['questionId' => ['order' => newOrder]]
991+
992+ // Store array of Question-Entities and check the Questions FormId & old Order.
993+ foreach ($ newOrder as $ arrayKey => $ questionId ) {
994+ try {
995+ $ questions [$ arrayKey ] = $ this ->questionMapper ->findById ($ questionId );
996+ } catch (IMapperException $ e ) {
997+ $ this ->logger ->debug ('Could not find question {questionId} ' , [
998+ 'questionId ' => $ questionId
999+ ]);
1000+ throw new OCSNotFoundException ('Could not find question ' );
1001+ }
1002+
1003+ // Abort if a question is not part of the Form.
1004+ if ($ questions [$ arrayKey ]->getFormId () !== $ formId ) {
1005+ $ this ->logger ->debug ('This Question is not part of the given form: {questionId} ' , [
1006+ 'questionId ' => $ questionId
1007+ ]);
1008+ throw new OCSBadRequestException ('Question doesn \'t belong to given Form ' );
1009+ }
1010+ // Abort if a question is not part of the Parent Question.
1011+ if ($ questions [$ arrayKey ]->getParentQuestionId () !== $ parentQuestionId ) {
1012+ $ this ->logger ->debug ('This Question is not part of the given parent question: {parentQuestionId} ' , [
1013+ 'parentQuestionId ' => $ parentQuestionId
1014+ ]);
1015+ throw new OCSBadRequestException ('Question doesn \'t belong to given Parent Question ' );
1016+ }
1017+
1018+ // Abort if a question is not part of the Branch.
1019+ if ($ questions [$ arrayKey ]->getBranchId () !== $ branchId ) {
1020+ $ this ->logger ->debug ('This Question is not part of the given branch: {branchId} ' , [
1021+ 'branchId ' => $ branchId
1022+ ]);
1023+ throw new OCSBadRequestException ('Question doesn \'t belong to given Branch ' );
1024+ }
1025+
1026+ // Abort if a question is already marked as deleted (order==0)
1027+ $ oldOrder = $ questions [$ arrayKey ]->getOrder ();
1028+ if ($ oldOrder === 0 ) {
1029+ $ this ->logger ->debug ('This question has already been marked as deleted: Id: {questionId} ' , [
1030+ 'questionId ' => $ questions [$ arrayKey ]->getId ()
1031+ ]);
1032+ throw new OCSBadRequestException ('One question has already been marked as deleted ' );
1033+ }
1034+
1035+ // Only set order, if it changed.
1036+ if ($ oldOrder !== $ arrayKey + 1 ) {
1037+ // Set Order. ArrayKey counts from zero, order counts from 1.
1038+ $ questions [$ arrayKey ]->setOrder ($ arrayKey + 1 );
1039+ }
1040+ }
1041+
1042+ // Write to Database
1043+ foreach ($ questions as $ question ) {
1044+ $ this ->questionMapper ->update ($ question );
1045+
1046+ $ response [(string )$ question ->getId ()] = [
1047+ 'order ' => $ question ->getOrder ()
1048+ ];
1049+ }
1050+
1051+ $ this ->formMapper ->update ($ form );
1052+
1053+ return new DataResponse ($ response );
1054+ }
1055+
9371056 // Options
9381057
9391058 /**
0 commit comments