Improve error handling in controllers/repositories

This commit is contained in:
2025-03-14 12:53:58 +01:00
parent 7dbaee55f6
commit 7baf759fd9
9 changed files with 158 additions and 11 deletions
+2
View File
@@ -15,6 +15,7 @@ use React\Socket\SocketServer;
use SlotDb\SlotDb\Bus\MessageBus;
use SlotDb\SlotDb\Data\Database;
use SlotDb\SlotDb\Data\Group\Group;
use SlotDb\SlotDb\Data\Schema\Schema;
use SlotDb\SlotDb\Data\Slot\Slot;
use SlotDb\SlotDb\Data\Slot\SlotRepository;
@@ -59,6 +60,7 @@ class Daemon
$routes = new RouteCollection();
$routes->addController(new Http\Controller\SlotsController($em->getRepository(Slot::class), $this->messageBus));
$routes->addController(new Http\Controller\GroupsController($em->getRepository(Group::class), $em->getRepository(Slot::class)));
$routes->addController(new Http\Controller\SchemassController($em->getRepository(Schema::class)));
$this->server = new HttpServer(
new Http\Middleware\LoggingMiddleware($httpLogger ?? $logger),
@@ -0,0 +1,7 @@
<?php
namespace SlotDb\SlotDb\Data\Group;
class GroupNotFoundException extends \RuntimeException
{}
-3
View File
@@ -43,6 +43,3 @@ class GroupRepository extends EntityRepository
$this->getEntityManager()->clear();
}
}
class GroupNotFoundException extends \RuntimeException
{}
+6
View File
@@ -0,0 +1,6 @@
<?php
namespace SlotDb\SlotDb\Data\Slot;
class SlotNotFoundException extends \RuntimeException
{}
-3
View File
@@ -91,6 +91,3 @@ class SlotRepository extends EntityRepository
$this->getEntityManager()->clear();
}
}
class SlotNotFoundException extends \RuntimeException
{}
+16 -3
View File
@@ -6,6 +6,7 @@ use NoccyLabs\React\Http\Attributes\Route;
use Psr\Http\Message\ServerRequestInterface;
use React\Http\Message\Response;
use SlotDb\SlotDb\Data\Group\Group;
use SlotDb\SlotDb\Data\Group\GroupNotFoundException;
use SlotDb\SlotDb\Data\Group\GroupRepository;
use SlotDb\SlotDb\Data\Slot\Slot;
use SlotDb\SlotDb\Data\Slot\SlotRepository;
@@ -45,7 +46,11 @@ class GroupsController extends Controller
#[Route(path:"/api/slotdb/v1/group/:group", methods:["GET"])]
public function queryGroup(ServerRequestInterface $request, string $group)
{
$groupObj = $this->groups->findGroup($group);
try {
$groupObj = $this->groups->findGroup($group);
} catch (GroupNotFoundException $e) {
return Response::json([ 'error'=>"Group not found" ])->withStatus(404);
}
$groupProps = $groupObj->getProperties();
@@ -63,7 +68,11 @@ class GroupsController extends Controller
#[Route(path:"/api/slotdb/v1/group/:group/members", methods:["GET"])]
public function queryGroupMembers(ServerRequestInterface $request, string $group)
{
$groupObj = $this->groups->findGroup($group);
try {
$groupObj = $this->groups->findGroup($group);
} catch (GroupNotFoundException $e) {
return Response::json([ 'error'=>"Group not found" ])->withStatus(404);
}
return Response::json(iterator_to_array($groupObj->getSlots()));
}
@@ -71,7 +80,11 @@ class GroupsController extends Controller
#[Route(path:"/api/slotdb/v1/group/:group", methods:["POST"])]
public function updateGroup(ServerRequestInterface $request, string $group)
{
$groupObj = $this->groups->findGroup($group);
try {
$groupObj = $this->groups->findGroup($group);
} catch (GroupNotFoundException $e) {
return Response::json([ 'error'=>"Group not found" ])->withStatus(404);
}
$groupProps = $groupObj->getProperties();
+54
View File
@@ -0,0 +1,54 @@
<?php
namespace SlotDb\SlotDb\Http\Controller;
use NoccyLabs\React\Http\Attributes\Route;
use Psr\Http\Message\ServerRequestInterface;
use React\Http\Message\Response;
use SlotDb\SlotDb\Data\Group\Group;
use SlotDb\SlotDb\Data\Group\GroupRepository;
use SlotDb\SlotDb\Data\Schema\SchemaRepository;
use SlotDb\SlotDb\Data\Slot\Slot;
use SlotDb\SlotDb\Data\Slot\SlotRepository;
class SchemassController extends Controller
{
public function __construct(
private readonly SchemaRepository $schemas
)
{
}
#[Route(path:"/api/slotdb/v1/schemas", methods:["GET"])]
public function listSchemas(ServerRequestInterface $request)
{
$slots = $this->schemas->findGroups();
return Response::json($slots);
}
#[Route(path:"/api/slotdb/v1/schema/:schema", methods:["GET"])]
public function getSchema(ServerRequestInterface $request, string $schema)
{
return Response::json(true);
}
#[Route(path:"/api/slotdb/v1/schema/:schema", methods:["POST"])]
public function createSchema(ServerRequestInterface $request, string $schema)
{
return Response::json(true);
}
#[Route(path:"/api/slotdb/v1/schema/:schema", methods:["PUT"])]
public function updateSchema(ServerRequestInterface $request, string $schema)
{
return Response::json(true);
}
#[Route(path:"/api/slotdb/v1/schema/:schema", methods:["DELETE"])]
public function deleteSchema(ServerRequestInterface $request, string $schema)
{
return Response::json(true);
}
}
+12 -2
View File
@@ -7,6 +7,7 @@ use Psr\Http\Message\ServerRequestInterface;
use React\Http\Message\Response;
use SlotDb\SlotDb\Bus\MessageBus;
use SlotDb\SlotDb\Data\Slot\Slot;
use SlotDb\SlotDb\Data\Slot\SlotNotFoundException;
use SlotDb\SlotDb\Data\Slot\SlotRepository;
@@ -80,7 +81,11 @@ class SlotsController extends Controller
#[Route(path:"/api/slotdb/v1/slot/:slot", methods:["GET"])]
public function querySlot(ServerRequestInterface $request, string $slot)
{
$slotObj = $this->slots->findOneBy(['slotId' => $slot]);
try {
$slotObj = $this->slots->findSlot($slot);
} catch (SlotNotFoundException $e) {
return Response::json([ 'error'=>"Slot not found" ])->withStatus(404);
}
return Response::json($slotObj);
}
@@ -88,7 +93,12 @@ class SlotsController extends Controller
#[Route(path:"/api/slotdb/v1/slot/:slot", methods:["POST"])]
public function updateSlot(ServerRequestInterface $request, string $slot)
{
$slotObj = $this->slots->findOneBy(['slotId' => $slot]);
try {
$slotObj = $this->slots->findSlot($slot);
} catch (SlotNotFoundException $e) {
return Response::json([ 'error'=>"Slot not found" ])->withStatus(404);
}
$slotProps = $slotObj->getProperties();
$posted = json_decode($request->getBody());
+61
View File
@@ -0,0 +1,61 @@
<?php
namespace SlotDb\SlotDb\Security;
use SlotDb\SlotDb\Data\Slot\Slot;
class AccessChecker
{
/** @var array<string,AceMatcher> */
private $aclCache = [];
/**
* Check if any of the ACL rules match the slot and property
*
* @param Slot $slot
* @param string $prop
* @param array<string> $acl
* @return bool
*/
public function checkAccess(Slot $slot, string $prop, array $acl, string $access): bool
{
$groupId = $slot->getGroup() ? $slot->getGroup()->getGroupId() : null;
$slotId = $slot->getSlotId();
foreach ($acl as $ace) {
$matcher = $this->getCompiledMatcher($ace);
if ($matcher->matches($slotId, $groupId, $prop, $access)) {
return true;
}
}
return false;
}
private function getCompiledMatcher(string $ace): AceMatcher
{
if (!isset($this->aclCache[$ace])) {
$this->aclCache[$ace] = new AceMatcher($ace);
}
return $this->aclCache[$ace];
}
}
class AceMatcher
{
public function __construct(
private readonly string $ace
)
{
}
public function matches(string $slot, string $group, string $prop, string $access): bool
{
}
public function getAce(): string
{
return $this->ace;
}
}