├── .env
├── .env.local.dist
├── .env.test
├── .env.test.local.dist
├── .github
└── workflows
│ ├── staging.yml
│ └── test.yml
├── .gitignore
├── .gitlab-ci.yml
├── .php-cs-fixer.dist.php
├── Makefile
├── README.md
├── bin
├── console
└── phpunit
├── composer.json
├── composer.lock
├── config
├── bundles.php
├── jwt
│ └── .gitkeep
├── packages
│ ├── cache.yaml
│ ├── doctrine.yaml
│ ├── doctrine_migrations.yaml
│ ├── framework.yaml
│ ├── gesdinet_jwt_refresh_token.yaml
│ ├── lexik_jwt_authentication.yaml
│ ├── messenger.yaml
│ ├── routing.yaml
│ └── security.yaml
├── preload.php
├── routes.yaml
├── routes
│ └── framework.yaml
├── services.yaml
└── services_test.yaml
├── deptrac-layers.yaml
├── deptrac-modules.yaml
├── docker
├── .env.dist
├── .gitignore
├── docker-compose.yml
├── php-fpm
│ ├── Dockerfile
│ ├── nginx.conf
│ ├── run.sh
│ ├── supervisord.conf
│ └── xdebug.ini
└── postgres
│ └── Dockerfile
├── docs
├── authorization.md
└── index.md
├── phpstan.neon
├── phpunit.xml.dist
├── public
└── index.php
├── src
├── Shared
│ ├── Application
│ │ ├── Command
│ │ │ ├── Command.php
│ │ │ ├── CommandBusInterface.php
│ │ │ ├── CommandHandlerInterface.php
│ │ │ └── CommandInterface.php
│ │ ├── Event
│ │ │ ├── EventBusInterface.php
│ │ │ └── EventHandlerInterface.php
│ │ ├── Query
│ │ │ ├── Query.php
│ │ │ ├── QueryBusInterface.php
│ │ │ ├── QueryHandlerInterface.php
│ │ │ └── QueryInterface.php
│ │ └── Security
│ │ │ └── AuthChecker.php
│ ├── Domain
│ │ ├── Aggregate
│ │ │ ├── Aggregate.php
│ │ │ └── Id.php
│ │ ├── Event
│ │ │ └── EventInterface.php
│ │ ├── Repository
│ │ │ ├── Pager.php
│ │ │ └── PaginationResult.php
│ │ ├── Security
│ │ │ ├── AuthUserInterface.php
│ │ │ ├── Role.php
│ │ │ └── UserFetcherInterface.php
│ │ ├── Service
│ │ │ ├── AssertService.php
│ │ │ └── UlidService.php
│ │ ├── Specification
│ │ │ └── SpecificationInterface.php
│ │ └── ValueObject
│ │ │ └── GlobalUserId.php
│ └── Infrastructure
│ │ ├── Bus
│ │ ├── CommandBus.php
│ │ ├── EventBus.php
│ │ └── QueryBus.php
│ │ ├── Controller
│ │ ├── .gitignore
│ │ └── HealthCheckAction.php
│ │ ├── Database
│ │ └── Migrations
│ │ │ ├── .gitignore
│ │ │ └── Version20231203205959.php
│ │ ├── EventListener
│ │ ├── Doctrine
│ │ │ ├── InitSpecificationOnPostLoadListener.php
│ │ │ └── PublishDomainEventsOnFlushListener.php
│ │ └── Exception
│ │ │ └── ExceptionListener.php
│ │ ├── Kernel.php
│ │ └── Security
│ │ └── UserFetcher.php
├── Skills
│ ├── Application
│ │ ├── DTO
│ │ │ ├── Skill
│ │ │ │ ├── SkillDTO.php
│ │ │ │ └── SkillDTOTransformer.php
│ │ │ ├── SkillGroup
│ │ │ │ ├── SkillGroupDTO.php
│ │ │ │ └── SkillGroupDTOTransformer.php
│ │ │ └── Speciality
│ │ │ │ ├── SpecialityDTO.php
│ │ │ │ ├── SpecialityDTOTransformer.php
│ │ │ │ ├── SpecialitySkillDTO.php
│ │ │ │ └── SpecialitySkillDTOTransformer.php
│ │ ├── Service
│ │ │ └── AccessControl
│ │ │ │ └── SkillAccessControl.php
│ │ └── UseCase
│ │ │ ├── AdminUseCaseInteractor.php
│ │ │ ├── Command
│ │ │ ├── AddSkillToSpeciality
│ │ │ │ ├── AddSkillToSpecialityCommand.php
│ │ │ │ ├── AddSkillToSpecialityCommandHandler.php
│ │ │ │ └── AddSkillToSpecialityCommandResult.php
│ │ │ ├── ConfirmSpecialistSkill
│ │ │ │ ├── ConfirmSpecialistSkillCommand.php
│ │ │ │ └── ConfirmSpecialistSkillCommandHandler.php
│ │ │ ├── CreateSkill
│ │ │ │ ├── CreateSkillCommand.php
│ │ │ │ ├── CreateSkillCommandHandler.php
│ │ │ │ └── CreateSkillCommandResult.php
│ │ │ ├── CreateSkillGroup
│ │ │ │ ├── CreateSkillGroupCommand.php
│ │ │ │ ├── CreateSkillGroupCommandHandler.php
│ │ │ │ └── CreateSkillGroupCommandResult.php
│ │ │ ├── CreateSpeciality
│ │ │ │ ├── CreateSpecialityCommand.php
│ │ │ │ ├── CreateSpecialityCommandHandler.php
│ │ │ │ └── CreateSpecialityCommandResult.php
│ │ │ ├── DeleteSkill
│ │ │ │ ├── DeleteSkillCommand.php
│ │ │ │ ├── DeleteSkillCommandHandler.php
│ │ │ │ └── DeleteSkillCommandResult.php
│ │ │ ├── DeleteSpeciality
│ │ │ │ ├── DeleteSpecialityCommand.php
│ │ │ │ ├── DeleteSpecialityCommandHandler.php
│ │ │ │ └── DeleteSpecialityCommandResult.php
│ │ │ ├── RemoveSkillFromSpeciality
│ │ │ │ ├── RemoveSkillFromSpecialityCommand.php
│ │ │ │ ├── RemoveSkillFromSpecialityCommandHandler.php
│ │ │ │ └── RemoveSkillFromSpecialityCommandResult.php
│ │ │ ├── UpdateSpeciality
│ │ │ │ ├── UpdateSpecialityCommand.php
│ │ │ │ ├── UpdateSpecialityCommandHandler.php
│ │ │ │ └── UpdateSpecialityCommandResult.php
│ │ │ └── UpdateSpecialityPublicationStatus
│ │ │ │ ├── UpdateSpecialityPublicationStatusCommand.php
│ │ │ │ ├── UpdateSpecialityPublicationStatusCommandHandler.php
│ │ │ │ └── UpdateSpecialityPublicationStatusCommandResult.php
│ │ │ ├── PrivateUseCaseInteractor.php
│ │ │ ├── PublicUseCaseInteractor.php
│ │ │ └── Query
│ │ │ ├── FindMySpeciality
│ │ │ ├── FindMySpecialityQuery.php
│ │ │ ├── FindMySpecialityQueryHandler.php
│ │ │ └── FindMySpecialityQueryResult.php
│ │ │ ├── FindSkill
│ │ │ ├── FindSkillQuery.php
│ │ │ ├── FindSkillQueryHandler.php
│ │ │ └── FindSkillQueryResult.php
│ │ │ ├── FindSkillGroup
│ │ │ ├── FindSkillGroupQuery.php
│ │ │ ├── FindSkillGroupQueryHandler.php
│ │ │ └── FindSkillGroupQueryResult.php
│ │ │ ├── FindSpeciality
│ │ │ ├── FindSpecialityQuery.php
│ │ │ ├── FindSpecialityQueryHandler.php
│ │ │ └── FindSpecialityQueryResult.php
│ │ │ ├── FindSpecialitySkill
│ │ │ ├── FindSpecialitySkillQuery.php
│ │ │ ├── FindSpecialitySkillQueryHandler.php
│ │ │ └── FindSpecialitySkillQueryResult.php
│ │ │ ├── GetMyPagedSpecialities
│ │ │ ├── GetMyPagedSpecialitiesQuery.php
│ │ │ ├── GetMyPagedSpecialitiesQueryHandler.php
│ │ │ └── GetMyPagedSpecialitiesQueryResult.php
│ │ │ ├── GetPagedSkillGroups
│ │ │ ├── GetPagedSkillGroupsQuery.php
│ │ │ ├── GetPagedSkillGroupsQueryHandler.php
│ │ │ └── GetPagedSkillGroupsQueryResult.php
│ │ │ ├── GetPagedSkills
│ │ │ ├── GetPagedSkillsQuery.php
│ │ │ ├── GetPagedSkillsQueryHandler.php
│ │ │ └── GetPagedSkillsQueryResult.php
│ │ │ └── GetPagedSpecialities
│ │ │ ├── GetPagedSpecialitiesQuery.php
│ │ │ ├── GetPagedSpecialitiesQueryHandler.php
│ │ │ └── GetPagedSpecialitiesQueryResult.php
│ ├── Domain
│ │ ├── Aggregate
│ │ │ ├── Skill
│ │ │ │ ├── Skill.php
│ │ │ │ ├── SkillGroup.php
│ │ │ │ └── Specification
│ │ │ │ │ ├── SkillGroupNameSpecification.php
│ │ │ │ │ ├── SkillSpecification.php
│ │ │ │ │ └── UniqueSkillInGroupSpecification.php
│ │ │ ├── SkillConfirmation
│ │ │ │ ├── Level.php
│ │ │ │ ├── Proof.php
│ │ │ │ └── SkillConfirmation.php
│ │ │ ├── Specialist
│ │ │ │ └── Specialist.php
│ │ │ └── Speciality
│ │ │ │ ├── Level.php
│ │ │ │ ├── PublicationStatus.php
│ │ │ │ ├── Speciality.php
│ │ │ │ ├── SpecialitySkill.php
│ │ │ │ └── Specification
│ │ │ │ └── SpecialitySpecification.php
│ │ ├── Factory
│ │ │ ├── SkillConfirmationFactory.php
│ │ │ ├── SkillFactory.php
│ │ │ ├── SkillGroupFactory.php
│ │ │ ├── SpecialistFactory.php
│ │ │ └── SpecialityFactory.php
│ │ ├── Repository
│ │ │ ├── SkillConfirmationRepositoryInterface.php
│ │ │ ├── SkillGroupRepositoryInterface.php
│ │ │ ├── SkillGroupsFilter.php
│ │ │ ├── SkillRepositoryInterface.php
│ │ │ ├── SkillsFilter.php
│ │ │ ├── SpecialistRepositoryInterface.php
│ │ │ ├── SpecialityFilter.php
│ │ │ ├── SpecialityRepositoryInterface.php
│ │ │ └── SpecialitySkillRepositoryInterface.php
│ │ └── Service
│ │ │ ├── SkillConfirmationService.php
│ │ │ ├── SkillFetcher.php
│ │ │ ├── SkillGroupMaker.php
│ │ │ ├── SkillMaker.php
│ │ │ ├── SpecialistMaker.php
│ │ │ ├── SpecialityFetcher.php
│ │ │ ├── SpecialityMaker.php
│ │ │ └── SpecialitySkillOrganizer.php
│ └── Infrastructure
│ │ ├── Api
│ │ └── SkillsApi.php
│ │ ├── Console
│ │ └── TestCommand.php
│ │ ├── Database
│ │ └── ORM
│ │ │ └── Aggregate
│ │ │ ├── Skill.Skill.orm.xml
│ │ │ ├── Skill.SkillGroup.orm.xml
│ │ │ ├── SkillConfirmation.Proof.orm.xml
│ │ │ ├── SkillConfirmation.SkillConfirmation.orm.xml
│ │ │ ├── Specialist.Specialist.orm.xml
│ │ │ ├── Speciality.Speciality.orm.xml
│ │ │ └── Speciality.SpecialitySkill.orm.xml
│ │ └── Repository
│ │ ├── SkillConfirmationRepository.php
│ │ ├── SkillGroupRepository.php
│ │ ├── SkillRepository.php
│ │ ├── SpecialistRepository.php
│ │ ├── SpecialityRepository.php
│ │ └── SpecialitySkillRepository.php
├── Testing
│ ├── Application
│ │ ├── Command
│ │ │ ├── CreateAnswerOption
│ │ │ │ ├── CreateAnswerOptionCommand.php
│ │ │ │ └── CreateAnswerOptionCommandHandler.php
│ │ │ ├── CreateQuestion
│ │ │ │ ├── CreateQuestionCommand.php
│ │ │ │ └── CreateQuestionCommandHandler.php
│ │ │ ├── CreateTest
│ │ │ │ ├── CreateTestCommand.php
│ │ │ │ └── CreateTestCommandHandler.php
│ │ │ └── CreateTestingSession
│ │ │ │ └── CreateTestingSessionCommand.php
│ │ ├── CommandInteractor.php
│ │ ├── Query
│ │ │ ├── DTO
│ │ │ │ ├── Test
│ │ │ │ │ ├── AnswerOptionDTO.php
│ │ │ │ │ ├── QuestionDTO.php
│ │ │ │ │ └── TestDTO.php
│ │ │ │ └── TestingSessionDTO.php
│ │ │ ├── FindAnswerOption
│ │ │ │ ├── FindAnswerOptionQuery.php
│ │ │ │ ├── FindAnswerOptionQueryHandler.php
│ │ │ │ └── FindAnswerOptionQueryResult.php
│ │ │ ├── FindQuestion
│ │ │ │ ├── FindQuestionQuery.php
│ │ │ │ ├── FindQuestionQueryHandler.php
│ │ │ │ └── FindQuestionQueryResult.php
│ │ │ ├── FindTest
│ │ │ │ ├── FindTestQuery.php
│ │ │ │ ├── FindTestQueryHandler.php
│ │ │ │ └── FindTestQueryResult.php
│ │ │ └── FindTestingSession
│ │ │ │ ├── FindTestingSessionQuery.php
│ │ │ │ ├── FindTestingSessionQueryHandler.php
│ │ │ │ └── FindTestingSessionQueryResult.php
│ │ └── QueryInteractor.php
│ ├── Domain
│ │ ├── Aggregate
│ │ │ ├── Test
│ │ │ │ ├── AnswerOption.php
│ │ │ │ ├── DifficultyLevel.php
│ │ │ │ ├── Question.php
│ │ │ │ ├── QuestionType.php
│ │ │ │ └── Test.php
│ │ │ └── TestingSession
│ │ │ │ ├── TestingSession.php
│ │ │ │ └── UserAnswer.php
│ │ ├── Event
│ │ │ └── TestingSessionCompletedEvent.php
│ │ ├── Factory
│ │ │ ├── AnswerOptionFactory.php
│ │ │ ├── QuestionFactory.php
│ │ │ ├── TestFactory.php
│ │ │ └── TestingSessionFactory.php
│ │ ├── Repository
│ │ │ ├── AnswerOptionRepositoryInterface.php
│ │ │ ├── QuestionRepositoryInterface.php
│ │ │ ├── TestRepositoryInterface.php
│ │ │ └── TestingSessionRepositoryInterface.php
│ │ ├── Service
│ │ │ └── TestingSessionMaker.php
│ │ └── Specification
│ │ │ ├── TestSpecification.php
│ │ │ └── UniqueTestNameSpecification.php
│ └── Infrastructure
│ │ ├── Adapter
│ │ ├── SkillsAdapter.php
│ │ └── SkillsApiInterface.php
│ │ ├── Database
│ │ └── ORM
│ │ │ └── Aggregate
│ │ │ ├── Test.AnswerOption.orm.xml
│ │ │ ├── Test.Question.orm.xml
│ │ │ ├── Test.Test.orm.xml
│ │ │ ├── TestingSession.TestingSession.orm.xml
│ │ │ └── TestingSession.UserAnswer.orm.xml
│ │ ├── EventHandler
│ │ └── TestingSessionCompletedEventHandler.php
│ │ └── Repository
│ │ ├── AnswerOptionRepository.php
│ │ ├── QuestionRepository.php
│ │ ├── TestRepository.php
│ │ └── TestingSessionRepository.php
└── Users
│ ├── Application
│ ├── DTO
│ │ └── UserDTO.php
│ └── UseCase
│ │ ├── AdminUseCaseInteractor.php
│ │ ├── Command
│ │ └── CreateUser
│ │ │ ├── CreateUserCommand.php
│ │ │ └── CreateUserCommandHandler.php
│ │ ├── PrivateUseCaseInteractor.php
│ │ ├── PublicUseCaseInteractor.php
│ │ └── Query
│ │ ├── FindUser
│ │ ├── FindUserQuery.php
│ │ ├── FindUserQueryHandler.php
│ │ └── FindUserQueryResult.php
│ │ ├── FindUserByEmail
│ │ ├── FindUserByEmailQuery.php
│ │ └── FindUserByEmailQueryHandler.php
│ │ └── GetMe
│ │ ├── GetMeQuery.php
│ │ ├── GetMeQueryHandler.php
│ │ └── GetMeQueryResult.php
│ ├── Domain
│ ├── Entity
│ │ ├── RefreshToken.php
│ │ └── User.php
│ ├── Factory
│ │ └── UserFactory.php
│ ├── Repository
│ │ └── UserRepositoryInterface.php
│ └── Service
│ │ └── UserPasswordHasherInterface.php
│ └── Infrastructure
│ ├── Console
│ └── CreateUserConsoleCommand.php
│ ├── Controller
│ └── GetMeAction.php
│ ├── Database
│ └── ORM
│ │ ├── RefreshToken.orm.xml
│ │ └── User.orm.xml
│ ├── Repository
│ └── UserRepository.php
│ └── UserPasswordHasher.php
├── symfony.lock
└── tests
├── Functional
├── Api
│ ├── ApiTestCase.php
│ └── AuthApiTestCase.php
├── Shared
│ └── Infrastructure
│ │ └── Controller
│ │ └── HealthCheckActionTest.php
├── Skills
│ └── Infrastructure
│ │ └── Repository
│ │ └── SkillGroupRepositoryTest.php
├── Testing
│ └── Domain
│ │ └── Entity
│ │ └── TestingSession
│ │ └── TestingSessionCompletionTest.php
└── Users
│ ├── Application
│ ├── Command
│ │ └── CreateUser
│ │ │ └── CreateUserCommandHandlerTest.php
│ └── Query
│ │ └── FindUserByEmail
│ │ └── FindUserByEmailQueryHandlerTest.php
│ └── Infrastructure
│ └── Repository
│ └── UserRepositoryTest.php
├── Resource
└── Fixture
│ ├── Skills
│ ├── SkillFixture.php
│ └── SkillGroupFixture.php
│ └── Users
│ └── UserFixture.php
├── Tools
├── DITools.php
├── FakerTools.php
└── FixtureTools.php
└── bootstrap.php
/.env:
--------------------------------------------------------------------------------
1 | #APP_ENV=prod
2 | #APP_SECRET=4dc864551c62905089314503222dccc748
3 |
4 | DB_HOST=
5 | DB_NAME=
6 | DB_USER=
7 | DB_PASSWORD=
8 | DB_PORT=
9 |
10 | #JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
11 | #JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
12 | JWT_SECRET_KEY=# Required base64 encoded Private Key
13 | JWT_PUBLIC_KEY=# Required base64 encoded Public Key
14 | JWT_TOKEN_TTL=3600
15 | JWT_PASSPHRASE=# Required
16 |
--------------------------------------------------------------------------------
/.env.test.local.dist:
--------------------------------------------------------------------------------
1 | DB_HOST=postgres
2 | DB_NAME=symfony
3 | DB_USER=symfony
4 | DB_PASSWORD=symfony
5 | DB_PORT=5432
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 |
3 | ###> symfony/framework-bundle ###
4 | /.env.local
5 | /.env.local.php
6 | /.env.*.local
7 | /config/secrets/prod/prod.decrypt.private.php
8 | /public/bundles/
9 | /var/
10 | /vendor/
11 | ###< symfony/framework-bundle ###
12 |
13 | ###> symfony/phpunit-bridge ###
14 | .phpunit.result.cache
15 | /phpunit.xml
16 | ###< symfony/phpunit-bridge ###
17 | ###> lexik/jwt-authentication-bundle ###
18 | /config/jwt/*.pem
19 | ###< lexik/jwt-authentication-bundle ###
20 |
21 | ###> friendsofphp/php-cs-fixer ###
22 | /.php-cs-fixer.php
23 | /.php-cs-fixer.cache
24 | ###< friendsofphp/php-cs-fixer ###
25 |
26 | .deptrac.cache
27 |
--------------------------------------------------------------------------------
/.php-cs-fixer.dist.php:
--------------------------------------------------------------------------------
1 | in(__DIR__)
5 | ->exclude(['var', 'vendor']);
6 |
7 | return (new PhpCsFixer\Config())
8 | ->setRules([
9 | '@Symfony' => true,
10 | 'php_unit_method_casing' => ['case' => 'snake_case'],
11 | ])
12 | ->setFinder($finder);
13 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | ['all' => true],
5 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
6 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
7 | Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
8 | Liip\TestFixturesBundle\LiipTestFixturesBundle::class => ['dev' => true, 'test' => true],
9 | DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['dev' => true, 'test' => true],
10 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
11 | Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
12 | Gesdinet\JWTRefreshTokenBundle\GesdinetJWTRefreshTokenBundle::class => ['all' => true],
13 | ];
14 |
--------------------------------------------------------------------------------
/config/jwt/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alejandro-yakovlev/symfony-docker/962cd7c94de822b37464eafbc493f0ea96423c02/config/jwt/.gitkeep
--------------------------------------------------------------------------------
/config/packages/cache.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | cache:
3 | # Unique name of your app: used to compute stable namespaces for cache keys.
4 | #prefix_seed: your_vendor_name/app_name
5 |
6 | # The "app" cache stores to the filesystem by default.
7 | # The data in this cache should persist between deploys.
8 | # Other options include:
9 |
10 | # Redis
11 | #app: cache.adapter.redis
12 | #default_redis_provider: redis://localhost
13 |
14 | # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
15 | #app: cache.adapter.apcu
16 |
17 | # Namespaced pools use the above "app" backend by default
18 | #pools:
19 | #my.dedicated.cache: null
20 |
--------------------------------------------------------------------------------
/config/packages/doctrine_migrations.yaml:
--------------------------------------------------------------------------------
1 | doctrine_migrations:
2 | migrations_paths:
3 | # namespace is arbitrary but should be different from App\Migrations
4 | # as Migrations classes should NOT be autoloaded
5 | 'App\Shared\Infrastructure\Database\Migrations': '%kernel.project_dir%/src/Shared/Infrastructure/Database/Migrations'
6 | enable_profiler: '%kernel.debug%'
7 |
--------------------------------------------------------------------------------
/config/packages/framework.yaml:
--------------------------------------------------------------------------------
1 | # see https://symfony.com/doc/current/reference/configuration/framework.html
2 | framework:
3 | secret: '%env(APP_SECRET)%'
4 | #csrf_protection: true
5 | http_method_override: false
6 |
7 | # Enables session support. Note that the session will ONLY be started if you read or write from it.
8 | # Remove or comment this section to explicitly disable session support.
9 | session:
10 | handler_id: null
11 | cookie_secure: auto
12 | cookie_samesite: lax
13 | storage_factory_id: session.storage.factory.native
14 |
15 | #esi: true
16 | #fragments: true
17 | php_errors:
18 | log: true
19 |
20 | when@test:
21 | framework:
22 | test: true
23 | session:
24 | storage_factory_id: session.storage.factory.mock_file
25 |
--------------------------------------------------------------------------------
/config/packages/gesdinet_jwt_refresh_token.yaml:
--------------------------------------------------------------------------------
1 | gesdinet_jwt_refresh_token:
2 | ttl: 2592000 # 30 days
3 | token_parameter_name: refreshToken
4 | refresh_token_class: App\Users\Domain\Entity\RefreshToken
--------------------------------------------------------------------------------
/config/packages/lexik_jwt_authentication.yaml:
--------------------------------------------------------------------------------
1 | lexik_jwt_authentication:
2 | # secret_key: '%env(resolve:JWT_SECRET_KEY)%'
3 | # public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
4 | secret_key: '%env(base64:JWT_SECRET_KEY)%'
5 | public_key: '%env(base64:JWT_PUBLIC_KEY)%'
6 | pass_phrase: '%env(JWT_PASSPHRASE)%'
7 | token_ttl: '%env(resolve:JWT_TOKEN_TTL)%'
8 | user_identity_field: email
--------------------------------------------------------------------------------
/config/packages/messenger.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | messenger:
3 | default_bus: command.bus
4 | buses:
5 | command.bus:
6 | middleware:
7 | - doctrine_transaction
8 | query.bus:
9 | event.bus:
10 | default_middleware: allow_no_handlers
11 |
12 | # Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
13 | # failure_transport: failed
14 |
15 | transports:
16 | # https://symfony.com/doc/current/messenger.html#transport-configuration
17 | # async: '%env(MESSENGER_TRANSPORT_DSN)%'
18 | # failed: 'doctrine://default?queue_name=failed'
19 | # sync: 'sync://'
20 |
21 | routing:
22 | # Route your messages to the transports
23 | # 'App\Message\YourMessage': async
24 |
--------------------------------------------------------------------------------
/config/packages/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | utf8: true
4 |
5 | # Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
6 | # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
7 | #default_uri: http://localhost
8 |
9 | when@prod:
10 | framework:
11 | router:
12 | strict_requirements: null
13 |
--------------------------------------------------------------------------------
/config/preload.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | tests
23 |
24 |
25 |
26 |
27 |
28 | src
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | authorizationChecker->isGranted($attribute, $subject);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Shared/Domain/Aggregate/Aggregate.php:
--------------------------------------------------------------------------------
1 | events;
24 | $this->events = [];
25 |
26 | return $events;
27 | }
28 |
29 | public function eventsEmpty(): bool
30 | {
31 | return empty($this->events);
32 | }
33 |
34 | protected function raise(EventInterface $event): void
35 | {
36 | $this->events[] = $event;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Shared/Domain/Aggregate/Id.php:
--------------------------------------------------------------------------------
1 | page) {
24 | return 0;
25 | }
26 |
27 | return $this->page * $this->perPage - $this->perPage;
28 | }
29 |
30 | public function getLimit(): int
31 | {
32 | return $this->perPage;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Shared/Domain/Repository/PaginationResult.php:
--------------------------------------------------------------------------------
1 | id = $id;
16 | }
17 |
18 | public function getId(): string
19 | {
20 | return $this->id;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Shared/Infrastructure/Bus/CommandBus.php:
--------------------------------------------------------------------------------
1 | messageBus = $commandBus;
20 | }
21 |
22 | public function execute(CommandInterface $command): mixed
23 | {
24 | try {
25 | return $this->handle($command);
26 | } catch (HandlerFailedException $exception) {
27 | throw $exception->getNestedExceptions()[0];
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Shared/Infrastructure/Bus/EventBus.php:
--------------------------------------------------------------------------------
1 | messageBus = $eventBus;
19 | }
20 |
21 | public function execute(EventInterface ...$events): void
22 | {
23 | foreach ($events as $event) {
24 | $this->messageBus->dispatch($event);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Shared/Infrastructure/Bus/QueryBus.php:
--------------------------------------------------------------------------------
1 | messageBus = $queryBus;
20 | }
21 |
22 | public function execute(QueryInterface $query): mixed
23 | {
24 | try {
25 | return $this->handle($query);
26 | } catch (HandlerFailedException $exception) {
27 | throw $exception->getNestedExceptions()[0];
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Shared/Infrastructure/Controller/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alejandro-yakovlev/symfony-docker/962cd7c94de822b37464eafbc493f0ea96423c02/src/Shared/Infrastructure/Controller/.gitignore
--------------------------------------------------------------------------------
/src/Shared/Infrastructure/Controller/HealthCheckAction.php:
--------------------------------------------------------------------------------
1 | 'ok']);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Shared/Infrastructure/Database/Migrations/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alejandro-yakovlev/symfony-docker/962cd7c94de822b37464eafbc493f0ea96423c02/src/Shared/Infrastructure/Database/Migrations/.gitignore
--------------------------------------------------------------------------------
/src/Shared/Infrastructure/EventListener/Doctrine/InitSpecificationOnPostLoadListener.php:
--------------------------------------------------------------------------------
1 | getObject();
23 |
24 | $reflect = new \ReflectionClass($entity);
25 |
26 | foreach ($reflect->getProperties() as $property) {
27 | $type = $property->getType();
28 |
29 | if (is_null($type) || $property->isInitialized($entity)) {
30 | continue;
31 | }
32 |
33 | if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
34 | // initialize specifications
35 | $interfaces = class_implements($type->getName());
36 | if (isset($interfaces[SpecificationInterface::class])) {
37 | $property->setValue($entity, $this->container->get($type->getName()));
38 | }
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Shared/Infrastructure/Kernel.php:
--------------------------------------------------------------------------------
1 | security->getUser();
23 |
24 | if (is_null($user)) {
25 | throw new AccessDeniedException('Access Denied.');
26 | }
27 |
28 | Assert::isInstanceOf($user, AuthUserInterface::class, sprintf('Invalid user type %s', \get_class($user)));
29 |
30 | return $user;
31 | }
32 |
33 | public function nullableUser(): ?AuthUserInterface
34 | {
35 | /** @var AuthUserInterface|null $user */
36 | $user = $this->security->getUser();
37 |
38 | return $user;
39 | }
40 |
41 | public function requiredUserId(): string
42 | {
43 | return $this->requiredUser()->getId();
44 | }
45 |
46 | public function nullableUserId(): ?string
47 | {
48 | return $this->nullableUser()?->getId();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Skills/Application/DTO/Skill/SkillDTO.php:
--------------------------------------------------------------------------------
1 | fromSkillEntity($entity);
23 | }
24 |
25 | return $skills;
26 | }
27 |
28 | public function fromSkillEntity(Skill $skill): SkillDTO
29 | {
30 | $dto = new SkillDTO();
31 | $dto->id = $skill->getId();
32 | $dto->name = $skill->getName();
33 |
34 | $skillGroup = new SkillGroupDTO();
35 | $skillGroup->id = $skill->getSkillGroup()->getId();
36 | $skillGroup->name = $skill->getSkillGroup()->getName();
37 | $dto->skillGroup = $skillGroup;
38 |
39 | return $dto;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Skills/Application/DTO/SkillGroup/SkillGroupDTO.php:
--------------------------------------------------------------------------------
1 | id = $entity->getId();
15 | $dto->name = $entity->getName();
16 |
17 | return $dto;
18 | }
19 |
20 | /**
21 | * @param array $skillGroups
22 | *
23 | * @return array
24 | */
25 | public function fromEntityList(array $skillGroups): array
26 | {
27 | $skillGroupDTOs = [];
28 | foreach ($skillGroups as $skillGroup) {
29 | $skillGroupDTOs[] = $this->fromEntity($skillGroup);
30 | }
31 |
32 | return $skillGroupDTOs;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Skills/Application/DTO/Speciality/SpecialityDTO.php:
--------------------------------------------------------------------------------
1 | getSkills()->toArray() as $skill) {
19 | $skills[] = $this->specialitySkillDTOTransformer->fromEntity($skill);
20 | }
21 |
22 | return new SpecialityDTO(
23 | id: $speciality->getId(),
24 | name: $speciality->getName(),
25 | description: $speciality->getDescription(),
26 | publicationStatus: $speciality->getPublicationStatus()->value,
27 | skills: $skills
28 | );
29 | }
30 |
31 | /**
32 | * @param Speciality[] $specialities
33 | *
34 | * @return SpecialityDTO[]
35 | */
36 | public function fromEntities(array $specialities): array
37 | {
38 | $specialitiesDTO = [];
39 | foreach ($specialities as $speciality) {
40 | $specialitiesDTO[] = $this->fromEntity($speciality);
41 | }
42 |
43 | return $specialitiesDTO;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Skills/Application/DTO/Speciality/SpecialitySkillDTO.php:
--------------------------------------------------------------------------------
1 | skillDTOTransformer->fromSkillEntity($specialitySkill->getSkill());
20 |
21 | return new SpecialitySkillDTO(
22 | id: $specialitySkill->getId(),
23 | specialityId: $specialitySkill->getId(),
24 | skill: $skillDTO,
25 | level: $specialitySkill->getLevel()->value,
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Skills/Application/Service/AccessControl/SkillAccessControl.php:
--------------------------------------------------------------------------------
1 | isAdmin()) {
30 | return true;
31 | }
32 |
33 | $skill = $this->skillFetcher->getRequiredSkill($skillId);
34 |
35 | return $skill->isOwnedBy($userId);
36 | }
37 |
38 | /**
39 | * Может ли пользователь добавить навык в специальность?
40 | */
41 | public function canAddSkillToSpeciality(string $userId, string $skillId, string $specialityId): bool
42 | {
43 | if ($this->isAdmin()) {
44 | return true;
45 | }
46 |
47 | $skill = $this->skillFetcher->getRequiredSkill($skillId);
48 | $speciality = $this->specialityFetcher->getRequiredSpeciality($specialityId);
49 |
50 | // Пользователь может добавить навык в специальность, если он является владельцем навыка и специальности
51 | return $skill->isOwnedBy($userId) && $speciality->isOwnedBy($userId);
52 | }
53 |
54 | private function isAdmin(): bool
55 | {
56 | return $this->authChecker->isGranted(Role::ROLE_ADMIN);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/AdminUseCaseInteractor.php:
--------------------------------------------------------------------------------
1 | commandBus->execute($command);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Command/AddSkillToSpeciality/AddSkillToSpecialityCommand.php:
--------------------------------------------------------------------------------
1 | skillAccessControl
26 | ->canAddSkillToSpeciality(
27 | $this->userFetcher->requiredUserId(),
28 | $command->skillId,
29 | $command->specialityId
30 | ),
31 | 'Запрещено'
32 | );
33 |
34 | $specialitySkill = $this->specialitySkillOrganizer->addSkillToSpeciality(
35 | $command->skillId,
36 | $command->specialityId,
37 | $command->level
38 | );
39 |
40 | return new AddSkillToSpecialityCommandResult($specialitySkill->getId());
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Command/AddSkillToSpeciality/AddSkillToSpecialityCommandResult.php:
--------------------------------------------------------------------------------
1 | skillConfirmationService->confirm($command->userId, $command->skillId, $command->testId, $command->correctAnswersPercentage);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Command/CreateSkill/CreateSkillCommand.php:
--------------------------------------------------------------------------------
1 | skillMaker->make(
22 | $command->name,
23 | $command->skillGroupId,
24 | $this->userFetcher->requiredUser()->getId()
25 | );
26 |
27 | return new CreateSkillCommandResult($skill->getId());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Command/CreateSkill/CreateSkillCommandResult.php:
--------------------------------------------------------------------------------
1 | skillGroupMaker->make(
22 | $command->name,
23 | $this->userFetcher->requiredUser()->getId()
24 | );
25 |
26 | return new CreateSkillGroupCommandResult($skillGroup->getId());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Command/CreateSkillGroup/CreateSkillGroupCommandResult.php:
--------------------------------------------------------------------------------
1 | userFetcher->requiredUser()->getId();
22 | $speciality = $this->specialityMaker->make($command->name, $ownerId);
23 |
24 | return new CreateSpecialityCommandResult($speciality->getId());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Command/CreateSpeciality/CreateSpecialityCommandResult.php:
--------------------------------------------------------------------------------
1 | skillAccessControl
28 | ->canDeleteSkill($this->userFetcher->requiredUserId(), $command->skillId),
29 | 'Запрещено'
30 | );
31 |
32 | $skill = $this->skillFetcher->getRequiredSkill($command->skillId);
33 | $this->skillRepository->delete($skill);
34 |
35 | return new DeleteSkillCommandResult();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Command/DeleteSkill/DeleteSkillCommandResult.php:
--------------------------------------------------------------------------------
1 | specialityFetcher->getRequiredSpeciality($command->specialityId);
22 | $speciality->delete();
23 | $this->specialityRepository->add($speciality);
24 |
25 | return new DeleteSpecialityCommandResult();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Command/DeleteSpeciality/DeleteSpecialityCommandResult.php:
--------------------------------------------------------------------------------
1 | specialitySkillRepository->findOne($command->specialitySkillId);
19 | $this->specialitySkillRepository->remove($specialitySkill);
20 |
21 | return new RemoveSkillFromSpecialityCommandResult();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Command/RemoveSkillFromSpeciality/RemoveSkillFromSpecialityCommandResult.php:
--------------------------------------------------------------------------------
1 | queryBus->execute($query);
29 | }
30 |
31 | public function getPagedSkillGroups(SkillGroupsFilter $filter): GetPagedSkillGroupsQueryResult
32 | {
33 | $query = new GetPagedSkillGroupsQuery($filter);
34 |
35 | return $this->queryBus->execute($query);
36 | }
37 |
38 | public function getPagedSpecialities(SpecialityFilter $filter): GetPagedSpecialitiesQueryResult
39 | {
40 | $query = new GetPagedSpecialitiesQuery($filter);
41 |
42 | return $this->queryBus->execute($query);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/FindMySpeciality/FindMySpecialityQuery.php:
--------------------------------------------------------------------------------
1 | specialityRepository->findOne(
24 | new SpecialityFilter(
25 | publicationStatuses: [
26 | PublicationStatus::PUBLISHED->value,
27 | PublicationStatus::DRAFT->value,
28 | ],
29 | id: $query->id
30 | )
31 | );
32 |
33 | if (!$speciality) {
34 | return new FindMySpecialityQueryResult(null);
35 | }
36 |
37 | $specialityDTO = $this->specialityDTOTransformer->fromEntity($speciality);
38 |
39 | return new FindMySpecialityQueryResult($specialityDTO);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/FindMySpeciality/FindMySpecialityQueryResult.php:
--------------------------------------------------------------------------------
1 | skillRepository->findOneById($query->id);
22 |
23 | if (!$skill) {
24 | return new FindSkillQueryResult(null);
25 | }
26 |
27 | $dto = $this->skillDTOHydrator->fromSkillEntity($skill);
28 |
29 | return new FindSkillQueryResult($dto);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/FindSkill/FindSkillQueryResult.php:
--------------------------------------------------------------------------------
1 | skillGroupRepository->findOneById($query->id);
22 |
23 | if (!$skillGroup) {
24 | return new FindSkillGroupQueryResult(null);
25 | }
26 |
27 | return new FindSkillGroupQueryResult(
28 | $this->skillGroupDTOHydrator->fromEntity($skillGroup)
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/FindSkillGroup/FindSkillGroupQueryResult.php:
--------------------------------------------------------------------------------
1 | specialityRepository->findOne(
24 | new SpecialityFilter(
25 | publicationStatuses: [PublicationStatus::PUBLISHED->value],
26 | id: $query->id
27 | )
28 | );
29 |
30 | if (!$speciality) {
31 | return new FindSpecialityQueryResult(null);
32 | }
33 |
34 | $specialityDTO = $this->specialityDTOTransformer->fromEntity($speciality);
35 |
36 | return new FindSpecialityQueryResult($specialityDTO);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/FindSpeciality/FindSpecialityQueryResult.php:
--------------------------------------------------------------------------------
1 | specialitySkillRepository->findOne($query->id);
22 | $specialitySkillDTO = $this->specialitySkillDTOTransformer->fromEntity($specialitySkill);
23 |
24 | return new FindSpecialitySkillQueryResult($specialitySkillDTO);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/FindSpecialitySkill/FindSpecialitySkillQueryResult.php:
--------------------------------------------------------------------------------
1 | specialitySkill);
18 |
19 | return $this;
20 | }
21 |
22 | public function onError(callable $callback): self
23 | {
24 | $callback($this->specialitySkill);
25 |
26 | return $this;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/GetMyPagedSpecialities/GetMyPagedSpecialitiesQuery.php:
--------------------------------------------------------------------------------
1 | filter->ownerId = $this->userFetcher->requiredUser()->getId();
27 |
28 | // Доступны только опубликованные специальности и черновики
29 | $query->filter->publicationStatuses = [
30 | PublicationStatus::PUBLISHED->value,
31 | PublicationStatus::DRAFT->value,
32 | ];
33 |
34 | $pagination = $this->specialityRepository->findPagedItems($query->filter);
35 | $specialities = $this->specialityDTOHydrator->fromEntities($pagination->items);
36 |
37 | return new GetMyPagedSpecialitiesQueryResult(
38 | $specialities,
39 | new Pager(
40 | $query->filter->pager->page,
41 | $query->filter->pager->perPage,
42 | $pagination->total
43 | )
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/GetMyPagedSpecialities/GetMyPagedSpecialitiesQueryResult.php:
--------------------------------------------------------------------------------
1 | skillGroupRepository->findByFilter($query->filter);
23 | $skillGroups = $this->skillGroupDTOHydrator->fromEntityList($paginator->items);
24 | $pager = new Pager(
25 | $query->filter->pager->page,
26 | $query->filter->pager->perPage,
27 | $paginator->total
28 | );
29 |
30 | return new GetPagedSkillGroupsQueryResult($skillGroups, $pager);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/GetPagedSkillGroups/GetPagedSkillGroupsQueryResult.php:
--------------------------------------------------------------------------------
1 | pager);
24 | $paginator = $this->skillRepository->findByFilter($filter);
25 | $pager = new Pager($query->pager->page, $query->pager->perPage, $paginator->total);
26 |
27 | $skills = $this->skillDTOHydrator->fromSkillEntityList($paginator->items);
28 |
29 | return new GetPagedSkillsQueryResult($skills, $pager);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/GetPagedSkills/GetPagedSkillsQueryResult.php:
--------------------------------------------------------------------------------
1 | filter->publicationStatuses = [
25 | PublicationStatus::PUBLISHED->value,
26 | ];
27 |
28 | $pagination = $this->specialityRepository->findPagedItems($query->filter);
29 | $specialities = $this->specialityDTOHydrator->fromEntities($pagination->items);
30 |
31 | return new GetPagedSpecialitiesQueryResult(
32 | $specialities,
33 | new Pager(
34 | $query->filter->pager->page,
35 | $query->filter->pager->perPage,
36 | $pagination->total
37 | )
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Skills/Application/UseCase/Query/GetPagedSpecialities/GetPagedSpecialitiesQueryResult.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | private Collection $skills;
28 |
29 | private SkillGroupNameSpecification $skillGroupNameSpecification;
30 | private string $ownerId;
31 |
32 | public function __construct(
33 | string $name,
34 | string $ownerId,
35 | SkillGroupNameSpecification $skillGroupNameSpecification
36 | ) {
37 | $this->skillGroupNameSpecification = $skillGroupNameSpecification;
38 | $this->id = Id::makeUlid();
39 | $this->skills = new ArrayCollection();
40 | $this->setName($name);
41 | $this->ownerId = $ownerId;
42 | }
43 |
44 | public function setName(string $name): void
45 | {
46 | $this->name = $name;
47 | $this->skillGroupNameSpecification->satisfy($this);
48 | }
49 |
50 | public function getName(): string
51 | {
52 | return $this->name;
53 | }
54 |
55 | public function getId(): string
56 | {
57 | return $this->id;
58 | }
59 |
60 | /**
61 | * @return Collection
62 | */
63 | public function getSkills(): Collection
64 | {
65 | return $this->skills;
66 | }
67 |
68 | public function getOwnerId(): string
69 | {
70 | return $this->ownerId;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Aggregate/Skill/Specification/SkillGroupNameSpecification.php:
--------------------------------------------------------------------------------
1 | getName(), 2, 100);
20 | AssertService::true(
21 | empty($this->skillGroupRepository->findOneByName($skillGroup->getName())),
22 | 'Название группы должно быть уникальным'
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Aggregate/Skill/Specification/SkillSpecification.php:
--------------------------------------------------------------------------------
1 | skillRepository->findByName($skill->getName()) as $foundSkill) {
19 | if ($skill->getId() === $foundSkill->getId()) {
20 | continue;
21 | }
22 |
23 | AssertService::notEq(
24 | $skill->getSkillGroup(),
25 | $foundSkill->getSkillGroup(),
26 | 'Навык с таким названием уже имеется в группе'
27 | );
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Aggregate/SkillConfirmation/Level.php:
--------------------------------------------------------------------------------
1 | id = Id::makeUlid();
21 | $this->testId = $testId;
22 | $this->skillConfirmation = $skillConfirmation;
23 | }
24 |
25 | public function getId(): string
26 | {
27 | return $this->id;
28 | }
29 |
30 | public function getTestId(): string
31 | {
32 | return $this->testId;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Aggregate/Specialist/Specialist.php:
--------------------------------------------------------------------------------
1 |
23 | */
24 | private Collection $specialties;
25 |
26 | public function __construct(string $publicUserId)
27 | {
28 | $this->id = Id::makeUlid();
29 | $this->specialties = new ArrayCollection();
30 | $this->publicUserId = $publicUserId;
31 | }
32 |
33 | public function addSpeciality(Speciality $speciality): void
34 | {
35 | if (!$this->specialties->contains($speciality)) {
36 | $this->specialties->add($speciality);
37 | }
38 | }
39 |
40 | public function getId(): string
41 | {
42 | return $this->id;
43 | }
44 |
45 | public function getPublicUserId(): ?string
46 | {
47 | return $this->publicUserId;
48 | }
49 |
50 | public function getSpecialties(): Collection
51 | {
52 | return $this->specialties;
53 | }
54 |
55 | public function setPublicUserId(?string $publicUserId): void
56 | {
57 | $this->publicUserId = $publicUserId;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Aggregate/Speciality/Level.php:
--------------------------------------------------------------------------------
1 | value === $publicationStatus->value;
20 | }
21 |
22 | public function isDraft(): bool
23 | {
24 | return $this->equals(self::DRAFT);
25 | }
26 |
27 | public function isPublished(): bool
28 | {
29 | return $this->equals(self::PUBLISHED);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Aggregate/Speciality/SpecialitySkill.php:
--------------------------------------------------------------------------------
1 | id = Id::makeUlid();
23 | $this->speciality = $specialist;
24 | $this->skill = $skill;
25 | $this->level = $level;
26 | }
27 |
28 | public function setLevel(Level $level): void
29 | {
30 | $this->level = $level;
31 | }
32 |
33 | public function getId(): string
34 | {
35 | return $this->id;
36 | }
37 |
38 | public function getSpeciality(): Speciality
39 | {
40 | return $this->speciality;
41 | }
42 |
43 | public function getSkill(): Skill
44 | {
45 | return $this->skill;
46 | }
47 |
48 | public function getLevel(): Level
49 | {
50 | return $this->level;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Aggregate/Speciality/Specification/SpecialitySpecification.php:
--------------------------------------------------------------------------------
1 | skillSpecification);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Factory/SkillGroupFactory.php:
--------------------------------------------------------------------------------
1 | skillGroupNameSpecification
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Factory/SpecialistFactory.php:
--------------------------------------------------------------------------------
1 | specialitySpecification);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Repository/SkillConfirmationRepositoryInterface.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | public function findAllBySpecialityId(string $specialityId): array;
19 |
20 | public function findOne(string $id): ?SpecialitySkill;
21 |
22 | public function findOneBySpecialityAndSkill(string $specialityId, string $skillId): ?SpecialitySkill;
23 | }
24 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Service/SkillFetcher.php:
--------------------------------------------------------------------------------
1 | skillRepository->findOneById($skillId);
20 | Assert::notNull($skill, 'Навык не найден');
21 |
22 | return $skill;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Service/SkillGroupMaker.php:
--------------------------------------------------------------------------------
1 | skillGroupFactory->create($name, $ownerId);
22 | $this->skillGroupRepository->add($skillGroup);
23 |
24 | return $skillGroup;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Service/SkillMaker.php:
--------------------------------------------------------------------------------
1 | skillGroupRepository->findOneById($skillGroupId);
24 | $skill = $this->skillFactory->create($name, $skillGroup, $ownerId);
25 | $this->skillRepository->add($skill);
26 |
27 | return $skill;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Service/SpecialistMaker.php:
--------------------------------------------------------------------------------
1 | specialistFactory->create($publicUserId);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Service/SpecialityFetcher.php:
--------------------------------------------------------------------------------
1 | specialityRepository->findOne(
21 | new SpecialityFilter(
22 | id: $id
23 | )
24 | );
25 | Assert::notEmpty($speciality, 'Специальность не найдена');
26 |
27 | return $speciality;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Service/SpecialityMaker.php:
--------------------------------------------------------------------------------
1 | specialityFactory->create($name, $ownerId);
22 | $this->specialityRepository->add($speciality);
23 |
24 | return $speciality;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Skills/Domain/Service/SpecialitySkillOrganizer.php:
--------------------------------------------------------------------------------
1 | skillFetcher->getRequiredSkill($skillId);
27 | $speciality = $this->specialityFetcher->getRequiredSpeciality($specialityId);
28 |
29 | $existingSpecialitySkill = $this->specialitySkillRepository
30 | ->findOneBySpecialityAndSkill($speciality->getId(), $skill->getId());
31 | Assert::null($existingSpecialitySkill, 'Навык уже добавлен');
32 |
33 | $specialitySkill = new SpecialitySkill($speciality, $skill, Level::from($level));
34 | $this->specialitySkillRepository->add($specialitySkill);
35 |
36 | return $specialitySkill;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Api/SkillsApi.php:
--------------------------------------------------------------------------------
1 | commandInteractor->confirmSpecialistSkill(
25 | new ConfirmSpecialistSkillCommand(
26 | $skillId, $userId, $testId, $correctAnswersPercentage
27 | )
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Console/TestCommand.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Database/ORM/Aggregate/Skill.SkillGroup.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Database/ORM/Aggregate/SkillConfirmation.Proof.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Database/ORM/Aggregate/SkillConfirmation.SkillConfirmation.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Database/ORM/Aggregate/Specialist.Specialist.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Database/ORM/Aggregate/Speciality.Speciality.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Database/ORM/Aggregate/Speciality.SpecialitySkill.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Repository/SkillConfirmationRepository.php:
--------------------------------------------------------------------------------
1 | findOneBy(['skill' => $skillId, 'specialist' => $specialistId]);
20 | }
21 |
22 | public function add(SkillConfirmation $skillConfirmation): void
23 | {
24 | $this->_em->persist($skillConfirmation);
25 | $this->_em->flush();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Repository/SkillGroupRepository.php:
--------------------------------------------------------------------------------
1 | findOneBy(['name' => $name]);
23 | }
24 |
25 | public function add(SkillGroup $entity): void
26 | {
27 | $this->_em->persist($entity);
28 | $this->_em->flush();
29 | }
30 |
31 | public function findOneById(string $id): ?SkillGroup
32 | {
33 | return $this->find($id);
34 | }
35 |
36 | public function findByFilter(SkillGroupsFilter $filter): PaginationResult
37 | {
38 | $qb = $this->createQueryBuilder('sg');
39 |
40 | if ($filter->name) {
41 | $qb->where($qb->expr()->like('sg.name', ':name'))
42 | ->setParameter('name', '%'.$filter->name.'%');
43 | }
44 |
45 | if ($filter->pager) {
46 | $qb->setMaxResults($filter->pager->getLimit());
47 | $qb->setFirstResult($filter->pager->getOffset());
48 | }
49 |
50 | $paginator = new Paginator($qb->getQuery());
51 |
52 | return new PaginationResult(iterator_to_array($paginator->getIterator()), $paginator->count());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Repository/SpecialistRepository.php:
--------------------------------------------------------------------------------
1 | findOneBy(['publicUserId' => $publicUserId]);
20 | }
21 |
22 | public function add(Specialist $specialist): void
23 | {
24 | $this->_em->persist($specialist);
25 | $this->_em->flush();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Skills/Infrastructure/Repository/SpecialitySkillRepository.php:
--------------------------------------------------------------------------------
1 | _em->persist($entity);
22 | $this->_em->flush();
23 | }
24 |
25 | public function remove(SpecialitySkill $entity): void
26 | {
27 | $this->_em->remove($entity);
28 | $this->_em->flush();
29 | }
30 |
31 | public function findAllBySpecialityId(string $specialityId): array
32 | {
33 | return $this->findBy(['speciality' => $specialityId]);
34 | }
35 |
36 | public function findOne(string $id): ?SpecialitySkill
37 | {
38 | return $this->find($id);
39 | }
40 |
41 | public function findOneBySpecialityAndSkill(string $specialityId, string $skillId): ?SpecialitySkill
42 | {
43 | return $this->findOneBy(['speciality' => $specialityId, 'skill' => $skillId]);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Testing/Application/Command/CreateAnswerOption/CreateAnswerOptionCommand.php:
--------------------------------------------------------------------------------
1 | questionRepository->findOneById($command->questionId);
23 | Assert::notEmpty($question, 'Тест не найден');
24 | $answerOption = $this->answerOptionFactory->create($question, $command->description, $command->correct);
25 | $question->addAnswerOption($answerOption);
26 | $this->questionRepository->add($question);
27 |
28 | return $answerOption->getId();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Testing/Application/Command/CreateQuestion/CreateQuestionCommand.php:
--------------------------------------------------------------------------------
1 | testRepository->findOneById($command->testId);
23 | $question = $this->questionFactory->create(
24 | $command->name,
25 | $command->description,
26 | QuestionType::from($command->type),
27 | $test
28 | );
29 | $test->addQuestion($question);
30 | $this->testRepository->add($test);
31 |
32 | return $question->getId();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Testing/Application/Command/CreateTest/CreateTestCommand.php:
--------------------------------------------------------------------------------
1 | testFactory->create(
26 | $command->ownerId,
27 | $command->name,
28 | $command->description,
29 | DifficultyLevel::from($command->difficultyLevel),
30 | $command->correctAnswersPercentage,
31 | $command->skillId,
32 | );
33 | $this->testRepository->add($test);
34 |
35 | return $test->getId();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Testing/Application/Command/CreateTestingSession/CreateTestingSessionCommand.php:
--------------------------------------------------------------------------------
1 | getId(),
22 | description: $answerOption->getDescription(),
23 | isCorrect: $answerOption->isCorrect(),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Testing/Application/Query/DTO/Test/QuestionDTO.php:
--------------------------------------------------------------------------------
1 | AnswerOptionDTO::fromEntity($a),
30 | $question->getAnswerOptions()->toArray()
31 | );
32 |
33 | return new self(
34 | id: $question->getId(),
35 | name: $question->getName(),
36 | description: $question->getDescription(),
37 | published: $question->isPublished(),
38 | type: $question->getType()->value,
39 | positionNumber: $question->getPositionNumber(),
40 | answerOptions: $answerOptions,
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Testing/Application/Query/DTO/Test/TestDTO.php:
--------------------------------------------------------------------------------
1 | QuestionDTO::fromEntity($question),
32 | $test->getQuestions()->toArray()
33 | );
34 |
35 | return new self(
36 | id: $test->getId(),
37 | creatorId: $test->getOwnerId(),
38 | name: $test->getName(),
39 | description: $test->getDescription(),
40 | difficultyLevel: $test->getDifficultyLevel()->value,
41 | questions: $questions,
42 | correctAnswersPercentage: $test->getCorrectAnswersPercentage(),
43 | skillId: $test->getSkillId(),
44 | isPublished: $test->published(),
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Testing/Application/Query/DTO/TestingSessionDTO.php:
--------------------------------------------------------------------------------
1 | getId(),
22 | $testingSession->getUserId(),
23 | $testingSession->getTest()->getId(),
24 | $testingSession->getCorrectAnswersPercentage(),
25 | $testingSession->getTest()->getSkillId()
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Testing/Application/Query/FindAnswerOption/FindAnswerOptionQuery.php:
--------------------------------------------------------------------------------
1 | answerOptionRepository->findOneById($query->answerOptionId);
20 |
21 | return new FindAnswerOptionQueryResult(
22 | $answerOption ? AnswerOptionDTO::fromEntity($answerOption) : null
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Testing/Application/Query/FindAnswerOption/FindAnswerOptionQueryResult.php:
--------------------------------------------------------------------------------
1 | questionRepository->findOneById($query->id);
20 |
21 | return new FindQuestionQueryResult($question ? QuestionDTO::fromEntity($question) : null);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Testing/Application/Query/FindQuestion/FindQuestionQueryResult.php:
--------------------------------------------------------------------------------
1 | testRepository->findOneById($query->id);
20 |
21 | return new FindTestQueryResult($test ? TestDTO::fromEntity($test) : null);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Testing/Application/Query/FindTest/FindTestQueryResult.php:
--------------------------------------------------------------------------------
1 | testingSessionRepository->findById($query->testingSessionId);
18 |
19 | return new FindTestingSessionQueryResult(
20 | $testingSession ? TestingSessionDTO::fromEntity($testingSession) : null
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Testing/Application/Query/FindTestingSession/FindTestingSessionQueryResult.php:
--------------------------------------------------------------------------------
1 | queryBus->execute($query);
26 | }
27 |
28 | public function findQuestion(FindQuestionQuery $query): FindQuestionQueryResult
29 | {
30 | return $this->queryBus->execute($query);
31 | }
32 |
33 | public function findAnswerOption(FindAnswerOptionQuery $query): FindAnswerOptionQueryResult
34 | {
35 | return $this->queryBus->execute($query);
36 | }
37 |
38 | public function findTestingSession(string $testingSessionId): FindTestingSessionQueryResult
39 | {
40 | return $this->queryBus->execute(new FindTestingSessionQuery($testingSessionId));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Testing/Domain/Aggregate/Test/AnswerOption.php:
--------------------------------------------------------------------------------
1 | id = UlidService::generate();
28 | $this->question = $question;
29 | $this->description = $description;
30 | $this->correct = $isCorrect;
31 | }
32 |
33 | public function isCorrect(): bool
34 | {
35 | return $this->correct;
36 | }
37 |
38 | public function getId(): string
39 | {
40 | return $this->id;
41 | }
42 |
43 | public function getQuestion(): Question
44 | {
45 | return $this->question;
46 | }
47 |
48 | public function getDescription(): string
49 | {
50 | return $this->description;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Testing/Domain/Aggregate/Test/DifficultyLevel.php:
--------------------------------------------------------------------------------
1 | id = UlidService::generate();
24 | $this->testingSession = $testingSession;
25 | $this->question = $question;
26 | }
27 |
28 | public function getQuestion(): Question
29 | {
30 | return $this->question;
31 | }
32 |
33 | public function isCorrect(): bool
34 | {
35 | foreach ($this->question->getAnswerOptions() as $answerOption) {
36 | if ($answerOption->isCorrect() && in_array($answerOption->getId(), $this->answeredOptions, true)) {
37 | return true;
38 | }
39 | }
40 |
41 | return false;
42 | }
43 |
44 | public function addAnswerOption(AnswerOption $answerOption): void
45 | {
46 | $this->answeredOptions[$answerOption->getId()] = $answerOption->getId();
47 | }
48 |
49 | public function getId(): string
50 | {
51 | return $this->id;
52 | }
53 |
54 | public function getTestingSession(): TestingSession
55 | {
56 | return $this->testingSession;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Testing/Domain/Event/TestingSessionCompletedEvent.php:
--------------------------------------------------------------------------------
1 | testSpecification);
26 | $test->setCorrectAnswersPercentage($correctAnswersPercentage);
27 |
28 | if ($skillId) {
29 | $test->setSkillId($skillId);
30 | }
31 |
32 | return $test;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Testing/Domain/Factory/TestingSessionFactory.php:
--------------------------------------------------------------------------------
1 | testRepository->findOneById($testId);
24 | $entity = $this->testingSessionFactory->create($test, $userId);
25 | $this->testingSessionRepository->add($entity);
26 |
27 | return $entity;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Testing/Domain/Specification/TestSpecification.php:
--------------------------------------------------------------------------------
1 | testRepository->findByName($test->getName()) as $existingTest) {
21 | AssertService::notEq(
22 | $existingTest->getName(),
23 | $test->getName(),
24 | 'Тест с таким названием уже существует'
25 | );
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Adapter/SkillsAdapter.php:
--------------------------------------------------------------------------------
1 | api->confirmSpecialistSkill($skillId, $userId, $testId, $correctAnswersPercentage);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Adapter/SkillsApiInterface.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Database/ORM/Aggregate/Test.Question.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Database/ORM/Aggregate/Test.Test.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Database/ORM/Aggregate/TestingSession.TestingSession.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Database/ORM/Aggregate/TestingSession.UserAnswer.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/EventHandler/TestingSessionCompletedEventHandler.php:
--------------------------------------------------------------------------------
1 | queryInteractor
21 | ->findTestingSession($event->testingSessionId)
22 | ->testingSession;
23 |
24 | $this->skillsAdapter->confirmSpecialistSkill(
25 | $testingSession->skillId,
26 | $testingSession->userId,
27 | $testingSession->testId,
28 | $testingSession->correctAnswersPercentage
29 | );
30 |
31 | return $testingSession->id;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Repository/AnswerOptionRepository.php:
--------------------------------------------------------------------------------
1 | find($answerOptionId);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Repository/QuestionRepository.php:
--------------------------------------------------------------------------------
1 | find($id);
22 | }
23 |
24 | public function add(Question $entity): void
25 | {
26 | $this->_em->persist($entity);
27 | $this->_em->flush();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Repository/TestRepository.php:
--------------------------------------------------------------------------------
1 | _em->persist($entity);
22 | $this->_em->flush();
23 | }
24 |
25 | public function findOneById(string $id): ?Test
26 | {
27 | return $this->find($id);
28 | }
29 |
30 | /**
31 | * @return Test[]
32 | */
33 | public function findBySkill(string $skillId): array
34 | {
35 | return $this->findBy(['skillId' => $skillId]);
36 | }
37 |
38 | public function findByName(string $name): array
39 | {
40 | return $this->findBy(['name' => $name]);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Testing/Infrastructure/Repository/TestingSessionRepository.php:
--------------------------------------------------------------------------------
1 | find($id);
20 | }
21 |
22 | public function add(TestingSession $testingSession): void
23 | {
24 | $this->_em->persist($testingSession);
25 | $this->_em->flush();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Users/Application/DTO/UserDTO.php:
--------------------------------------------------------------------------------
1 | getId(), name: '', email: $user->getEmail());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Users/Application/UseCase/AdminUseCaseInteractor.php:
--------------------------------------------------------------------------------
1 | commandBus->execute($command);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Users/Application/UseCase/Command/CreateUser/CreateUserCommand.php:
--------------------------------------------------------------------------------
1 | userFactory->create($createUserCommand->email, $createUserCommand->password);
23 | $this->userRepository->add($user);
24 |
25 | return $user->getId();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Users/Application/UseCase/PrivateUseCaseInteractor.php:
--------------------------------------------------------------------------------
1 | queryBus->execute(new GetMeQuery());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Users/Application/UseCase/PublicUseCaseInteractor.php:
--------------------------------------------------------------------------------
1 | queryBus->execute($query);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Users/Application/UseCase/Query/FindUser/FindUserQuery.php:
--------------------------------------------------------------------------------
1 | userRepository->findById($query->userId);
20 | $userDTO = $user ? UserDTO::fromEntity($user) : null;
21 |
22 | return new FindUserQueryResult($userDTO);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Users/Application/UseCase/Query/FindUser/FindUserQueryResult.php:
--------------------------------------------------------------------------------
1 | userRepository->findByEmail($query->email);
20 |
21 | if (!$user) {
22 | throw new \Exception('User not found');
23 | }
24 |
25 | return UserDTO::fromEntity($user);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Users/Application/UseCase/Query/GetMe/GetMeQuery.php:
--------------------------------------------------------------------------------
1 | userRepository->findById($this->userFetcher->requiredUser()->getId());
23 | $userDTO = $user ? UserDTO::fromEntity($user) : null;
24 |
25 | return new GetMeQueryResult($userDTO);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Users/Application/UseCase/Query/GetMe/GetMeQueryResult.php:
--------------------------------------------------------------------------------
1 | setPassword($password, $this->passwordHasher);
21 |
22 | return $user;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Users/Domain/Repository/UserRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | userFetcher->requiredUser();
23 |
24 | return new JsonResponse([
25 | 'ulid' => $user->getId(),
26 | 'email' => $user->getEmail(),
27 | ]);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Users/Infrastructure/Database/ORM/RefreshToken.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Users/Infrastructure/Database/ORM/User.orm.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Users/Infrastructure/Repository/UserRepository.php:
--------------------------------------------------------------------------------
1 | _em->persist($user);
22 | $this->_em->flush();
23 | }
24 |
25 | public function findById(string $ulid): ?User
26 | {
27 | return $this->find($ulid);
28 | }
29 |
30 | public function findByEmail(string $email): ?User
31 | {
32 | return $this->findOneBy(['email' => $email]);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Users/Infrastructure/UserPasswordHasher.php:
--------------------------------------------------------------------------------
1 | passwordHasher->hashPassword($user, $password);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tests/Functional/Api/ApiTestCase.php:
--------------------------------------------------------------------------------
1 | client = static::createClient();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/Functional/Api/AuthApiTestCase.php:
--------------------------------------------------------------------------------
1 | authenticate();
27 | }
28 |
29 | public function authenticate(): void
30 | {
31 | $this->user = $this->loadUserFixture();
32 | $jwtEncoder = $this->getService(JWTEncoderInterface::class);
33 | $this->client->setServerParameter(
34 | 'HTTP_AUTHORIZATION',
35 | sprintf(
36 | 'Bearer %s',
37 | $jwtEncoder->encode([
38 | 'email' => $this->user->getEmail(),
39 | ]
40 | )
41 | )
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/Functional/Shared/Infrastructure/Controller/HealthCheckActionTest.php:
--------------------------------------------------------------------------------
1 | request(Request::METHOD_GET, '/health-check');
15 |
16 | $this->assertResponseIsSuccessful();
17 | $jsonResult = json_decode($client->getResponse()->getContent(), true);
18 | $this->assertEquals($jsonResult['status'], 'ok');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/Functional/Users/Application/Command/CreateUser/CreateUserCommandHandlerTest.php:
--------------------------------------------------------------------------------
1 | commandBus = $this->getService(CommandBusInterface::class);
24 | $this->userRepository = $this->getService(UserRepositoryInterface::class);
25 | }
26 |
27 | public function test_user_created_successfully(): void
28 | {
29 | $command = new CreateUserCommand($this->getFaker()->email(), $this->getFaker()->password());
30 |
31 | // act
32 | $userUlid = $this->commandBus->execute($command);
33 |
34 | // assert
35 | $user = $this->userRepository->findById($userUlid);
36 | $this->assertNotEmpty($user);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/Functional/Users/Application/Query/FindUserByEmail/FindUserByEmailQueryHandlerTest.php:
--------------------------------------------------------------------------------
1 | queryBus = $this->getService(QueryBusInterface::class);
26 | $this->databaseTool = $this->getService(DatabaseToolCollection::class)->get();
27 | }
28 |
29 | public function test_user_created_when_command_executed(): void
30 | {
31 | // arrange
32 | $referenceRepository = $this->databaseTool->loadFixtures([UserFixture::class])->getReferenceRepository();
33 | /** @var User $user */
34 | $user = $referenceRepository->getReference(UserFixture::REFERENCE);
35 | $query = new FindUserByEmailQuery($user->getEmail());
36 |
37 | // act
38 | $userDTO = $this->queryBus->execute($query);
39 |
40 | // assert
41 | $this->assertInstanceOf(UserDTO::class, $userDTO);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Resource/Fixture/Skills/SkillFixture.php:
--------------------------------------------------------------------------------
1 | getReference(SkillGroupFixture::REFERENCE);
29 | $skill = $this->skillFactory->create($this->getFaker()->name(), $skillGroup, $skillGroup->getOwnerId());
30 |
31 | $manager->persist($skill);
32 | $manager->flush();
33 |
34 | $this->addReference(self::REFERENCE, $skill);
35 | }
36 |
37 | public function getDependencies(): array
38 | {
39 | return [
40 | SkillGroupFixture::class,
41 | ];
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Resource/Fixture/Skills/SkillGroupFixture.php:
--------------------------------------------------------------------------------
1 | getReference(UserFixture::REFERENCE);
30 | $skillGroup = $this->skillGroupFactory->create($this->getFaker()->name(), $user->getId());
31 |
32 | $manager->persist($skillGroup);
33 | $manager->flush();
34 |
35 | $this->addReference(self::REFERENCE, $skillGroup);
36 | }
37 |
38 | public function getDependencies(): array
39 | {
40 | return [
41 | UserFixture::class,
42 | ];
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/Resource/Fixture/Users/UserFixture.php:
--------------------------------------------------------------------------------
1 | getFaker()->email();
25 |
26 | $password = $this->getFaker()->password();
27 | $user = $this->userFactory->create($email, $password);
28 |
29 | $manager->persist($user);
30 | $manager->flush();
31 |
32 | $this->addReference(self::REFERENCE, $user);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/Tools/DITools.php:
--------------------------------------------------------------------------------
1 | $service
15 | *
16 | * @return T|object|null
17 | */
18 | public function getService(string $service)
19 | {
20 | return static::getContainer()->get($service);
21 | }
22 |
23 | public function getUrlGenerator(): UrlGeneratorInterface
24 | {
25 | return $this->getService(UrlGeneratorInterface::class);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Tools/FakerTools.php:
--------------------------------------------------------------------------------
1 | get(DatabaseToolCollection::class)->get();
19 | }
20 |
21 | public function loadUserFixture(): User
22 | {
23 | $executor = $this->getDatabaseTools()->loadFixtures([UserFixture::class], true);
24 | /** @var User $user */
25 | $user = $executor->getReferenceRepository()->getReference(UserFixture::REFERENCE);
26 |
27 | return $user;
28 | }
29 |
30 | public function loadSkillGroupFixture(): SkillGroup
31 | {
32 | $executor = $this->getDatabaseTools()->loadFixtures([SkillGroupFixture::class], true);
33 |
34 | return $executor->getReferenceRepository()->getReference(SkillGroupFixture::REFERENCE);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | bootEnv(dirname(__DIR__).'/.env');
11 | }
12 |
--------------------------------------------------------------------------------