PHPackages                             gfabrizi/plain-simple-framework - 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. gfabrizi/plain-simple-framework

ActiveLibrary[Framework](/categories/framework)

gfabrizi/plain-simple-framework
===============================

Zero dependencies PHP framework

02PHP

Since Oct 28Pushed 4y ago1 watchersCompare

[ Source](https://github.com/gfabrizi/PlainSimpleFramework)[ Packagist](https://packagist.org/packages/gfabrizi/plain-simple-framework)[ RSS](/packages/gfabrizi-plain-simple-framework/feed)WikiDiscussions master Synced 3d ago

READMEChangelogDependenciesVersions (2)Used By (0)

[![Build Status](https://camo.githubusercontent.com/c427e6e390901e9ea1823addd7d0cedfbc7e2e62a9df8ff1835032511036d1ba/68747470733a2f2f7472617669732d63692e636f6d2f6766616272697a692f506c61696e53696d706c654672616d65776f726b2e7376673f6272616e63683d6d6173746572)](https://travis-ci.com/gfabrizi/PlainSimpleFramework)[![codecov](https://camo.githubusercontent.com/f0d583796fcd9d55a2c70660d71c4c690792a77797f0974e233089973e7b861a/68747470733a2f2f636f6465636f762e696f2f67682f6766616272697a692f506c61696e53696d706c654672616d65776f726b2f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/gfabrizi/PlainSimpleFramework)[![Codacy Badge](https://camo.githubusercontent.com/daa985d3c1dcd49d3421df996482bf91e246c7733ac475d6aca784a5750763c2/68747470733a2f2f6170692e636f646163792e636f6d2f70726f6a6563742f62616467652f47726164652f6333363535363762343963363439373062336163303832636361336132353136)](https://www.codacy.com/app/gfabrizi/PlainSimpleFramework?utm_source=github.com&utm_medium=referral&utm_content=gfabrizi/PlainSimpleFramework&utm_campaign=Badge_Grade)

PlainSimpleFramework
====================

[](#plainsimpleframework)

**What is this?**
This is a simple PHP framework, written as a code test for a job interview. It is written in pure PHP, without external dependencies.

**Can I use for my next big work-related project?**
What?!? NO!!

**Can I use for my small personal website?**
Are you sure? I mean, I don't see why you want to do this... anyway if you are so inclined...

**Can I use it for learning the basics of a simple PHP framework?**
Yes, sure! Now we're talking!

**No external dependencies... so why there are a `composer.json` and a `composer.lock`?**
The `composer.json` file is used primary for autoloading classes. Also for installing a local version of phpunit used for testing the framework (dev dependency).

How to use
----------

[](#how-to-use)

### Create a new project

[](#create-a-new-project)

Create a new project with composer, by issuing the command:

```
composer create-project --prefer-dist --stability=dev gfabrizi/plain-simple-framework my-app
```

(here `my-app` is the name of the new folder where you want the project to be downloaded)

Assuming that you have PHP &gt;= 8.0 installed and configured on your machine, you can start a local web server with:

```
php -S localhost:8080 -t my-app/web/
```

Now you can open you web browser and go to `http://localhost:8080` to see your app.

### The config file

[](#the-config-file)

There is a basic config file located at `app/config/config.ini`; it contains the parameters used to connect to your MySql database and some other basic settings.

### The router

[](#the-router)

The route file is located in `web/index.php`; here you can declare all the routes that you want to manage.
The `Router` component has 4 methods, each one corresponding to one HTTP verb:

- `get()`
- `post()`
- `put()`
- `delete()`

You can define your routes with a callback:

```
$router->get('/test', function() {
    echo "This is a very bad example of code design";
});
```

or with a classic controller:

```
$router->get('/', 'HomeController@index');
```

You can also define a named placeholder in your route like:

```
$router->get('/users/{id}', 'UserController@edit');
```

### Controllers

[](#controllers)

Controllers are located in `app/Controllers`. There are no conventions imposed for the naming, but it's a good practice to use the `*Controller.php` suffix pattern.
Each methods in a Controller receive a `Request` object (used to access get/post parameters) and returns a `ResponseInterface` response.

You can access to all the get/post parameters passed to your route with a `$request->getBody()` call.

To access the named placeholder in your route, you can add it in your method signature:

```
public function edit(RequestInterface $request, $id): ResponseInterface {
   // do something with $id
}
```

**Note:** actually the placeholder parameters are not type-casted/hinted, so you have to check for the correct data type in your code.

### Entities

[](#entities)

An Entity class should extends the `framework\Entities\BaseEntity` abstract class. This is an example of a simple Entity:

```
class User extends BaseEntity
{
    protected static $tableName = 'users';
    protected static $fields = [
        'id' => ['type' => 'int'],
        'first_name' => [],
        'last_name' => []
    ];
}
```

in the `$tablename` property you have to specify the name of the table this Entity refers to; in the `$fields` property you should write an array in wich each field is a column name on the db (key) plus an array of optional parameters (value).
For now you can only specify the base data type of the column ('int', 'string' or 'float'). You can omit the optional parameters altogheter; in this case you still have to specify an empty array (i.e. `first_name' => []`).

### Identity mappers

[](#identity-mappers)

Identity mappers are what `map` an Entity to the corresponding db entry. You can place Mappers in `app/Mappers`.

Each Entity should have one Identity Mapper, and each Identity Mapper should extends `framework\Mappers\IdentityMapper` abstract class.
For each mapper you have to implement:

- `getTargetClass()` returns the name of the Entity class

You can provide your own code for the `doInsert()` and `doUpdate()` methods; otherwise, generic ones will be used.
If you want to customize the way datas are casted to Entity when you retrieve them from db (for instance if your Entity has correlation with another Entity), then you should implement your own `doHydrateEntity()` method.
In the constructor of an Identity Mapper you can also define relations between Entities (for now only HasOne is implemented):

```
$this->addRelation(new HasOne(User::class, 'user_id', 'id'));
```

### Collections

[](#collections)

Collections are aggregates of entities.
You can place Collections in `app/Mappers` alongside with your Mappers. Each collections have to extends `framework\Mappers\Collection`.

Custom Collections are not really necessaries, unless you want to customize the standard behaviour. Otherwise, you can use the base Collection class.

### Views

[](#views)

Views are simple html files saved as `.php` file in `app/Views`.
You can specify a base layout for your view with the code:

```

```

From your base layout you can output the view code by accessing the `$contentInLayout` variable.

### Responses

[](#responses)

There are 2 Responses available out of the box:

- `framework\Responses\Response` used to return an HTML view
    You can pass to the `Response` constructor: the view you intend to use, then an array with data you want to pass to the view and finally an optional HTTP status code (default is 200).
- `framework\Responses\JsonResponse` used to return a JSON response You can pass to the `JsonResponse` constructor: the data you wish to output (preferably as an array) and an optional HTTP status code (default is 200).

### Service Container

[](#service-container)

PSF has a simple Service Container for dependency injection:

```
// Model Logger depends on FileLogger
class Logger {
    public function __construct(private FileLogger $logger)
    {
    }

    public function doLog($message): void
    {
        $this->logger->log($message);
    }
}

// Model FileLogger is a dependency of Logger
class FileLogger {
    private const LOGFILE = "/var/log/app.log";

    public function log($message): void
    {
        file_put_contents(self::LOGFILE, $message . PHP_EOL, FILE_APPEND);
    }
}

// In your Controller:
$container = new Container();
$logger = $container->get(Logger::class);
$logger->doLog("This is a log");
```

Unfortunately (for now) the dependency injection can be made only with concrete classes, not with interfaces.

Test suite
----------

[](#test-suite)

The test suite can be run with the command:

```
/vendor/bin/phpunit --configuration framework/phpunit.xml
```

###  Health Score

16

—

LowBetter than 5% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity2

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity30

Early-stage or recently created project

 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.

### Community

Maintainers

![](https://www.gravatar.com/avatar/76c96dfdb11a6cb244af69eeef35489e53b5efcc372c9330d68ceff8dc5918ee?d=identicon)[gfabrizi](/maintainers/gfabrizi)

---

Top Contributors

[![gfabrizi](https://avatars.githubusercontent.com/u/5486679?v=4)](https://github.com/gfabrizi "gfabrizi (24 commits)")

---

Tags

educational-projectframeworkphpzero-dependency

### Embed Badge

![Health badge](/badges/gfabrizi-plain-simple-framework/health.svg)

```
[![Health](https://phpackages.com/badges/gfabrizi-plain-simple-framework/health.svg)](https://phpackages.com/packages/gfabrizi-plain-simple-framework)
```

###  Alternatives

[laravel/telescope

An elegant debug assistant for the Laravel framework.

5.2k67.8M192](/packages/laravel-telescope)[spiral/roadrunner

RoadRunner: High-performance PHP application server and process manager written in Go and powered with plugins

8.4k12.2M84](/packages/spiral-roadrunner)[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.

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

A simple API extension for DateTime.

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

PHPackages © 2026

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