PHPackages                             adaiasmagdiel/erlenmeyer - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. adaiasmagdiel/erlenmeyer

ActiveLibrary[Framework](/categories/framework)

adaiasmagdiel/erlenmeyer
========================

Erlenmeyer is a lightweight PHP framework designed to create web applications simply and efficiently.

v5.0.0(3mo ago)0335↓50%1GPL-3.0-onlyPHPPHP ^8.1

Since Apr 13Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/AdaiasMagdiel/erlenmeyer)[ Packagist](https://packagist.org/packages/adaiasmagdiel/erlenmeyer)[ RSS](/packages/adaiasmagdiel-erlenmeyer/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (1)Versions (34)Used By (1)

Erlenmeyer - Minimal PHP Framework for Web Applications
=======================================================

[](#erlenmeyer---minimal-php-framework-for-web-applications)

[![License: GPL v3](https://camo.githubusercontent.com/48bf9b56d44f38db53ce21294cf0b9487d0a3734ab3ba1fe4c69858ae20db2c1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d47504c76332d626c75652e737667)](https://www.gnu.org/licenses/gpl-3.0)
[![Composer](https://camo.githubusercontent.com/bf1d7e3afdc010af79b9ebca2f7b441cf66a105758fa4b84a973559197ff3f03/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6d706f7365722d6164616961736d61676469656c2f65726c656e6d657965722d626c7565)](https://packagist.org/packages/adaiasmagdiel/erlenmeyer)
[![GitHub Repository](https://camo.githubusercontent.com/373353379d3399e8a9fa0be5d04bbc261de589735d22e201e7ffddebeb706a8c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4769744875622d4164616961734d61676469656c2f45726c656e6d657965722d626c7565)](https://github.com/AdaiasMagdiel/Erlenmeyer)

**Erlenmeyer** is a lightweight PHP framework designed for simplicity and efficiency in building web applications. Inspired by the minimalism of Python's Flask, Erlenmeyer is not a direct clone but a unique solution tailored for PHP developers. It is currently in its early stages, making it perfect for small projects, APIs, or microservices where a lean setup is preferred. I created Erlenmeyer to streamline my own projects, but it's open for anyone seeking a straightforward, no-frills framework.

Table of Contents
-----------------

[](#table-of-contents)

- [Introduction](#introduction)
- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Getting Started](#getting-started)
- [Routing](#routing)
- [Middlewares](#middlewares)
- [Error Handling](#error-handling)
- [Asset Management](#asset-management)
- [Session Management](#session-management)
- [Request and Response Objects](#request-and-response-objects)
- [Logging](#logging)
- [Tests](#tests)
- [Use Cases](#use-cases)
- [License](#license)
- [Reference](#reference)

Introduction
------------

[](#introduction)

Erlenmeyer is a lightweight PHP framework designed for simplicity and efficiency in building web applications. Inspired by the minimalism of Python's Flask, Erlenmeyer is not a direct clone but a unique solution tailored for PHP developers. It is currently in its early stages, making it perfect for small projects, APIs, or microservices where a lean setup is preferred. I created Erlenmeyer to streamline my own projects, but it's open for anyone seeking a straightforward, no-frills framework.

**Key Characteristics:**

- **Minimalist**: Small footprint, easy to learn and use.
- **Flexible**: Supports various use cases, from simple scripts to full applications.
- **Extensible**: Built with extensibility in mind, allowing custom functionality.
- **Flask-Inspired**: Familiar routing and handler concepts for developers coming from Python.

Features
--------

[](#features)

- Simple and intuitive routing system with support for dynamic routes.
- Support for global and route-specific middlewares.
- Custom error handling for 404 errors and exceptions.
- Integrated session management with flash messages.
- Static asset server for CSS, JavaScript, images, and more.
- Comprehensive `Request` and `Response` objects for handling HTTP requests and responses.
- Logging with file rotation for application event monitoring.

Requirements
------------

[](#requirements)

- **PHP**: 8.1 or higher
- **Composer**: For dependency management
- **Web Server**: Apache with `mod_rewrite` or Nginx
- **PHP Extensions**: `json`, `mbstring`
- **Optional**: `getallheaders` for enhanced header support (not always necessary)

Installation
------------

[](#installation)

Install Erlenmeyer using Composer:

```
composer require adaiasmagdiel/erlenmeyer
```

Include it in your PHP project:

```
require_once 'vendor/autoload.php';
```

Getting Started
---------------

[](#getting-started)

First, make sure to import the necessary classes:

```
use AdaiasMagdiel\Erlenmeyer\App;
use AdaiasMagdiel\Erlenmeyer\Request;
use AdaiasMagdiel\Erlenmeyer\Response;
```

Create a new instance of the `App` class:

```
$app = new App();
```

Define routes:

```
$app->get('/', function (Request $req, Response $res, $params) {
    $res->withHtml('Hello, World!')->send();
});
```

Run the application:

```
$app->run();
```

Routing
-------

[](#routing)

Erlenmeyer supports various HTTP methods for routing:

```
$app->get('/path', $handler);
$app->post('/path', $handler);
$app->put('/path', $handler);
$app->delete('/path', $handler);
$app->patch('/path', $handler);
$app->options('/path', $handler);
$app->head('/path', $handler);
$app->any('/path', $handler); // Matches any HTTP method
$app->match(['GET', 'POST'], '/path', $handler); // Matches specified methods
```

### Dynamic Routes

[](#dynamic-routes)

Define routes with parameters:

```
$app->get('/user/[id]', function (Request $req, Response $res, $params) {
    $id = $params->id;
    $res->withHtml("User ID: $id")->send();
});
```

### Redirects

[](#redirects)

Set up redirects:

```
$app->redirect('/old', '/new', false); // Temporary redirect (302)
```

Middlewares
-----------

[](#middlewares)

Add global middlewares:

```
$app->addMiddleware(function (Request $req, Response $res, callable $next, $params) {
    // Middleware logic
    $next($req, $res, $params);
});
```

Add route-specific middlewares:

```
$app->get('/admin', $handler, [$middleware1, $middleware2]);
```

Error Handling
--------------

[](#error-handling)

Set a custom 404 handler:

```
$app->set404Handler(function (Request $req, Response $res, $params) {
    $res->setStatusCode(404)->withHtml('Custom 404')->send();
});
```

Set exception handlers:

```
$app->setExceptionHandler(\Exception::class, function (Request $req, Response $res, \Exception $e) {
    $res->setStatusCode(500)->withHtml('Error: ' . $e->getMessage())->send();
});
```

Asset Management
----------------

[](#asset-management)

Serve static assets by creating an instance of `Assets`:

```
use AdaiasMagdiel\Erlenmeyer\Assets;

$assets = new Assets(assetsDirectory: __DIR__ . '/public', assetsRoute: '/assets');
$app = new App(assets: $assets);
```

Access assets via `/assets/file.ext`. For example:

```

```

Session Management
------------------

[](#session-management)

Use the `Session` class to manage sessions:

```
use AdaiasMagdiel\Erlenmeyer\Session;

Session::set('key', 'value');
$value = Session::get('key', 'default');
Session::flash('message', 'Flash message');
$flash = Session::getFlash('message');
```

Request and Response Objects
----------------------------

[](#request-and-response-objects)

### Request

[](#request)

The `Request` object provides access to request data:

```
$method = $req->getMethod();
$uri = $req->getUri();
$queryParams = $req->getQueryParams();
$formData = $req->getFormData();
$jsonData = $req->getJson();
$files = $req->getFiles();
$isAjax = $req->isAjax();
$isSecure = $req->isSecure();
```

### Response

[](#response)

The `Response` object allows building responses:

```
$res->withHtml('HTML content');
$res->withJson(['key' => 'value']);
$res->withText('Plain text');
$res->withFile('/path/to/file');
$res->redirect('/path');
$res->setStatusCode(404);
$res->setHeader('Key', 'Value');
$res->setCORS(['origin' => '*', 'methods' => 'GET,POST']);
$res->send();
```

Logging
-------

[](#logging)

Erlenmeyer provides a flexible and extensible logging system to help you monitor and debug your application. Logging is essential for tracking events, identifying issues, and understanding application behavior. The logging system is based on the `LoggerInterface`, which defines the contract for logging messages and exceptions.

### Using Loggers

[](#using-loggers)

Erlenmeyer provides two built-in loggers: `FileLogger` for file-based logging with rotation, and `ConsoleLogger` for logging to the command line using `error_log`. You can choose either by passing an instance to the `App` constructor.

**Example with FileLogger:**

```
use AdaiasMagdiel\Erlenmeyer\Logging\FileLogger;
use AdaiasMagdiel\Erlenmeyer\App;

$logger = new FileLogger('/path/to/logs');
$app = new App(logger: $logger);
```

- Logs are written to `/path/to/logs/info.log`.
- The `FileLogger` automatically rotates the log file when it exceeds 3MB, keeping up to 5 rotated files (e.g., `info.log.1`, `info.log.2`, etc.).
- If no log directory is provided, `FileLogger` will not log anything.

**Example with ConsoleLogger:**

```
use AdaiasMagdiel\Erlenmeyer\Logging\ConsoleLogger;
use AdaiasMagdiel\Erlenmeyer\App;

$logger = new ConsoleLogger();
$app = new App(logger: $logger);
```

- Logs are output to the command line using `error_log`, appearing in the terminal or server error log.
- No configuration is required for `ConsoleLogger`, making it ideal for debugging or CLI environments.

### Log Levels

[](#log-levels)

The logging system supports the following levels, defined in the `LogLevel` enum:

LevelDescription`INFO`General operational information`DEBUG`Detailed debug information`WARNING`Indicates something unexpected but recoverable`ERROR`Indicates a serious error affecting functionality`CRITICAL`Indicates a critical error that may cause the application to crashThese levels can be used when logging messages to categorize their severity.

### Creating a Custom Logger

[](#creating-a-custom-logger)

If you need advanced logging features, such as logging to a database, sending logs to an external service, or using a custom format, you can create a custom logger by implementing the `LoggerInterface`.

**Example of a Custom Logger:**

```
use AdaiasMagdiel\Erlenmeyer\Logging\LoggerInterface;
use AdaiasMagdiel\Erlenmeyer\Logging\LogLevel;
use Exception;
use AdaiasMagdiel\Erlenmeyer\Request;

class CustomLogger implements LoggerInterface
{
    private $logFile;

    public function __construct(string $logFile)
    {
        $this->logFile = $logFile;
    }

    public function log(LogLevel $level, string $message): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $logEntry = "[$timestamp] [$level->value] $message\n";
        file_put_contents($this->logFile, $logEntry, FILE_APPEND);
    }

    public function logException(Exception $e, ?Request $request = null): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $message = "[$timestamp] [ERROR] Exception: " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine() . "\n";
        if ($request) {
            $message .= "Request: " . $request->getMethod() . " " . $request->getUri() . "\n";
        }
        $message .= $e->getTraceAsString() . "\n";
        file_put_contents($this->logFile, $message, FILE_APPEND);
    }
}
```

To use the custom logger, pass an instance to the `App` constructor:

```
$customLogger = new CustomLogger('/path/to/custom.log');
$app = new App(logger: $customLogger);
```

**Important Note:** If no logger is explicitly provided, the `App` will create a `FileLogger` without a log directory, which means no logging will occur. You must configure a logger explicitly to enable logging.

Tests
-----

[](#tests)

Erlenmeyer uses PestPHP for testing. Run tests with:

```
./vendor/bin/pest
```

Use Cases
---------

[](#use-cases)

Erlenmeyer is suitable for a wide range of web applications. Here are some example use cases:

Use CaseDescription**Simple REST API**Create an API with endpoints for GET, POST, PUT, and DELETE, returning JSON responses.**Basic Web Application**Develop an application with routes for HTML pages and session management.**Static Page Generator**Serve static assets like CSS and JavaScript for landing pages.**Forms and Uploads**Handle POST forms and file uploads with validation.**Example REST API:**

```
$app->get('/api/users/[id]', function (Request $req, Response $res, $params) {
    $id = $params->id;
    $res->withJson(['id' => $id, 'name' => 'User ' . $id])->send();
});
```

**Example Form Handling:**

```
$app->post('/submit', function (Request $req, Response $res, $params) {
    $name = $req->getFormDataParam('name', 'Guest');
    Session::flash('message', 'Form submitted successfully!');
    $res->redirect('/thank-you')->send();
});
```

Development
-----------

[](#development)

Documentation using mkdocs

```
py -m venv .venv
.venv/bin/activate  # .venv\Scripts\activate (on windows)
pip install mkdocs mkdocs-material

```

License
-------

[](#license)

Erlenmeyer is licensed under the GPLv3. See the [LICENSE](LICENSE) and the [COPYRIGHT](COPYRIGHT) files for details.

Reference
---------

[](#reference)

### App

[](#app)

MethodDescription`__construct(?Assets $assets = null, ?string $logDir = null)`Initializes the application.`route(string $method, string $route, callable $action, array $middlewares = [])`Registers a route for an HTTP method.`get(string $route, callable $action, array $middlewares = [])`Registers a GET route.`post(string $route, callable $action, array $middlewares = [])`Registers a POST route.`any(string $route, callable $action, array $middlewares = [])`Registers a route for any HTTP method.`match(array $methods, string $route, callable $action, array $middlewares = [])`Registers a route for specified methods.`redirect(string $from, string $to, bool $permanent = false)`Registers a redirect.`set404Handler(callable $action)`Sets the 404 error handler.`addMiddleware(callable $middleware)`Adds a global middleware.`setExceptionHandler(string $exceptionClass, callable $handler)`Sets an exception handler.`run()`Runs the application.### Assets

[](#assets)

MethodDescription`__construct(string $assetsDirectory = "/public", string $assetsRoute = "/assets")`Initializes the asset manager.`getAssetsDirectory(): string`Returns the assets directory.`getAssetsRoute(): string`Returns the assets route.`isAssetRequest(): bool`Checks if the request is for an asset.`serveAsset(): bool`Serves the requested asset.### Session

[](#session)

MethodDescription`static get(string $key, $default = null)`Gets a session value.`static set(string $key, $value)`Sets a session value.`static has(string $key): bool`Checks if a session key exists.`static remove(string $key)`Removes a session key.`static flash(string $key, $value)`Sets a flash message.`static getFlash(string $key, $default = null)`Gets and removes a flash message.`static hasFlash(string $key): bool`Checks if a flash message exists.### Request

[](#request-1)

MethodDescription`__construct(?array $server = null, ?array $get = null, ?array $post = null, ?array $files = null, string $inputStream = 'php://input')`Initializes the request.`getHeader(string $name): ?string`Gets a specific header.`getHeaders(): array`Gets all headers.`getMethod(): string`Gets the HTTP method.`getUri(): string`Gets the request URI.`getQueryParams(): array`Gets query parameters.`getFormData(): array`Gets form data.`getJson(): mixed`Gets JSON data from the body.`getFiles(): array`Gets uploaded files.`isAjax(): bool`Checks if the request is AJAX.`isSecure(): bool`Checks if the request is secure (HTTPS).### Response

[](#response-1)

MethodDescription`__construct(int $statusCode = 200, array $headers = [])`Initializes the response.`setStatusCode(int $code): self`Sets the HTTP status code.`getStatusCode(): int`Gets the HTTP status code.`setHeader(string $name, string $value): self`Sets an HTTP header.`removeHeader(string $name): self`Removes an HTTP header.`getHeaders(): array`Gets all headers.`setContentType(string $contentType): self`Sets the content type.`getContentType(): string`Gets the content type.`setBody(string $body): self`Sets the response body.`getBody(): ?string`Gets the response body.`withHtml(string $html): self`Sets HTML content.`withTemplate(string $templatePath, array $data = []): self`Sets content from a template.`withJson($data, int $options = JSON_PRETTY_PRINT): self`Sets JSON content.`withText(string $text): self`Sets plain text content.`redirect(string $url, int $statusCode = 302): self`Sets a redirect.`withCookie(string $name, string $value, int $expire = 0, string $path = '/', string $domain = '', bool $secure = false, bool $httpOnly = true): self`Sets a cookie.`send(): void`Sends the response.`isSent(): bool`Checks if the response has been sent.`clear(): self`Clears the response body and headers.`withError(int $statusCode, string $message = '', ?callable $logger = null): self`Sets an error response.`withFile(string $filePath): self`Sets the response to send a file.`setCORS(array $options): self`Configures CORS headers.

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance79

Regular maintenance activity

Popularity16

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~8 days

Total

33

Last Release

118d ago

Major Versions

v0.2.1 → v1.0.02025-04-21

v1.0.3 → v2.0.02025-04-24

v2.3.0 → v3.0.02025-05-07

v3.2.1 → v4.0.02025-10-13

v4.2.8 → v5.0.02026-01-20

### Community

Maintainers

![](https://www.gravatar.com/avatar/a44b4a5387a9a6f2c8d9ffedbb3dbc73263643d7dc737868609a5bba02c7a6b4?d=identicon)[adaiasmagdiel](/maintainers/adaiasmagdiel)

---

Top Contributors

[![AdaiasMagdiel](https://avatars.githubusercontent.com/u/22068596?v=4)](https://github.com/AdaiasMagdiel "AdaiasMagdiel (104 commits)")

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/adaiasmagdiel-erlenmeyer/health.svg)

```
[![Health](https://phpackages.com/badges/adaiasmagdiel-erlenmeyer/health.svg)](https://phpackages.com/packages/adaiasmagdiel-erlenmeyer)
```

###  Alternatives

[laravel/passport

Laravel Passport provides OAuth2 server support to Laravel.

3.4k85.0M532](/packages/laravel-passport)[nolimits4web/swiper

Most modern mobile touch slider and framework with hardware accelerated transitions

41.8k177.2k1](/packages/nolimits4web-swiper)[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k36.7M259](/packages/laravel-dusk)[laravel/prompts

Add beautiful and user-friendly forms to your command-line applications.

712181.8M596](/packages/laravel-prompts)[cakephp/chronos

A simple API extension for DateTime.

1.4k47.7M121](/packages/cakephp-chronos)[laravel/pail

Easily delve into your Laravel application's log files directly from the command line.

91545.3M590](/packages/laravel-pail)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
