Skip to content
This repository has been archived by the owner on Sep 5, 2023. It is now read-only.

(WIP) BACKEND-7355 :: Feature :: Harmony PHP | Custom Kernel #61

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@

## Develop Installation

1. `npm install`
2. Setup [Sample](sample/README.md)
1. `nvm install`
2. `nvm use`
3. `npm ci --also=dev`
4. Setup [Sample](sample/README.md)

## Author

Expand Down
8 changes: 8 additions & 0 deletions core/src/Domain/Exception/HarmonyException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Harmony\Core\Domain\Exception;

use Exception;

class HarmonyException extends Exception {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Harmony\Core\Shared\Error;
namespace Harmony\Core\Domain\Exception;

use InvalidArgumentException;
use Throwable;
Expand Down
11 changes: 11 additions & 0 deletions core/src/Domain/Exception/MethodNotImplementedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Harmony\Core\Domain\Exception;

class MethodNotImplementedException extends HarmonyException {
public function __construct(
string $message = "This method is not implemented yet.",
) {
parent::__construct($message);
}
}
36 changes: 36 additions & 0 deletions core/src/Module/Config/Env/DotEnvPathsContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Harmony\Core\Module\Config\Env;

use Harmony\Core\Module\FileSystem\Exception\FileNotExistException;
use Harmony\Core\Module\FileSystem\ValueObject\ValidFilePath;

class DotEnvPathsContainer implements DotEnvPathsContainerInterface {
/** @var ValidFilePath[] */
protected array $paths = [];

/**
* @param string[] $paths
*
* @throws FileNotExistException
*/
public function __construct(array $paths = []) {
foreach ($paths as $path) {
$this->add($path);
}
}

/**
* @throws FileNotExistException
*/
public function add(string $path): void {
$this->paths[] = new ValidFilePath($path);
}

/**
* @return ValidFilePath[]
*/
public function getEnvPaths(): array {
return $this->paths;
}
}
12 changes: 12 additions & 0 deletions core/src/Module/Config/Env/DotEnvPathsContainerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Harmony\Core\Module\Config\Env;

use Harmony\Core\Module\FileSystem\ValueObject\ValidFilePath;

interface DotEnvPathsContainerInterface {
/**
* @return ValidFilePath[]
*/
public function getEnvPaths(): array;
}
6 changes: 6 additions & 0 deletions core/src/Module/Config/ModuleCommandsInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

namespace Harmony\Core\Module\Config;

interface ModuleCommandsInterface {
}
6 changes: 6 additions & 0 deletions core/src/Module/Config/ModuleConfigsInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

namespace Harmony\Core\Module\Config;

interface ModuleConfigsInterface {
}
6 changes: 6 additions & 0 deletions core/src/Module/Config/ModuleRoutesInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

namespace Harmony\Core\Module\Config;

interface ModuleRoutesInterface {
}
8 changes: 8 additions & 0 deletions core/src/Module/Config/ModulesToLoadInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Harmony\Core\Module\Config;

interface ModulesToLoadInterface {
/** @return class-string<ProviderInterface>[] */
public function getProviders(): array;
}
23 changes: 23 additions & 0 deletions core/src/Module/Config/ProviderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Harmony\Core\Module\Config;

use Harmony\Core\Module\Router\Route;
use Symfony\Component\Console\Command\Command;

interface ProviderInterface {
/**
* @return Route[]
*/
public function getRoutes(): array;

/**
* @return class-string<Command>[]
*/
public function getCommands(): array;

/**
* @return array<string, callable>
*/
public function getResolverDefinitions(): array;
}
10 changes: 10 additions & 0 deletions core/src/Module/Config/ResolverInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Harmony\Core\Module\Config;

interface ResolverInterface {
/**
* @return array<string, callable>
*/
public function __invoke(): array;
}
11 changes: 11 additions & 0 deletions core/src/Module/FileSystem/Exception/FileNotExistException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Harmony\Core\Module\FileSystem\Exception;

use Harmony\Core\Domain\Exception\HarmonyException;

class FileNotExistException extends HarmonyException {
public function __construct(string $filePath) {
parent::__construct("File not exist: " . $filePath);
}
}
23 changes: 23 additions & 0 deletions core/src/Module/FileSystem/ValueObject/ValidFilePath.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Harmony\Core\Module\FileSystem\ValueObject;

use Harmony\Core\Module\FileSystem\Exception\FileNotExistException;

class ValidFilePath {
/**
* @throws FileNotExistException
*/
public function __construct(public string $value) {
$this->validateOrFail();
}

/**
* @throws FileNotExistException
*/
protected function validateOrFail(): void {
if (!file_exists($this->value)) {
throw new FileNotExistException($this->value);
}
}
}
35 changes: 35 additions & 0 deletions core/src/Module/Kernel/ConsoleKernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Harmony\Core\Module\Kernel;

use Exception;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;

class ConsoleKernel extends Kernel {
/**
* @return int
* @throws Exception
*/
public function handleCommand(): int {
$commands = [];

foreach ($this->commands as $command) {
$commandName = $command::getDefaultName();

if (is_string($commandName)) {
$commands[$commandName] = function () use ($command): Command {
return new $command();
};
}
}

$commandLoader = new FactoryCommandLoader($commands);

$application = new Application();
$application->setCommandLoader($commandLoader);

return $application->run();
}
}
29 changes: 29 additions & 0 deletions core/src/Module/Kernel/HttpKernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Harmony\Core\Module\Kernel;

use Harmony\Core\Module\Router\ControllerActionInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Matcher\UrlMatcher;

class HttpKernel extends Kernel {
protected ?Request $request = null;

public function handleRequest(Request $request): Response {
$this->request = $request;

$matcher = new UrlMatcher($this->routes, $this->context);
$parameters = $matcher->match($this->request->getPathInfo());
/** @var class-string $controllerActionClass */
$controllerActionClass = $parameters["_controller"];

/** @var ControllerActionInterface $controllerAction */
$controllerAction = $this->diContainer->get($controllerActionClass);

$response = $controllerAction($this->request);
$response->prepare($this->request);

return $response;
}
}
112 changes: 112 additions & 0 deletions core/src/Module/Kernel/Kernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

namespace Harmony\Core\Module\Kernel;

use DI\Container;
use DI\ContainerBuilder;
use Exception;
use Harmony\Core\Module\Config\Env\DotEnvPathsContainerInterface;
use Harmony\Core\Module\Config\ModulesToLoadInterface;
use Harmony\Core\Module\Config\ProviderInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

class Kernel {
/** @var ProviderInterface[] */
protected array $modules = [];

protected Container $diContainer;

/** @var class-string<Command>[] */
protected array $commands = [];

protected RouteCollection $routes;
protected UrlGenerator $urlGenerator;

protected RequestContext $context;

public function __construct(
protected ?DotEnvPathsContainerInterface $dotEnvs = null,
protected ?ModulesToLoadInterface $modulesToLoad = null,
) {
$this->loadEnv();
$this->loadModules();
$this->loadDI();
$this->loadCommands();
$this->loadRouting();
}

protected function loadEnv(): void {
if ($this->dotEnvs === null) {
return;
}

$dotenv = new Dotenv();
$dotEnvPaths = $this->dotEnvs->getEnvPaths();

foreach ($dotEnvPaths as $path) {
$dotenv->load($path->value);

unset($path);
}
}

protected function loadModules(): void {
if ($this->modulesToLoad === null) {
return;
}

foreach ($this->modulesToLoad->getProviders() as $module) {
$this->modules[] = new $module();

unset($module);
}
}

/**
* @throws Exception
*/
protected function loadDI(): void {
$diBuilder = new ContainerBuilder();

foreach ($this->modules as $module) {
$definitions = $module->getResolverDefinitions();
$diBuilder->addDefinitions($definitions);

unset($definitions);
}

$this->diContainer = $diBuilder->build();
}

protected function loadCommands(): void {
foreach ($this->modules as $module) {
$commands = $module->getCommands();
$this->commands += $commands;

unset($commands);
}
}

protected function loadRouting(): void {
$this->routes = new RouteCollection();

foreach ($this->modules as $module) {
$routes = $module->getRoutes();

foreach ($routes as $route) {
$symfonyRoute = new Route($route->uri, [
"_controller" => $route->controllerAction,
]);
$this->routes->add($route->name, $symfonyRoute);
}
}

$this->context = new RequestContext();
$this->urlGenerator = new UrlGenerator($this->routes, $this->context);
}
}
Loading