Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VSVGVQ-106 Add Projections for Statistics. #68

Merged
merged 49 commits into from
Aug 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
503de45
VSVGVQ-106 Add StatisticsKey and StartedQuizzesProjection.
Jul 27, 2018
e49046d
VSVGVQ-106 Merge branch 'feature/VSVGVQ-104' into feature/VSVGVQ-106
Jul 27, 2018
4cfa4ec
VSVGVQ-106 Use Quiz channel and language to determine StatisticsKey.
Jul 27, 2018
353ad69
VSVGVQ-106 Rename from StartedQuizzes to StartedQuiz.
Jul 30, 2018
73b13c6
VSVGVQ-106 Add QuizRepository.
Jul 30, 2018
5daa970
VSVGVQ-106 Rename StartedQuizProjection to QuizStartedListener.
Jul 30, 2018
b38fddd
VSVGVQ-106 Add unit test for StatisticsKey.
Jul 30, 2018
9308cd4
VSVGVQ-106 Add unit test for QuizStartedListener.
Jul 30, 2018
7454d54
VSVGVQ-106 Merge branch 'master' into feature/VSVGVQ-106
Jul 31, 2018
6e85a61
VSVGVQ-106 Basic setup for simple event bus and in memory aggregate r…
Jul 31, 2018
f8c4d3f
VSVGVQ-106 Add unit test for QuizRedisRepository.
Jul 31, 2018
dc245d2
VSVGVQ-106 Add unit test for StartedQuizRedisRepository.
Jul 31, 2018
d5939a9
VSVGVQ-106 Exclude QuizController from code coverage.
Jul 31, 2018
e99b3de
VSVGVQ-106 incrementTotal changed to incrementCount.
Jul 31, 2018
b14dade
VSVGVQ-106 Add unit test for QuizAggregateRepository construction.
Aug 1, 2018
cc395a2
VSVGVQ-106 Add Doctrine implementation of Event Store (WIP).
Aug 1, 2018
f4925b5
VSVGVQ-106 Add missing strict_types.
Aug 1, 2018
8f3babd
VSVGVQ-106 Fix coding standard.
Aug 1, 2018
5cc6a17
VSVGVQ-106 Add normalizer and denormalizer for QuizStarted and unit t…
Aug 1, 2018
140ec6c
VSVGVQ-106 QuestionAsked has no normalizer and denormalizer.
Aug 1, 2018
cc5bc65
VSVGVQ-106 Fix type conflict.
Aug 1, 2018
38c9a3e
VSVGVQ-106 Implement loading from playhead for DoctrineEventStore.
Aug 2, 2018
5237c4b
VSVGVQ-106 Use DOCKER_HOST_IP for docker compose of test.
Aug 2, 2018
911f491
VSVGVQ-106 Add basic meta data serialization.
Aug 2, 2018
52dd73d
VSVGVQ-106 add test for QuizStartedSerializers
stejes Aug 2, 2018
9e8d884
Merge remote-tracking branch 'origin/feature/VSVGVQ-106' into feature…
stejes Aug 2, 2018
2972cc6
VSVGVQ-106 Remove incomplete code for meta data serialization.
Aug 2, 2018
66e48f4
VSVGVQ-106 Merge branch 'master' into feature/VSVGVQ-106
Aug 2, 2018
8ba1238
VSVGVQ-106 add serializers for QuestionAsked
stejes Aug 2, 2018
216ad0e
VSVGVQ-106 add answeredevent serializers (WIP)
stejes Aug 2, 2018
615847d
VSVGVQ-106 Unit test for AnsweredCorrect serializer.
Aug 3, 2018
b9cd7e3
VSVGVQ-106 Unit test for AnsweredIncorrect serializer.
Aug 3, 2018
bbad90a
VSVGVQ-106 Add unit test for EventEntity.
Aug 3, 2018
ce204bd
VSVGVQ-106 Add strict_types declaration.
Aug 3, 2018
4e50759
VSVGVQ-106 Add unit test for id of EventEntity.
Aug 3, 2018
5721301
VSVGVQ-106 Add simple unit test for event store rollback on exception.
Aug 3, 2018
632d3b8
VSVGVQ-106 Inject QuizService in QuizController and wire the service.
Aug 3, 2018
0b6ce86
VSVGVQ-106 Use Doctrine event store.
Aug 6, 2018
1997148
VSVGVQ-106 Add routes and methods for quiz.
Aug 6, 2018
941bb50
VSVGVQ-106 Add route for asking and answering a question.
Aug 6, 2018
bc9b359
VSVGVQ-106 Add unit test for StartQuiz command.
Aug 6, 2018
b30f89c
VSVGVQ-106 Add unit test for prevention of asking or answering same q…
Aug 6, 2018
a90bd9e
VSVGVQ-106 Add unit test for StartQuizSerializer.
Aug 6, 2018
1c982b9
VSVGVQ-106 Add unit test for CurrentQuestionRedisRepository.
Aug 6, 2018
2f1f66e
VSVGVQ-106 Add unit test for QuestionAskedListener.
Aug 6, 2018
cec75f6
VSVGVQ-106 Add unit test for AnswerDoctrineRepository.
Aug 6, 2018
0982de9
VSVGVQ-106 Comply to coding standards.
Aug 6, 2018
b529a04
VSVGVQ-106 Add normalizer and denormalizer for QuizFinished.
Aug 6, 2018
1b05612
VSVGVQ-106 Hotfix: no port binding for Redis
Aug 7, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions bluegreen/docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,4 @@ services:

redis:
image: redis:alpine
ports:
- 63799:6379
restart: always
17 changes: 16 additions & 1 deletion config/routes.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#
# VIEWS
#

accounts_view_register:
path: /{_locale}/view/accounts/register
controller: VSV\GVQ_API\Account\Controllers\AccountViewController::register
Expand Down Expand Up @@ -137,3 +136,19 @@ users_export:
documents_kickoff:
path: /documents/{document}
methods: [GET]

#
# API
#
quiz_start:
path: /quiz
controller: VSV\GVQ_API\Quiz\Controllers\QuizController::start
methods: [POST]
quiz_ask_question:
path: /quiz/{quizId}/question
controller: VSV\GVQ_API\Quiz\Controllers\QuizController::askQuestion
methods: [GET]
quiz_answer_question:
path: /quiz/{quizId}/question/{answerId}
controller: VSV\GVQ_API\Quiz\Controllers\QuizController::answerQuestion
methods: [POST]
93 changes: 93 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ services:
arguments:
- 'Europe/Brussels'

quiz_delay:
class: VSV\GVQ_API\Quiz\ValueObjects\AllowedDelay
arguments:
$value: 40

quiz_year:
class: \VSV\GVQ_API\Question\ValueObjects\Year
arguments:
$value: 2018

quiz_start_date:
class: \DateTimeImmutable
arguments:
Expand All @@ -98,6 +108,80 @@ services:
arguments:
$partnerFile: '%kernel.project_dir%/config/partners.yaml'

redis_service:
class: \Redis
calls:
- method: connect
arguments:
- 'redis'
- 6379

quiz_redis_repository:
class: VSV\GVQ_API\Quiz\Repositories\QuizRedisRepository
arguments:
$redis: '@redis_service'

started_quiz_redis_repository:
class: VSV\GVQ_API\Quiz\Repositories\StartedQuizRedisRepository
arguments:
$redis: '@redis_service'

current_question_redis_repository:
class: VSV\GVQ_API\Quiz\Repositories\CurrentQuestionRedisRepository
arguments:
$redis: '@redis_service'

quiz_started_listener:
class: VSV\GVQ_API\Quiz\EventListeners\QuizStartedListener
arguments:
$quizRepository: '@quiz_redis_repository'
$startedQuizRepository: '@started_quiz_redis_repository'

question_asked_listener:
class: VSV\GVQ_API\Quiz\EventListeners\QuestionAskedListener
arguments:
$currentQuestionRepository: '@current_question_redis_repository'

in_memory_event_store:
class: Broadway\EventStore\InMemoryEventStore

doctrine_event_store:
class: VSV\GVQ_API\Quiz\EventStore\DoctrineEventStore

simple_event_bus:
class: Broadway\EventHandling\SimpleEventBus
calls:
- method: subscribe
arguments:
- '@quiz_started_listener'
- method: subscribe
arguments:
- '@question_asked_listener'

quiz_aggregate_repository:
class: VSV\GVQ_API\Quiz\Repositories\QuizAggregateRepository
arguments:
$eventStore: '@doctrine_event_store'
$eventBus: '@simple_event_bus'

quiz_composition_repository:
class: VSV\GVQ_API\Quiz\Repositories\QuizCompositionYamlRepository
arguments:
$quizCompositionFile: '%kernel.project_dir%/config/quiz_composition.yaml'

team_repository:
class: VSV\GVQ_API\Team\Repositories\TeamYamlRepository
arguments:
$teamFile: '%kernel.project_dir%/config/teams.yaml'

quiz_service:
class: VSV\GVQ_API\Quiz\Service\QuizService
arguments:
$uuidFactory: '@uuid_factory'
$quizCompositionRepository: '@quiz_composition_repository'
$year: '@quiz_year'
$allowedDelay: '@quiz_delay'

### CONTROLLERS ###
VSV\GVQ_API\Account\Controllers\AccountController:
arguments:
Expand Down Expand Up @@ -145,3 +229,12 @@ services:
$imageValidator: '@image_validator'
$uuidFactory: '@uuid_factory'
tags: ['controller.service_arguments']

VSV\GVQ_API\Quiz\Controllers\QuizController:
arguments:
$quizService: '@quiz_service'
$quizAggregateRepository: '@quiz_aggregate_repository'
$partnerRepository: '@partner_yaml_repository'
$teamRepository: '@team_repository'
$currentQuestionRepository: '@current_question_redis_repository'
tags: ['controller.service_arguments']
5 changes: 3 additions & 2 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@
<directory suffix=".php">./src/*</directory>
<exclude>
<file>./src/Kernel.php</file>
<file>./src/Account/Controllers/AccountViewController.php</file>
<file>./src/Account/Forms/RegistrationFormType.php</file>
<file>./src/Command/RedisCommand.php</file>
<file>./src/Company/Controllers/CompanyViewController.php</file>
<file>./src/Company/Forms/CompanyFormType.php</file>
<file>./src/Question/Controllers/QuestionViewController.php</file>
<file>./src/Question/Forms/QuestionFormType.php</file>
<file>./src/Quiz/Controllers/QuizController.php</file>
<file>./src/User/Controllers/UserViewController.php</file>
<file>./src/User/Forms/UserFormType.php</file>
<file>./src/Account/Controllers/AccountViewController.php</file>
<file>./src/Account/Forms/RegistrationFormType.php</file>
</exclude>
</whitelist>
</filter>
Expand Down
34 changes: 34 additions & 0 deletions src/Question/Repositories/AnswerDoctrineRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare(strict_types=1);

namespace VSV\GVQ_API\Question\Repositories;

use Ramsey\Uuid\UuidInterface;
use VSV\GVQ_API\Common\Repositories\AbstractDoctrineRepository;
use VSV\GVQ_API\Question\Models\Answer;
use VSV\GVQ_API\Question\Repositories\Entities\AnswerEntity;

class AnswerDoctrineRepository extends AbstractDoctrineRepository implements AnswerRepository
{
/**
* @inheritdoc
*/
protected function getRepositoryName(): string
{
return AnswerEntity::class;
}

/**
* @inheritdoc
*/
public function getById(UuidInterface $id): ?Answer
{
/** @var AnswerEntity|null $answerEntity */
$answerEntity = $this->objectRepository->findOneBy(
[
'id' => $id,
]
);

return $answerEntity ? $answerEntity->toAnswer() : null;
}
}
15 changes: 15 additions & 0 deletions src/Question/Repositories/AnswerRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php declare(strict_types=1);

namespace VSV\GVQ_API\Question\Repositories;

use Ramsey\Uuid\UuidInterface;
use VSV\GVQ_API\Question\Models\Answer;

interface AnswerRepository
{
/**
* @param UuidInterface $id
* @return null|Answer
*/
public function getById(UuidInterface $id): ?Answer;
}
86 changes: 50 additions & 36 deletions src/Quiz/Aggregate/QuizAggregate.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class QuizAggregate extends EventSourcedAggregateRoot
*/
private $questionAskedOn;

/**
* @var bool
*/
private $askingQuestion;

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -60,20 +65,23 @@ protected function applyQuizStarted(QuizStarted $quizStarted): void
$this->quiz = $quizStarted->getQuiz();

$this->questionIndex = 0;
$this->askingQuestion = false;
}

/**
* @param \DateTimeImmutable $askedOn
*/
public function askQuestion(\DateTimeImmutable $askedOn): void
{
$this->apply(
new QuestionAsked(
$this->quiz->getId(),
$this->getCurrentQuestion(),
$askedOn
)
);
if (!$this->askingQuestion) {
$this->apply(
new QuestionAsked(
$this->quiz->getId(),
$this->getCurrentQuestion(),
$askedOn
)
);
}
}

/**
Expand All @@ -82,6 +90,7 @@ public function askQuestion(\DateTimeImmutable $askedOn): void
protected function applyQuestionAsked(QuestionAsked $questionAsked): void
{
$this->questionAskedOn = $questionAsked->getAskedOn();
$this->askingQuestion = true;
}

/**
Expand All @@ -92,51 +101,56 @@ public function answerQuestion(
\DateTimeImmutable $answeredOn,
Answer $answer
): void {
$currentQuestion = $this->getCurrentQuestion();

if ($this->answeredToLate($this->questionAskedOn, $answeredOn, $this->quiz->getAllowedDelay()) ||
!$this->answeredCorrect($currentQuestion->getAnswers(), $answer)) {
$this->apply(
new AnsweredIncorrect(
$this->quiz->getId(),
$currentQuestion,
$answer,
$answeredOn
)
);
} else {
$this->apply(
new AnsweredCorrect(
$this->quiz->getId(),
$currentQuestion,
$answer,
$answeredOn
)
);
}

if (count($this->quiz->getQuestions()) === $this->questionIndex) {
$this->apply(
new QuizFinished(
$this->quiz->getId()
)
);
if ($this->askingQuestion) {
$currentQuestion = $this->getCurrentQuestion();

if ($this->answeredToLate($this->questionAskedOn, $answeredOn, $this->quiz->getAllowedDelay()) ||
!$this->answeredCorrect($currentQuestion->getAnswers(), $answer)) {
$this->apply(
new AnsweredIncorrect(
$this->quiz->getId(),
$currentQuestion,
$answer,
$answeredOn
)
);
} else {
$this->apply(
new AnsweredCorrect(
$this->quiz->getId(),
$currentQuestion,
$answer,
$answeredOn
)
);
}

if (count($this->quiz->getQuestions()) === $this->questionIndex) {
$this->apply(
new QuizFinished(
$this->quiz->getId()
)
);
}
}
}

protected function applyAnsweredIncorrect(): void
{
$this->questionIndex++;
$this->askingQuestion = false;
}

protected function applyAnsweredCorrect(): void
{
$this->questionIndex++;
$this->askingQuestion = false;
}

protected function applyQuizFinished(): void
{
$this->questionIndex = -1;
$this->askingQuestion = false;
}

/**
Expand Down
Loading