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