responsive-sk/slim4-root

Root path management with auto-discovery for Slim 4 applications

v1.1.0 2025-04-25 12:09 UTC

This package is not auto-updated.

Last update: 2025-04-25 13:48:48 UTC


README

Root path management with auto-discovery for Slim 4 applications. Say goodbye to relative paths like __DIR__ . '/../../../config' and hello to clean, consistent path access.

Latest Version on Packagist Software License Total Downloads

New in 2.0

  • Automatic root path discovery for common directory structures
  • Built-in path validation with detailed error messages
  • Cross-platform path normalization for Windows and Unix
  • Dedicated exception handling for path-related errors
  • Enhanced developer experience with more intuitive API
  • No more relative paths with ../ - everything is relative to the root

Features

  • Centralized path management for Slim 4 applications
  • Auto-discovery of common directory structures
  • Support for custom directory structures
  • Path validation and normalization
  • Middleware for accessing paths in route handlers
  • PSR-11 container integration
  • No dependencies (except Slim 4 and PSR Container)
  • Fully tested
  • Ready for PHP 7.4 and 8.0+

Requirements

  • PHP 7.4+ or 8.0+
  • Slim 4

Installation

composer require responsive-sk/slim4-root

Usage

Basic Usage

use Slim4\Root\Paths;

// Create a new Paths instance with auto-discovery enabled
$paths = new Paths(__DIR__);

// Get paths relative to the root
$configPath = $paths->getConfigPath();
$viewsPath = $paths->getViewsPath();
$logsPath = $paths->getLogsPath();

// Get all paths at once
$allPaths = $paths->getPaths();

// No more ../../../ paths!
// Instead of:
// require_once __DIR__ . '/../../../vendor/autoload.php';
// Use:
// require_once $paths->path('vendor/autoload.php');

With Custom Paths

use Slim4\Root\Paths;

// Create a new Paths instance with custom paths
$paths = new Paths(
    __DIR__,
    [
        'config' => __DIR__ . '/app/config',
        'views' => __DIR__ . '/app/views',
        'logs' => __DIR__ . '/app/logs',
    ],
    true, // Enable auto-discovery (default: true)
    false // Disable path validation (default: false)
);

// Get paths
$configPath = $paths->getConfigPath(); // Returns __DIR__ . '/app/config'
$viewsPath = $paths->getViewsPath(); // Returns __DIR__ . '/app/views'
$logsPath = $paths->getLogsPath(); // Returns __DIR__ . '/app/logs'

Path Auto-Discovery

use Slim4\Root\PathsDiscoverer;

// Create a new PathsDiscoverer instance
$discoverer = new PathsDiscoverer();

// Discover paths
$discoveredPaths = $discoverer->discover(__DIR__);

// Use discovered paths
var_dump($discoveredPaths);

Path Validation

use Slim4\Root\PathsValidator;
use Slim4\Root\Exception\InvalidPathException;

// Create a new PathsValidator instance
$validator = new PathsValidator();

// Validate paths
try {
    $validator->validate([
        'config' => __DIR__ . '/config',
        'views' => __DIR__ . '/views',
    ], true); // Strict validation (throws exception if path doesn't exist)
} catch (InvalidPathException $e) {
    echo $e->getMessage();
}

Path Normalization

use Slim4\Root\PathsNormalizer;

// Create a new PathsNormalizer instance
$normalizer = new PathsNormalizer();

// Normalize paths
$normalizedPath = $normalizer->normalize('C:\\path\\to\\project\\');
// Returns: 'C:/path/to/project'

With DI Container

use Slim4\Root\PathsProvider;
use DI\ContainerBuilder;

// Create container
$containerBuilder = new ContainerBuilder();

// Register paths services
$rootPath = dirname(__DIR__);
PathsProvider::register(
    $containerBuilder->build(),
    $rootPath,
    [], // Custom paths
    true, // Enable auto-discovery
    false // Disable path validation
);

// Get paths from the container
$paths = $container->get(Slim4\Root\PathsInterface::class);

With Middleware

use Slim4\Root\PathsMiddleware;
use Slim\Factory\AppFactory;

// Create app
$app = AppFactory::createFromContainer($container);

// Add the middleware to the app
$app->add($container->get(PathsMiddleware::class));

// Access paths in a route handler
$app->get('/', function ($request, $response) {
    $paths = $request->getAttribute('paths');
    $configPath = $paths->getConfigPath();

    // ...

    return $response;
});

Integration with Twig

use Slim\Views\Twig;
use Slim4\Root\PathsInterface;

// Register Twig with the container
$container->set(Twig::class, function (ContainerInterface $container) {
    $paths = $container->get(PathsInterface::class);

    $twig = Twig::create($paths->getViewsPath(), [
        'cache' => $paths->getCachePath() . '/twig',
        'debug' => true,
        'auto_reload' => true,
    ]);

    return $twig;
});

Integration with Monolog

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Psr\Log\LoggerInterface;
use Slim4\Root\PathsInterface;

// Register Logger with the container
$container->set(LoggerInterface::class, function (ContainerInterface $container) {
    $paths = $container->get(PathsInterface::class);

    $logger = new Logger('app');
    $logger->pushHandler(new StreamHandler($paths->getLogsPath() . '/app.log', Logger::DEBUG));

    return $logger;
});

Available Methods

PathsInterface

  • getRootPath() - Get the root path of the project
  • getConfigPath() - Get the config path
  • getResourcesPath() - Get the resources path
  • getViewsPath() - Get the views path
  • getAssetsPath() - Get the assets path
  • getCachePath() - Get the cache path
  • getLogsPath() - Get the logs path
  • getPublicPath() - Get the public path
  • getDatabasePath() - Get the database path
  • getMigrationsPath() - Get the migrations path
  • getStoragePath() - Get the storage path
  • getTestsPath() - Get the tests path
  • path(string $path) - Get a path relative to the root path
  • getPaths() - Get all paths as an associative array

PathsDiscoverer

  • discover(string $rootPath) - Discover paths in the given root path

PathsValidator

  • validate(array $paths, bool $strict) - Validate paths

PathsNormalizer

  • normalize(string $path) - Normalize path

Customizing Paths

You can customize the paths by passing an array of custom paths to the constructor:

$paths = new Paths(
    __DIR__,
    [
        'config' => __DIR__ . '/app/config',
        'views' => __DIR__ . '/app/views',
        'logs' => __DIR__ . '/app/logs',
        'cache' => __DIR__ . '/app/cache',
        'public' => __DIR__ . '/public',
        'database' => __DIR__ . '/app/database',
        'migrations' => __DIR__ . '/app/database/migrations',
        'storage' => __DIR__ . '/app/storage',
        'tests' => __DIR__ . '/tests',
    ],
    true, // Enable auto-discovery
    false // Disable path validation
);

Feature Comparison

Feature v1.x v2.x
Auto-discovery ❌ No ✅ Yes
Path validation ❌ Basic ✅ Comprehensive
Path normalization ❌ No ✅ Yes
Error handling ❌ Generic exceptions ✅ Dedicated exceptions
Relative paths ❌ Manual ../ ✅ Everything relative to root
Test coverage ✅ Good ✅ Excellent
Flexibility ✅ Good ✅ Excellent

Auto-Discovery

The Paths class can automatically discover common directory structures in your project. This is enabled by default, but you can disable it by passing false as the third parameter to the constructor.

// With auto-discovery (default)
$paths = new Paths(__DIR__);

// Without auto-discovery
$paths = new Paths(__DIR__, [], false);

The auto-discovery process looks for the following directories:

  • config - Looks for config, app/config, etc
  • resources - Looks for resources, app/resources, res
  • views - Looks for resources/views, templates, views, app/views
  • assets - Looks for resources/assets, assets, public/assets
  • cache - Looks for var/cache, cache, tmp/cache, storage/cache
  • logs - Looks for var/logs, logs, log, storage/logs
  • public - Looks for public, web, www, htdocs
  • database - Looks for database, db, storage/database
  • migrations - Looks for database/migrations, migrations, db/migrations
  • storage - Looks for storage, var, data
  • tests - Looks for tests, test

Path Validation

The Paths class can validate that all paths exist. This is disabled by default, but you can enable it by passing true as the fourth parameter to the constructor.

// Without validation (default)
$paths = new Paths(__DIR__);

// With validation
$paths = new Paths(__DIR__, [], true, true);

If validation is enabled and a path doesn't exist, an InvalidPathException will be thrown:

try {
    $paths = new Paths(__DIR__, [], true, true);
} catch (\Slim4\Path\Exception\InvalidPathException $e) {
    echo $e->getMessage(); // "Configured path for 'views' is not a valid directory: /path/to/views"
}

Testing

composer test

Documentation

For detailed documentation, see:

Examples

License

The MIT License (MIT). Please see License File for more information.

Credits

About Responsive.sk

Responsive.sk is a web development company specializing in creating modern, responsive web applications using the latest technologies and best practices.

Roadmap

We're planning to expand this package with integrations for other frameworks and libraries. Check out our TODO list for upcoming features and ways to contribute.

Community

We're looking to collaborate with Laminas and Cycle ORM communities to create integrations for these frameworks. If you're interested in contributing, please check out our TODO list and get in touch!