refactor: restructure into proper directory hierarchy

- Move Config class to src/Config/Config.php
- Move exception classes to src/Exception/
- Move Router components to src/Router/
- Update test files with proper namespace references
This commit is contained in:
Funky Waddle 2026-02-13 17:26:31 -06:00
parent 29980d8bc6
commit 30f84a5023
13 changed files with 67 additions and 66 deletions

View file

@ -25,6 +25,7 @@
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"Atlas\\": "src/",
"Atlas\\Tests\\": "tests/" "Atlas\\Tests\\": "tests/"
} }
}, },

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Atlas; namespace Atlas\Config;
use ArrayAccess; use ArrayAccess;
use IteratorAggregate; use IteratorAggregate;

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Atlas; namespace Atlas\Exception;
class MissingConfigurationException extends \RuntimeException class MissingConfigurationException extends \RuntimeException
{ {

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Atlas; namespace Atlas\Exception;
class NotFoundRouteException extends \RuntimeException class NotFoundRouteException extends \RuntimeException
{ {

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Atlas; namespace Atlas\Exception;
class RouteNotFoundException extends \RuntimeException class RouteNotFoundException extends \RuntimeException
{ {

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Atlas; namespace Atlas\Exception;
class RouteValidationException extends \RuntimeException class RouteValidationException extends \RuntimeException
{ {

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Atlas; namespace Atlas\Router;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Atlas; namespace Atlas\Router;
use Psr\Http\Message\UriInterface; use Psr\Http\Message\UriInterface;

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Atlas; namespace Atlas\Router;
class RouteGroup class RouteGroup
{ {

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Atlas; namespace Atlas\Router;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -10,8 +10,9 @@ class Router
protected mixed $fallbackHandler = null; protected mixed $fallbackHandler = null;
public function __construct( public function __construct(
private readonly Config $config private readonly Config\Config $config
) {} ) {
}
public function get(string $path, string|callable $handler, string|null $name = null): self public function get(string $path, string|callable $handler, string|null $name = null): self
{ {

View file

@ -2,7 +2,7 @@
namespace Atlas\Tests\Unit; namespace Atlas\Tests\Unit;
use Atlas\Router; use Atlas\Router\Router;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UriInterface; use Psr\Http\Message\UriInterface;
@ -11,11 +11,11 @@ final class ErrorHandlingTest extends TestCase
{ {
public function testMatchOrFailThrowsExceptionWhenNoRouteFound(): void public function testMatchOrFailThrowsExceptionWhenNoRouteFound(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$uri = $this->createMock(UriInterface::class); $uri = $this->createMock(UriInterface::class);
$uri->method('getPath')->willReturn('/nonexistent'); $uri->method('getPath')->willReturn('/nonexistent');
@ -27,18 +27,18 @@ final class ErrorHandlingTest extends TestCase
$request->method('getMethod')->willReturn('GET'); $request->method('getMethod')->willReturn('GET');
$request->method('getUri')->willReturn($uri); $request->method('getUri')->willReturn($uri);
$this->expectException(\Atlas\NotFoundRouteException::class); $this->expectException(\Atlas\Exception\NotFoundRouteException::class);
$router->matchOrFail($request); $router->matchOrFail($request);
} }
public function testMatchReturnsNullWhenNoRouteFound(): void public function testMatchReturnsNullWhenNoRouteFound(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$uri = $this->createMock(UriInterface::class); $uri = $this->createMock(UriInterface::class);
$uri->method('getPath')->willReturn('/nonexistent'); $uri->method('getPath')->willReturn('/nonexistent');
@ -57,40 +57,38 @@ final class ErrorHandlingTest extends TestCase
public function testRouteChainingWithDifferentHttpMethods(): void public function testRouteChainingWithDifferentHttpMethods(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $result = new \Atlas\Router\Router($config)->get('/test', 'GetHandler')->post('/test', 'PostHandler');
$result = $router->get('/test', 'GetHandler')->post('/test', 'PostHandler'); $this->assertTrue($result instanceof \Atlas\Router\Router);
$this->assertCount(2, $result->getRoutes());
$this->assertTrue($result instanceof Router);
$this->assertCount(2, $router->getRoutes());
} }
public function testMatchUsingRouteDefinition(): void public function testMatchUsingRouteDefinition(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/test', 'TestMethod'); $router->get('/test', 'TestMethod');
$routes = $router->getRoutes(); $routes = $router->getRoutes();
$this->assertCount(1, $routes); $this->assertCount(1, $routes);
$this->assertInstanceOf(\Atlas\RouteDefinition::class, $routes[0]); $this->assertInstanceOf(\Atlas\Router\RouteDefinition::class, $routes[0]);
} }
public function testCaseInsensitiveHttpMethodMatching(): void public function testCaseInsensitiveHttpMethodMatching(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/test', 'TestHandler'); $router->get('/test', 'TestHandler');
@ -111,11 +109,11 @@ final class ErrorHandlingTest extends TestCase
public function testPathNormalizationLeadingSlashes(): void public function testPathNormalizationLeadingSlashes(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/test', 'TestHandler'); $router->get('/test', 'TestHandler');
@ -136,11 +134,11 @@ final class ErrorHandlingTest extends TestCase
public function testMatchOrFailThrowsExceptionForMultipleRoutes(): void public function testMatchOrFailThrowsExceptionForMultipleRoutes(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/test', 'TestHandler'); $router->get('/test', 'TestHandler');
@ -156,6 +154,6 @@ final class ErrorHandlingTest extends TestCase
$matchedRoute = $router->matchOrFail($request); $matchedRoute = $router->matchOrFail($request);
$this->assertInstanceOf(\Atlas\RouteDefinition::class, $matchedRoute); $this->assertInstanceOf(\Atlas\Router\RouteDefinition::class, $matchedRoute);
} }
} }

View file

@ -2,7 +2,7 @@
namespace Atlas\Tests\Unit; namespace Atlas\Tests\Unit;
use Atlas\Router; use Atlas\Router\Router;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UriInterface; use Psr\Http\Message\UriInterface;
@ -11,11 +11,11 @@ final class RouteMatcherTest extends TestCase
{ {
public function testReturnsRouteOnSuccessfulMatch(): void public function testReturnsRouteOnSuccessfulMatch(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/hello', 'HelloWorldHandler'); $router->get('/hello', 'HelloWorldHandler');
@ -31,18 +31,18 @@ final class RouteMatcherTest extends TestCase
$matchedRoute = $router->match($request); $matchedRoute = $router->match($request);
$this->assertInstanceOf(\Atlas\RouteDefinition::class, $matchedRoute); $this->assertInstanceOf(\Atlas\Router\RouteDefinition::class, $matchedRoute);
$this->assertSame('/hello', $matchedRoute->getPath()); $this->assertSame('/hello', $matchedRoute->getPath());
$this->assertSame('HelloWorldHandler', $matchedRoute->getHandler()); $this->assertSame('HelloWorldHandler', $matchedRoute->getHandler());
} }
public function testReturnsNullOnNoMatch(): void public function testReturnsNullOnNoMatch(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/test', 'Handler'); $router->get('/test', 'Handler');
@ -61,13 +61,13 @@ final class RouteMatcherTest extends TestCase
$this->assertNull($matchedRoute); $this->assertNull($matchedRoute);
} }
public function testHttpMethodMatchingCaseInsensitive(): void public function testCaseInsensitiveHttpMethodMatching(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/test', 'Handler'); $router->get('/test', 'Handler');
@ -88,11 +88,11 @@ final class RouteMatcherTest extends TestCase
public function testRouteCollectionIteratesCorrectly(): void public function testRouteCollectionIteratesCorrectly(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/route1', 'Handler1'); $router->get('/route1', 'Handler1');
$router->post('/route2', 'Handler2'); $router->post('/route2', 'Handler2');
@ -102,31 +102,32 @@ final class RouteMatcherTest extends TestCase
$routeArray = iterator_to_array($routes); $routeArray = iterator_to_array($routes);
$this->assertCount(2, $routeArray); $this->assertCount(2, $routeArray);
$this->assertInstanceOf(\Atlas\RouteDefinition::class, $routeArray[0]); $this->assertInstanceOf(\Atlas\Router\RouteDefinition::class, $routeArray[0]);
$this->assertInstanceOf(\Atlas\RouteDefinition::class, $routeArray[1]); $this->assertInstanceOf(\Atlas\Router\RouteDefinition::class, $routeArray[1]);
} }
public function testUrlGenerationWithNamedRoute(): void public function testUrlGenerationWithNamedRoute(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/users', 'UserListHandler', 'user_list'); $router->get('/users', 'UserListHandler', 'user_list');
$url = $router->url('user_list'); $url = $router->url('user_list');
$this->assertSame('/users', $url); $this->assertSame('/users', $url);
} }
public function testHttpMethodsReturnSameInstanceForChaining(): void public function testHttpMethodsReturnSameInstanceForChaining(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$methodsResult = $router $methodsResult = $router
->get('/get', 'Handler') ->get('/get', 'Handler')
@ -135,6 +136,6 @@ final class RouteMatcherTest extends TestCase
->patch('/patch', 'Handler') ->patch('/patch', 'Handler')
->delete('/delete', 'Handler'); ->delete('/delete', 'Handler');
$this->assertTrue($methodsResult instanceof Router); $this->assertTrue($methodsResult instanceof \Atlas\Router\Router);
} }
} }

View file

@ -2,30 +2,30 @@
namespace Atlas\Tests\Unit; namespace Atlas\Tests\Unit;
use Atlas\Router; use Atlas\Router\Router;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class RouterBasicTest extends TestCase class RouterBasicTest extends TestCase
{ {
public function testRouterCanBeCreatedWithValidConfig(): void public function testRouterCanBeCreatedWithValidConfig(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'], 'modules_path' => ['/path/to/modules'],
'routes_file' => 'routes.php' 'routes_file' => 'routes.php'
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$this->assertInstanceOf(Router::class, $router); $this->assertInstanceOf(\Atlas\Router\Router::class, $router);
} }
public function testRouterCanCreateSimpleRoute(): void public function testRouterCanCreateSimpleRoute(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/hello', function() { $router->get('/hello', function() {
return 'Hello World'; return 'Hello World';
@ -36,31 +36,31 @@ class RouterBasicTest extends TestCase
public function testRouterReturnsSameInstanceForChaining(): void public function testRouterReturnsSameInstanceForChaining(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$result = $router->get('/get', 'handler')->post('/post', 'handler'); $result = $router->get('/get', 'handler')->post('/post', 'handler');
$this->assertTrue($result instanceof Router); $this->assertTrue($result instanceof \Atlas\Router\Router);
} }
public function testRouteHasCorrectProperties(): void public function testRouteHasCorrectProperties(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/test', 'test_handler', 'test_route'); $router->get('/test', 'test_handler', 'test_route');
$routes = $router->getRoutes(); $routes = $router->getRoutes();
$route = $routes[0] ?? null; $route = $routes[0] ?? null;
$this->assertInstanceOf(\Atlas\RouteDefinition::class, $route); $this->assertInstanceOf(\Atlas\Router\RouteDefinition::class, $route);
$this->assertSame('GET', $route->getMethod()); $this->assertSame('GET', $route->getMethod());
$this->assertSame('/test', $route->getPath()); $this->assertSame('/test', $route->getPath());
$this->assertSame('test_handler', $route->getHandler()); $this->assertSame('test_handler', $route->getHandler());
@ -72,18 +72,18 @@ class RouterBasicTest extends TestCase
public function testRouteNormalizesPath(): void public function testRouteNormalizesPath(): void
{ {
$config = new \Atlas\Config([ $config = new \Atlas\Tests\Config\Config([
'modules_path' => ['/path/to/modules'] 'modules_path' => ['/path/to/modules']
]); ]);
$router = new Router($config); $router = new \Atlas\Router\Router($config);
$router->get('/api/test', 'handler'); $router->get('/api/test', 'handler');
$routes = $router->getRoutes(); $routes = $router->getRoutes();
$route = $routes[0] ?? null; $route = $routes[0] ?? null;
$this->assertInstanceOf(\Atlas\RouteDefinition::class, $route); $this->assertInstanceOf(\Atlas\Router\RouteDefinition::class, $route);
$this->assertSame('/api/test', $route->getPath()); $this->assertSame('/api/test', $route->getPath());
} }
} }