Compare commits
No commits in common. "main" and "master" have entirely different histories.
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
vendor/
|
vendor/
|
||||||
composer.lock
|
composer.lock
|
||||||
.idea/
|
.idea/
|
||||||
build/
|
*.phar
|
||||||
@ -1,9 +0,0 @@
|
|||||||
# versa digitale
|
|
||||||
|
|
||||||
*versa digitale* is an modern high-performance application platform, with an modular development approach.
|
|
||||||
|
|
||||||
The platform has the following features:
|
|
||||||
- HTTP Server written with ReactPHP
|
|
||||||
- high-performant async handling of requests
|
|
||||||
- Caching
|
|
||||||
-
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . "/vendor/autoload.php";
|
require_once __DIR__ . "/../vendor/autoload.php";
|
||||||
|
|
||||||
(new \VersaDigitale\Platform\Console\VersaCLI())->run();
|
(new \VersaDigitale\Platform\Console\VersaCLI())->run();
|
||||||
0
build/.gitkeep
Normal file
0
build/.gitkeep
Normal file
@ -3,6 +3,7 @@
|
|||||||
"description": "Anwendungsserver der modularen versa digitale Anwendungsplatform",
|
"description": "Anwendungsserver der modularen versa digitale Anwendungsplatform",
|
||||||
"type": "platform",
|
"type": "platform",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"version": "1.0",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"VersaDigitale\\Platform\\": "src/"
|
"VersaDigitale\\Platform\\": "src/"
|
||||||
@ -18,16 +19,6 @@
|
|||||||
"symfony/console": "^7.1",
|
"symfony/console": "^7.1",
|
||||||
"react/http": "^3@dev",
|
"react/http": "^3@dev",
|
||||||
"react/async": "^3@dev",
|
"react/async": "^3@dev",
|
||||||
"secondtruth/phar-compiler": "^1.2",
|
"secondtruth/phar-compiler": "^1.2"
|
||||||
"symfony/http-kernel": "^7.1",
|
|
||||||
"symfony/http-foundation": "^7.1",
|
|
||||||
"doctrine/orm": "^3.3",
|
|
||||||
"doctrine/dbal": "^4.2",
|
|
||||||
"symfony/cache": "^7.1",
|
|
||||||
"nilportugues/sql-query-builder": "^1.8",
|
|
||||||
"bramus/router": "^1.6",
|
|
||||||
"symfony/routing": "^7.1",
|
|
||||||
"symfony/psr-http-message-bridge": "^7.1",
|
|
||||||
"nyholm/psr7": "^1.8"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use VersaDigitale\Platform\Logging\Log;
|
|
||||||
use VersaDigitale\Platform\Module\AbstractModule;
|
|
||||||
use VersaDigitale\Platform\Module\Module;
|
|
||||||
|
|
||||||
class DashboardModule extends AbstractModule
|
|
||||||
{
|
|
||||||
|
|
||||||
public function init(): void
|
|
||||||
{
|
|
||||||
// TODO: Implement init() method.
|
|
||||||
Log::info("Hallo aus dem Dashboard-Modul!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"host": "0.0.0.0",
|
|
||||||
"port": 8080
|
|
||||||
}
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Auth;
|
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
|
||||||
use Doctrine\Common\Collections\Collection;
|
|
||||||
use VersaDigitale\Platform\Database\Model\BaseModel;
|
|
||||||
|
|
||||||
#[ORM\Entity]
|
|
||||||
#[ORM\Table(name: 'permission_nodes')]
|
|
||||||
class PermissionNode extends BaseModel
|
|
||||||
{
|
|
||||||
|
|
||||||
#[ORM\Column(type: 'string', length: 255)]
|
|
||||||
private string $name;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')]
|
|
||||||
private ?self $parent = null;
|
|
||||||
|
|
||||||
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
|
|
||||||
private Collection $children;
|
|
||||||
|
|
||||||
#[ORM\ManyToMany(targetEntity: UserGroup::class, mappedBy: 'permissions')]
|
|
||||||
private Collection $userGroups;
|
|
||||||
|
|
||||||
#[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'permissions')]
|
|
||||||
private Collection $users;
|
|
||||||
|
|
||||||
public function __construct(string $name, ?self $parent = null)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->parent = $parent;
|
|
||||||
$this->children = new ArrayCollection();
|
|
||||||
$this->userGroups = new ArrayCollection();
|
|
||||||
$this->users = new ArrayCollection();
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getName(): string
|
|
||||||
{
|
|
||||||
return $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getParent(): ?self
|
|
||||||
{
|
|
||||||
return $this->parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getChildren(): Collection
|
|
||||||
{
|
|
||||||
return $this->children;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addChild(PermissionNode $child): void
|
|
||||||
{
|
|
||||||
if (!$this->children->contains($child)) {
|
|
||||||
$this->children->add($child);
|
|
||||||
$child->parent = $this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removeChild(PermissionNode $child): void
|
|
||||||
{
|
|
||||||
if ($this->children->removeElement($child)) {
|
|
||||||
$child->parent = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUserGroups(): Collection
|
|
||||||
{
|
|
||||||
return $this->userGroups;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUsers(): Collection
|
|
||||||
{
|
|
||||||
return $this->users;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Auth;
|
|
||||||
|
|
||||||
class Session
|
|
||||||
{
|
|
||||||
|
|
||||||
private string $authToken = "";
|
|
||||||
private User $user;
|
|
||||||
|
|
||||||
public function __construct(User $user) {
|
|
||||||
$this->user = $user;
|
|
||||||
$authToken = md5(uniqid(rand(), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthToken(): string
|
|
||||||
{
|
|
||||||
return $this->authToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return User
|
|
||||||
*/
|
|
||||||
public function getUser(): User
|
|
||||||
{
|
|
||||||
return $this->user;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Auth;
|
|
||||||
|
|
||||||
class SessionManager
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Session[]
|
|
||||||
*/
|
|
||||||
private static array $sessions = [];
|
|
||||||
|
|
||||||
public static function getSession(string $authToken): ?Session
|
|
||||||
{
|
|
||||||
foreach (self::$sessions as $session) {
|
|
||||||
if ($session->getAuthToken() === $authToken) {
|
|
||||||
return $session;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function createSession(User $user): Session
|
|
||||||
{
|
|
||||||
$session = new Session($user);
|
|
||||||
self::$sessions[] = $session;
|
|
||||||
return $session;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,181 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Auth;
|
|
||||||
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
|
||||||
use Doctrine\Common\Collections\Collection;
|
|
||||||
use VersaDigitale\Platform\Database\Model\BaseModel;
|
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
use Doctrine\DBAL\Types\Types;
|
|
||||||
use DateTimeImmutable;
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
#[ORM\Entity]
|
|
||||||
#[ORM\Table(name: 'users')]
|
|
||||||
class User extends BaseModel
|
|
||||||
{
|
|
||||||
#[ORM\Column(type: Types::STRING, length: 180, unique: true)]
|
|
||||||
private string $username;
|
|
||||||
|
|
||||||
#[ORM\Column(type: Types::STRING, length: 255)]
|
|
||||||
private string $email;
|
|
||||||
|
|
||||||
#[ORM\Column(type: Types::STRING)]
|
|
||||||
private string $password;
|
|
||||||
|
|
||||||
#[ORM\Column(type: Types::BOOLEAN)]
|
|
||||||
private bool $isActive = true;
|
|
||||||
|
|
||||||
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
|
|
||||||
private ?DateTimeImmutable $lastLoginAt = null;
|
|
||||||
|
|
||||||
#[ORM\ManyToMany(targetEntity: UserGroup::class, inversedBy: 'users')]
|
|
||||||
#[ORM\JoinTable(name: 'user_user_groups')]
|
|
||||||
private Collection $userGroups;
|
|
||||||
|
|
||||||
#[ORM\ManyToMany(targetEntity: PermissionNode::class, inversedBy: 'users')]
|
|
||||||
#[ORM\JoinTable(name: 'user_permissions')]
|
|
||||||
private Collection $permissions;
|
|
||||||
|
|
||||||
public function __construct(string $username, string $email, string $password)
|
|
||||||
{
|
|
||||||
$this->username = $username;
|
|
||||||
$this->email = $email;
|
|
||||||
$this->password = $this->hashPassword($password);
|
|
||||||
$this->userGroups = new ArrayCollection();
|
|
||||||
$this->permissions = new ArrayCollection();
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUsername(): string
|
|
||||||
{
|
|
||||||
return $this->username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setUsername(string $username): void
|
|
||||||
{
|
|
||||||
$this->username = $username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEmail(): string
|
|
||||||
{
|
|
||||||
return $this->email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setEmail(string $email): void
|
|
||||||
{
|
|
||||||
$this->email = $email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPassword(): string
|
|
||||||
{
|
|
||||||
return $this->password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setPassword(string $password): void
|
|
||||||
{
|
|
||||||
$this->password = $this->hashPassword($password);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isActive(): bool
|
|
||||||
{
|
|
||||||
return $this->isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function activate(): void
|
|
||||||
{
|
|
||||||
$this->isActive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deactivate(): void
|
|
||||||
{
|
|
||||||
$this->isActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLastLoginAt(): ?DateTimeImmutable
|
|
||||||
{
|
|
||||||
return $this->lastLoginAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setLastLoginAt(DateTimeImmutable $lastLoginAt): void
|
|
||||||
{
|
|
||||||
$this->lastLoginAt = $lastLoginAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function login(): void
|
|
||||||
{
|
|
||||||
$this->lastLoginAt = new DateTimeImmutable();
|
|
||||||
$this->updateTimestamps();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUserGroups(): Collection
|
|
||||||
{
|
|
||||||
return $this->userGroups;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addUserGroup(UserGroup $group): void
|
|
||||||
{
|
|
||||||
if (!$this->userGroups->contains($group)) {
|
|
||||||
$this->userGroups->add($group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removeUserGroup(UserGroup $group): void
|
|
||||||
{
|
|
||||||
$this->userGroups->removeElement($group);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPermissions(): Collection
|
|
||||||
{
|
|
||||||
return $this->permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addPermission(PermissionNode $permission): void
|
|
||||||
{
|
|
||||||
if (!$this->permissions->contains($permission)) {
|
|
||||||
$this->permissions->add($permission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removePermission(PermissionNode $permission): void
|
|
||||||
{
|
|
||||||
$this->permissions->removeElement($permission);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEffectivePermissions(): Collection
|
|
||||||
{
|
|
||||||
$effectivePermissions = new ArrayCollection();
|
|
||||||
|
|
||||||
// Direct permissions
|
|
||||||
foreach ($this->permissions as $permission) {
|
|
||||||
if (!$effectivePermissions->contains($permission)) {
|
|
||||||
$effectivePermissions->add($permission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group permissions
|
|
||||||
foreach ($this->userGroups as $group) {
|
|
||||||
foreach ($group->getPermissions() as $permission) {
|
|
||||||
if (!$effectivePermissions->contains($permission)) {
|
|
||||||
$effectivePermissions->add($permission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $effectivePermissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function hashPassword(string $password): string
|
|
||||||
{
|
|
||||||
if (strlen($password) < 8) {
|
|
||||||
throw new Exception('Password must be at least 8 characters long.');
|
|
||||||
}
|
|
||||||
return password_hash($password, PASSWORD_BCRYPT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function verifyPassword(string $password): bool
|
|
||||||
{
|
|
||||||
return password_verify($password, $this->password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Auth;
|
|
||||||
|
|
||||||
use VersaDigitale\Platform\Database\Model\BaseModel;
|
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
|
||||||
use Doctrine\Common\Collections\Collection;
|
|
||||||
|
|
||||||
#[ORM\Entity]
|
|
||||||
#[ORM\Table(name: 'user_groups')]
|
|
||||||
|
|
||||||
class UserGroup extends BaseModel
|
|
||||||
{
|
|
||||||
|
|
||||||
#[ORM\Column(type: 'string', length: 255)]
|
|
||||||
private string $name;
|
|
||||||
|
|
||||||
#[ORM\ManyToMany(targetEntity: PermissionNode::class, inversedBy: 'userGroups')]
|
|
||||||
#[ORM\JoinTable(name: 'user_group_permissions')]
|
|
||||||
private Collection $permissions;
|
|
||||||
|
|
||||||
#[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'userGroups')]
|
|
||||||
private Collection $users;
|
|
||||||
|
|
||||||
public function __construct(string $name)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->permissions = new ArrayCollection();
|
|
||||||
$this->users = new ArrayCollection();
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getName(): string
|
|
||||||
{
|
|
||||||
return $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPermissions(): Collection
|
|
||||||
{
|
|
||||||
return $this->permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addPermission(PermissionNode $permission): void
|
|
||||||
{
|
|
||||||
if (!$this->permissions->contains($permission)) {
|
|
||||||
$this->permissions->add($permission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removePermission(PermissionNode $permission): void
|
|
||||||
{
|
|
||||||
$this->permissions->removeElement($permission);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUsers(): Collection
|
|
||||||
{
|
|
||||||
return $this->users;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -20,16 +20,11 @@ class CompilePlatformCommand extends Command
|
|||||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
// Deine Logik für den Compiler
|
// Deine Logik für den Compiler
|
||||||
$output->writeln("Kompiliere die Platform...");
|
$output->writeln('Starte den Compiler...');
|
||||||
|
|
||||||
// mkdirs
|
|
||||||
if (!is_dir(__DIR__ . "/../../../../" . 'build')) {
|
|
||||||
mkdir(__DIR__ . "/../../../../" .'build');
|
|
||||||
}
|
|
||||||
|
|
||||||
$compiler = new Compiler(__DIR__ . "/../../../../");
|
$compiler = new Compiler(__DIR__ . "/../../../../");
|
||||||
|
|
||||||
$compiler->addIndexFile("versa");
|
$compiler->addIndexFile("bin/versa");
|
||||||
$compiler->addFile("composer.json");
|
$compiler->addFile("composer.json");
|
||||||
$compiler->addDirectory("src", '!*.php');
|
$compiler->addDirectory("src", '!*.php');
|
||||||
$compiler->addDirectory("vendor");
|
$compiler->addDirectory("vendor");
|
||||||
|
|||||||
@ -6,7 +6,6 @@ use Symfony\Component\Console\Attribute\AsCommand;
|
|||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use VersaDigitale\Platform\Kernel\VersaKernel;
|
|
||||||
use VersaDigitale\Platform\Logging\Log;
|
use VersaDigitale\Platform\Logging\Log;
|
||||||
use VersaDigitale\Platform\Server\VersaServer;
|
use VersaDigitale\Platform\Server\VersaServer;
|
||||||
|
|
||||||
@ -24,7 +23,12 @@ class StartServerCommand extends Command
|
|||||||
// Deine Logik für den Compiler
|
// Deine Logik für den Compiler
|
||||||
$ver = phpversion();
|
$ver = phpversion();
|
||||||
Log::info("Starte den versa digitale Platformserver - powered by ReactPHP");
|
Log::info("Starte den versa digitale Platformserver - powered by ReactPHP");
|
||||||
VersaKernel::__startServer();
|
$server = new VersaServer(
|
||||||
|
host: "0.0.0.0",
|
||||||
|
port: 8080
|
||||||
|
);
|
||||||
|
|
||||||
|
$server->start();
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,63 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Console\Commands\User;
|
|
||||||
|
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
|
||||||
use VersaDigitale\Platform\Auth\User;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Symfony\Component\Console\Command\Command;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
|
||||||
use VersaDigitale\Platform\Database\VersaBase;
|
|
||||||
|
|
||||||
#[AsCommand(name: "user:create")]
|
|
||||||
class CreateUserCommand extends Command
|
|
||||||
{
|
|
||||||
private EntityManagerInterface $entityManager;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
|
|
||||||
$this->entityManager = VersaBase::$em;
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->setDescription('Creates a new user')
|
|
||||||
->setHelp('This command allows you to create a user...')
|
|
||||||
->addArgument('username', InputArgument::REQUIRED, 'The username of the user')
|
|
||||||
->addArgument('email', InputArgument::REQUIRED, 'The email of the user')
|
|
||||||
->addArgument('password', InputArgument::REQUIRED, 'The password of the user');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
|
||||||
{
|
|
||||||
$io = new SymfonyStyle($input, $output);
|
|
||||||
|
|
||||||
// Retrieve input arguments
|
|
||||||
$username = $input->getArgument('username');
|
|
||||||
$email = $input->getArgument('email');
|
|
||||||
$password = $input->getArgument('password');
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Create new user instance
|
|
||||||
$user = new User($username, $email, $password);
|
|
||||||
|
|
||||||
// Persist the user to the database
|
|
||||||
$this->entityManager->persist($user);
|
|
||||||
$this->entityManager->flush();
|
|
||||||
|
|
||||||
$io->success('User created successfully.');
|
|
||||||
|
|
||||||
return Command::SUCCESS;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$io->error('Error creating user: ' . $e->getMessage());
|
|
||||||
|
|
||||||
return Command::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,8 +7,6 @@ use Symfony\Component\Console\Command\ListCommand;
|
|||||||
use VersaDigitale\Platform\Console\Commands\Development\CompilePlatformCommand;
|
use VersaDigitale\Platform\Console\Commands\Development\CompilePlatformCommand;
|
||||||
use VersaDigitale\Platform\Console\Commands\Module\CompileModuleCommand;
|
use VersaDigitale\Platform\Console\Commands\Module\CompileModuleCommand;
|
||||||
use VersaDigitale\Platform\Console\Commands\Server\StartServerCommand;
|
use VersaDigitale\Platform\Console\Commands\Server\StartServerCommand;
|
||||||
use VersaDigitale\Platform\Console\Commands\User\CreateUserCommand;
|
|
||||||
use VersaDigitale\Platform\Kernel\VersaKernel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class VersaCLI
|
* Class VersaCLI
|
||||||
@ -24,6 +22,19 @@ class VersaCLI {
|
|||||||
public ?ConsoleApplication $application = null
|
public ?ConsoleApplication $application = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
$this->application = new ConsoleApplication();
|
||||||
|
|
||||||
|
$this->application->addCommands([
|
||||||
|
new CompilePlatformCommand(),
|
||||||
|
new CompileModuleCommand(),
|
||||||
|
new StartServerCommand()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
// Output pink text to stdout using fwrite
|
||||||
|
|
||||||
$logo = <<<LOGO
|
$logo = <<<LOGO
|
||||||
_ _ _ _ _
|
_ _ _ _ _
|
||||||
@ -36,24 +47,6 @@ class VersaCLI {
|
|||||||
|
|
||||||
|
|
||||||
fwrite(STDOUT, "\033[35m". $logo. "\033[0m\n\n");
|
fwrite(STDOUT, "\033[35m". $logo. "\033[0m\n\n");
|
||||||
VersaKernel::__initKernel();
|
|
||||||
$this->application = new ConsoleApplication();
|
|
||||||
|
|
||||||
$this->application->addCommands([
|
|
||||||
new CompilePlatformCommand(),
|
|
||||||
new CompileModuleCommand(),
|
|
||||||
new StartServerCommand(),
|
|
||||||
new CreateUserCommand()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function run(): void
|
|
||||||
{
|
|
||||||
|
|
||||||
// Output pink text to stdout using fwrite
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$this->application->run();
|
$this->application->run();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Database\Model;
|
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
use Doctrine\DBAL\Types\Types;
|
|
||||||
use DateTimeImmutable;
|
|
||||||
use DateTimeInterface;
|
|
||||||
|
|
||||||
#[ORM\MappedSuperclass]
|
|
||||||
abstract class BaseModel
|
|
||||||
{
|
|
||||||
#[ORM\Id]
|
|
||||||
#[ORM\GeneratedValue]
|
|
||||||
#[ORM\Column(type: Types::INTEGER)]
|
|
||||||
protected ?int $id = null;
|
|
||||||
|
|
||||||
#[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
|
|
||||||
protected DateTimeInterface $createdAt;
|
|
||||||
|
|
||||||
#[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
|
|
||||||
protected DateTimeInterface $updatedAt;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->createdAt = new DateTimeImmutable();
|
|
||||||
$this->updatedAt = new DateTimeImmutable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): ?int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCreatedAt(): DateTimeInterface
|
|
||||||
{
|
|
||||||
return $this->createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUpdatedAt(): DateTimeInterface
|
|
||||||
{
|
|
||||||
return $this->updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateTimestamps(): void
|
|
||||||
{
|
|
||||||
$this->updatedAt = new DateTimeImmutable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Database;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\DriverManager;
|
|
||||||
use Doctrine\ORM\EntityManager;
|
|
||||||
use Doctrine\ORM\ORMSetup;
|
|
||||||
use Doctrine\ORM\Tools\SchemaTool;
|
|
||||||
use Symfony\Component\HttpFoundation\Session\Session;
|
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler;
|
|
||||||
use VersaDigitale\Platform\Logging\Log;
|
|
||||||
|
|
||||||
class VersaBase
|
|
||||||
{
|
|
||||||
|
|
||||||
public static EntityManager $em;
|
|
||||||
|
|
||||||
public static function __init(): void
|
|
||||||
{
|
|
||||||
|
|
||||||
$config = ORMSetup::createAttributeMetadataConfiguration(
|
|
||||||
paths: [__DIR__ . "/../"],
|
|
||||||
isDevMode: true
|
|
||||||
);
|
|
||||||
|
|
||||||
$connection = DriverManager::getConnection([
|
|
||||||
'driver' => 'pdo_sqlite',
|
|
||||||
'path' => __DIR__ . '/../../db.sqlite',
|
|
||||||
], $config);
|
|
||||||
|
|
||||||
// obtaining the entity manager
|
|
||||||
self::$em = new EntityManager($connection, $config);
|
|
||||||
Log::info("Doctrine ORM geladen!");
|
|
||||||
self::checkModels();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function checkModels() {
|
|
||||||
$sm = self::$em->getConnection()->createSchemaManager();
|
|
||||||
$models = self::$em->getMetadataFactory()->getAllMetadata();
|
|
||||||
$schemaTool = new SchemaTool(self::$em);
|
|
||||||
Log::info(count($models) . " Modelle gefunden");
|
|
||||||
foreach($models as $model) {
|
|
||||||
if(!$sm->tableExists($model->getTableName()) and !$model->isMappedSuperclass) {
|
|
||||||
|
|
||||||
$schemaTool->createSchema([$model]);
|
|
||||||
Log::info("Modell \"" . $model->getTableName() . "\" erstellt!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Kernel\Attributes;
|
|
||||||
|
|
||||||
use Attribute;
|
|
||||||
|
|
||||||
#[Attribute(Attribute::TARGET_METHOD)]
|
|
||||||
class Route
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
public string $path,
|
|
||||||
public string $method = 'GET'
|
|
||||||
) {}
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Kernel\Config;
|
|
||||||
|
|
||||||
class PlatformConfig
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Kernel;
|
|
||||||
|
|
||||||
class Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Kernel\Http;
|
|
||||||
|
|
||||||
class Request extends \Symfony\Component\HttpFoundation\Request
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Kernel\Http;
|
|
||||||
|
|
||||||
class Response extends \Symfony\Component\HttpFoundation\Response
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Kernel\InternalModule\Controller;
|
|
||||||
|
|
||||||
use VersaDigitale\Platform\Kernel\Attributes\Route;
|
|
||||||
use VersaDigitale\Platform\Kernel\Http\Request;
|
|
||||||
use VersaDigitale\Platform\Kernel\Http\Response;
|
|
||||||
use VersaDigitale\Platform\Logging\Log;
|
|
||||||
|
|
||||||
class InternalAuthController
|
|
||||||
{
|
|
||||||
|
|
||||||
#[Route(path: "/", method: "GET")]
|
|
||||||
public function index(Request $request) {
|
|
||||||
Log::info("Test");
|
|
||||||
return new Response("Ok!");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Kernel\InternalModule;
|
|
||||||
|
|
||||||
use VersaDigitale\Platform\Kernel\InternalModule\Controller\InternalAuthController;
|
|
||||||
use VersaDigitale\Platform\Module\AbstractModule;
|
|
||||||
|
|
||||||
class InternalModule extends AbstractModule
|
|
||||||
{
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct("internal", "Internes Modul der versa digitale Platform.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function init(): void
|
|
||||||
{
|
|
||||||
$this->registerController(InternalAuthController::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Kernel;
|
|
||||||
|
|
||||||
use Bramus\Router\Router;
|
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
|
||||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
|
|
||||||
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
|
|
||||||
use Symfony\Component\HttpKernel\HttpKernel;
|
|
||||||
use Symfony\Component\Routing\Matcher\UrlMatcher;
|
|
||||||
use Symfony\Component\Routing\RequestContext;
|
|
||||||
use Symfony\Component\Routing\RouteCollection;
|
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
|
||||||
use VersaDigitale\Platform\Database\VersaBase;
|
|
||||||
use VersaDigitale\Platform\Kernel\Attributes\Route;
|
|
||||||
use VersaDigitale\Platform\Kernel\Http\Request;
|
|
||||||
use VersaDigitale\Platform\Kernel\Http\Response;
|
|
||||||
use VersaDigitale\Platform\Kernel\InternalModule\InternalModule;
|
|
||||||
use VersaDigitale\Platform\Logging\Log;
|
|
||||||
use VersaDigitale\Platform\Module\ModuleManager;
|
|
||||||
use VersaDigitale\Platform\Server\VersaServer;
|
|
||||||
|
|
||||||
class VersaKernel
|
|
||||||
{
|
|
||||||
|
|
||||||
private static VersaServer $server;
|
|
||||||
private static bool $isInitialized = false;
|
|
||||||
private static RouteCollection $routes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
public static array $controllerClasses;
|
|
||||||
|
|
||||||
public static function __initKernel(): void
|
|
||||||
{
|
|
||||||
|
|
||||||
if(!self::$isInitialized) {
|
|
||||||
VersaBase::__init();
|
|
||||||
self::$routes = new RouteCollection();
|
|
||||||
|
|
||||||
|
|
||||||
ModuleManager::addModule(new InternalModule());
|
|
||||||
ModuleManager::initModules();
|
|
||||||
|
|
||||||
foreach(self::$controllerClasses as $class) {
|
|
||||||
self::__registerControllerRoutes($class);
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$isInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function __registerControllerRoutes(string $controllerClass)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$controllerReflection = new \ReflectionClass($controllerClass);
|
|
||||||
|
|
||||||
foreach ($controllerReflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
|
|
||||||
$attributes = $method->getAttributes(Route::class);
|
|
||||||
|
|
||||||
foreach ($attributes as $attribute) {
|
|
||||||
/** @var Route $route */
|
|
||||||
$route = $attribute->newInstance();
|
|
||||||
|
|
||||||
// Create a Symfony route
|
|
||||||
$symfonyRoute = new \Symfony\Component\Routing\Route(
|
|
||||||
$route->path,
|
|
||||||
['_controller' => [$controllerClass, $method->getName()]]
|
|
||||||
);
|
|
||||||
$symfonyRoute->setMethods([$route->method]);
|
|
||||||
|
|
||||||
// Add the route to the RouteCollection
|
|
||||||
self::$routes->add($route->path, $symfonyRoute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
Log::error("Error while registering controller routes: ".$e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function __handleRequest(Request $request): Response
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$context = new RequestContext();
|
|
||||||
$context->fromRequest($request);
|
|
||||||
$matcher = new UrlMatcher(self::$routes, $context);
|
|
||||||
Log::info("Incoming " . $request->getMethod() . " request for path " . $request->getPathInfo());
|
|
||||||
try {
|
|
||||||
$routeInfo = $matcher->match($request->getPathInfo());
|
|
||||||
[$controllerClass, $method] = $routeInfo['_controller'];
|
|
||||||
unset($routeInfo['_controller']); // Remove the controller key from params
|
|
||||||
|
|
||||||
// Call the controller and get the response
|
|
||||||
$controller = new $controllerClass();
|
|
||||||
Log::info("Found controller " . $controllerClass . " with method " . $method);
|
|
||||||
return $controller->$method($request);
|
|
||||||
} catch (\Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
|
|
||||||
return new Response('404 Not Found', 404);
|
|
||||||
} catch (\Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
|
|
||||||
return new Response('405 Method Not Allowed', 405);
|
|
||||||
}
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
return new Response($e->getTraceAsString(), 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function __startServer(string $host = "0.0.0.0", int $port = 8080) {
|
|
||||||
if(!self::$isInitialized) {
|
|
||||||
self::__initKernel();
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$server = new VersaServer(
|
|
||||||
host: $host,
|
|
||||||
port: $port,
|
|
||||||
);
|
|
||||||
|
|
||||||
self::$server->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Module;
|
|
||||||
|
|
||||||
abstract class AbstractModule extends Module
|
|
||||||
{
|
|
||||||
|
|
||||||
public abstract function init(): void;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Module;
|
|
||||||
|
|
||||||
use VersaDigitale\Platform\Kernel\VersaKernel;
|
|
||||||
use VersaDigitale\Platform\Module\AbstractModule;
|
|
||||||
|
|
||||||
class Module
|
|
||||||
{
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
public string $name,
|
|
||||||
public string $description,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function registerController(string $class) {
|
|
||||||
VersaKernel::$controllerClasses[] = $class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace VersaDigitale\Platform\Module;
|
|
||||||
|
|
||||||
use VersaDigitale\Platform\Logging\Log;
|
|
||||||
|
|
||||||
class ModuleManager
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var AbstractModule[]
|
|
||||||
*/
|
|
||||||
public static array $modules = [];
|
|
||||||
|
|
||||||
public static function __init(): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function addModule(AbstractModule $module): void {
|
|
||||||
self::$modules[] = $module;
|
|
||||||
Log::info("Modul \"" . $module->name . "\" geladen.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function initModules(): void
|
|
||||||
{
|
|
||||||
foreach (self::$modules as $module) {
|
|
||||||
$module->init();
|
|
||||||
Log::info("Modul \"" . $module->name . "\" initialisiert.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -2,15 +2,10 @@
|
|||||||
|
|
||||||
namespace VersaDigitale\Platform\Server;
|
namespace VersaDigitale\Platform\Server;
|
||||||
|
|
||||||
use Nyholm\Psr7\Factory\Psr17Factory;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use React\Http\HttpServer;
|
use React\Http\HttpServer;
|
||||||
use React\Http\Message\Response;
|
use React\Http\Message\Response;
|
||||||
use React\Socket\SocketServer;
|
use React\Socket\SocketServer;
|
||||||
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
|
|
||||||
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use VersaDigitale\Platform\Kernel\VersaKernel;
|
|
||||||
use VersaDigitale\Platform\Logging\Log;
|
use VersaDigitale\Platform\Logging\Log;
|
||||||
|
|
||||||
class VersaServer
|
class VersaServer
|
||||||
@ -26,31 +21,12 @@ class VersaServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function start(): void {
|
public function start(): void {
|
||||||
$psr17Factory = new Psr17Factory();
|
$this->http = new HttpServer(function (ServerRequestInterface $request) {
|
||||||
$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);
|
return Response::plaintext(
|
||||||
$this->http = new HttpServer(function (ServerRequestInterface $request) use($psrHttpFactory) {
|
"Hello World!\n"
|
||||||
$httpFoundationFactory = new HttpFoundationFactory();
|
);
|
||||||
Log::info("Test");
|
|
||||||
try {
|
|
||||||
$symfonyRequest = $httpFoundationFactory->createRequest($request);
|
|
||||||
$versaRequest = new \VersaDigitale\Platform\Kernel\Http\Request($symfonyRequest->query->all(), $symfonyRequest->request->all(), $symfonyRequest->attributes->all(), $symfonyRequest->cookies->all(), $symfonyRequest->files->all(), $symfonyRequest->server->all(), $symfonyRequest->getContent());
|
|
||||||
$versaResponse = VersaKernel::__handleRequest($versaRequest);
|
|
||||||
|
|
||||||
return $psrHttpFactory->createResponse($versaResponse);
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
return Response::plaintext($e->getTraceAsString())->withStatus(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
$this->http->on("error", function(\Throwable $e) {
|
|
||||||
Log::error($e->getTraceAsString());
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->socket = new SocketServer("{$this->host}:{$this->port}");
|
$this->socket = new SocketServer("{$this->host}:{$this->port}");
|
||||||
$this->socket->on("error", function(\Throwable $e) {
|
|
||||||
Log::error($e->getTraceAsString());
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->http->listen($this->socket);
|
$this->http->listen($this->socket);
|
||||||
Log::info("versa digitale Platform erreichbar unter {$this->host}:{$this->port}");
|
Log::info("versa digitale Platform erreichbar unter {$this->host}:{$this->port}");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"base_dir": "example-app"
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user