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

Commit

Permalink
Refactors code
Browse files Browse the repository at this point in the history
- Covers with tests all controllers
- Disables Event sourcing
- Adds laravel attribute routes
- Redesigned all controllers
- Adds user module

fixes #45
  • Loading branch information
butschster committed Nov 17, 2021
1 parent 9830d82 commit 821d6f2
Show file tree
Hide file tree
Showing 85 changed files with 1,584 additions and 478 deletions.
12 changes: 12 additions & 0 deletions app/Application/Contracts/EventSource/Event.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace App\Contracts\EventSource;

use EventSauce\EventSourcing\Serialization\SerializablePayload;

interface Event extends SerializablePayload
{

}
10 changes: 10 additions & 0 deletions app/Application/Exceptions/EntityNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace App\Exceptions;

class EntityNotFoundException extends \DomainException
{

}
67 changes: 67 additions & 0 deletions app/Infrastructure/CycleOrm/Auth/UserProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace Infrastructure\CycleOrm\Auth;

use Cycle\ORM\ORMInterface;
use Cycle\ORM\RepositoryInterface;
use Cycle\ORM\TransactionInterface;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Support\Str;

final class UserProvider implements \Illuminate\Contracts\Auth\UserProvider
{
public function __construct(
private ORMInterface $orm,
private TransactionInterface $transaction,
private string $model,
private Hasher $hasher
) {
}

public function retrieveById($identifier)
{
return $this->getRepository()->findByPK($identifier);
}

public function retrieveByToken($identifier, $token)
{
return $this->getRepository()->findOne([
'uuid' => $identifier,
'remember_token' => $token,
]);
}

public function updateRememberToken(Authenticatable $user, $token)
{
// TODO: use command handler

$user->setRememberToken($token);
$this->transaction->persist($user);
$this->transaction->run();
}

public function retrieveByCredentials(array $credentials)
{
$criteria = [];
foreach ($credentials as $key => $value) {
if (!Str::contains($key, 'password')) {
$criteria[$key] = $value;
}
}

return $this->getRepository()->findOne($criteria);
}

public function validateCredentials(Authenticatable $user, array $credentials)
{
return $this->hasher->check($credentials['password'], $user->getAuthPassword());
}

protected function getRepository(): RepositoryInterface
{
return $this->orm->getRepository($this->model);
}
}
15 changes: 14 additions & 1 deletion app/Infrastructure/CycleOrm/CycleOrmServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Cycle\ORM\Transaction;
use Cycle\ORM\TransactionInterface;
use Illuminate\Support\ServiceProvider;
use Infrastructure\CycleOrm\Auth\UserProvider;
use Spiral\Core\Container as SpiralContainer;

final class CycleOrmServiceProvider extends ServiceProvider
Expand All @@ -21,8 +22,8 @@ public function register(): void
$this->initContainer();
$this->initFactory();
$this->initOrm();

$this->app->bind(TransactionInterface::class, Transaction::class);
$this->registerAuthUserProvider();
}

private function initContainer(): void
Expand Down Expand Up @@ -58,4 +59,16 @@ private function initOrm(): void
);
});
}

private function registerAuthUserProvider(): void
{
$this->app['auth']->provider('cycle', function ($app, $config) {
return new UserProvider(
$app[ORMInterface::class],
$app[TransactionInterface::class],
$config['model'],
$app['hash'],
);
});
}
}
7 changes: 4 additions & 3 deletions app/Infrastructure/EventSauce/ConsumerLocator.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<?php

declare(strict_types=1);

namespace Infrastructure\EventSauce;

use App\Attributes\Locator;
use App\Attributes\Projectors\Projector;
use App\Contracts\EventSource\Event;
use EventSauce\EventSourcing\Message;
use EventSauce\EventSourcing\Serialization\SerializablePayload;

final class ConsumerLocator
{
Expand Down Expand Up @@ -36,10 +37,10 @@ private function processProjectors(\ReflectionClass $class)
{
foreach ($class->getMethods() as $method) {
foreach ($method->getParameters() as $parameter) {
if (is_a($parameter->getType()->getName(), SerializablePayload::class, true)) {
if (is_a($parameter->getType()->getName(), Event::class, true)) {
$this->consumers[$parameter->getType()->getName()][] = [
$method->getDeclaringClass()->getName(),
$method->getName()
$method->getName(),
];
}
}
Expand Down
1 change: 1 addition & 0 deletions app/Infrastructure/EventSauce/Domain/Entities/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#[Entity(role: 'stored_events')]
class Event
{
/** @internal */
public function __construct(
#[Column(name: 'event_id', type: 'string(36)', typecast: 'uuid', primary: true)]
private Uuid $id,
Expand Down
6 changes: 3 additions & 3 deletions app/Interfaces/Http/Middleware/SubstituteUuids.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?php

declare(strict_types=1);

namespace Interfaces\Http\Middleware;

use App\Domain\ValueObjects\Uuid;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Reflector;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use ReflectionParameter;

class SubstituteUuids
Expand All @@ -20,7 +20,7 @@ public function handle(Request $request, Closure $next)
// Filter only parameters type-hinted with Ramsey\Uuid\UuidInterface
/** @var ReflectionParameter[] $parameters */
$parameters = array_filter($route->signatureParameters(), function ($p) {
return Reflector::getParameterClassName($p) === UuidInterface::class;
return Reflector::getParameterClassName($p) === Uuid::class;
});

foreach ($parameters as $parameter) {
Expand Down
48 changes: 33 additions & 15 deletions app/Interfaces/Providers/RouteServiceProvider.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

declare(strict_types=1);

namespace Interfaces\Providers;
Expand All @@ -8,25 +9,11 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
use Spatie\RouteAttributes\RouteRegistrar;

class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* @var string
*/
public const HOME = '/dashboard';

/**
* The controller namespace for the application.
*
* When present, controller route declarations will automatically be prefixed with this namespace.
*
* @var string|null
*/
// protected $namespace = 'Interfaces\\Http\\Controllers';

public function boot()
Expand All @@ -41,6 +28,8 @@ public function boot()
Route::middleware('web')
->group(base_path('routes/web.php'));
});

$this->registerRoutesFromAttributes();
}

protected function configureRateLimiting()
Expand All @@ -49,4 +38,33 @@ protected function configureRateLimiting()
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
});
}

private function registerRoutesFromAttributes(): void
{
if (!$this->shouldRegisterRoutes()) {
return;
}

$routeRegistrar = (new RouteRegistrar(app()->router))
->useRootNamespace('')
->useMiddleware(config('route-attributes.middleware') ?? []);

collect(config('route-attributes.directories'))
->each(
fn(string $directory) => $routeRegistrar->registerDirectory($directory)
);
}

private function shouldRegisterRoutes(): bool
{
if (!config('route-attributes.enabled')) {
return false;
}

if ($this->app->routesAreCached()) {
return false;
}

return true;
}
}
16 changes: 10 additions & 6 deletions app/Interfaces/Websocket/Controllers/ConnectAction.php
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
<?php

declare(strict_types=1);

namespace Interfaces\Websocket\Controllers;

use Illuminate\Contracts\Broadcasting\Broadcaster;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Interfaces\Http\Controllers\Controller;
use Interfaces\Websocket\Middleware\ChannelJoined;
use Spatie\RouteAttributes\Attributes\Get;

class ConnectAction extends Controller
{
#[Get(uri: '/ws', name: 'ws.join', middleware: [ChannelJoined::class])]
public function __invoke(
Request $request,
Request $request,
Broadcaster $broadcaster,
): JsonResponse
{
$response = new JsonResponse([]);
): JsonResponse {
$response = new JsonResponse();

if ($request->attributes->has('ws:joinTopics')) {
$channelName = $request->attributes->get('ws:joinTopics');
$channelName = $request->attributes->get('ws:joinTopics') ?? $request->header('X-WS-Join-Topics');
if ($channelName) {

if ($broadcaster->isGuardedChannel($channelName)) {
$request->offsetSet('channel_name', $channelName);
Expand Down
2 changes: 1 addition & 1 deletion app/Interfaces/Websocket/Middleware/ChannelJoined.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function handle($request, Closure $next)
return $next($request);
}

public function terminate(Request $request, Response $response): void
public function terminate(Request $request, $response): void
{
if (!$request->attributes->has('ws:joinTopics')) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ class Command implements \App\Contracts\Command\Command
// TODO: use readonly property
public function __construct(
public ?string $type = null
)
{
) {
}
}
17 changes: 14 additions & 3 deletions app/Modules/Events/Application/Commands/ClearEvents/Handler.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
<?php

declare(strict_types=1);

namespace Modules\Events\Application\Commands\ClearEvents;

use App\Commands\ClearEvents;
use App\Contracts\Command\CommandHandler;
use Cycle\ORM\TransactionInterface;
use Illuminate\Contracts\Events\Dispatcher;
use Modules\Events\Domain\Event;
use Modules\Events\Domain\EventRepository;
use Modules\IncommingEvents\Domain\Events\EventsWasClear;

class Handler implements CommandHandler
{
public function __construct(
private EventRepository $events,
private EventRepository $events,
private Dispatcher $dispatcher,
private TransactionInterface $transaction
)
{
) {
}

#[\App\Attributes\CommandBus\CommandHandler]
Expand All @@ -32,4 +36,11 @@ public function __invoke(Command $command): void

$this->transaction->run();
}

#[\App\Attributes\CommandBus\CommandHandler]
public function handle(ClearEvents $command): void
{
$this->__invoke(new Command(type: $command->type));
$this->dispatcher->dispatch(new EventsWasClear(type: $command->type));
}
}
Loading

0 comments on commit 821d6f2

Please sign in to comment.