HEX
Server: Apache
System: Linux WWW 6.1.0-40-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.153-1 (2025-09-20) x86_64
User: web11 (1011)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/apklausos/application/models/services/QuestionAggregateService/AttributesService.php
<?php

namespace LimeSurvey\Models\Services\QuestionAggregateService;

use LimeSurvey\Models\Services\QuestionAttributeHelper;
use Question;
use QuestionAttribute;
use LimeSurvey\Models\Services\Exception\PersistErrorException;
use Survey;

/**
 * Question Aggregate Attributes Service
 *
 * Service class for editing question attributes data.
 *
 * Based on QuestionAdministrationController::unparseAndSetAdvancedOptions()
 */
class AttributesService
{
    private QuestionAttribute $modelQuestionAttribute;
    private QuestionAttributeHelper $questionAttributeHelper;
    private Survey $modelSurvey;

    public function __construct(
        QuestionAttribute $modelQuestionAttribute,
        QuestionAttributeHelper $questionAttributeHelper,
        Survey $modelSurvey
    ) {
        $this->modelQuestionAttribute = $modelQuestionAttribute;
        $this->questionAttributeHelper = $questionAttributeHelper;
        $this->modelSurvey = $modelSurvey;
    }

    /**
     * Based on QuestionAdministrationController::unparseAndSetAdvancedOptions()
     * Saves the advanced question attributes as they are in the $dataSet array
     *
     * @param Question $question
     * @param array {
     *      ?logic: array{
     *          ?min_answers: int,
     *          ?max_answers: int,
     *          ?array_filter_style: int,
     *          ?array_filter: string,
     *          ?array_filter_exclude: string,
     *          ?exclude_all_others: int,
     *          ?random_group: string,
     *          ?em_validation_q: string,
     *          ?em_validation_q_tip: array{
     *              ?en: string,
     *              ?de: string,
     *              ...<array-key, mixed>
     *          },
     *          ...<array-key, mixed>
     *      },
     *      ?display: array{
     *          ...<array-key, mixed>
     *      },
     *      ?statistics: array{
     *          ...<array-key, mixed>
     *      },
     *      ...<array-key, mixed>
     * } $dataSet
     * @return void
     * @throws PersistErrorException
     */
    public function saveAdvanced($question, $dataSet)
    {
        foreach ($dataSet as $category => $categorySettings) {
            if ($category === 'debug') {
                continue;
            }
            $this->save($question, $categorySettings);
        }

        if (!$question->save()) {
            throw new PersistErrorException(
                gT('Could not store advanced options')
            );
        }
    }

    /**
     * Saves the base attributes of questions as they come in
     *
     * @param Question $question
     * @param array {
     *      ?min_answers: int,
     *      ?max_answers: int,
     *      ?array_filter_style: int,
     *      ?array_filter: string,
     *      ?array_filter_exclude: string,
     *      ?exclude_all_others: int,
     *      ?random_group: string,
     *      ?em_validation_q: string,
     *      ?em_validation_q_tip: array{
     *          ?en: string,
     *          de: string,
     *          ...<array-key, mixed>
     *      },
     *      ...<array-key, mixed>
     * } $dataSet
     * @return void
     * @throws PersistErrorException
     */
    public function save($question, $dataSet)
    {
        $questionBaseAttributes = $question->attributes;

        foreach ($dataSet as $attributeKey => $attributeValue) {
            if (
                !isset($attributeValue) ||
                in_array($attributeKey, ['qid', 'debug', 'tempId'])
            ) {
                continue;
            }

            if (is_array($attributeValue)) {
                foreach ($attributeValue as $lngKey => $content) {
                    if ($lngKey === 'expression') {
                        continue;
                    }
                    if (
                        !$this->modelQuestionAttribute->setQuestionAttributeWithLanguage(
                            $question->qid,
                            $attributeKey,
                            $content,
                            $lngKey
                        )
                    ) {
                        throw new PersistErrorException(
                            gT("Could not store advanced options")
                        );
                    }
                }
            } elseif (
                array_key_exists(
                    $attributeKey,
                    $questionBaseAttributes
                )
            ) {
                $question->$attributeKey = $attributeValue;
            } elseif (
                !$this->modelQuestionAttribute->setQuestionAttribute(
                    $question->qid,
                    $attributeKey,
                    $attributeValue
                )
            ) {
                throw new PersistErrorException(
                    gT('Could not save question attributes')
                );
            }
        }

        if (!$question->save()) {
            throw new PersistErrorException(
                gT('Could not save question')
            );
        }

        $question->refresh();
    }

    /**
     * Adds missing question attributes with default values to the passed question
     * @param Question $question
     * @param int $surveyId
     * @return Question
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function saveMissingAttributes(Question $question, int $surveyId)
    {
        $existingAttrSimplified = [];
        $existingAttributes = $this->modelQuestionAttribute->resetScope(
        )->findAll(
            'qid = :qid',
            [':qid' => $question->qid]
        );

        foreach ($existingAttributes as $attr) {
            /* @var QuestionAttribute $attr ; */
                $existingAttrSimplified[$attr->attribute][$attr->language] = $attr->value;
        }

        $defaultSet = $this->questionAttributeHelper->getQuestionAttributesWithValues(
            $question,
            null,
            null,
            true
        );
        // get all languages of the survey:
        $surveyModel = $this->modelSurvey->findByPk($surveyId);
        $allSurveyLanguages = $surveyModel->getAllLanguages();

        //only add those with their default values who are not already there
        foreach ($defaultSet as $attrName => $attrData) {
            $default = $attrData['default'] !== null ? $attrData['default'] : '';
            if (
                $attrData['i18n'] !== '1' &&
                !array_key_exists(
                    $attrName,
                    $existingAttrSimplified
                )
            ) {
                $this->modelQuestionAttribute->setQuestionAttributeWithLanguage(
                    $question->qid,
                    $attrName,
                    $default,
                    ''
                );
            } elseif ($attrData['i18n'] === '1') {
                // for language based attributes, add the default value for each language if not existing
                foreach ($allSurveyLanguages as $lngKey) {
                    if (
                        !array_key_exists($attrName, $existingAttrSimplified) ||
                        !array_key_exists(
                            $lngKey,
                            $existingAttrSimplified[$attrName]
                        )
                    ) {
                        $this->modelQuestionAttribute->setQuestionAttributeWithLanguage(
                            $question->qid,
                            $attrName,
                            $default,
                            $lngKey
                        );
                    }
                }
            }
        }
        $question->refresh();
        return $question;
    }
}