Download the PHP package simcript/pano without Composer

On this page you can find all versions of the php package simcript/pano. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package pano

Pano Application Skeleton

A minimal, ready-to-run application skeleton built on top of the Pano nano-framework.

Pano is a lightweight PHP runtime that gives you an explicit, predictable foundation with full architectural control. This skeleton wires up that runtime with a sensible project layout, a working Default module, configuration, and a web + CLI entry point so you can start building your own domains immediately.

Built for Pano Framework ^1.4 (currently v1.4.4).


Requirements


Installation

Create a new project with Composer:

Or clone this repository and install dependencies manually:

The .env file is created automatically from .env.example after install. If it isn't, copy it yourself:


Quick Start

Start the built-in PHP development server:

Open http://localhost:8000 in your browser — you should see the "It works!" welcome page. The skeleton is alive.


Project Structure

Two constants are defined at the very start of every entry point and drive the whole runtime:

Constant Meaning
PANO_STARTED Request start timestamp (microtime), for timing
BASE_PATH Absolute path to the project root, with trailing /

Everything — config loading, .env resolution, module paths — is relative to BASE_PATH, so keep that in mind if you move entry points.


Configuration

.env

Tip: Pano parses .env values. true/false/null become proper booleans/null, and numeric strings become numbers.

config/app.php

Reads environment values into a config array. Access any value anywhere using the config() helper:

config/modules.php

Maps a module key to a module class. This is how Pano decides which module handles the current request:


The Module Resolver

Pano routes an incoming request to a module before it routes to a handler. How the module is chosen depends on MODULE_RESOLVER:

path (default)

The first URL segment is the module key. The remainder is the route path.

URL Module key Route
/blog/posts/12 blog /posts/12
/ '' /

subdomain

The subdomain is the module key. The root domain is derived from APP_URL, so only the leading sub-part of that host is treated as a module:

Host Module key
blog.neda.tst (APP_URL=https://neda.tst) blog
api.v2.neda.tst api.v2
neda.tst (the root itself) ''

If the resolver is neither path nor subdomain, an Exception is thrown.

If no module matches the resolved key, Pano throws "No module found for '<name>'". Make sure every reachable key is registered in config/modules.php.


Core Concepts

Pano is intentionally small. Five concepts carry the whole runtime:

Concept Responsibility
Module A self-contained domain; defines routes, views, logging
Handler A controller-like class that produces a Response
Interceptor Runs before handlers (onRequest) and after (onResponse)
Command A CLI action, like a console controller
View Renders templates with layouts and sections

The base contracts live in the Pano\Kernel namespace; ready-to-use concrete implementations live in Pano\Foundation.

Concept Base (abstract) contract Concrete implementation
Module Pano\Kernel\BaseModule (you extend it)
Router Pano\Kernel\BaseRouter Pano\Foundation\Router
Request Pano\Kernel\BaseRequest Pano\Foundation\Request
Response Pano\Kernel\BaseResponse Pano\Foundation\Response
View Pano\Kernel\BaseView Pano\Foundation\View
Handler Pano\Kernel\BaseHandler (you extend it)
Interceptor Pano\Kernel\BaseInterceptor (you extend it)
Command Pano\Kernel\BaseCommand (you extend it)
Logger Pano\Kernel\BaseLogger Pano\Foundation\Logger
Exception Pano\Kernel\BaseException Pano\Foundation\Exception

Important: Always extend the Pano\Kernel\Base* contracts (and use the Pano\Foundation\* implementations). The older Pano\Core / Pano\Enum namespaces no longer exist.


Building a Module

A module is a readonly class extending BaseModule. It must define three methods: routes(), view(), and log().

BaseModule gives you convenient path helpers, all resolved relative to the module's own directory via reflection:

Register the module in config/modules.php:

Now requests to /blog/... are handled by BlogModule.


Routing

Routes are registered inside the module's routes() method on the injected $router. Supported HTTP verbs:

Route Parameters

Parameters are declared with brackets and are passed as method arguments in declaration order:

Parameter flags:

Syntax Meaning
[id] Required segment
[id?] Optional (must be the last segment)
[id*] Catch-all (must be the last segment)

Optional and catch-all parameters must always be the last route segment.


Handlers

A handler is a class extending BaseHandler. Each action is a public method that returns a Response. The return type must be declared and must be BaseResponse (or a subclass) — Pano enforces this.

The handler receives the request and its module via constructor injection:

BaseHandler exposes:

Method override

HTML forms can only GET/POST. To submit PUT/DELETE/PATCH, Pano honors a method override on POST requests via either:

The resolved verb becomes the route's HTTP method automatically.


Responses

Pano\Foundation\Response offers expressive factory methods:

Every method accepts an optional HttpStatusEnum and a headers array. The JSON helper encodes with JSON_UNESCAPED_UNICODE so Persian/Arabic text is preserved.

Fluent mutation

Every mutator returns $this, so you can chain after construction:

Useful HttpStatusEnum values: OK, CREATED, NO_CONTENT, MOVED_PERMANENTLY, FOUND, BAD_REQUEST, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, UNPROCESSABLE_ENTITY, INTERNAL_SERVER_ERROR, … (all standard HTTP codes).

Automatic error rendering

If a handler (or anything in the pipeline) throws, Response::exception($e, $request) turns the throwable into an appropriate response:

Context Output
CLI request colored terminal line, ResultCodeEnum::ERROR
expectsJson() $e->toArray($debug) as JSON
otherwise $e->toHtml($debug) as HTML

This is wired into the global handler, so you never need to wrap your handlers in try/catch for rendering.

Sending

Calling send() writes the HTTP status line, headers, and body to the output stream. It is idempotent — a response can only be sent once. The router calls send() for you; you normally just return the response.


The Bag

Bag (Pano\Foundation\Bag, extending Pano\Kernel\BaseBag) is Pano's lightweight, chainable key/value container. You already met it as $request->attributes. You can also use it anywhere you need structured data.

It behaves like an array — it implements ArrayAccess, IteratorAggregate, and Countable:

Basic operations

Functional helpers

Most helpers return a new Bag (immutable style), so they chain:

Deep search

Bags can be nested (arrays and other Bags inside). Pano finds values or keys anywhere in the tree and returns their dot-paths:

Paths use . as the separator (e.g. user.address.city), making Bag handy for config trees, JSON payloads, and nested request data.


Interceptors

Interceptors are cross-cutting filters. They run before the handler (onRequest) and after it returns (onResponse), in registration order.

Attach interceptors to a route as the fourth argument:

Execution order

For a route registered with [A::class, B::class]:

So onRequest runs in registration order and onResponse runs in reverse order — exactly like layered middleware (Russian-doll model).

Sharing state with the handler

The same $request instance is shared across all interceptors and the handler, so data left on $request->attributes in onRequest() is visible in the handler. This is the recommended way to pass the authenticated user, a request ID, etc. (See The Bag.)


Requests

The current request is available on handlers and interceptors as $this->request (Pano\Foundation\Request). Key accessors:

Body parsing (getData())

getData() decodes the request body based on the Content-Type:

Content-Type getData() returns
(form submitted) $_POST
application/json decoded JSON array
application/x-www-form-urlencoded parse_str array
other / empty [] (empty array)

File uploads (getFiles())

getFiles() returns $_FILES normalized. Multi-file inputs (e.g. <input name="photos[]">) are restructured into an indexed list, so you always iterate a flat array:

Headers

Keys are lowercased, so read them in lowercase regardless of how the client sent them:

Sharing state — $request->attributes

The request carries a mutable Bag named attributes. It is the idiomatic channel for passing data from an interceptor to the handler — the authenticated user, a request ID, feature flags, etc. (See The Bag.)


Views & Templating

A module renders templates from its Views/ directory using Pano\Foundation\View. Templates are plain PHP, with layout + section support.

Render a view with data:

Views/layout.php — the wrapper:

Views/post/show.php — a page that fills the layout's sections:

Template helpers available as $this inside views:

Method Description
$this->start('name') / $this->end() Open/close a named section
$this->section('name', 'default') Echo a section's content (with fallback)
$this->fragment('partials/card', $data) Include a sub-template (with extra data)
$this->e($value) HTML-escape a stringable value

Always escape untrusted output with $this->e().


Logging

Each module owns its logs. Create the logger via $this->log() and call any PSR-style level method:

Available levels: emergency, alert, critical, error, warning, notice, info, debug.

By default the framework's Logger writes to a daily file under the module's Logs/ directory (log-YYYY-MM-DD.log).


CLI Commands

Pano has a single CLI entry point: the pano executable at the project root.

Invocation format

The first positional argument is the module path (matching a key in config/modules.php), the second is the command name.

Examples for the skeleton's Default module:

Windows note: The / used for the root module can be mangled by cmd.exe / Git Bash path conversion. Prefix the command with MSYS_NO_PATHCONV=1 when invoking from Git Bash, or use a named module key instead:

Registering a command

Inside a module's routes(), call command() with a command name and a command class:

The command class must extend BaseCommand and implement handle():

Inside a command

BaseCommand gives you:

The $arguments array received by handle() is exactly getPositional() (i.e. everything after the command that does not start with --).

Return codes

handle() returns a ResultCodeEnum:

Value Meaning
OK success
ERROR general failure
INVALID invalid input / usage error

This drives the terminal output color and signals failure to the shell.


Exceptions & Errors

Throw Pano\Foundation\Exception to control the HTTP response status, message, and optional payload. Pano formats it automatically based on the request:

How it renders

Context Output
CLI request colored terminal line
expectsJson() JSON body { "message": ..., "data": ... }
otherwise HTML error page

In APP_DEBUG=true mode, the rendered body includes the exception class name and stack trace; in production it is hidden.

Custom exception types

For richer domain errors, extend BaseException and implement toArray() and toHtml():

Throw it anywhere in a handler or interceptor — the global handler will render it correctly.

Non-BaseException throwables

Plain \Throwable instances (PHP errors, third-party exceptions) are rendered as a generic 500 Server Error, with the real message shown only in debug mode.


Helper Functions

These globals are always available (autoloaded by the framework):

Function Description
env($key, $default = null) Read a value from .env
config($key, $default = null) Dot-notation config read (e.g. config('app.name'))
url($path) Build an absolute URL using APP_URL
currentUrl() The current request's absolute URL
dd(...$args) Dump-and-die debug helper (CLI or HTML aware)

Testing

The skeleton ships with PHPUnit. Tests live in tests/ under the Tests\ namespace.

A starter test is included at tests/DefaultModuleTest.php. Example:

phpunit.xml is preconfigured with the Pano Test Suite.


Web Server Setup

Apache

public/.htaccess is already configured. Point your virtual host DocumentRoot to the public/ directory. It handles:

Nginx

Development server


Build Your First Feature — Checklist

  1. Create a module under modules/<Name>/<Name>Module.php extending Pano\Kernel\BaseModule.
  2. Register it in config/modules.php under a resolver key.
  3. Add handlers (extending Pano\Kernel\BaseHandler) returning a Pano\Foundation\Response.
  4. Define routes in the module's routes() method.
  5. (Optional) Add interceptors for auth/validation, commands for CLI tasks, and views for HTML.
  6. Test it with ./vendor/bin/phpunit.

Learn More

Pano is deliberately unopinionated — you bring the architecture. The framework should never make decisions on your behalf.


License

The MIT License (MIT). See LICENSE.


All versions of pano with dependencies

PHP Build Version
Package Version
Requires php Version >=8.2
simcript/pano-framework Version ^1.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package simcript/pano contains the following files

Loading the files please wait ...