generated from flo/template-backend
Initial commit
This commit is contained in:
commit
3d60d4b9dc
20
.env.example
Normal file
20
.env.example
Normal file
@ -0,0 +1,20 @@
|
||||
# DB Configuration
|
||||
DB_DRIVER=pdo_mysql
|
||||
DB_HOST=template-backend-mysql
|
||||
DB_PORT=3306
|
||||
DB_USER=template
|
||||
DB_PASSWORD=pass
|
||||
DB_NAME=template
|
||||
DB_NAME_LOG=log
|
||||
|
||||
# API Keys
|
||||
AUTH_API_KEY=
|
||||
NOTIFICATION_API_KEY=
|
||||
FILE_API_KEY=
|
||||
HOMEPAGE_API_KEY=
|
||||
BEE_API_KEY=
|
||||
|
||||
# Template Setup
|
||||
INIT_USER_NAME=admin
|
||||
INIT_USER_PASSWORD=password
|
||||
INIT_USER_MAIL=admin@test.com
|
||||
7
.gitattributes
vendored
Normal file
7
.gitattributes
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/.gitattributes export-ignore
|
||||
/.github/ export-ignore
|
||||
/.laminas-ci.json export-ignore
|
||||
/phpcs.xml.dist export-ignore
|
||||
/psalm.xml.dist export-ignore
|
||||
/psalm-baseline.xml export-ignore
|
||||
/renovate.json export-ignore
|
||||
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
/.phpcs-cache
|
||||
/.phpunit.result.cache
|
||||
/.idea
|
||||
/clover.xml
|
||||
/coveralls-upload.json
|
||||
/phpunit.xml
|
||||
|
||||
/data/cache/
|
||||
/data/db/
|
||||
/public/data/
|
||||
/var/
|
||||
/vendor/
|
||||
|
||||
*.env
|
||||
composer.lock
|
||||
composer.development.json
|
||||
3
.htaccess
Normal file
3
.htaccess
Normal file
@ -0,0 +1,3 @@
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
RewriteRule ^pages/([^/]*)/(.*)$ pages.php?$1=$2
|
||||
1
COPYRIGHT.md
Normal file
1
COPYRIGHT.md
Normal file
@ -0,0 +1 @@
|
||||
Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
|
||||
26
LICENSE.md
Normal file
26
LICENSE.md
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Laminas Foundation nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
39
bin/clear-config-cache.php
Normal file
39
bin/clear-config-cache.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
chdir(__DIR__ . '/../');
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
$config = include 'config/config.php';
|
||||
|
||||
if (! isset($config['config_cache_path'])) {
|
||||
echo "No configuration cache path found" . PHP_EOL;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (! file_exists($config['config_cache_path'])) {
|
||||
printf(
|
||||
"Configured config cache file '%s' not found%s",
|
||||
$config['config_cache_path'],
|
||||
PHP_EOL
|
||||
);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (false === unlink($config['config_cache_path'])) {
|
||||
printf(
|
||||
"Error removing config cache file '%s'%s",
|
||||
$config['config_cache_path'],
|
||||
PHP_EOL
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf(
|
||||
"Removed configured config cache file '%s'%s",
|
||||
$config['config_cache_path'],
|
||||
PHP_EOL
|
||||
);
|
||||
exit(0);
|
||||
30
bin/console.php
Normal file
30
bin/console.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Template\Infrastructure\Logging\Logger\Logger;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
require_once __DIR__ . '/../config/autoload/defines.php';
|
||||
require APP_ROOT . '/vendor/autoload.php';
|
||||
|
||||
call_user_func(function() {
|
||||
$container = require APP_ROOT . '/config/container.php';
|
||||
|
||||
$config = $container->get('config');
|
||||
$commands = $config['console']['commands'];
|
||||
|
||||
$app = new Application();
|
||||
foreach ($commands as $command) {
|
||||
$app->add($container->get($command));
|
||||
}
|
||||
|
||||
try {
|
||||
$app->setCatchExceptions(false);
|
||||
$app->run();
|
||||
} catch (Throwable $e) {
|
||||
$logger = new Logger();
|
||||
$logger->error(
|
||||
$e->getMessage(),
|
||||
['exception' => $e]
|
||||
);
|
||||
}
|
||||
});
|
||||
319
bin/createApi.php
Normal file
319
bin/createApi.php
Normal file
@ -0,0 +1,319 @@
|
||||
<?php
|
||||
|
||||
if (count($argv) !== 6) {
|
||||
echo 'Use of this Command:' . PHP_EOL
|
||||
. 'createApi API_IsExternal API_Namespace API_Name CQRS_IsCommand CQRS_Namespace' . PHP_EOL;
|
||||
die;
|
||||
}
|
||||
|
||||
$projectSourceDirectory = 'src/';
|
||||
$projectNamespace = 'Template';
|
||||
|
||||
$apiType = strtolower($argv[1]) === 'true' ? 'External' : 'Internal';
|
||||
$apiNamespace = $argv[2];
|
||||
$apiName = $argv[3];
|
||||
$cqrsType = strtolower($argv[4]) === 'true' ? 'Command' : 'Query';
|
||||
$cqrsNamespace = $argv[5];
|
||||
|
||||
## API
|
||||
$apiNamespacePath = $projectSourceDirectory . 'ApiDomain/' . $apiType . '/' . $apiNamespace;
|
||||
$apiNamespace = $projectNamespace . '\\API\\' . $apiType . '\\' . $apiNamespace;
|
||||
|
||||
# API Handler
|
||||
$apiHandlerName = $apiName . 'Handler';
|
||||
$apiHandlerNamespace = $apiNamespace . '\\Handler';
|
||||
$apiHandlerUsingNamespace = $apiHandlerNamespace . '\\' . $apiHandlerName;
|
||||
$apiHandlerFilePath = $apiNamespacePath . '/src/Handler/' . $apiHandlerName . '.php';
|
||||
|
||||
# API Response Formatter
|
||||
$apiResponseFormatterName = $apiName . 'ResponseFormatter';
|
||||
$apiResponseFormatterNamespace = $apiNamespace . '\\ResponseFormatter';
|
||||
$apiResponseFormatterUsingNamespace = $apiResponseFormatterNamespace . '\\' . $apiResponseFormatterName;
|
||||
$apiResponseFormatterFilePath = $apiNamespacePath . '/src/ResponseFormatter/' . $apiResponseFormatterName . '.php';
|
||||
|
||||
## CQRS
|
||||
$cqrsNamespacePath = $projectSourceDirectory . 'HandlingDomain/' . $cqrsNamespace;
|
||||
$cqrsFilePath = $cqrsNamespacePath . '/src/Handler/' . $cqrsType . '/' . $apiName . '/';
|
||||
$cqrsName = $apiName . $cqrsType;
|
||||
$cqrsVariableName = lcfirst($cqrsName);
|
||||
$cqrsNamespace = $projectNamespace . '\\Handling\\' . $cqrsNamespace;
|
||||
$cqrsHandlerNamespace = $cqrsNamespace . '\\Handler\\' . $cqrsType . '\\' . $apiName;
|
||||
|
||||
# Command / Query
|
||||
$cqrsPath = $cqrsFilePath . $cqrsName . '.php';
|
||||
|
||||
# Handler
|
||||
$cqrsHandlerName = $cqrsName . 'Handler';
|
||||
$cqrsHandlerVariableName = lcfirst($cqrsHandlerName);
|
||||
$cqrsHandlerPath = $cqrsFilePath . $cqrsName . 'Handler' . '.php';
|
||||
$cqrsHandlerUsingNamespace = $cqrsHandlerNamespace . '\\' . $cqrsHandlerName;
|
||||
|
||||
# Result
|
||||
$cqrsResultName = $cqrsName . 'Result';
|
||||
$cqrsResultVariableName = lcfirst($cqrsResultName);
|
||||
$cqrsResultPath = $cqrsFilePath . $cqrsName . 'Result' . '.php';
|
||||
$cqrsResultUsingNamespace = $cqrsHandlerNamespace . '\\' . $cqrsResultName;
|
||||
|
||||
# Builder
|
||||
$cqrsBuilderName = $cqrsName . 'Builder';
|
||||
$cqrsBuilderVariableName = lcfirst($cqrsBuilderName);
|
||||
$cqrsBuilderPath = $cqrsFilePath . $cqrsName . 'Builder' . '.php';
|
||||
$cqrsBuilderUsingNamespace = $cqrsHandlerNamespace . '\\' . $cqrsBuilderName;
|
||||
|
||||
|
||||
########## COMMON ################
|
||||
function writeToFile($path, $content) {
|
||||
echo 'Writing contents to file ' . $path . PHP_EOL;
|
||||
|
||||
$directory = pathinfo($path, PATHINFO_DIRNAME);
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
file_put_contents($path, $content);
|
||||
}
|
||||
|
||||
########## CREATE CONFIGS #############
|
||||
if (!is_dir($apiNamespacePath)) {
|
||||
// API Namespace is new, create Configs
|
||||
// Config Provider
|
||||
$configProviderFilePath = $apiNamespacePath . '/src/ConfigProvider.php';
|
||||
$configProviderFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$apiNamespace};
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . '/./../config/service_manager.php',
|
||||
'routes' => require __DIR__ . '/./../config/routes.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($configProviderFilePath, $configProviderFileContent);
|
||||
|
||||
// Service Manager
|
||||
$serviceManagerFilePath = $apiNamespacePath . '/config/service_manager.php';
|
||||
$serviceManagerFileContent = "<?php
|
||||
|
||||
use {$apiHandlerUsingNamespace};
|
||||
use {$apiResponseFormatterUsingNamespace};
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
// Handler
|
||||
{$apiHandlerName}::class => AutoWiringFactory::class,
|
||||
|
||||
// Response Formatter
|
||||
{$apiResponseFormatterName}::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
";
|
||||
writeToFile($serviceManagerFilePath, $serviceManagerFileContent);
|
||||
|
||||
// Routes
|
||||
$routeName = strtolower($argv[2]) . '.' . strtolower($argv[3]);
|
||||
$routePath = strtolower($argv[2]) . '/' . strtolower($argv[3]);
|
||||
$routesFilePath = $apiNamespacePath . '/config/routes.php';
|
||||
$routesFileContent = "<?php
|
||||
|
||||
use {$apiHandlerUsingNamespace};
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => '{$routeName}',
|
||||
'path' => '/api/{$routePath}/',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
{$apiHandlerName}::class,
|
||||
],
|
||||
],
|
||||
];
|
||||
";
|
||||
writeToFile($routesFilePath, $routesFileContent);
|
||||
}
|
||||
|
||||
if (!is_dir($cqrsNamespacePath)) {
|
||||
// CQRS Namespace is new, create Configs
|
||||
// API Namespace is new, create Configs
|
||||
// Config Provider
|
||||
$configProviderFilePath = $cqrsNamespacePath . '/src/ConfigProvider.php';
|
||||
$configProviderFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$cqrsNamespace};
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . '/./../config/service_manager.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($configProviderFilePath, $configProviderFileContent);
|
||||
|
||||
// Service Manager
|
||||
$serviceManagerFilePath = $cqrsNamespacePath . '/config/service_manager.php';
|
||||
$serviceManagerFileContent = "<?php
|
||||
|
||||
use {$cqrsBuilderUsingNamespace};
|
||||
use {$cqrsHandlerUsingNamespace};
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
/// CQRS
|
||||
// {$apiName}
|
||||
{$cqrsBuilderName}::class => AutoWiringFactory::class,
|
||||
{$cqrsHandlerName}::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
";
|
||||
writeToFile($serviceManagerFilePath, $serviceManagerFileContent);
|
||||
}
|
||||
|
||||
########## WRITE FILES ###############
|
||||
$apiHandlerFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$apiHandlerNamespace};
|
||||
|
||||
use {$apiResponseFormatterUsingNamespace};
|
||||
use {$cqrsBuilderUsingNamespace};
|
||||
use {$cqrsHandlerUsingNamespace};
|
||||
use {$projectNamespace}\\Infrastructure\\Request\\Middleware\\AnalyzeBodyMiddleware;
|
||||
use {$projectNamespace}\\Infrastructure\\Response\\SuccessResponse;
|
||||
use Psr\\Http\\Message\\ResponseInterface;
|
||||
use Psr\\Http\\Message\\ServerRequestInterface;
|
||||
use Psr\\Http\\Server\\RequestHandlerInterface;
|
||||
|
||||
class {$apiHandlerName} implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly {$cqrsHandlerName} \${$cqrsHandlerVariableName},
|
||||
private readonly {$cqrsBuilderName} \${$cqrsBuilderVariableName},
|
||||
private readonly {$apiResponseFormatterName} \$responseFormatter,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface \$request): ResponseInterface
|
||||
{
|
||||
\$data = \$request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
|
||||
|
||||
\${$cqrsVariableName} = \$this->{$cqrsBuilderVariableName}->build(
|
||||
\$data
|
||||
);
|
||||
\$result = \$this->{$cqrsHandlerVariableName}->execute(\${$cqrsVariableName});
|
||||
|
||||
return new SuccessResponse(\$this->responseFormatter->format(\$result));
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($apiHandlerFilePath, $apiHandlerFileContent);
|
||||
|
||||
$apiResponseFormatterFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$apiResponseFormatterNamespace};
|
||||
|
||||
use {$cqrsResultUsingNamespace};
|
||||
|
||||
class {$apiResponseFormatterName}
|
||||
{
|
||||
public function format({$cqrsResultName} \${$cqrsResultVariableName}): array
|
||||
{
|
||||
return [
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($apiResponseFormatterFilePath, $apiResponseFormatterFileContent);
|
||||
|
||||
$cqrsFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$cqrsHandlerNamespace};
|
||||
|
||||
class {$cqrsName}
|
||||
{
|
||||
public function __construct(
|
||||
#TODO
|
||||
) {
|
||||
}
|
||||
|
||||
#TODO
|
||||
}
|
||||
";
|
||||
writeToFile($cqrsPath, $cqrsFileContent);
|
||||
|
||||
$cqrsHandlerFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$cqrsHandlerNamespace};
|
||||
|
||||
class {$cqrsHandlerName}
|
||||
{
|
||||
public function __construct(
|
||||
#TODO
|
||||
) {
|
||||
}
|
||||
|
||||
public function execute({$cqrsName} \${$cqrsVariableName}): {$cqrsResultName}
|
||||
{
|
||||
return new {$cqrsResultName}(
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($cqrsHandlerPath, $cqrsHandlerFileContent);
|
||||
|
||||
$cqrsBuilderFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$cqrsHandlerNamespace};
|
||||
|
||||
class {$cqrsBuilderName}
|
||||
{
|
||||
public function build(
|
||||
#TODO
|
||||
): {$cqrsName} {
|
||||
return new {$cqrsName}(
|
||||
#TODO
|
||||
);
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($cqrsBuilderPath, $cqrsBuilderFileContent);
|
||||
|
||||
$cqrsResultFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$cqrsHandlerNamespace};
|
||||
|
||||
class {$cqrsResultName}
|
||||
{
|
||||
public function __construct(
|
||||
#TODO
|
||||
) {
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($cqrsResultPath, $cqrsResultFileContent);
|
||||
151
bin/createPipeline.php
Normal file
151
bin/createPipeline.php
Normal file
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
if (count($argv) < 4) {
|
||||
echo 'Use of this Command:' . PHP_EOL
|
||||
. 'createPipeline Handling_Namespace Pipeline_Name Step_1_Name Step_2_Name' . PHP_EOL;
|
||||
die;
|
||||
}
|
||||
|
||||
$projectSourceDirectory = 'src/';
|
||||
$projectNamespace = 'Template';
|
||||
|
||||
$pipelineNamespace = $argv[1];
|
||||
$pipelineName = $argv[2];
|
||||
$stepNames = array_slice($argv, 3);
|
||||
|
||||
# Pipeline
|
||||
$pipelineClassName = $pipelineName . 'Pipeline';
|
||||
$pipelineVariableName = lcfirst($pipelineClassName);
|
||||
$pipelineFilePath = $projectSourceDirectory . 'HandlingDomain/' . $pipelineNamespace . '/src/Pipeline/' . $pipelineName . '/' . $pipelineClassName . '.php';
|
||||
$pipelineFullNamespace = $projectNamespace . '\\Handling\\' . $pipelineNamespace . '\\Pipeline\\' . $pipelineName;
|
||||
$pipelineUsingNamespace = $pipelineFullNamespace . '\\' . $pipelineClassName;
|
||||
|
||||
# Payload
|
||||
$payloadClassName = $pipelineName . 'Payload';
|
||||
$payloadVariableName = lcfirst($payloadClassName);
|
||||
$payloadFilePath = $projectSourceDirectory . 'HandlingDomain/' . $pipelineNamespace . '/src/Pipeline/' . $pipelineName . '/' . $payloadClassName . '.php';
|
||||
$payloadFullNamespace = $projectNamespace . '\\Handling\\' . $pipelineNamespace . '\\Pipeline\\' . $pipelineName;
|
||||
$payloadUsingNamespace = $payloadFullNamespace . '\\' . $payloadClassName;
|
||||
|
||||
# Step
|
||||
$stepsFilePath = $projectSourceDirectory . 'HandlingDomain/' . $pipelineNamespace . '/src/Pipeline/' . $pipelineName . '/Step/';
|
||||
$stepsFullNamespace = $projectNamespace . '\\Handling\\' . $pipelineNamespace . '\\Pipeline\\' . $pipelineName . '\\Step';
|
||||
|
||||
$steps = [];
|
||||
foreach ($stepNames as $stepName) {
|
||||
$stepClassName = $stepName . 'Step';
|
||||
$steps[] = [
|
||||
'stepClassName' => $stepClassName,
|
||||
'stepVariableName' => lcfirst($stepClassName),
|
||||
'stepFilePath' => $stepsFilePath . $stepClassName . '.php',
|
||||
'stepUsingNamespace' => 'use ' . $payloadFullNamespace . '\\Step\\' . $stepClassName,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
########## WRITE FILES ###############
|
||||
function writeToFile($path, $content) {
|
||||
echo 'Writing contents to file ' . $path . PHP_EOL;
|
||||
|
||||
$directory = pathinfo($path, PATHINFO_DIRNAME);
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
file_put_contents($path, $content);
|
||||
}
|
||||
|
||||
$stepsUsingNamespaces = [];
|
||||
$stepsDeclarations = [];
|
||||
$stepsReferences = [];
|
||||
|
||||
foreach ($steps as $step) {
|
||||
$stepClassName = $step['stepClassName'];
|
||||
$stepVariableName = $step['stepVariableName'];
|
||||
$stepFilePath = $step['stepFilePath'];
|
||||
$stepUsingNamespace = $step['stepUsingNamespace'];
|
||||
|
||||
$stepsUsingNamespaces[] = $stepUsingNamespace . ';';
|
||||
$stepsDeclarations[] = 'private readonly ' . $stepClassName . ' $' . $stepVariableName . ',';
|
||||
$stepsReferences[] = '$this->' . $stepVariableName . ',';
|
||||
|
||||
$stepFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$stepsFullNamespace};
|
||||
|
||||
use {$payloadUsingNamespace};
|
||||
|
||||
use teewurst\\Pipeline\\PipelineInterface;
|
||||
use teewurst\\Pipeline\\TaskInterface;
|
||||
|
||||
class {$stepClassName} implements TaskInterface
|
||||
{
|
||||
public function __construct(
|
||||
#TODO
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(
|
||||
\$payload,
|
||||
PipelineInterface \$pipeline
|
||||
): void
|
||||
{
|
||||
/** @var {$payloadClassName} \${$payloadVariableName} */
|
||||
\${$payloadVariableName} = \$payload;
|
||||
|
||||
|
||||
|
||||
\$pipeline->next()(\$payload, \$pipeline);
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($stepFilePath, $stepFileContent);
|
||||
}
|
||||
|
||||
$stepsUsingNamespace = implode(PHP_EOL, $stepsUsingNamespaces);
|
||||
$stepsDeclaration = implode(PHP_EOL . ' ', $stepsDeclarations);
|
||||
$stepsReference = implode(PHP_EOL . ' ', $stepsReferences);
|
||||
|
||||
|
||||
|
||||
$pipelineFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$pipelineFullNamespace};
|
||||
|
||||
{$stepsUsingNamespace}
|
||||
use teewurst\\Pipeline\\Pipeline;
|
||||
|
||||
class {$pipelineClassName} extends Pipeline
|
||||
{
|
||||
public function __construct(
|
||||
{$stepsDeclaration}
|
||||
) {
|
||||
parent::__construct([
|
||||
{$stepsReference}
|
||||
]);
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($pipelineFilePath, $pipelineFileContent);
|
||||
|
||||
$payloadFileContent = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$payloadFullNamespace};
|
||||
|
||||
class {$payloadClassName}
|
||||
{
|
||||
public function __construct(
|
||||
#TODO
|
||||
) {
|
||||
}
|
||||
}
|
||||
";
|
||||
writeToFile($payloadFilePath, $payloadFileContent);
|
||||
91
bin/doctrine-migrations-log.php
Normal file
91
bin/doctrine-migrations-log.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../config/autoload/defines.php';
|
||||
require APP_ROOT . '/vendor/autoload.php';
|
||||
|
||||
use Template\Data\Business\Manager\EntityManager;
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\Migrations\Configuration\Configuration;
|
||||
use Doctrine\Migrations\Configuration\Connection\ExistingConnection;
|
||||
use Doctrine\Migrations\Configuration\Migration\ExistingConfiguration;
|
||||
use Doctrine\Migrations\DependencyFactory;
|
||||
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
|
||||
use Doctrine\Migrations\Tools\Console\Command\DumpSchemaCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\ExecuteCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\GenerateCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\LatestCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\ListCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\MigrateCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\RollupCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\StatusCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\SyncMetadataCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\VersionCommand;
|
||||
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
|
||||
use Doctrine\ORM\Tools\Setup;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
$isDevMode = true;
|
||||
|
||||
$container = require APP_ROOT . '/config/container.php';
|
||||
$config = $container->get('config');
|
||||
$doctrineConfig = $config['doctrine'];
|
||||
$paths = $doctrineConfig['driver']['orm_log_annotation_driver']['paths'];
|
||||
|
||||
$dbParams = $doctrineConfig['connection']['orm_log']['params'];
|
||||
$migrationsConf = $doctrineConfig['migrations_configuration']['orm_log'];
|
||||
|
||||
$reader = new AnnotationReader();
|
||||
$driver = new AnnotationDriver($reader, $paths);
|
||||
|
||||
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
|
||||
$config->setMetadataDriverImpl($driver);
|
||||
$entityManager = $container->get(EntityManager::class);
|
||||
|
||||
try {
|
||||
$connection = DriverManager::getConnection($dbParams);
|
||||
} catch (\Doctrine\DBAL\Exception $e) {
|
||||
echo $e->getMessage();
|
||||
exit;
|
||||
}
|
||||
|
||||
$configuration = new Configuration($connection);
|
||||
|
||||
$configuration->addMigrationsDirectory(
|
||||
$migrationsConf['namespace'],
|
||||
$migrationsConf['directory']
|
||||
);
|
||||
$configuration->setAllOrNothing(true);
|
||||
$configuration->setCheckDatabasePlatform(false);
|
||||
|
||||
$storageConfiguration = new TableMetadataStorageConfiguration();
|
||||
$storageConfiguration->setTableName($migrationsConf['table']);
|
||||
|
||||
$configuration->setMetadataStorageConfiguration($storageConfiguration);
|
||||
|
||||
$dependencyFactory = DependencyFactory::fromConnection(
|
||||
new ExistingConfiguration($configuration),
|
||||
new ExistingConnection($connection)
|
||||
);
|
||||
|
||||
$cli = new Application('Doctrine Migrations');
|
||||
$cli->setCatchExceptions(true);
|
||||
|
||||
$cli->addCommands([
|
||||
new DumpSchemaCommand($dependencyFactory),
|
||||
new ExecuteCommand($dependencyFactory),
|
||||
new GenerateCommand($dependencyFactory),
|
||||
new LatestCommand($dependencyFactory),
|
||||
new ListCommand($dependencyFactory),
|
||||
new MigrateCommand($dependencyFactory),
|
||||
new RollupCommand($dependencyFactory),
|
||||
new StatusCommand($dependencyFactory),
|
||||
new SyncMetadataCommand($dependencyFactory),
|
||||
new VersionCommand($dependencyFactory),
|
||||
]);
|
||||
|
||||
try {
|
||||
$cli->run();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
91
bin/doctrine-migrations.php
Normal file
91
bin/doctrine-migrations.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../config/autoload/defines.php';
|
||||
require APP_ROOT . '/vendor/autoload.php';
|
||||
|
||||
use Template\Data\Business\Manager\EntityManager;
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\Migrations\Configuration\Configuration;
|
||||
use Doctrine\Migrations\Configuration\Connection\ExistingConnection;
|
||||
use Doctrine\Migrations\Configuration\Migration\ExistingConfiguration;
|
||||
use Doctrine\Migrations\DependencyFactory;
|
||||
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
|
||||
use Doctrine\Migrations\Tools\Console\Command\DumpSchemaCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\ExecuteCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\GenerateCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\LatestCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\ListCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\MigrateCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\RollupCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\StatusCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\SyncMetadataCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Command\VersionCommand;
|
||||
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
|
||||
use Doctrine\ORM\Tools\Setup;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
$isDevMode = true;
|
||||
|
||||
$container = require APP_ROOT . '/config/container.php';
|
||||
$config = $container->get('config');
|
||||
$doctrineConfig = $config['doctrine'];
|
||||
$paths = $doctrineConfig['driver']['orm_template_annotation_driver']['paths'];
|
||||
|
||||
$dbParams = $doctrineConfig['connection']['orm_template']['params'];
|
||||
$migrationsConf = $doctrineConfig['migrations_configuration']['orm_template'];
|
||||
|
||||
$reader = new AnnotationReader();
|
||||
$driver = new AnnotationDriver($reader, $paths);
|
||||
|
||||
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
|
||||
$config->setMetadataDriverImpl($driver);
|
||||
$entityManager = $container->get(EntityManager::class);
|
||||
|
||||
try {
|
||||
$connection = DriverManager::getConnection($dbParams);
|
||||
} catch (\Doctrine\DBAL\Exception $e) {
|
||||
echo $e->getMessage();
|
||||
exit;
|
||||
}
|
||||
|
||||
$configuration = new Configuration($connection);
|
||||
|
||||
$configuration->addMigrationsDirectory(
|
||||
$migrationsConf['namespace'],
|
||||
$migrationsConf['directory']
|
||||
);
|
||||
$configuration->setAllOrNothing(true);
|
||||
$configuration->setCheckDatabasePlatform(false);
|
||||
|
||||
$storageConfiguration = new TableMetadataStorageConfiguration();
|
||||
$storageConfiguration->setTableName($migrationsConf['table']);
|
||||
|
||||
$configuration->setMetadataStorageConfiguration($storageConfiguration);
|
||||
|
||||
$dependencyFactory = DependencyFactory::fromConnection(
|
||||
new ExistingConfiguration($configuration),
|
||||
new ExistingConnection($connection)
|
||||
);
|
||||
|
||||
$cli = new Application('Doctrine Migrations');
|
||||
$cli->setCatchExceptions(true);
|
||||
|
||||
$cli->addCommands([
|
||||
new DumpSchemaCommand($dependencyFactory),
|
||||
new ExecuteCommand($dependencyFactory),
|
||||
new GenerateCommand($dependencyFactory),
|
||||
new LatestCommand($dependencyFactory),
|
||||
new ListCommand($dependencyFactory),
|
||||
new MigrateCommand($dependencyFactory),
|
||||
new RollupCommand($dependencyFactory),
|
||||
new StatusCommand($dependencyFactory),
|
||||
new SyncMetadataCommand($dependencyFactory),
|
||||
new VersionCommand($dependencyFactory),
|
||||
]);
|
||||
|
||||
try {
|
||||
$cli->run();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
36
bin/script/init
Executable file
36
bin/script/init
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
PROJECT_DIR=$(realpath $SCRIPT_DIR/../../)
|
||||
ENV_DIR=$(realpath $PROJECT_DIR/../../../)
|
||||
|
||||
# Check .env file
|
||||
if [ ! -f "$PROJECT_DIR/.env" ]
|
||||
then
|
||||
echo "Create .env file from example..."
|
||||
cp "$PROJECT_DIR/.env.example" "$PROJECT_DIR/.env"
|
||||
echo ".env file created, please change variables and call init again"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Source key-scripts
|
||||
source $ENV_DIR/bin/drun
|
||||
source $ENV_DIR/bin/dexec
|
||||
|
||||
# Build and start docker containers
|
||||
dexec template-backend build
|
||||
dexec template-backend up -d
|
||||
|
||||
# Install PHP packages
|
||||
drun template-backend composer install
|
||||
|
||||
# Dump autoload
|
||||
drun template-backend composer da
|
||||
|
||||
# Migrate databases to current version
|
||||
drun template-backend composer dmm
|
||||
drun template-backend composer dmlm
|
||||
|
||||
# Insert setup for project after this line
|
||||
drun template-backend composer console rbac:update
|
||||
drun template-backend composer console init:data
|
||||
76
composer.json
Normal file
76
composer.json
Normal file
@ -0,0 +1,76 @@
|
||||
{
|
||||
"require": {
|
||||
"laminas/laminas-servicemanager": "^3.21",
|
||||
"mezzio/mezzio-laminasrouter": "^3.8",
|
||||
"reinfi/zf-dependency-injection": "^5.4",
|
||||
"laminas/laminas-config-aggregator": "^1.13",
|
||||
"doctrine/doctrine-orm-module": "5.0.*",
|
||||
"doctrine/migrations": "^3.5",
|
||||
"doctrine/orm": "2.11.3",
|
||||
"doctrine/persistence": "2.2.*",
|
||||
"ramsey/uuid-doctrine": "^1.8",
|
||||
"roave/psr-container-doctrine": "^3.1",
|
||||
"mezzio/mezzio": "^3.17",
|
||||
"mezzio/mezzio-helpers": "^5.15",
|
||||
"symfony/cache": "5.4.8",
|
||||
"doctrine/dbal": "^3.6",
|
||||
"teewurst/psr4-advanced-wildcard-composer-plugin": "^3.0",
|
||||
"laminas/laminas-crypt": "^3.10",
|
||||
"monolog/monolog": "^3.4",
|
||||
"laminas/laminas-mail": "^2.23",
|
||||
"teewurst/pipeline": "^3.0",
|
||||
"guzzlehttp/guzzle": "^7.8"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Template\\API\\Console\\": "src/ApiDomain/Console/src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"teewurst/psr4-advanced-wildcard-composer-plugin": {
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Template\\API\\%s\\%s\\": "src/ApiDomain/{*}/{*}/src/",
|
||||
"Template\\Data\\%s\\": "src/DataDomain/{*}/src/",
|
||||
"Template\\Handling\\%s\\": "src/HandlingDomain/{*}/src/",
|
||||
"Template\\Infrastructure\\%s\\": "src/Infrastructure/{*}/src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Template\\API\\%s\\%s\\": "src/ApiDomain/{*}/{*}/src/",
|
||||
"Template\\Data\\%s\\": "src/DataDomain/{*}/src/",
|
||||
"Template\\Handling\\%s\\": "src/HandlingDomain/{*}/src/",
|
||||
"Template\\Infrastructure\\%s\\": "src/Infrastructure/{*}/src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"dmg": "php bin/doctrine-migrations.php migrations:generate --no-interaction",
|
||||
"dmm": "php bin/doctrine-migrations.php migrations:migrate --no-interaction",
|
||||
"dmlg": "php bin/doctrine-migrations-log.php migrations:generate --no-interaction",
|
||||
"dmlm": "php bin/doctrine-migrations-log.php migrations:migrate --no-interaction",
|
||||
"console": "php bin/console.php",
|
||||
"createApi": "php bin/createApi.php",
|
||||
"createPipeline": "php bin/createPipeline.php",
|
||||
"da": [
|
||||
"composer dump-autoload",
|
||||
"composer dump-autoload --dev"
|
||||
],
|
||||
"initdb": [
|
||||
"@composer dmm",
|
||||
"@composer dmlm",
|
||||
"@composer console rbac:update",
|
||||
"@composer console init:data"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"teewurst/psr4-advanced-wildcard-composer-plugin": true
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/dotenv": "^6.3"
|
||||
}
|
||||
}
|
||||
2
config/autoload/.gitignore
vendored
Normal file
2
config/autoload/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
local.php
|
||||
*.local.php
|
||||
29
config/autoload/api.global.php
Normal file
29
config/autoload/api.global.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'api' => [
|
||||
'keys' => [
|
||||
'template' => $_ENV['HOMEPAGE_API_KEY'],
|
||||
'notification' => $_ENV['NOTIFICATION_API_KEY'],
|
||||
],
|
||||
|
||||
'services' => [
|
||||
'template' => [
|
||||
'host' => 'template-backend-nginx',
|
||||
'apis' => [
|
||||
|
||||
]
|
||||
],
|
||||
'notification' => [
|
||||
'host' => 'notification-backend-nginx',
|
||||
'apis' => [
|
||||
'send-mail' => [
|
||||
'path' => '/api/mail/send',
|
||||
'method' => 'POST'
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
22
config/autoload/authorization.global.php
Normal file
22
config/autoload/authorization.global.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'template-rbac' => [
|
||||
'roles' => [
|
||||
'admin',
|
||||
'user',
|
||||
],
|
||||
'permissions' => [
|
||||
'user' => [
|
||||
'product.product-list',
|
||||
],
|
||||
'admin' => [
|
||||
'product.create-product',
|
||||
'product.delete-product',
|
||||
'product.product-list',
|
||||
'product.update-product',
|
||||
'user.create-user',
|
||||
],
|
||||
]
|
||||
]
|
||||
];
|
||||
6
config/autoload/defines.php
Normal file
6
config/autoload/defines.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
|
||||
if (! defined('APP_ROOT')) {
|
||||
define('APP_ROOT', realpath(__DIR__ . '/../../'));
|
||||
}
|
||||
26
config/autoload/dependencies.global.php
Normal file
26
config/autoload/dependencies.global.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
// Provides application-wide services.
|
||||
// We recommend using fully-qualified class names whenever possible as
|
||||
// service names.
|
||||
'dependencies' => [
|
||||
// Use 'aliases' to alias a service name to another service. The
|
||||
// key is the alias name, the value is the service to which it points.
|
||||
'aliases' => [
|
||||
// Fully\Qualified\ClassOrInterfaceName::class => Fully\Qualified\ClassName::class,
|
||||
],
|
||||
// Use 'invokables' for constructor-less services, or services that do
|
||||
// not require arguments to the constructor. Map a service name to the
|
||||
// class name.
|
||||
'invokables' => [
|
||||
// Fully\Qualified\InterfaceName::class => Fully\Qualified\ClassName::class,
|
||||
],
|
||||
// Use 'factories' for services provided by callbacks/factory classes.
|
||||
'factories' => [
|
||||
// Fully\Qualified\ClassName::class => Fully\Qualified\FactoryName::class,
|
||||
],
|
||||
],
|
||||
];
|
||||
14
config/autoload/doctrine.global.php
Normal file
14
config/autoload/doctrine.global.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use Doctrine\DBAL\Driver\PDO\MySQL\Driver;
|
||||
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
|
||||
use Ramsey\Uuid\Doctrine\UuidBinaryOrderedTimeType;
|
||||
|
||||
return [
|
||||
'doctrine' => [
|
||||
'types' => [
|
||||
UuidBinaryOrderedTimeType::NAME => UuidBinaryOrderedTimeType::class,
|
||||
],
|
||||
],
|
||||
];
|
||||
14
config/autoload/logger.global.php
Normal file
14
config/autoload/logger.global.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Monolog\Level;
|
||||
|
||||
return [
|
||||
'logger' => [
|
||||
'name' => 'template.backend',
|
||||
'path' => APP_ROOT . '/var/log/template.backend.log',
|
||||
'level' => Level::Debug,
|
||||
'pretty' => true,
|
||||
]
|
||||
];
|
||||
24
config/autoload/mezzio.global.php
Normal file
24
config/autoload/mezzio.global.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laminas\ConfigAggregator\ConfigAggregator;
|
||||
|
||||
return [
|
||||
// Toggle the configuration cache. Set this to boolean false, or remove the
|
||||
// directive, to disable configuration caching. Toggling development mode
|
||||
// will also disable it by default; clear the configuration cache using
|
||||
// `composer clear-config-cache`.
|
||||
ConfigAggregator::ENABLE_CACHE => false,
|
||||
|
||||
// Enable debugging; typically used to provide debugging information within templates.
|
||||
'debug' => false,
|
||||
'mezzio' => [
|
||||
// Provide templates for the error handling middleware to use when
|
||||
// generating responses.
|
||||
'error_handler' => [
|
||||
'template_404' => 'error::404',
|
||||
'template_error' => 'error::error',
|
||||
],
|
||||
],
|
||||
];
|
||||
89
config/config.php
Normal file
89
config/config.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laminas\ConfigAggregator\ArrayProvider;
|
||||
use Laminas\ConfigAggregator\ConfigAggregator;
|
||||
use Laminas\ConfigAggregator\PhpFileProvider;
|
||||
|
||||
// To enable or disable caching, set the `ConfigAggregator::ENABLE_CACHE` boolean in
|
||||
// `config/autoload/local.php`.
|
||||
$cacheConfig = [
|
||||
'config_cache_path' => 'data/cache/config-cache.php',
|
||||
];
|
||||
|
||||
$aggregator = new ConfigAggregator([
|
||||
// Include cache configuration
|
||||
new ArrayProvider($cacheConfig),
|
||||
\Mezzio\Helper\ConfigProvider::class,
|
||||
\Mezzio\ConfigProvider::class,
|
||||
\Mezzio\Router\ConfigProvider::class,
|
||||
\Mezzio\Router\LaminasRouter\ConfigProvider::class,
|
||||
|
||||
\Laminas\Diactoros\ConfigProvider::class,
|
||||
\Laminas\HttpHandlerRunner\ConfigProvider::class,
|
||||
\Laminas\Validator\ConfigProvider::class,
|
||||
\Laminas\Router\ConfigProvider::class,
|
||||
|
||||
\Reinfi\DependencyInjection\ConfigProvider::class,
|
||||
|
||||
\DoctrineORMModule\ConfigProvider::class,
|
||||
\DoctrineModule\ConfigProvider::class,
|
||||
|
||||
|
||||
// Swoole config to overwrite some services (if installed)
|
||||
class_exists(\Mezzio\Swoole\ConfigProvider::class)
|
||||
? \Mezzio\Swoole\ConfigProvider::class
|
||||
: function (): array {
|
||||
return [];
|
||||
},
|
||||
|
||||
|
||||
// Data
|
||||
\Template\Data\Business\ConfigProvider::class,
|
||||
\Template\Data\Log\ConfigProvider::class,
|
||||
|
||||
// Infrastructure
|
||||
\Template\Infrastructure\Database\ConfigProvider::class,
|
||||
\Template\Infrastructure\DependencyInjection\ConfigProvider::class,
|
||||
\Template\Infrastructure\Encryption\ConfigProvider::class,
|
||||
\Template\Infrastructure\Exception\ConfigProvider::class,
|
||||
\Template\Infrastructure\Logging\ConfigProvider::class,
|
||||
\Template\Infrastructure\Rbac\ConfigProvider::class,
|
||||
\Template\Infrastructure\Request\ConfigProvider::class,
|
||||
\Template\Infrastructure\Session\ConfigProvider::class,
|
||||
|
||||
// HandlingDomain
|
||||
\Template\Handling\User\ConfigProvider::class,
|
||||
\Template\Handling\UserSession\ConfigProvider::class,
|
||||
\Template\Handling\Registration\ConfigProvider::class,
|
||||
|
||||
// API
|
||||
/// Command
|
||||
\Template\API\Console\ConfigProvider::class,
|
||||
|
||||
/// External
|
||||
\Template\API\External\Health\ConfigProvider::class,
|
||||
\Template\API\External\User\ConfigProvider::class,
|
||||
\Template\API\External\Authentication\ConfigProvider::class,
|
||||
|
||||
/// Internal
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Load application config in a pre-defined order in such a way that local settings
|
||||
// overwrite global settings. (Loaded as first to last):
|
||||
// - `global.php`
|
||||
// - `*.global.php`
|
||||
// - `local.php`
|
||||
// - `*.local.php`
|
||||
new PhpFileProvider(realpath(__DIR__) . '/autoload/{{,*.}global,{,*.}local}.php'),
|
||||
|
||||
// Load development config if it exists
|
||||
new PhpFileProvider(realpath(__DIR__) . '/development.config.php'),
|
||||
], $cacheConfig['config_cache_path']);
|
||||
|
||||
return $aggregator->getMergedConfig();
|
||||
21
config/container.php
Normal file
21
config/container.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laminas\ServiceManager\ServiceManager;
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
|
||||
$dotenv = new Dotenv();
|
||||
|
||||
if (file_exists(__DIR__ . '/../.env')) {
|
||||
$dotenv->load(__DIR__ . '/../.env');
|
||||
}
|
||||
|
||||
// Load configuration
|
||||
$config = require __DIR__ . '/config.php';
|
||||
|
||||
$dependencies = $config['dependencies'];
|
||||
$dependencies['services']['config'] = $config;
|
||||
|
||||
// Build container
|
||||
return new ServiceManager($dependencies);
|
||||
31
config/development.config.php
Normal file
31
config/development.config.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* File required to allow enablement of development mode.
|
||||
*
|
||||
* For use with the laminas-development-mode tool.
|
||||
*
|
||||
* Usage:
|
||||
* $ composer development-disable
|
||||
* $ composer development-enable
|
||||
* $ composer development-status
|
||||
*
|
||||
* DO NOT MODIFY THIS FILE.
|
||||
*
|
||||
* Provide your own development-mode settings by editing the file
|
||||
* `config/autoload/development.local.php.dist`.
|
||||
*
|
||||
* Because this file is aggregated last, it simply ensures:
|
||||
*
|
||||
* - The `debug` flag is _enabled_.
|
||||
* - Configuration caching is _disabled_.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laminas\ConfigAggregator\ConfigAggregator;
|
||||
|
||||
return [
|
||||
'debug' => true,
|
||||
ConfigAggregator::ENABLE_CACHE => false,
|
||||
];
|
||||
94
config/pipeline.php
Normal file
94
config/pipeline.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Template\Infrastructure\Exception\Middleware\ExceptionHandlerMiddleware;
|
||||
use Template\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
|
||||
use Template\Infrastructure\Request\Middleware\AnalyzeHeaderMiddleware;
|
||||
use Template\Infrastructure\Session\Middleware\SessionMiddleware;
|
||||
use Laminas\Stratigility\Middleware\ErrorHandler;
|
||||
use Mezzio\Application;
|
||||
use Mezzio\Handler\NotFoundHandler;
|
||||
use Mezzio\Helper\ServerUrlMiddleware;
|
||||
use Mezzio\Helper\UrlHelperMiddleware;
|
||||
use Mezzio\MiddlewareFactory;
|
||||
use Mezzio\Router\Middleware\DispatchMiddleware;
|
||||
use Mezzio\Router\Middleware\ImplicitHeadMiddleware;
|
||||
use Mezzio\Router\Middleware\ImplicitOptionsMiddleware;
|
||||
use Mezzio\Router\Middleware\MethodNotAllowedMiddleware;
|
||||
use Mezzio\Router\Middleware\RouteMiddleware;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Setup middleware pipeline:
|
||||
*/
|
||||
|
||||
return function (Application $app, MiddlewareFactory $factory, ContainerInterface $container): void {
|
||||
// The error handler should be the first (most outer) middleware to catch
|
||||
// all Exceptions.
|
||||
$app->pipe(ErrorHandler::class);
|
||||
$app->pipe(ServerUrlMiddleware::class);
|
||||
|
||||
// Pipe more middleware here that you want to execute on every request:
|
||||
// - bootstrapping
|
||||
// - pre-conditions
|
||||
// - modifications to outgoing responses
|
||||
//
|
||||
// Piped Middleware may be either callables or service names. Middleware may
|
||||
// also be passed as an array; each item in the array must resolve to
|
||||
// middleware eventually (i.e., callable or service name).
|
||||
//
|
||||
// Middleware can be attached to specific paths, allowing you to mix and match
|
||||
// applications under a common domain. The handlers in each middleware
|
||||
// attached this way will see a URI with the matched path segment removed.
|
||||
//
|
||||
// i.e., path of "/api/member/profile" only passes "/member/profile" to $apiMiddleware
|
||||
// - $app->pipe('/api', $apiMiddleware);
|
||||
// - $app->pipe('/docs', $apiDocMiddleware);
|
||||
// - $app->pipe('/files', $filesMiddleware);
|
||||
|
||||
// Register the routing middleware in the middleware pipeline.
|
||||
// This middleware registers the Mezzio\Router\RouteResult request attribute.
|
||||
$app->pipe(RouteMiddleware::class);
|
||||
|
||||
// The following handle routing failures for common conditions:
|
||||
// - HEAD request but no routes answer that method
|
||||
// - OPTIONS request but no routes answer that method
|
||||
// - method not allowed
|
||||
// Order here matters; the MethodNotAllowedMiddleware should be placed
|
||||
// after the Implicit*Middleware.
|
||||
$app->pipe(ImplicitHeadMiddleware::class);
|
||||
$app->pipe(ImplicitOptionsMiddleware::class);
|
||||
$app->pipe(MethodNotAllowedMiddleware::class);
|
||||
|
||||
// Seed the UrlHelper with the routing results:
|
||||
$app->pipe(UrlHelperMiddleware::class);
|
||||
|
||||
|
||||
|
||||
|
||||
//// Pre Template Space
|
||||
$app->pipe(ExceptionHandlerMiddleware::class);
|
||||
$app->pipe(AnalyzeHeaderMiddleware::class);
|
||||
$app->pipe(AnalyzeBodyMiddleware::class);
|
||||
|
||||
//// Template Space
|
||||
$app->pipe(SessionMiddleware::class);
|
||||
|
||||
|
||||
|
||||
// Add more middleware here that needs to introspect the routing results; this
|
||||
// might include:
|
||||
//
|
||||
// - route-based authentication
|
||||
// - route-based validation
|
||||
// - etc.
|
||||
|
||||
// Register the dispatch middleware in the middleware pipeline
|
||||
$app->pipe(DispatchMiddleware::class);
|
||||
|
||||
// At this point, if no Response is returned by any middleware, the
|
||||
// NotFoundHandler kicks in; alternately, you can provide other fallback
|
||||
// middleware to execute.
|
||||
$app->pipe(NotFoundHandler::class);
|
||||
};
|
||||
52
config/routes.php
Normal file
52
config/routes.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Mezzio\Application;
|
||||
use Mezzio\MiddlewareFactory;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Template\Infrastructure\Session\Middleware\LoggedInUserMiddleware;
|
||||
|
||||
/**
|
||||
* laminas-router route configuration
|
||||
*
|
||||
* @see https://docs.laminas.dev/laminas-router/
|
||||
*
|
||||
* Setup routes with a single request method:
|
||||
*
|
||||
* $app->get('/', App\Handler\HomePageHandler::class, 'home');
|
||||
* $app->post('/album', App\Handler\AlbumCreateHandler::class, 'album.create');
|
||||
* $app->put('/album/:id', App\Handler\AlbumUpdateHandler::class, 'album.put');
|
||||
* $app->patch('/album/:id', App\Handler\AlbumUpdateHandler::class, 'album.patch');
|
||||
* $app->delete('/album/:id', App\Handler\AlbumDeleteHandler::class, 'album.delete');
|
||||
*
|
||||
* Or with multiple request methods:
|
||||
*
|
||||
* $app->route('/contact', App\Handler\ContactHandler::class, ['GET', 'POST', ...], 'contact');
|
||||
*
|
||||
* Or handling all request methods:
|
||||
*
|
||||
* $app->route('/contact', App\Handler\ContactHandler::class)->setName('contact');
|
||||
*
|
||||
* or:
|
||||
*
|
||||
* $app->route(
|
||||
* '/contact',
|
||||
* App\Handler\ContactHandler::class,
|
||||
* Mezzio\Router\Route::HTTP_METHOD_ANY,
|
||||
* 'contact'
|
||||
* );
|
||||
*/
|
||||
|
||||
return static function (Application $app, MiddlewareFactory $factory, ContainerInterface $container): void {
|
||||
$config = $container->get('config');
|
||||
|
||||
foreach ($config['routes'] as $routeConfig) {
|
||||
$app->route(
|
||||
name: $routeConfig['name'],
|
||||
path: $routeConfig['path'],
|
||||
middleware: $routeConfig['middleware'],
|
||||
methods: $routeConfig['allowed_methods']
|
||||
);
|
||||
}
|
||||
};
|
||||
32
data/migrations/business/Version20230922085011.php
Normal file
32
data/migrations/business/Version20230922085011.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Migrations\Template;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20230922085011 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Create Table 'role'";
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$sql = "CREATE TABLE role (
|
||||
id binary(16) NOT NULL,
|
||||
identifier varchar(255) UNIQUE NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);";
|
||||
|
||||
$this->addSql($sql);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("DROP TABLE role;");
|
||||
}
|
||||
}
|
||||
35
data/migrations/business/Version20230922092351.php
Normal file
35
data/migrations/business/Version20230922092351.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Migrations\Template;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20230922092351 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Create Table 'permission'";
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$sql = "CREATE TABLE permission (
|
||||
id binary(16) NOT NULL,
|
||||
identifier varchar(255) UNIQUE NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);";
|
||||
|
||||
$this->addSql($sql);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("DROP TABLE permission;");
|
||||
}
|
||||
}
|
||||
36
data/migrations/business/Version20230922092754.php
Normal file
36
data/migrations/business/Version20230922092754.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Migrations\Template;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20230922092754 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Create Table 'role_permission'";
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$sql = "CREATE TABLE role_permission (
|
||||
id binary(16) NOT NULL DEFAULT (uuid_to_bin(uuid())),
|
||||
role_id binary(16) NOT NULL,
|
||||
permission_id binary(16) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);";
|
||||
|
||||
$this->addSql($sql);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("DROP TABLE role_permission;");
|
||||
}
|
||||
}
|
||||
41
data/migrations/business/Version20230922101354.php
Normal file
41
data/migrations/business/Version20230922101354.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Migrations\Template;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20230922101354 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Create Table 'user'";
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$sql = "CREATE TABLE user (
|
||||
id binary(16) NOT NULL,
|
||||
role_id binary(16) NOT NULL,
|
||||
username varchar(255) UNIQUE NOT NULL,
|
||||
mail varchar(255) UNIQUE NOT NULL,
|
||||
password varchar(255) UNIQUE NOT NULL,
|
||||
last_login_at datetime DEFAULT NULL,
|
||||
updated_at datetime NOT NULL,
|
||||
created_at datetime NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);";
|
||||
|
||||
$this->addSql($sql);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("DROP TABLE user;");
|
||||
}
|
||||
}
|
||||
38
data/migrations/business/Version20230922101355.php
Normal file
38
data/migrations/business/Version20230922101355.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Migrations\Template;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20230922101355 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Create Table 'user_session'";
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$sql = "CREATE TABLE user_session (
|
||||
id binary(16) NOT NULL,
|
||||
user_id binary(16) DEFAULT NULL,
|
||||
csrf binary(16) DEFAULT NULL,
|
||||
updated_at datetime NOT NULL,
|
||||
created_at datetime NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);";
|
||||
|
||||
$this->addSql($sql);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("DROP TABLE role_permission;");
|
||||
}
|
||||
}
|
||||
37
data/migrations/business/Version20230924113403.php
Normal file
37
data/migrations/business/Version20230924113403.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Migrations\Template;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20230924113403 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Create Table 'registration'";
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$sql = "CREATE TABLE registration (
|
||||
id binary(16) NOT NULL,
|
||||
mail varchar(255) NOT NULL,
|
||||
username varchar(255) NOT NULL,
|
||||
created_at datetime NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);";
|
||||
|
||||
$this->addSql($sql);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("DROP TABLE registration;");
|
||||
}
|
||||
}
|
||||
40
data/migrations/log/Version20230922150649.php
Normal file
40
data/migrations/log/Version20230922150649.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Migrations\Log;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20230922150649 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Create Table 'log'";
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$query = 'CREATE TABLE log (
|
||||
id BINARY(16) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
context JSON DEFAULT NULL,
|
||||
level INT NOT NULL ,
|
||||
level_name VARCHAR(50) NOT NULL,
|
||||
extra JSON DEFAULT NULL,
|
||||
created_at datetime NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
)';
|
||||
|
||||
$this->addSql($query);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('DROP TABLE log');
|
||||
}
|
||||
}
|
||||
50
docker/docker-compose-mac.yml
Normal file
50
docker/docker-compose-mac.yml
Normal file
@ -0,0 +1,50 @@
|
||||
networks:
|
||||
template:
|
||||
external: true
|
||||
|
||||
services:
|
||||
template-backend-mysql:
|
||||
image: template-backend-mysql
|
||||
networks:
|
||||
- template
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/mysql/dockerfile
|
||||
volumes:
|
||||
- /Users/flo/dev/backend/template/var/db:/var/lib/mysql:z
|
||||
environment:
|
||||
MYSQL_USER: ${DB_USER}
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||
ports:
|
||||
- 3306:3306
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
template-backend-app:
|
||||
image: template-backend-app
|
||||
networks:
|
||||
- template
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/php/dockerfile
|
||||
volumes:
|
||||
- /Users/flo/dev/backend/template/:/var/www/html:z
|
||||
ports:
|
||||
- 9000:9000
|
||||
depends_on:
|
||||
template-backend-mysql:
|
||||
condition: service_healthy
|
||||
|
||||
template-backend-nginx:
|
||||
image: template-backend-nginx
|
||||
networks:
|
||||
- template
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/nginx/dockerfile
|
||||
ports:
|
||||
- 8080:80
|
||||
depends_on:
|
||||
- template-backend-app
|
||||
50
docker/docker-compose.yml
Normal file
50
docker/docker-compose.yml
Normal file
@ -0,0 +1,50 @@
|
||||
networks:
|
||||
template:
|
||||
external: true
|
||||
|
||||
services:
|
||||
template-backend-mysql:
|
||||
image: template-backend-mysql
|
||||
networks:
|
||||
- template
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/mysql/dockerfile
|
||||
volumes:
|
||||
- ./../var/db:/var/lib/mysql:z
|
||||
environment:
|
||||
MYSQL_USER: ${DB_USER}
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||
ports:
|
||||
- 3306:3306
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
template-backend-app:
|
||||
image: template-backend-app
|
||||
networks:
|
||||
- template
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/php/dockerfile
|
||||
volumes:
|
||||
- ./../:/var/www/html:z
|
||||
ports:
|
||||
- 9000:9000
|
||||
depends_on:
|
||||
template-backend-mysql:
|
||||
condition: service_healthy
|
||||
|
||||
template-backend-nginx:
|
||||
image: template-backend-nginx
|
||||
networks:
|
||||
- template
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/nginx/dockerfile
|
||||
ports:
|
||||
- 8080:80
|
||||
depends_on:
|
||||
- template-backend-app
|
||||
7
docker/mysql/dockerfile
Normal file
7
docker/mysql/dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
FROM mysql:latest
|
||||
|
||||
ENV MYSQL_RANDOM_ROOT_PASSWORD=1
|
||||
|
||||
COPY docker/mysql/scripts /docker-entrypoint-initdb.d/
|
||||
|
||||
CMD ["mysqld"]
|
||||
4
docker/mysql/scripts/initdb.sql
Normal file
4
docker/mysql/scripts/initdb.sql
Normal file
@ -0,0 +1,4 @@
|
||||
CREATE DATABASE IF NOT EXISTS `log`;
|
||||
CREATE DATABASE IF NOT EXISTS `template`;
|
||||
|
||||
GRANT ALL PRIVILEGES on *.* to 'template'@'%';
|
||||
15
docker/nginx/config/nginx.conf
Normal file
15
docker/nginx/config/nginx.conf
Normal file
@ -0,0 +1,15 @@
|
||||
upstream host-backend-app {
|
||||
server template-backend-app:9000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
|
||||
location / {
|
||||
fastcgi_pass host-backend-app;
|
||||
fastcgi_index index.php;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME /var/www/html/public/index.php;
|
||||
}
|
||||
}
|
||||
3
docker/nginx/config/upstream.conf
Normal file
3
docker/nginx/config/upstream.conf
Normal file
@ -0,0 +1,3 @@
|
||||
upstream backend-dev {
|
||||
server backend-app:9000;
|
||||
}
|
||||
5
docker/nginx/dockerfile
Normal file
5
docker/nginx/dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
COPY docker/nginx/config/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
15
docker/php/dockerfile
Normal file
15
docker/php/dockerfile
Normal file
@ -0,0 +1,15 @@
|
||||
FROM php:8.1-fpm
|
||||
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y install git
|
||||
|
||||
RUN chown -R www-data:www-data /var/www/html
|
||||
WORKDIR /var/www/html
|
||||
|
||||
RUN docker-php-ext-install pdo pdo_mysql
|
||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
|
||||
USER docker
|
||||
|
||||
CMD ["php-fpm"]
|
||||
26
phpunit.xml.dist
Normal file
26
phpunit.xml.dist
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
beStrictAboutCoversAnnotation="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
bootstrap="vendor/autoload.php"
|
||||
convertDeprecationsToExceptions="true"
|
||||
executionOrder="depends,defects"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
verbose="true"
|
||||
colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="default">
|
||||
<directory suffix="Test.php">test</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
</phpunit>
|
||||
19
public/.htaccess
Normal file
19
public/.htaccess
Normal file
@ -0,0 +1,19 @@
|
||||
RewriteEngine On
|
||||
# The following rule allows authentication to work with fast-cgi
|
||||
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
# The following rule tells Apache that if the requested filename
|
||||
# exists, simply serve it.
|
||||
RewriteCond %{REQUEST_FILENAME} -f [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -l [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^ - [NC,L]
|
||||
|
||||
# The following rewrites all other queries to index.php. The
|
||||
# condition ensures that if you are using Apache aliases to do
|
||||
# mass virtual hosting, the base path will be prepended to
|
||||
# allow proper resolution of the index.php file; it will work
|
||||
# in non-aliased environments as well, providing a safe, one-size
|
||||
# fits all solution.
|
||||
RewriteCond $0::%{REQUEST_URI} ^([^:]*+(?::[^:]*+)*?)::(/.+?)\1$
|
||||
RewriteRule .+ - [E=BASE:%2]
|
||||
RewriteRule .* %{ENV:BASE}index.php [NC,L]
|
||||
48
public/index.php
Normal file
48
public/index.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Mezzio\Application;
|
||||
use Mezzio\MiddlewareFactory;
|
||||
|
||||
if (PHP_SAPI === 'cli-server' && $_SERVER['SCRIPT_FILENAME'] !== __FILE__) {
|
||||
return false;
|
||||
}
|
||||
|
||||
require './../vendor/autoload.php';
|
||||
|
||||
require './../config/autoload/defines.php';
|
||||
|
||||
function throwableToMessageArray(Throwable $e): array {
|
||||
$messageArray = [];
|
||||
while($e !== null) {
|
||||
$messageArray[] = $e->getMessage();
|
||||
$e = $e->getPrevious();
|
||||
}
|
||||
return $messageArray;
|
||||
}
|
||||
|
||||
function throwableToMessageArrayString(Throwable $e): string {
|
||||
return implode( PHP_EOL, throwableToMessageArray($e) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Self-called anonymous function that creates its own scope and keeps the global namespace clean.
|
||||
*/
|
||||
(function () {
|
||||
|
||||
/** @var \Psr\Container\ContainerInterface $container */
|
||||
$container = require './../config/container.php';
|
||||
|
||||
/** @var Application $app */
|
||||
$app = $container->get(Application::class);
|
||||
$factory = $container->get(MiddlewareFactory::class);
|
||||
|
||||
// Execute programmatic/declarative middleware pipeline and routing
|
||||
// configuration statements
|
||||
(require './../config/pipeline.php')($app, $factory, $container);
|
||||
(require './../config/routes.php')($app, $factory, $container);
|
||||
|
||||
$app->run();
|
||||
|
||||
})();
|
||||
11
src/ApiDomain/Console/config/console.php
Normal file
11
src/ApiDomain/Console/config/console.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
use Template\API\Console\Command\InitializeDataCommand;
|
||||
use Template\API\Console\Command\RbacUpdateCommand;
|
||||
|
||||
return [
|
||||
'commands' => [
|
||||
InitializeDataCommand::class,
|
||||
RbacUpdateCommand::class,
|
||||
]
|
||||
];
|
||||
12
src/ApiDomain/Console/config/service_manager.php
Normal file
12
src/ApiDomain/Console/config/service_manager.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Template\API\Console\Command\InitializeDataCommand;
|
||||
use Template\API\Console\Command\RbacUpdateCommand;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
InitializeDataCommand::class => AutoWiringFactory::class,
|
||||
RbacUpdateCommand::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
80
src/ApiDomain/Console/src/Command/InitializeDataCommand.php
Normal file
80
src/ApiDomain/Console/src/Command/InitializeDataCommand.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Template\API\Console\Command;
|
||||
|
||||
use Template\Data\Business\Entity\Role;
|
||||
use Template\Data\Business\Entity\User;
|
||||
use Template\Data\Business\Repository\RoleRepository;
|
||||
use Template\Data\Business\Repository\UserRepository;
|
||||
use Template\Data\Business\Manager\EntityManager;
|
||||
use Template\Infrastructure\Encryption\Client\EncryptionClient;
|
||||
use Template\Infrastructure\Logging\Logger\Logger;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(name: 'init:data', description: 'Initializes the applications data')]
|
||||
class InitializeDataCommand extends Command
|
||||
{
|
||||
private readonly RoleRepository $roleRepository;
|
||||
private readonly UserRepository $userRepository;
|
||||
|
||||
public function __construct(
|
||||
private readonly EncryptionClient $encryptionClient,
|
||||
private readonly EntityManager $entityManager,
|
||||
private readonly Logger $logger,
|
||||
) {
|
||||
parent::__construct($this->getName());
|
||||
|
||||
$this->roleRepository = $this->entityManager->getRepository(Role::class);
|
||||
$this->userRepository = $this->entityManager->getRepository(User::class);
|
||||
}
|
||||
|
||||
protected function execute(
|
||||
InputInterface $input,
|
||||
OutputInterface $output
|
||||
): int {
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
try {
|
||||
$admin = $this->roleRepository->findOneBy([
|
||||
'identifier' => 'admin'
|
||||
]) ?? null;
|
||||
if ($admin === null) {
|
||||
throw new \Exception('Admin role does not exist!');
|
||||
}
|
||||
|
||||
$adminUser = $this->userRepository->findOneBy([
|
||||
'roleId' => $admin->getId()
|
||||
]) ?? null;
|
||||
|
||||
if ($adminUser === null) {
|
||||
$io->info('Create admin');
|
||||
|
||||
$adminUser = new User();
|
||||
$adminUser->setRole($admin);
|
||||
$adminUser->setUsername($_ENV['INIT_USER_NAME']);
|
||||
$adminUser->setMail($_ENV['INIT_USER_MAIL']);
|
||||
$adminUser->setPassword(
|
||||
$this->encryptionClient->encrypt(
|
||||
$_ENV['INIT_USER_PASSWORD']
|
||||
)
|
||||
);
|
||||
|
||||
$this->entityManager->persist($adminUser);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
$io->success('OK!');
|
||||
} catch (\Throwable $e) {
|
||||
$io->error($e->getMessage());
|
||||
$io->error($e->getTraceAsString());
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
98
src/ApiDomain/Console/src/Command/RbacUpdateCommand.php
Normal file
98
src/ApiDomain/Console/src/Command/RbacUpdateCommand.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Template\API\Console\Command;
|
||||
|
||||
use Template\Data\Business\Entity\Permission;
|
||||
use Template\Data\Business\Entity\Role;
|
||||
use Template\Data\Business\Repository\PermissionRepository;
|
||||
use Template\Data\Business\Repository\RoleRepository;
|
||||
use Template\Data\Business\Manager\EntityManager;
|
||||
use Template\Infrastructure\Logging\Logger\Logger;
|
||||
use Reinfi\DependencyInjection\Service\ConfigService;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(name: 'rbac:update', description: 'Updates RBAC entries in DB')]
|
||||
class RbacUpdateCommand extends Command
|
||||
{
|
||||
private array $rbacConfig;
|
||||
private RoleRepository $roleRepository;
|
||||
private PermissionRepository $permissionRepository;
|
||||
|
||||
public function __construct(
|
||||
private readonly ConfigService $configService,
|
||||
private readonly EntityManager $entityManager,
|
||||
private readonly Logger $logger,
|
||||
) {
|
||||
parent::__construct($this->getName());
|
||||
|
||||
$this->roleRepository = $this->entityManager->getRepository(Role::class);
|
||||
$this->permissionRepository = $this->entityManager->getRepository(Permission::class);
|
||||
|
||||
$this->rbacConfig = $this->configService->resolve('template-rbac')->toArray();
|
||||
}
|
||||
|
||||
protected function execute(
|
||||
InputInterface $input,
|
||||
OutputInterface $output
|
||||
): int {
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
try {
|
||||
|
||||
$roles = [];
|
||||
|
||||
foreach ($this->rbacConfig['roles'] as $roleIdentifier) {
|
||||
$role = $this->roleRepository->findOneBy([
|
||||
'identifier' => $roleIdentifier
|
||||
]) ?? null;
|
||||
|
||||
if ($role === null) {
|
||||
$role = new Role();
|
||||
$role->setIdentifier($roleIdentifier);
|
||||
|
||||
$this->entityManager->persist($role);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
$roles[$roleIdentifier] = $role;
|
||||
}
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$roleIdentifier = $role->getIdentifier();
|
||||
|
||||
foreach ($this->rbacConfig['permissions'][$roleIdentifier] as $permissionIdentifier) {
|
||||
$io->info($role->getIdentifier() . '.' . $permissionIdentifier);
|
||||
|
||||
$permission = $this->permissionRepository->findOneBy([
|
||||
'identifier' => $permissionIdentifier
|
||||
]) ?? null;
|
||||
|
||||
if ($permission === null) {
|
||||
$permission = new Permission();
|
||||
$permission->setIdentifier($permissionIdentifier);
|
||||
|
||||
$this->entityManager->persist($permission);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
$role->addPermission($permission);
|
||||
$this->entityManager->persist($role);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
}
|
||||
|
||||
$io->success('OK!');
|
||||
} catch (\Throwable $e) {
|
||||
$io->error($e->getMessage());
|
||||
$io->error($e->getTraceAsString());
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
16
src/ApiDomain/Console/src/ConfigProvider.php
Normal file
16
src/ApiDomain/Console/src/ConfigProvider.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\Console;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . './../config/service_manager.php',
|
||||
'console' => require __DIR__ . '/./../config/console.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
43
src/ApiDomain/External/Authentication/config/routes.php
vendored
Normal file
43
src/ApiDomain/External/Authentication/config/routes.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Template\API\External\Authentication\Handler\ConfirmRegistrationHandler;
|
||||
use Template\API\External\Authentication\Handler\LoginUserHandler;
|
||||
use Template\API\External\Authentication\Handler\LogoutUserHandler;
|
||||
use Template\API\External\Authentication\Handler\RegisterUserHandler;
|
||||
use Template\Infrastructure\Session\Middleware\LoggedInUserMiddleware;
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => 'auth.login-user',
|
||||
'path' => '/api/auth/login-user',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
LoginUserHandler::class
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'auth.logout-user',
|
||||
'path' => '/api/auth/logout-user',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
LoggedInUserMiddleware::class,
|
||||
LogoutUserHandler::class
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'auth.confirm-registration',
|
||||
'path' => '/api/auth/confirm-registration',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
ConfirmRegistrationHandler::class
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'auth.register-user',
|
||||
'path' => '/api/auth/register-user',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
RegisterUserHandler::class
|
||||
],
|
||||
],
|
||||
];
|
||||
17
src/ApiDomain/External/Authentication/config/service_manager.php
vendored
Normal file
17
src/ApiDomain/External/Authentication/config/service_manager.php
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
use Template\API\External\Authentication\Handler\ConfirmRegistrationHandler;
|
||||
use Template\API\External\Authentication\Handler\LoginUserHandler;
|
||||
use Template\API\External\Authentication\Handler\LogoutUserHandler;
|
||||
use Template\API\External\Authentication\Handler\RegisterUserHandler;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
// Handler
|
||||
LoginUserHandler::class => AutoWiringFactory::class,
|
||||
LogoutUserHandler::class => AutoWiringFactory::class,
|
||||
ConfirmRegistrationHandler::class => AutoWiringFactory::class,
|
||||
RegisterUserHandler::class => AutoWiringFactory::class
|
||||
],
|
||||
];
|
||||
16
src/ApiDomain/External/Authentication/src/ConfigProvider.php
vendored
Normal file
16
src/ApiDomain/External/Authentication/src/ConfigProvider.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\Authentication;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . '/./../config/service_manager.php',
|
||||
'routes' => require __DIR__ . '/./../config/routes.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
44
src/ApiDomain/External/Authentication/src/Handler/ConfirmRegistrationHandler.php
vendored
Normal file
44
src/ApiDomain/External/Authentication/src/Handler/ConfirmRegistrationHandler.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\Authentication\Handler;
|
||||
|
||||
use Template\API\External\User\Formatter\UserFormatter;
|
||||
use Template\Handling\Registration\Handler\Command\ConfirmRegistration\ConfirmRegistrationCommandBuilder;
|
||||
use Template\Handling\Registration\Handler\Command\ConfirmRegistration\ConfirmRegistrationCommandHandler;
|
||||
use Template\Infrastructure\Session\Middleware\SessionMiddleware;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
class ConfirmRegistrationHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ConfirmRegistrationCommandHandler $handler,
|
||||
private readonly ConfirmRegistrationCommandBuilder $builder,
|
||||
private readonly UserFormatter $userFormatter
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$data = json_decode(
|
||||
$request->getBody()->getContents(),
|
||||
true
|
||||
);
|
||||
|
||||
$query = $this->builder->build(
|
||||
Uuid::fromString($data['id']),
|
||||
$data['password'],
|
||||
$data['passwordConfirmation'],
|
||||
);
|
||||
|
||||
$result = $this->handler->execute($query);
|
||||
return new JsonResponse(
|
||||
$this->userFormatter->format($result)
|
||||
);
|
||||
}
|
||||
}
|
||||
42
src/ApiDomain/External/Authentication/src/Handler/LoginUserHandler.php
vendored
Normal file
42
src/ApiDomain/External/Authentication/src/Handler/LoginUserHandler.php
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\Authentication\Handler;
|
||||
|
||||
use Template\Handling\UserSession\Handler\Command\LoginUser\LoginUserCommandBuilder;
|
||||
use Template\Handling\UserSession\Handler\Command\LoginUser\LoginUserCommandHandler;
|
||||
use Template\Infrastructure\Session\Middleware\SessionMiddleware;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class LoginUserHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LoginUserCommandHandler $handler,
|
||||
private readonly LoginUserCommandBuilder $builder
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
|
||||
$data = json_decode(
|
||||
$request->getBody()->getContents(),
|
||||
true
|
||||
);
|
||||
|
||||
$query = $this->builder->build(
|
||||
$session,
|
||||
$data['identifier'],
|
||||
$data['password'],
|
||||
);
|
||||
|
||||
$result = $this->handler->execute($query);
|
||||
return new JsonResponse([
|
||||
'sessionId' => $result->getId()->toString()
|
||||
]);
|
||||
}
|
||||
}
|
||||
35
src/ApiDomain/External/Authentication/src/Handler/LogoutUserHandler.php
vendored
Normal file
35
src/ApiDomain/External/Authentication/src/Handler/LogoutUserHandler.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\Authentication\Handler;
|
||||
|
||||
use Template\Handling\UserSession\Handler\Command\LogoutUser\LogoutUserCommandBuilder;
|
||||
use Template\Handling\UserSession\Handler\Command\LogoutUser\LogoutUserCommandHandler;
|
||||
use Template\Infrastructure\Response\SuccessResponse;
|
||||
use Template\Infrastructure\Session\Middleware\SessionMiddleware;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class LogoutUserHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LogoutUserCommandHandler $handler,
|
||||
private readonly LogoutUserCommandBuilder $builder
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
|
||||
|
||||
$query = $this->builder->build(
|
||||
$session
|
||||
);
|
||||
$this->handler->execute($query);
|
||||
|
||||
return new JsonResponse('OK');
|
||||
}
|
||||
}
|
||||
41
src/ApiDomain/External/Authentication/src/Handler/RegisterUserHandler.php
vendored
Normal file
41
src/ApiDomain/External/Authentication/src/Handler/RegisterUserHandler.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\Authentication\Handler;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Template\Handling\Registration\Handler\Command\RegisterUser\RegisterUserCommandBuilder;
|
||||
use Template\Handling\Registration\Handler\Command\RegisterUser\RegisterUserCommandHandler;
|
||||
use Template\Infrastructure\Logging\Logger\Logger;
|
||||
use Template\Infrastructure\Request\Middleware\AnalyzeHeaderMiddleware;
|
||||
use Template\Infrastructure\Response\SuccessResponse;
|
||||
|
||||
class RegisterUserHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly RegisterUserCommandHandler $handler,
|
||||
private readonly RegisterUserCommandBuilder $builder
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$host = $request->getAttribute(AnalyzeHeaderMiddleware::HOST_ATTRIBUTE);
|
||||
$data = json_decode(
|
||||
$request->getBody()->getContents(),
|
||||
true
|
||||
);
|
||||
|
||||
$query = $this->builder->build(
|
||||
$data['username'],
|
||||
$data['mail'],
|
||||
$host
|
||||
);
|
||||
|
||||
$this->handler->execute($query);
|
||||
return new SuccessResponse();
|
||||
}
|
||||
}
|
||||
16
src/ApiDomain/External/Health/config/routes.php
vendored
Normal file
16
src/ApiDomain/External/Health/config/routes.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Template\API\External\Health\Handler\HealthHandler;
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => 'health',
|
||||
'path' => '/api/health',
|
||||
'allowed_methods' => ['GET'],
|
||||
'middleware' => [
|
||||
HealthHandler::class
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
?>
|
||||
12
src/ApiDomain/External/Health/config/service_manager.php
vendored
Normal file
12
src/ApiDomain/External/Health/config/service_manager.php
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Template\API\External\Health\Handler\HealthHandler;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
HealthHandler::class => AutoWiringFactory::class
|
||||
],
|
||||
]
|
||||
|
||||
?>
|
||||
16
src/ApiDomain/External/Health/src/ConfigProvider.php
vendored
Normal file
16
src/ApiDomain/External/Health/src/ConfigProvider.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\Health;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . './../config/service_manager.php',
|
||||
'routes' => require __DIR__ . '/./../config/routes.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
23
src/ApiDomain/External/Health/src/Handler/HealthHandler.php
vendored
Normal file
23
src/ApiDomain/External/Health/src/Handler/HealthHandler.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\Health\Handler;
|
||||
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class HealthHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return new JsonResponse("I'm fine. :)");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
48
src/ApiDomain/External/User/config/routes.php
vendored
Normal file
48
src/ApiDomain/External/User/config/routes.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
use Template\API\External\User\Handler\ChangePasswordHandler;
|
||||
use Template\API\External\User\Handler\ChangeUsernameHandler;
|
||||
use Template\API\External\User\Handler\CreateUserHandler;
|
||||
use Template\API\External\User\Handler\UserStateHandler;
|
||||
use Template\Infrastructure\Rbac\Middleware\EnsureAuthorizationMiddleware;
|
||||
use Template\Infrastructure\Session\Middleware\LoggedInUserMiddleware;
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => 'user.create-user',
|
||||
'path' => '/api/user/create-user',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
LoggedInUserMiddleware::class,
|
||||
EnsureAuthorizationMiddleware::class,
|
||||
CreateUserHandler::class
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'user.change-password',
|
||||
'path' => '/api/user/change-password',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
LoggedInUserMiddleware::class,
|
||||
ChangePasswordHandler::class
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'user.change-username',
|
||||
'path' => '/api/user/change-username',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
LoggedInUserMiddleware::class,
|
||||
ChangeUsernameHandler::class
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'user.state',
|
||||
'path' => '/api/user/state',
|
||||
'allowed_methods' => ['GET'],
|
||||
'middleware' => [
|
||||
LoggedInUserMiddleware::class,
|
||||
UserStateHandler::class
|
||||
],
|
||||
],
|
||||
];
|
||||
21
src/ApiDomain/External/User/config/service_manager.php
vendored
Normal file
21
src/ApiDomain/External/User/config/service_manager.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use Template\API\External\User\Formatter\UserFormatter;
|
||||
use Template\API\External\User\Handler\ChangePasswordHandler;
|
||||
use Template\API\External\User\Handler\ChangeUsernameHandler;
|
||||
use Template\API\External\User\Handler\CreateUserHandler;
|
||||
use Template\API\External\User\Handler\UserStateHandler;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
// Formatter
|
||||
UserFormatter::class => AutoWiringFactory::class,
|
||||
|
||||
// Handler
|
||||
CreateUserHandler::class => AutoWiringFactory::class,
|
||||
UserStateHandler::class => AutoWiringFactory::class,
|
||||
ChangePasswordHandler::class => AutoWiringFactory::class,
|
||||
ChangeUsernameHandler::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
16
src/ApiDomain/External/User/src/ConfigProvider.php
vendored
Normal file
16
src/ApiDomain/External/User/src/ConfigProvider.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\User;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . '/./../config/service_manager.php',
|
||||
'routes' => require __DIR__ . '/./../config/routes.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
27
src/ApiDomain/External/User/src/Formatter/UserFormatter.php
vendored
Normal file
27
src/ApiDomain/External/User/src/Formatter/UserFormatter.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Template\API\External\User\Formatter;
|
||||
|
||||
use DateTime;
|
||||
use Template\Data\Business\Entity\User;
|
||||
|
||||
class UserFormatter {
|
||||
|
||||
public function format(User $user): array {
|
||||
$userArray = [
|
||||
'id' => $user->getId()->toString(),
|
||||
'username' => $user->getUsername(),
|
||||
'role' => $user->getRole()->getIdentifier(),
|
||||
'created' => $user->getCreatedAt()->format(DateTime::ATOM),
|
||||
'updated' => $user->getUpdatedAt()->format(DateTime::ATOM)
|
||||
];
|
||||
|
||||
$userArray['permissions'] = [];
|
||||
|
||||
foreach ($user->getRole()->getPermissions()->toArray() as $permission) {
|
||||
$userArray['permissions'][] = $permission->getIdentifier();
|
||||
}
|
||||
|
||||
return $userArray;
|
||||
}
|
||||
}
|
||||
43
src/ApiDomain/External/User/src/Handler/ChangePasswordHandler.php
vendored
Normal file
43
src/ApiDomain/External/User/src/Handler/ChangePasswordHandler.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\User\Handler;
|
||||
|
||||
use Template\Data\Business\Entity\User;
|
||||
use Template\Handling\User\Handler\Command\ChangePassword\ChangePasswordCommandBuilder;
|
||||
use Template\Handling\User\Handler\Command\ChangePassword\ChangePasswordCommandHandler;
|
||||
use Template\Infrastructure\Response\SuccessResponse;
|
||||
use Template\Infrastructure\Session\Middleware\LoggedInUserMiddleware;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class ChangePasswordHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ChangePasswordCommandHandler $handler,
|
||||
private readonly ChangePasswordCommandBuilder $builder,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->getAttribute(LoggedInUserMiddleware::USER_KEY);
|
||||
|
||||
$data = json_decode(
|
||||
$request->getBody()->getContents(),
|
||||
true
|
||||
);
|
||||
|
||||
$query = $this->builder->build(
|
||||
$user,
|
||||
$data['password'],
|
||||
$data['newPassword'],
|
||||
);
|
||||
$this->handler->execute($query);
|
||||
|
||||
return new SuccessResponse();
|
||||
}
|
||||
}
|
||||
43
src/ApiDomain/External/User/src/Handler/ChangeUsernameHandler.php
vendored
Normal file
43
src/ApiDomain/External/User/src/Handler/ChangeUsernameHandler.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\User\Handler;
|
||||
|
||||
use Template\Data\Business\Entity\User;
|
||||
use Template\Handling\User\Handler\Command\ChangeUsername\ChangeUsernameCommandBuilder;
|
||||
use Template\Handling\User\Handler\Command\ChangeUsername\ChangeUsernameCommandHandler;
|
||||
use Template\Infrastructure\Response\SuccessResponse;
|
||||
use Template\Infrastructure\Session\Middleware\LoggedInUserMiddleware;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class ChangeUsernameHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ChangeUsernameCommandHandler $handler,
|
||||
private readonly ChangeUsernameCommandBuilder $builder,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->getAttribute(LoggedInUserMiddleware::USER_KEY);
|
||||
|
||||
$data = json_decode(
|
||||
$request->getBody()->getContents(),
|
||||
true
|
||||
);
|
||||
|
||||
$query = $this->builder->build(
|
||||
$user,
|
||||
$data['password'],
|
||||
$data['newUsername'],
|
||||
);
|
||||
$this->handler->execute($query);
|
||||
|
||||
return new SuccessResponse();
|
||||
}
|
||||
}
|
||||
44
src/ApiDomain/External/User/src/Handler/CreateUserHandler.php
vendored
Normal file
44
src/ApiDomain/External/User/src/Handler/CreateUserHandler.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\User\Handler;
|
||||
|
||||
use Template\API\External\User\Formatter\UserFormatter;
|
||||
use Template\Handling\User\Handler\Command\CreateUser\CreateUserCommandBuilder;
|
||||
use Template\Handling\User\Handler\Command\CreateUser\CreateUserCommandHandler;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class CreateUserHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly CreateUserCommandHandler $handler,
|
||||
private readonly CreateUserCommandBuilder $builder,
|
||||
private readonly UserFormatter $userFormatter,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$data = json_decode(
|
||||
$request->getBody()->getContents(),
|
||||
true
|
||||
);
|
||||
|
||||
$query = $this->builder->build(
|
||||
$data['username'],
|
||||
$data['mail'],
|
||||
$data['password'],
|
||||
);
|
||||
$result = $this->handler->execute($query);
|
||||
|
||||
return new JsonResponse(
|
||||
$this->userFormatter->format($result)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
34
src/ApiDomain/External/User/src/Handler/UserStateHandler.php
vendored
Normal file
34
src/ApiDomain/External/User/src/Handler/UserStateHandler.php
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\API\External\User\Handler;
|
||||
|
||||
use Template\API\External\User\Formatter\UserFormatter;
|
||||
use Template\Data\Business\Entity\User;
|
||||
use Template\Handling\User\Handler\Command\CreateUser\CreateUserCommandBuilder;
|
||||
use Template\Handling\User\Handler\Command\CreateUser\ChangePasswordCommandHandler;
|
||||
use Template\Infrastructure\Session\Middleware\LoggedInUserMiddleware;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class UserStateHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserFormatter $userFormatter,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->getAttribute(LoggedInUserMiddleware::USER_KEY);
|
||||
|
||||
$response = $this->userFormatter->format($user);
|
||||
$response['sessionId'] = $user->getSession()->getId()->toString();
|
||||
|
||||
return new JsonResponse($response);
|
||||
}
|
||||
}
|
||||
55
src/DataDomain/Business/config/doctrine.php
Normal file
55
src/DataDomain/Business/config/doctrine.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use Doctrine\DBAL\Driver\PDO\MySQL\Driver;
|
||||
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
|
||||
|
||||
return [
|
||||
'configuration' => [
|
||||
'orm_template' => [
|
||||
'second_level_cache' => [
|
||||
'enabled' => false,
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
'driver' => [
|
||||
'orm_template_annotation_driver' => [
|
||||
'class' => AnnotationDriver::class,
|
||||
'cache' => 'array',
|
||||
'paths' => [
|
||||
realpath(APP_ROOT . '/src/DataDomain/Business/Entity/')
|
||||
],
|
||||
],
|
||||
|
||||
'orm_template' => [
|
||||
'class' => MappingDriverChain::class,
|
||||
'drivers' => [
|
||||
'Template\Data\Business\Entity' => 'orm_template_annotation_driver',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'connection' => [
|
||||
'orm_template' => [
|
||||
'driverClass' => Driver::class,
|
||||
'params' => [
|
||||
'driver' => $_ENV['DB_DRIVER'],
|
||||
'host' => $_ENV['DB_HOST'],
|
||||
'port' => $_ENV['DB_PORT'],
|
||||
'user' => $_ENV['DB_USER'],
|
||||
'password' => $_ENV['DB_PASSWORD'],
|
||||
'dbname' => $_ENV['DB_NAME'],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'migrations_configuration' => [
|
||||
'orm_template' => [
|
||||
'directory' => 'data/migrations/business',
|
||||
'name' => 'Doctrine Database Migrations for Template',
|
||||
'namespace' => 'Template\Migrations\Template',
|
||||
'table' => 'migrations',
|
||||
],
|
||||
],
|
||||
];
|
||||
21
src/DataDomain/Business/config/service_manager.php
Normal file
21
src/DataDomain/Business/config/service_manager.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use Template\Data\Business\Entity\User;
|
||||
use Template\Data\Business\Factory\EntityManagerFactory;
|
||||
use Template\Data\Business\Manager\EntityManager;
|
||||
use Template\Data\Business\Repository\UserRepository;
|
||||
use Template\Infrastructure\Database\AutowireRepositoryFactory;
|
||||
use Roave\PsrContainerDoctrine\ConfigurationFactory;
|
||||
use Roave\PsrContainerDoctrine\ConnectionFactory;
|
||||
use Roave\PsrContainerDoctrine\EntityManagerFactory as BaseEntityManagerFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
'doctrine.entity_manager.orm_template' => [BaseEntityManagerFactory::class, 'orm_template'],
|
||||
'doctrine.configuration.orm_template' => [ConfigurationFactory::class, 'orm_template'],
|
||||
'doctrine.connection.orm_template' => [ConnectionFactory::class, 'orm_template'],
|
||||
EntityManager::class => EntityManagerFactory::class,
|
||||
|
||||
UserRepository::class => [AutowireRepositoryFactory::class, EntityManager::class, User::class],
|
||||
],
|
||||
];
|
||||
16
src/DataDomain/Business/src/ConfigProvider.php
Normal file
16
src/DataDomain/Business/src/ConfigProvider.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Data\Business;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . './../config/service_manager.php',
|
||||
'doctrine' => require __DIR__ . './../config/doctrine.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
75
src/DataDomain/Business/src/Entity/Permission.php
Normal file
75
src/DataDomain/Business/src/Entity/Permission.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Entity;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Template\Infrastructure\UuidGenerator\UuidGenerator;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="Template\Data\Business\Repository\PermissionRepository")
|
||||
* @ORM\Table(name="permission")
|
||||
*/
|
||||
class Permission {
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="id", type="uuid_binary_ordered_time")
|
||||
*/
|
||||
private UuidInterface $id;
|
||||
|
||||
/** @ORM\Column(name="identifier", type="string") */
|
||||
private string $identifier;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity="Template\Data\Business\Entity\Role", inversedBy="permissions")
|
||||
* @ORM\JoinTable(
|
||||
* name="role_permission",
|
||||
* joinColumns={@ORM\JoinColumn(name="permission_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
|
||||
* )
|
||||
*/
|
||||
private Collection $roles;
|
||||
|
||||
|
||||
public function __construct() {
|
||||
$this->id = UuidGenerator::generate();
|
||||
$this->roles = new ArrayCollection();
|
||||
}
|
||||
|
||||
|
||||
public function getId(): UuidInterface {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getIdentifier(): string {
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
public function setIdentifier(string $identifier): void {
|
||||
$this->identifier = $identifier;
|
||||
}
|
||||
|
||||
public function getRoles(): Collection {
|
||||
return $this->roles;
|
||||
}
|
||||
|
||||
public function setRoles(Collection $roles): void {
|
||||
$this->roles = $roles;
|
||||
}
|
||||
|
||||
public function addRole(Role $role): void {
|
||||
if (!$this->roles->contains($role)) {
|
||||
$this->roles->add($role);
|
||||
$role->addPermission($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function removeRole(Role $role): void {
|
||||
if ($this->roles->contains($role)) {
|
||||
$this->roles->remove($role);
|
||||
$role->removePermission($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/DataDomain/Business/src/Entity/Registration.php
Normal file
66
src/DataDomain/Business/src/Entity/Registration.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Entity;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Template\Infrastructure\UuidGenerator\UuidGenerator;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="Template\Data\Business\Repository\RegistrationRepository")
|
||||
* @ORM\Table(name="registration")
|
||||
*/
|
||||
class Registration {
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="id", type="uuid_binary_ordered_time")
|
||||
*/
|
||||
private UuidInterface $id;
|
||||
|
||||
/** @ORM\Column(name="username", type="string") */
|
||||
private string $username;
|
||||
|
||||
/** @ORM\Column(name="mail", type="string") */
|
||||
private string $mail;
|
||||
|
||||
/** @ORM\Column(name="created_at", type="datetime") */
|
||||
private DateTime $createdAt;
|
||||
|
||||
|
||||
public function __construct() {
|
||||
$this->id = UuidGenerator::generate();
|
||||
|
||||
$now = new DateTime();
|
||||
$this->setCreatedAt($now);
|
||||
}
|
||||
|
||||
|
||||
public function getId(): UuidInterface {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUsername(): string {
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function setUsername(string $username): void {
|
||||
$this->username = $username;
|
||||
}
|
||||
|
||||
public function getMail(): ?string {
|
||||
return $this->mail;
|
||||
}
|
||||
|
||||
public function setMail(?string $mail): void {
|
||||
$this->mail = $mail;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): DateTime {
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function setCreatedAt(DateTime $createdAt): void {
|
||||
$this->createdAt = $createdAt;
|
||||
}
|
||||
}
|
||||
76
src/DataDomain/Business/src/Entity/Role.php
Normal file
76
src/DataDomain/Business/src/Entity/Role.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Entity;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Template\Infrastructure\UuidGenerator\UuidGenerator;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="Template\Data\Business\Repository\RoleRepository")
|
||||
* @ORM\Table(name="role")
|
||||
*/
|
||||
class Role {
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="id", type="uuid_binary_ordered_time")
|
||||
*/
|
||||
private UuidInterface $id;
|
||||
|
||||
/** @ORM\Column(name="identifier", type="string") */
|
||||
private string $identifier;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity="Template\Data\Business\Entity\Permission", mappedBy="roles")
|
||||
* @ORM\JoinTable(
|
||||
* name="role_permission",
|
||||
* joinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@ORM\JoinColumn(name="permission_id", referencedColumnName="id")}
|
||||
* )
|
||||
*/
|
||||
private Collection $permissions;
|
||||
|
||||
|
||||
public function __construct() {
|
||||
$this->id = UuidGenerator::generate();
|
||||
$this->permissions = new ArrayCollection();
|
||||
}
|
||||
|
||||
|
||||
public function getId(): UuidInterface {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getIdentifier(): string {
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
public function setIdentifier(string $identifier): void {
|
||||
$this->identifier = $identifier;
|
||||
}
|
||||
|
||||
public function getPermissions(): Collection {
|
||||
return $this->permissions;
|
||||
}
|
||||
|
||||
public function setPermissions(Collection $permissions): void {
|
||||
$this->permissions = $permissions;
|
||||
}
|
||||
|
||||
public function addPermission(Permission $permission): void {
|
||||
if (!$this->permissions->contains($permission)) {
|
||||
$this->permissions->add($permission);
|
||||
$permission->addRole($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function removePermission(Permission $permission): void {
|
||||
if ($this->permissions->contains($permission)) {
|
||||
$this->permissions->remove($permission);
|
||||
$permission->removeRole($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
148
src/DataDomain/Business/src/Entity/User.php
Normal file
148
src/DataDomain/Business/src/Entity/User.php
Normal file
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Entity;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Template\Infrastructure\UuidGenerator\UuidGenerator;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="Template\Data\Business\Repository\UserRepository")
|
||||
* @ORM\Table(name="user")
|
||||
*/
|
||||
class User {
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="id", type="uuid_binary_ordered_time")
|
||||
*/
|
||||
private UuidInterface $id;
|
||||
|
||||
/** @ORM\Column(name="role_id", type="uuid_binary_ordered_time") */
|
||||
private UuidInterface $roleId;
|
||||
|
||||
/**
|
||||
* @ORM\OneToOne(targetEntity="Template\Data\Business\Entity\Role")
|
||||
* @ORM\JoinColumn(name="role_id", referencedColumnName="id")
|
||||
*/
|
||||
private Role $role;
|
||||
|
||||
/** @ORM\Column(name="username", type="string") */
|
||||
private string $username;
|
||||
|
||||
/** @ORM\Column(name="mail", type="string") */
|
||||
private string $mail;
|
||||
|
||||
/** @ORM\Column(name="password", type="string") */
|
||||
private string $password;
|
||||
|
||||
/** @ORM\OneToOne(targetEntity="Template\Data\Business\Entity\UserSession", mappedBy="user") */
|
||||
private ?UserSession $session;
|
||||
|
||||
/** @ORM\Column(name="last_login_at", type="datetime", nullable=true) */
|
||||
private DateTime $lastLoginAt;
|
||||
|
||||
/** @ORM\Column(name="created_at", type="datetime") */
|
||||
private DateTime $createdAt;
|
||||
|
||||
/** @ORM\Column(name="updated_at", type="datetime") */
|
||||
private DateTime $updatedAt;
|
||||
|
||||
|
||||
public function __construct() {
|
||||
$this->id = UuidGenerator::generate();
|
||||
|
||||
$now = new DateTime();
|
||||
$this->setCreatedAt($now);
|
||||
$this->setUpdatedAt($now);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\PrePersist
|
||||
* @ORM\PreUpdate
|
||||
*/
|
||||
public function updateTimestamps(): void {
|
||||
$now = new DateTime();
|
||||
$this->setUpdatedAt($now);
|
||||
}
|
||||
|
||||
|
||||
public function getId(): UuidInterface {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getRoleId(): UuidInterface {
|
||||
return $this->roleId;
|
||||
}
|
||||
|
||||
public function setRoleId(UuidInterface $roleId): void {
|
||||
$this->roleId = $roleId;
|
||||
}
|
||||
|
||||
public function getRole(): Role {
|
||||
return $this->role;
|
||||
}
|
||||
|
||||
public function setRole(Role $role): void {
|
||||
$this->role = $role;
|
||||
}
|
||||
|
||||
public function getUsername(): string {
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function setUsername(string $username): void {
|
||||
$this->username = $username;
|
||||
}
|
||||
|
||||
public function getMail(): ?string {
|
||||
return $this->mail;
|
||||
}
|
||||
|
||||
public function setMail(?string $mail): void {
|
||||
$this->mail = $mail;
|
||||
}
|
||||
|
||||
public function getPassword(): ?string {
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(?string $password): void {
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
public function getSession(): ?UserSession {
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
public function setSession(?UserSession $session): void {
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
public function getLastLoginAt(): ?DateTime {
|
||||
return $this->lastLoginAt;
|
||||
}
|
||||
|
||||
public function setLastLoginAt(?DateTime $lastLoginAt): void {
|
||||
$this->lastLoginAt = $lastLoginAt;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): DateTime {
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function setCreatedAt(DateTime $createdAt): void {
|
||||
$this->createdAt = $createdAt;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): DateTime {
|
||||
return $this->updatedAt;
|
||||
}
|
||||
|
||||
public function setUpdatedAt(DateTime $updatedAt): void {
|
||||
$this->updatedAt = $updatedAt;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
105
src/DataDomain/Business/src/Entity/UserSession.php
Normal file
105
src/DataDomain/Business/src/Entity/UserSession.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Entity;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Template\Infrastructure\UuidGenerator\UuidGenerator;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="Template\Data\Business\Repository\UserSessionRepository")
|
||||
* @ORM\Table(name="user_session")
|
||||
*/
|
||||
class UserSession {
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="id", type="uuid_binary_ordered_time")
|
||||
*/
|
||||
private UuidInterface $id;
|
||||
|
||||
/** @ORM\Column(name="user_id", type="uuid_binary_ordered_time", nullable=true) */
|
||||
private ?UuidInterface $userId;
|
||||
|
||||
/**
|
||||
* @ORM\OneToOne(targetEntity="Template\Data\Business\Entity\User", mappedBy="session")
|
||||
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
private ?User $user;
|
||||
|
||||
/** @ORM\Column(name="csrf", type="uuid_binary_ordered_time", nullable=true) */
|
||||
private ?UuidInterface $csrf;
|
||||
|
||||
/** @ORM\Column(name="created_at", type="datetime") */
|
||||
private DateTime $createdAt;
|
||||
|
||||
/** @ORM\Column(name="updated_at", type="datetime") */
|
||||
private DateTime $updatedAt;
|
||||
|
||||
|
||||
public function __construct() {
|
||||
$this->id = UuidGenerator::generate();
|
||||
|
||||
$now = new DateTime();
|
||||
$this->setCreatedAt($now);
|
||||
$this->setUpdatedAt($now);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\PrePersist
|
||||
* @ORM\PreUpdate
|
||||
*/
|
||||
public function updateTimestamps(): void {
|
||||
$now = new DateTime();
|
||||
$this->setUpdatedAt($now);
|
||||
}
|
||||
|
||||
|
||||
public function getId(): UuidInterface {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUserId(): ?UuidInterface {
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
public function setUserId(?UuidInterface $userId): void {
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
public function getUser(): ?User {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function setUser(?User $user): void {
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function getCsrf(): ?UuidInterface {
|
||||
return $this->csrf;
|
||||
}
|
||||
|
||||
public function setCsrf(?UuidInterface $csrf): void {
|
||||
$this->csrf = $csrf;
|
||||
}
|
||||
|
||||
|
||||
public function getCreatedAt(): DateTime {
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function setCreatedAt(DateTime $createdAt): void {
|
||||
$this->createdAt = $createdAt;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): DateTime {
|
||||
return $this->updatedAt;
|
||||
}
|
||||
|
||||
public function setUpdatedAt(DateTime $updatedAt): void {
|
||||
$this->updatedAt = $updatedAt;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
19
src/DataDomain/Business/src/Factory/EntityManagerFactory.php
Normal file
19
src/DataDomain/Business/src/Factory/EntityManagerFactory.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Data\Business\Factory;
|
||||
|
||||
use Template\Data\Business\Manager\EntityManager;
|
||||
use Laminas\ServiceManager\Factory\FactoryInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class EntityManagerFactory implements FactoryInterface
|
||||
{
|
||||
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null): EntityManager
|
||||
{
|
||||
return new EntityManager(
|
||||
$container->get('doctrine.entity_manager.orm_template')
|
||||
);
|
||||
}
|
||||
}
|
||||
11
src/DataDomain/Business/src/Manager/EntityManager.php
Normal file
11
src/DataDomain/Business/src/Manager/EntityManager.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Data\Business\Manager;
|
||||
|
||||
use Doctrine\ORM\Decorator\EntityManagerDecorator;
|
||||
|
||||
class EntityManager extends EntityManagerDecorator
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class PermissionRepository extends EntityRepository {
|
||||
}
|
||||
|
||||
?>
|
||||
10
src/DataDomain/Business/src/Repository/ProductRepository.php
Normal file
10
src/DataDomain/Business/src/Repository/ProductRepository.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class ProductRepository extends EntityRepository {
|
||||
}
|
||||
|
||||
?>
|
||||
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Repository;
|
||||
|
||||
use Template\Data\Business\Entity\Registration;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class RegistrationRepository extends EntityRepository {
|
||||
public function findByIdentifier(string $identifier) : ?Registration {
|
||||
$queryBuilder = $this->createQueryBuilder('r');
|
||||
$queryBuilder->where(
|
||||
$queryBuilder->expr()->orX(
|
||||
$queryBuilder->expr()->eq('r.username', ':identifier'),
|
||||
$queryBuilder->expr()->eq('r.mail', ':identifier')
|
||||
)
|
||||
)
|
||||
->setParameter('identifier', $identifier);
|
||||
$query = $queryBuilder->getQuery();
|
||||
|
||||
/** @var ?Registration $registration */
|
||||
$registration = $query->execute()[0] ?? null;
|
||||
return $registration;
|
||||
}
|
||||
}
|
||||
10
src/DataDomain/Business/src/Repository/RoleRepository.php
Normal file
10
src/DataDomain/Business/src/Repository/RoleRepository.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class RoleRepository extends EntityRepository {
|
||||
}
|
||||
|
||||
?>
|
||||
26
src/DataDomain/Business/src/Repository/UserRepository.php
Normal file
26
src/DataDomain/Business/src/Repository/UserRepository.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Repository;
|
||||
|
||||
use Template\Data\Business\Entity\User;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class UserRepository extends EntityRepository {
|
||||
public function findByIdentifier(string $identifier) : ?User {
|
||||
$queryBuilder = $this->createQueryBuilder('u');
|
||||
$queryBuilder->where(
|
||||
$queryBuilder->expr()->orX(
|
||||
$queryBuilder->expr()->eq('u.username', ':identifier'),
|
||||
$queryBuilder->expr()->eq('u.mail', ':identifier')
|
||||
)
|
||||
)
|
||||
->setParameter('identifier', $identifier);
|
||||
$query = $queryBuilder->getQuery();
|
||||
|
||||
/** @var ?User $user */
|
||||
$user = $query->execute()[0] ?? null;
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Business\Repository;
|
||||
|
||||
use Template\Data\Business\Entity\User;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Template\Data\Business\Entity\UserSession;
|
||||
|
||||
class UserSessionRepository extends EntityRepository {
|
||||
public function findByUser(User $user) : ?UserSession {
|
||||
$queryBuilder = $this->createQueryBuilder('us');
|
||||
$queryBuilder
|
||||
->where("us.userId = :userId")
|
||||
->setParameter('userId', $user->getId());
|
||||
|
||||
/** @var ?UserSession $userSession */
|
||||
$userSession = $queryBuilder->getQuery()->execute()[0] ?? null;
|
||||
return $userSession;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
55
src/DataDomain/Log/config/doctrine.php
Normal file
55
src/DataDomain/Log/config/doctrine.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use Doctrine\DBAL\Driver\PDO\MySQL\Driver;
|
||||
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
|
||||
|
||||
return [
|
||||
'configuration' => [
|
||||
'orm_log' => [
|
||||
'second_level_cache' => [
|
||||
'enabled' => false,
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
'driver' => [
|
||||
'orm_log_annotation_driver' => [
|
||||
'class' => AnnotationDriver::class,
|
||||
'cache' => 'array',
|
||||
'paths' => [
|
||||
realpath(APP_ROOT . '/src/DataDomain/Log/Entity/')
|
||||
],
|
||||
],
|
||||
|
||||
'orm_log' => [
|
||||
'class' => MappingDriverChain::class,
|
||||
'drivers' => [
|
||||
'Template\Data\Log\Entity' => 'orm_log_annotation_driver',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'connection' => [
|
||||
'orm_log' => [
|
||||
'driverClass' => Driver::class,
|
||||
'params' => [
|
||||
'driver' => $_ENV['DB_DRIVER'],
|
||||
'host' => $_ENV['DB_HOST'],
|
||||
'port' => $_ENV['DB_PORT'],
|
||||
'user' => $_ENV['DB_USER'],
|
||||
'password' => $_ENV['DB_PASSWORD'],
|
||||
'dbname' => $_ENV['DB_NAME_LOG'],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'migrations_configuration' => [
|
||||
'orm_log' => [
|
||||
'directory' => 'data/migrations/log',
|
||||
'name' => 'Doctrine Database Migrations for Log',
|
||||
'namespace' => 'Template\Migrations\Log',
|
||||
'table' => 'migrations',
|
||||
],
|
||||
],
|
||||
];
|
||||
16
src/DataDomain/Log/config/service_manager.php
Normal file
16
src/DataDomain/Log/config/service_manager.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Template\Data\Log\Factory\LogEntityManagerFactory;
|
||||
use Template\Data\Log\Manager\LogEntityManager;
|
||||
use Roave\PsrContainerDoctrine\ConfigurationFactory;
|
||||
use Roave\PsrContainerDoctrine\ConnectionFactory;
|
||||
use Roave\PsrContainerDoctrine\EntityManagerFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
'doctrine.entity_manager.orm_log' => [EntityManagerFactory::class, 'orm_log'],
|
||||
'doctrine.configuration.orm_log' => [ConfigurationFactory::class, 'orm_log'],
|
||||
'doctrine.connection.orm_log' => [ConnectionFactory::class, 'orm_log'],
|
||||
LogEntityManager::class => LogEntityManagerFactory::class,
|
||||
],
|
||||
];
|
||||
16
src/DataDomain/Log/src/ConfigProvider.php
Normal file
16
src/DataDomain/Log/src/ConfigProvider.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Data\Log;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . './../config/service_manager.php',
|
||||
'doctrine' => require __DIR__ . './../config/doctrine.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
129
src/DataDomain/Log/src/Entity/Log.php
Normal file
129
src/DataDomain/Log/src/Entity/Log.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Log\Entity;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Template\Infrastructure\UuidGenerator\UuidGenerator;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
/**
|
||||
* Member
|
||||
* @ORM\Entity(repositoryClass="Template\Data\Log\Repository\LogRepository")
|
||||
* @ORM\Table(name="log")
|
||||
*/
|
||||
class Log
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="id", type="uuid_binary_ordered_time", unique=true, nullable=false)
|
||||
*/
|
||||
private UuidInterface $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="message", type="text", nullable=false)
|
||||
*/
|
||||
private string $message;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="context", type="json", nullable=true)
|
||||
*/
|
||||
private ?array $context;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="level", type="smallint", nullable=false)
|
||||
*/
|
||||
private int $level;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="level_name", type="string", length=50, nullable=false)
|
||||
*/
|
||||
private string $levelName;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="extra", type="json", nullable=true)
|
||||
*/
|
||||
private ?array $extra;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="created_at", type="datetime")
|
||||
*/
|
||||
private DateTime $createdAt;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->id = UuidGenerator::generate();
|
||||
}
|
||||
|
||||
|
||||
public function getId(): UuidInterface
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(UuidInterface $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function getMessage(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function setMessage(string $message): void
|
||||
{
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
public function getContext(): ?array
|
||||
{
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
public function setContext(?array $context): void
|
||||
{
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
public function getLevel(): int
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
public function setLevel(int $level): void
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
public function getLevelName(): string
|
||||
{
|
||||
return $this->levelName;
|
||||
}
|
||||
|
||||
public function setLevelName(string $levelName): void
|
||||
{
|
||||
$this->levelName = $levelName;
|
||||
}
|
||||
|
||||
public function getExtra(): ?array
|
||||
{
|
||||
return $this->extra;
|
||||
}
|
||||
|
||||
public function setExtra(?array $extra): void
|
||||
{
|
||||
$this->extra = $extra;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): DateTime
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function setCreatedAt(DateTime $createdAt): void
|
||||
{
|
||||
$this->createdAt = $createdAt;
|
||||
}
|
||||
}
|
||||
21
src/DataDomain/Log/src/Factory/LogEntityManagerFactory.php
Normal file
21
src/DataDomain/Log/src/Factory/LogEntityManagerFactory.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Data\Log\Factory;
|
||||
|
||||
use Template\Data\Log\Manager\LogEntityManager;
|
||||
use Laminas\ServiceManager\Factory\FactoryInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class LogEntityManagerFactory implements FactoryInterface
|
||||
{
|
||||
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null): LogEntityManager
|
||||
{
|
||||
$lem = new LogEntityManager(
|
||||
$container->get('doctrine.entity_manager.orm_log')
|
||||
);
|
||||
|
||||
return $lem;
|
||||
}
|
||||
}
|
||||
11
src/DataDomain/Log/src/Manager/LogEntityManager.php
Normal file
11
src/DataDomain/Log/src/Manager/LogEntityManager.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Data\Log\Manager;
|
||||
|
||||
use Doctrine\ORM\Decorator\EntityManagerDecorator;
|
||||
|
||||
class LogEntityManager extends EntityManagerDecorator
|
||||
{
|
||||
}
|
||||
8
src/DataDomain/Log/src/Repository/LogRepository.php
Normal file
8
src/DataDomain/Log/src/Repository/LogRepository.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Data\Log\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class LogRepository extends EntityRepository {
|
||||
}
|
||||
53
src/HandlingDomain/Registration/config/service_manager.php
Normal file
53
src/HandlingDomain/Registration/config/service_manager.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
use Template\Handling\Registration\Builder\RegistrationBuilder;
|
||||
use Template\Handling\Registration\Handler\Command\ConfirmRegistration\ConfirmRegistrationCommandBuilder;
|
||||
use Template\Handling\Registration\Handler\Command\ConfirmRegistration\ConfirmRegistrationCommandHandler;
|
||||
use Template\Handling\Registration\Handler\Command\RegisterUser\RegisterUserCommandBuilder;
|
||||
use Template\Handling\Registration\Handler\Command\RegisterUser\RegisterUserCommandHandler;
|
||||
use Template\Handling\Registration\Pipeline\ConfirmRegistration\ConfirmRegistrationPipeline;
|
||||
use Template\Handling\Registration\Pipeline\ConfirmRegistration\Step\CreateUserStep;
|
||||
use Template\Handling\Registration\Pipeline\ConfirmRegistration\Step\LoadRegistrationStep;
|
||||
use Template\Handling\Registration\Pipeline\ConfirmRegistration\Step\SaveRegistrationAndUserStep;
|
||||
use Template\Handling\Registration\Pipeline\RegisterUser\RegisterUserPipeline;
|
||||
use Template\Handling\Registration\Pipeline\RegisterUser\Step\BuildRegistrationStep;
|
||||
use Template\Handling\Registration\Pipeline\RegisterUser\Step\CheckIdentifierStep;
|
||||
use Template\Handling\Registration\Pipeline\RegisterUser\Step\SaveRegistrationStep;
|
||||
use Template\Handling\Registration\Pipeline\RegisterUser\Step\SendMailStep;
|
||||
use Template\Handling\Registration\Rule\RegistrationWithIdentifierAlreadyExistsRule;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
use Reinfi\DependencyInjection\Factory\InjectionFactory;
|
||||
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
/// Builder
|
||||
RegistrationBuilder::class => AutoWiringFactory::class,
|
||||
|
||||
/// Rule
|
||||
RegistrationWithIdentifierAlreadyExistsRule::class => InjectionFactory::class,
|
||||
|
||||
/// Pipeline
|
||||
// Register User
|
||||
RegisterUserPipeline::class => AutoWiringFactory::class,
|
||||
CheckIdentifierStep::class => AutoWiringFactory::class,
|
||||
BuildRegistrationStep::class => AutoWiringFactory::class,
|
||||
SendMailStep::class => AutoWiringFactory::class,
|
||||
SaveRegistrationStep::class => AutoWiringFactory::class,
|
||||
|
||||
// Confirm Registration
|
||||
ConfirmRegistrationPipeline::class => AutoWiringFactory::class,
|
||||
LoadRegistrationStep::class => InjectionFactory::class,
|
||||
CreateUserStep::class => AutoWiringFactory::class,
|
||||
SaveRegistrationAndUserStep::class => AutoWiringFactory::class,
|
||||
|
||||
/// CQRS
|
||||
// Register User
|
||||
RegisterUserCommandHandler::class => AutoWiringFactory::class,
|
||||
RegisterUserCommandBuilder::class => AutoWiringFactory::class,
|
||||
|
||||
// Confirm Registration
|
||||
ConfirmRegistrationCommandHandler::class => AutoWiringFactory::class,
|
||||
ConfirmRegistrationCommandBuilder::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Handling\Registration\Builder;
|
||||
|
||||
use Template\Data\Business\Entity\Registration;
|
||||
|
||||
class RegistrationBuilder
|
||||
{
|
||||
public function build(
|
||||
string $username,
|
||||
string $mail
|
||||
): Registration
|
||||
{
|
||||
$registration = new Registration();
|
||||
$registration->setUsername($username);
|
||||
$registration->setMail($mail);
|
||||
return $registration;
|
||||
}
|
||||
}
|
||||
15
src/HandlingDomain/Registration/src/ConfigProvider.php
Normal file
15
src/HandlingDomain/Registration/src/ConfigProvider.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Template\Handling\Registration;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . '/./../config/service_manager.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Handling\Registration\Exception;
|
||||
|
||||
use Template\Infrastructure\Exception\ErrorCode;
|
||||
use Template\Infrastructure\Exception\ErrorDomain;
|
||||
use Template\Infrastructure\Exception\Exception\Exception;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
class RegistrationNotFoundByIdException extends Exception
|
||||
{
|
||||
private const MESSAGE = 'A Registration with the id %s was not be found!';
|
||||
public function __construct(
|
||||
UuidInterface $id
|
||||
) {
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
self::MESSAGE,
|
||||
$id->toString()
|
||||
),
|
||||
ErrorDomain::Registration,
|
||||
ErrorCode::NotFound
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Handling\Registration\Exception;
|
||||
|
||||
use Template\Infrastructure\Exception\ErrorCode;
|
||||
use Template\Infrastructure\Exception\ErrorDomain;
|
||||
use Template\Infrastructure\Exception\Exception\Exception;
|
||||
|
||||
class RegistrationWithIdentifierAlreadyExistsException extends Exception
|
||||
{
|
||||
private const MESSAGE = 'A Registration with the identifier %s does already exist!';
|
||||
|
||||
public function __construct(
|
||||
string $identifier
|
||||
) {
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
self::MESSAGE,
|
||||
$identifier
|
||||
),
|
||||
ErrorDomain::Registration,
|
||||
ErrorCode::AlreadyExists
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Handling\Registration\Handler\Command\ConfirmRegistration;
|
||||
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
class ConfirmRegistrationCommand
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UuidInterface $id,
|
||||
private readonly string $password,
|
||||
private readonly string $passwordConfirmation,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getId(): UuidInterface {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getPassword(): string {
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
|
||||
public function getPasswordConfirmation(): string {
|
||||
return $this->passwordConfirmation;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Template\Handling\Registration\Handler\Command\ConfirmRegistration;
|
||||
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
class ConfirmRegistrationCommandBuilder
|
||||
{
|
||||
public function build(
|
||||
UuidInterface $id,
|
||||
string $password,
|
||||
string $passwordConfirmation,
|
||||
): ConfirmRegistrationCommand
|
||||
{
|
||||
return new ConfirmRegistrationCommand(
|
||||
$id,
|
||||
$password,
|
||||
$passwordConfirmation
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user