Skip to content

Repository files navigation

Parina Framework

Scrutinizer Code Quality Build Status

πŸ‡ΊπŸ‡Έ English | πŸ‡ͺπŸ‡Έ EspaΓ±ol

Altiplano Edition: Less is more. The web framework for clear thinking.


πŸ’‘ What is Parina?

Parina is a minimal micro-framework for modern PHP applications. It provides just enough structure to build applications with clarity, control, and peak performance, adhering to Feature-Driven Architecture and clean design patterns.


πŸ› οΈ Key Features

  • DI Container with Reflection: Automatic resolution and constructor injection of dependencies for Handlers and Middlewares.
  • Feature-Driven Architecture: Handlers, views, and tests organized by cohesive business features (e.g. Authentication, UserManagement, Marketing) instead of role-based folders or separate technical layers.
  • Stateless HTTP Request (Request): Unified payload input (input()), simple HTTP header fetching (header()), and local request context attributes (setAttribute()) for clean middleware-to-handler data sharing.
  • CQS & Adapter Patterns: Separation of read queries and write commands inside Repositories (validated automatically by the system Linter), coupled with dynamic database driver adapters (SQLite, MySQL, PostgreSQL) adhering to the Open/Closed Principle. See CQS Recommendations for detailed rules.
  • XSS Protection: Secure variable escaping inside templates using the global helper function h().

πŸŒ„ Philosophy

Clarity over abstraction. Control over convenience.

Parina focuses on:

  • Explicit design: No magic, no hidden lifecycles.
  • Minimal overhead: Every byte and millisecond counts.
  • Predictable flow: What you see is exactly what executes.

🧱 Architecture in 10 Lines

  1. A request enters through a front controller.
  2. It goes through the middleware pipeline.
  3. Middleware can block or pass.
  4. It reaches the registered handler.
  5. Handler executes core logic.
  6. Returns a standard response.
  7. No heavy magic.
  8. No hidden framework lifecycles.
  9. No unnecessary abstractions.
  10. Just clear, linear execution.

πŸ”„ Request Lifecycle

[ Request ] ───> [ Middleware Pipeline ] ───> [ Handler ]
                          β”‚                       β”‚
                          β”‚ (Returns Response)    β”‚ (Returns Response)
                          β–Ό                       β–Ό
                    [ Response ] <β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Middleware Model

Each middleware layer follows a simple binary rule:

  • Returns Response β†’ Stop execution and emit response.
  • Returns null β†’ Continue to the next layer.

Middleware Example

namespace Parina\Shared\Middlewares;

use Parina\Core\Interfaces\RequestInterface;
use Parina\Core\Interfaces\Middleware;
use Parina\Core\Interfaces\Response;
use Parina\Core\Responses\ErrorResponse;

class SimpleAuth implements Middleware
{
    public function handle(RequestInterface $request): ?Response
    {
        if (!isset($_SESSION['user'])) {
            return new ErrorResponse("Unauthorized", 401);
        }
        return null; // Move to the next layer
    }
}

πŸ”’ Security

Security is first-class and lives exactly where it belongs: in the middleware pipeline.

  • Rate limiting
  • Request size validation
  • CSRF protection
  • Same-origin policy (CORS)
  • Authentication (Basic / JWT)
  • Authorization (ACL)

⚑ Performance

Designed for minimal overhead and microsecond-accuracy:

  • ~0.0007 seconds per request execution.
  • ~0.05 MB RAM footprint.
  • Fully Opcache friendly.

πŸš€ Example (Bootstrapping)

// public/index.php
use Parina\Core\Router;
use Parina\Core\Kernel;
use Parina\Core\Container;
use Parina\Core\Config;
use Parina\Shared\Infrastructure\Db;

require_once __DIR__ . '/../src/autoload.php';

// Instantiate DI container & load dynamic dependencies
$container = new Container();
if (file_exists(__DIR__ . '/../config/dependencies.php')) {
    $container->load(require __DIR__ . '/../config/dependencies.php');
}

// Initialize database with dynamically resolved adapter (OCP)
Db::setConfig(Config::getDbConfig());
Db::init($container->get(\Parina\Shared\Infrastructure\DatabaseAdapter::class));

$router = new Router();
$routes = require '../config/routes.php';
foreach ($routes as $route) {
    $router->add($route['method'], $route['path'], $route['handler'], $route['middleware'] ?? []);
}

$request = \Parina\Core\Request::capture();
$kernel = new Kernel($router, $container);
$response = $kernel->handle($request);

$emitter = new \Parina\Core\ResponseEmitter();
$emitter->emit($response);

🏠 Minimal Handler Example

namespace Parina\Features\UserManagement\Handlers;

use Parina\Core\Interfaces\Handler;
use Parina\Core\Interfaces\Response;
use Parina\Core\Interfaces\RequestInterface;
use Parina\Core\Responses\HtmlResponse;
use Parina\Core\View;
use Parina\Features\UserManagement\Queries\UserQueryRepositoryInterface;

class UsersListHandler implements Handler
{
    // Resolved and injected automatically by the DI Container via Reflection
    public function __construct(private UserQueryRepositoryInterface $userRepo) {}

    public function handle(RequestInterface $request): Response
    {
        $users = $this->userRepo->all();
        // Secure HTML output using the global h() helper to prevent XSS
        $content = View::renderWithLayout("UserManagement/Views/list", "default", ['users' => $users]);
        return new HtmlResponse($content, 200);
    }
}

πŸ–Ό Minimal View Example

<!-- Features/UserManagement/Views/list.php -->
<h1>Users List</h1>
<ul>
  <?php foreach ($users as $user): ?>
    <li><?= h($user['username']) ?></li>
  <?php endforeach; ?>
</ul>

πŸ› οΈ CLI Scaffolding

Parina includes a CLI tool to generate routing configurations, handler classes, and unit tests directly from a CSV file.

  1. Define your routes in a CSV file (e.g., routes.csv):

    Method,Path,Feature,HandlerName,Middlewares,Description
    GET,/,Marketing,Home,,Home page
    GET,/about,Marketing,About,,About us
  2. Run the scaffolding tool:

    php bin/scaffold.php routes.csv

This will automatically generate:

  • Route configurations in config/routes.php.
  • Missing Handler classes in src/Features/.
  • Basic unit tests in tests/Features/ to verify your handlers.

πŸ§ͺ Included Tests

Parina is developed with PHPUnit, focusing on complete coverage.

tests/
 β”œβ”€β”€ KernelTest.php
 β”œβ”€β”€ RouterTest.php
 β”œβ”€β”€ ContainerTest.php
 └── Features/

🧘 Why Parina Exists

Most complexity in software is accidental. Parina asks:

What is the smallest structure that still works correctly, securely, and fast?

Parina is not minimal by limitation. It is minimal by intention. It removes everything you do not actually need.

For a detailed explanation of the core philosophy and how the entire framework fits in a paper napkin diagram, see THE-NAPKIN-REVOLUTION.md.


πŸ“¦ Deployment & Installation

Production Deployment

For directory layout, permissions, and production tips, see DEPLOY.md.

Cleanup & Reset

To remove all demo files and reset the framework to a fresh state, see CLEANUP.md.

CLI Tools & Console Guide

For a detailed guide on generating commands, queries, scaffolding features, and managing active routes, see docs/tools.md.

Quick Start / Local Installation

To run the framework locally using PHP's built-in development server:

git clone https://github.com/nelsonrojasn/Parina-Framework.git
cd Parina-Framework
php -S localhost:8000 -t public

πŸͺΆ License

MIT License.

About

🦩 Parina Framework is a micro-architectural PHP framework, crafted with the Pin philosophy: embracing extreme minimalism, guiding developers through explicit routes, and stripping away the weight of corporate overengineering.

Resources

Stars

7 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages