Refine survey editor workflow and publication handling
This commit is contained in:
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Mummert\SurveyBundle\Repository;
|
||||
|
||||
use Doctrine\DBAL\ArrayParameterType;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
final class SurveyAnswerRepository
|
||||
@@ -12,7 +13,15 @@ final class SurveyAnswerRepository
|
||||
{
|
||||
}
|
||||
|
||||
public function saveAnswer(int $submissionId, int $questionId, string $questionType, string $value): void
|
||||
public function saveAnswer(
|
||||
int $submissionId,
|
||||
int $questionId,
|
||||
string $questionType,
|
||||
string $questionLabel,
|
||||
string $questionDescription,
|
||||
int $questionSorting,
|
||||
string $value,
|
||||
): void
|
||||
{
|
||||
$existingId = $this->connection->fetchOne(
|
||||
'SELECT id FROM tl_survey_answer WHERE submission = ? AND question = ? LIMIT 1',
|
||||
@@ -22,6 +31,9 @@ final class SurveyAnswerRepository
|
||||
if (false !== $existingId) {
|
||||
$this->connection->update('tl_survey_answer', [
|
||||
'questionType' => $questionType,
|
||||
'questionLabel' => $questionLabel,
|
||||
'questionDescription' => $questionDescription,
|
||||
'questionSorting' => $questionSorting,
|
||||
'value' => $value,
|
||||
], [
|
||||
'id' => (int) $existingId,
|
||||
@@ -35,6 +47,9 @@ final class SurveyAnswerRepository
|
||||
'submission' => $submissionId,
|
||||
'question' => $questionId,
|
||||
'questionType' => $questionType,
|
||||
'questionLabel' => $questionLabel,
|
||||
'questionDescription' => $questionDescription,
|
||||
'questionSorting' => $questionSorting,
|
||||
'value' => $value,
|
||||
]);
|
||||
}
|
||||
@@ -53,8 +68,36 @@ final class SurveyAnswerRepository
|
||||
);
|
||||
}
|
||||
|
||||
public function findStoredAnswerValue(int $submissionId, int $questionId): ?string
|
||||
{
|
||||
$value = $this->connection->fetchOne(
|
||||
'SELECT value FROM tl_survey_answer WHERE submission = ? AND question = ? LIMIT 1',
|
||||
[$submissionId, $questionId],
|
||||
);
|
||||
|
||||
return false === $value ? null : (string) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{questionId:int,value:string}>
|
||||
* @param list<int> $questionIds
|
||||
*/
|
||||
public function deleteAnswersForSubmissionExceptQuestions(int $submissionId, array $questionIds): void
|
||||
{
|
||||
if ([] === $questionIds) {
|
||||
$this->connection->delete('tl_survey_answer', ['submission' => $submissionId]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->connection->executeStatement(
|
||||
'DELETE FROM tl_survey_answer WHERE submission = ? AND question NOT IN (?)',
|
||||
[$submissionId, array_values(array_unique(array_map('intval', $questionIds)))],
|
||||
[\PDO::PARAM_INT, ArrayParameterType::INTEGER],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{questionId:int,questionType:string,questionLabel:string,questionDescription:string,questionSorting:int,value:string}>
|
||||
*/
|
||||
public function findFinishedAnswersBySurvey(int $surveyId): array
|
||||
{
|
||||
@@ -62,11 +105,15 @@ final class SurveyAnswerRepository
|
||||
<<<'SQL'
|
||||
SELECT
|
||||
a.question AS questionId,
|
||||
a.questionType,
|
||||
a.questionLabel,
|
||||
a.questionDescription,
|
||||
a.questionSorting,
|
||||
a.value
|
||||
FROM tl_survey_answer a
|
||||
INNER JOIN tl_survey_submission sub ON sub.id = a.submission
|
||||
WHERE sub.survey = :survey AND sub.isFinished = 1
|
||||
ORDER BY a.question ASC, a.id ASC
|
||||
ORDER BY a.questionSorting ASC, a.question ASC, a.id ASC
|
||||
SQL,
|
||||
['survey' => $surveyId],
|
||||
);
|
||||
@@ -74,6 +121,10 @@ final class SurveyAnswerRepository
|
||||
return array_map(
|
||||
static fn (array $row): array => [
|
||||
'questionId' => (int) $row['questionId'],
|
||||
'questionType' => (string) ($row['questionType'] ?? ''),
|
||||
'questionLabel' => (string) ($row['questionLabel'] ?? ''),
|
||||
'questionDescription' => (string) ($row['questionDescription'] ?? ''),
|
||||
'questionSorting' => (int) ($row['questionSorting'] ?? 0),
|
||||
'value' => (string) $row['value'],
|
||||
],
|
||||
$rows,
|
||||
@@ -92,11 +143,12 @@ final class SurveyAnswerRepository
|
||||
a.question AS questionId,
|
||||
a.value,
|
||||
a.questionType,
|
||||
q.question
|
||||
COALESCE(NULLIF(a.questionLabel, ''), q.question, CONCAT('Frage #', a.question)) AS question,
|
||||
COALESCE(a.questionDescription, q.description, '') AS questionDescription
|
||||
FROM tl_survey_answer a
|
||||
INNER JOIN tl_survey_content q ON q.id = a.question
|
||||
LEFT JOIN tl_survey_content q ON q.id = a.question
|
||||
WHERE a.submission = :submission
|
||||
ORDER BY q.sorting ASC
|
||||
ORDER BY COALESCE(NULLIF(a.questionSorting, 0), q.sorting, 0) ASC, a.id ASC
|
||||
SQL,
|
||||
['submission' => $submissionId],
|
||||
);
|
||||
|
||||
@@ -41,6 +41,7 @@ final class SurveyRepository
|
||||
|
||||
if ($publishedOnly) {
|
||||
$qb->andWhere('published = 1');
|
||||
$qb->andWhere('isActive = 1');
|
||||
}
|
||||
|
||||
$id = $qb->executeQuery()->fetchOne();
|
||||
@@ -65,6 +66,7 @@ final class SurveyRepository
|
||||
s.alias,
|
||||
s.description,
|
||||
s.published,
|
||||
s.isActive,
|
||||
s.isLocked,
|
||||
s.updatedAt,
|
||||
COUNT(DISTINCT q.id) AS questionCount,
|
||||
@@ -92,6 +94,7 @@ final class SurveyRepository
|
||||
'category' => serialize($this->normalizeCategoryIds($data['category'] ?? [])),
|
||||
'description' => (string) ($data['description'] ?? ''),
|
||||
'published' => '',
|
||||
'isActive' => '',
|
||||
'isLocked' => '',
|
||||
'createdBy' => $memberId,
|
||||
'updatedBy' => $memberId,
|
||||
@@ -115,7 +118,8 @@ final class SurveyRepository
|
||||
'alias' => $this->ensurePublicAlias((string) $survey->alias, (int) $survey->id),
|
||||
'category' => serialize($this->normalizeCategoryIds($data['category'] ?? StringUtil::deserialize($survey->category, true))),
|
||||
'description' => (string) ($data['description'] ?? $survey->description),
|
||||
'published' => !empty($data['published']) ? '1' : '',
|
||||
'published' => array_key_exists('published', $data) ? (!empty($data['published']) ? '1' : '') : (string) $survey->published,
|
||||
'isActive' => array_key_exists('isActive', $data) ? (!empty($data['isActive']) ? '1' : '') : (string) ($survey->isActive ?? ''),
|
||||
'updatedBy' => $memberId,
|
||||
'updatedAt' => time(),
|
||||
], [
|
||||
@@ -182,6 +186,8 @@ final class SurveyRepository
|
||||
$this->connection->update('tl_survey', [
|
||||
'categoryFilter' => implode(',', $categoryIds),
|
||||
'categorySummary' => implode(', ', $categoryTitles),
|
||||
'templateFilter' => '1' === (string) $survey->isTemplate ? '1' : '0',
|
||||
'templateSummary' => '1' === (string) $survey->isTemplate ? 'Ja' : 'Nein',
|
||||
'assignedMembersFilter' => implode(',', $memberIds),
|
||||
'assignedMembersSummary' => implode(', ', $memberNames),
|
||||
], [
|
||||
@@ -212,6 +218,36 @@ final class SurveyRepository
|
||||
]);
|
||||
}
|
||||
|
||||
public function publish(int $surveyId, int $memberId): void
|
||||
{
|
||||
$now = time();
|
||||
|
||||
$this->connection->update('tl_survey', [
|
||||
'published' => '1',
|
||||
'isActive' => '1',
|
||||
'isLocked' => '1',
|
||||
'tstamp' => $now,
|
||||
'updatedBy' => $memberId,
|
||||
'updatedAt' => $now,
|
||||
], [
|
||||
'id' => $surveyId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function setActive(int $surveyId, int $memberId, bool $isActive): void
|
||||
{
|
||||
$now = time();
|
||||
|
||||
$this->connection->update('tl_survey', [
|
||||
'isActive' => $isActive ? '1' : '',
|
||||
'tstamp' => $now,
|
||||
'updatedBy' => $memberId,
|
||||
'updatedAt' => $now,
|
||||
], [
|
||||
'id' => $surveyId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteCascade(int $surveyId): void
|
||||
{
|
||||
$this->connection->transactional(function () use ($surveyId): void {
|
||||
@@ -347,7 +383,7 @@ final class SurveyRepository
|
||||
);
|
||||
|
||||
return $this->hasListMetadataColumns = !array_diff(
|
||||
['categoryfilter', 'categorysummary', 'assignedmembersfilter', 'assignedmemberssummary'],
|
||||
['categoryfilter', 'categorysummary', 'templatefilter', 'templatesummary', 'assignedmembersfilter', 'assignedmemberssummary'],
|
||||
$columnNames,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,17 @@ final class SurveySubmissionRepository
|
||||
]);
|
||||
}
|
||||
|
||||
public function reopen(int $submissionId, int $questionId): void
|
||||
{
|
||||
$this->connection->update('tl_survey_submission', [
|
||||
'isFinished' => '',
|
||||
'completedAt' => 0,
|
||||
'currentQuestion' => $questionId,
|
||||
], [
|
||||
'id' => $submissionId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user