Framework X – the simple and fast micro framework for building reactive web applications that run anywhere.

Overview

Framework X

CI status

Framework X – the simple and fast micro framework for building reactive web applications that run anywhere.

Quickstart

Start by creating an empty project directory. Next, we can start by taking a look at a simple example application. You can use this example to get started by creating a new public/ directory with an index.php file inside:

<?php

require __DIR__ . '/../vendor/autoload.php';

$app = new FrameworkX\App();

$app->get('/', function () {
    return new React\Http\Message\Response(
        200,
        [],
        "Hello wörld!\n"
    );
});

$app->get('/users/{name}', function (Psr\Http\Message\ServerRequestInterface $request) {
    return new React\Http\Message\Response(
        200,
        [],
        "Hello " . $request->getAttribute('name') . "!\n"
    );
});

$app->run();

Next, we need to install X and its dependencies to actually run this project. In your project directory, simply run the following command:

$ composer require clue/framework-x:dev-main

That's it already! The next step is now to serve this web application. One of the nice properties of this project is that is works both behind traditional web server setups as well as in a stand-alone environment.

For example, you can run the above example using the built-in web server like this:

$ php public/index.php

You can now use your favorite web browser or command line tool to check your web application responds as expected:

$ curl http://localhost:8080/
Hello wörld!

Documentation

Hooked? See website for full documentation.

Found a typo or want to contribute? The website documentation is build from the source documentation files in the docs/ folder.

Tests

To run the test suite, you first need to clone this repo and then install all dependencies through Composer:

$ composer install

To run the test suite, go to the project root and run:

$ vendor/bin/phpunit --stderr

Additionally, you can run some simple acceptance tests to verify the framework examples work as expected behind your web server. Use your web server of choice (see deployment documentation) and execute the tests with the URL to your installation like this:

$ php examples/index.php
$ tests/acceptance.sh http://localhost:8080

License

This project is released under the permissive MIT license.

Did you know that I offer custom development services and issuing invoices for sponsorships of releases and for contributions? Contact me (@clue) for details.

Comments
  • Use DI container to load global middleware classes

    Use DI container to load global middleware classes

    This changeset makes sure we use the same DI container instance to also load global middleware classes. This allows us to take advantage of autowiring for global middleware classes the same way it can be done for route request handlers as implemented in #92. This does not otherwise break existing APIs, so this is a pure feature addition.

    Builds on top of #92 and #89

    new feature 
    opened by clue 5
  • Respect explicit response status code when `Location` response header is given (PHP SAPI)

    Respect explicit response status code when `Location` response header is given (PHP SAPI)

    Let's say, this is your code:

    $app->get('/foo', function () {
        return new \React\Http\Message\Response(202, [
            'Location' => '/bar',
        ]);
    });
    
    • When you use ReactPHP as webserver, the status code will be 202 (as expected).
    • When you use PHP's built-in webserver, the status code will be 302 (unexpected).

    So, why does this happen?

    When you use header(...) to set the Location header, PHP will update the status code to 302. This behavior is even mentioned in the official documentation: PHP: header - Manual

    The second special case is the "Location:" header. Not only does it send this header back to the browser, but it also returns a REDIRECT (302) status code to the browser unless the 201 or a 3xx status code has already been set.
    

    Here is the corresponding code in php/php-src: https://github.com/php/php-src/blob/php-8.1.11/main/SAPI.c#L806-L821

    Should this happen?

    I think, this behavior is more confusing than it is helpful. It should not be the decision of PHP to override my status code. According to RFC 9110, the Location header has a defined behavior for the status codes 201 and 3xx.

    But that is not an exclusive definition. Any HTTP response may contain a Location header, but the expected behavior is not defined by this RFC. That means, it can be used by a proprietary API definition for other status codes.

    What does this change do?

    The status code is now set after setting all other headers. This will override any status code that has priorly been set by PHP. So now my choice of status code is respected.

    bug 
    opened by jkrzefski 4
  • Add instructions to specify port, if using Docker

    Add instructions to specify port, if using Docker

    If the running container is not mapped to any port, then not all requests would be able to pass through, unless the server is setup to expose the mentioned port (8080, in this case).

    documentation 
    opened by jdecode 4
  • Minor fixes

    Minor fixes

    • Display UTF-8 characters correctly in the browser, also shows how to add headers to responses
    • Add command to create empty composer.json before running require (stops potential prompts about the file being missing)
    documentation 
    opened by weareredrobot 3
  • [RFC] PSR-11 Container support

    [RFC] PSR-11 Container support

    This is just a request for comments PR.

    This implementation is a discussion starter for DI in fx, it replaces the $loop constructor variable with the ContainerInterface. I know this is a breaking change but keeping several legacy layers before a public release doesn't makes much sense and increases the maintenance effort.

    I implemented also 2-3 example usages for the container.

    1. loop
    2. logger
    3. socketServerContext

    The loop entry is just a simple replacement for the existing $loop parameter.

    The logger entry is a LoggerInterface defined by PSR-3 standard. It's used in the log function. Additional to this the request Logger supports now a logger attribute from the request. This can be used for context logging.

    The socketServerContext is an array for the socketServer with on addition, it can hold a key named uri which is used for the socketServer uri parameter. This allows us to define a custom IP and port. Also we can use TLS and set custom parameters for the socketServer.

    It adds 2 dependencies

    1. php-di PSR-11
    2. psr/log PSR-3

    php-di brings a complete dependency injection package but required for other packages is only the ContainerInterface psr/log brings only the PSR-3 LoggerInterface

    Both dependencies are optional for applications based on fx.

    Missing

    • [X] Tested in a 3rd party application
    • [ ] Documentation
    • [ ] Tests
    • [ ] Think about it

    Just as remark this is just a discussion PR and should be a proof of concept.

    help wanted new feature question 
    opened by HLeithner 3
  • Add Caddy to deployment docs

    Add Caddy to deployment docs

    Caddy has a bunch of ease of use and convenience benefits over both Nginx and Apache, and supports both the php-fpm and proxy workflows well. It can proxy websocket traffic without any additional config as well (on the same port as regular HTTP traffic).

    What's awkward is the docs for Nginx and Caddy both end up extremely similar, because they have a lot of similarities from a usage standpoint for PHP apps. Not sure if you'd want to reconcile/merge their docs somehow to deal with that.

    documentation 
    opened by francislavoie 2
  • Use platform specific EOL constant for log tests

    Use platform specific EOL constant for log tests

    The following tests are failing if you run phpunit on windows

    1. FrameworkX\Tests\AppTest::testLogRequestResponsePrintsRequestLogWithCurrentDateAndTime Failed asserting that '2021-07-02 11:29:09.446 127.0.0.1 "GET /users HTTP/1.1" 200 6\r\n ' matches PCRE pattern "/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} 127.0.0.1 "GET /users HTTP/1.1" 200 6 $/".

    2. FrameworkX\Tests\AppTest::testLogRequestResponseWithoutRemoteAddressPrintsRequestLogWithDashAsPlaceholder Failed asserting that '2021-07-02 11:29:09.447 - "GET /users HTTP/1.1" 200 6\r\n ' matches PCRE pattern "/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} - "GET /users HTTP/1.1" 200 6 $/".

    3. FrameworkX\Tests\AppTest::testLogPrintsMessageWithCurrentDateAndTime Failed asserting that '2021-07-02 11:29:09.448 Hello\r\n ' matches PCRE pattern "/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} Hello $/".

    The reason for this is that PHP_EOL uses "\r\n" on windows and not "\n" as expected by the test.

    I'm not sure if logging output should have system specific line endings. As alternativ PHP_EOL can be replaced by "\n" in App:log()

    bug maintenance 
    opened by HLeithner 2
  • Heads up! Public issues and discussions

    Heads up! Public issues and discussions

    If you're currently using this project and there are any issues or if there's anything you'd like to discuss, head over to the public https://github.com/clue/framework-x repository :tada:

    • Issues: https://github.com/clue/framework-x/issues
    • Discussions: https://github.com/clue/framework-x/discussions

    This way, more people (including those without early access) get a chance to follow the project development and take part in discussions.

    Head over to https://github.com/clue/framework-x and rock on 🤘

    maintenance 
    opened by clue 2
  • Increase sleep time to cover test case for inaccurate clocks

    Increase sleep time to cover test case for inaccurate clocks

    Over time we recognized failing tests because of an incorrect time measurement in our tests which mostly occurred when running our test suite under windows. Last seen here: https://github.com/clue/framework-x/actions/runs/3741602828/jobs/6351445435

    I raised the sleep-time inside the responsible test to avoid any future tests failing because of inaccurate clocks.

    maintenance 
    opened by SimonFrings 1
  • Forward compatibility with upcoming Promise v3

    Forward compatibility with upcoming Promise v3

    Builds on top of https://github.com/reactphp/http/pull/460 and https://github.com/reactphp/promise/pull/138 (and countless upstream tickets referenced in https://github.com/reactphp/http/pull/460)

    new feature 
    opened by clue 1
  • 404 when running on apache

    404 when running on apache

    Discussed in https://github.com/clue/framework-x/discussions/164

    Originally posted by juanbautista0 July 4, 2022 I am testing apache2 ubuntu and I get error 404. I have configured the htaccess as recommended but still the error message persists.

    The same thing happened to me testing the Slim frame and with a method where the base path was defined, it was solved.

    $app->setBasePath('/test');
    

    What do you do here ?

    The configuration is as follows:

    acme/
    ├── public/
    │   ├── .htaccess
    │   └── index.php
    ├── vendor/
    ├── composer.json
    └── composer.lock
    

    path: /.htaccess

    RewriteEngine on
    RewriteRule ^$ public/ [L]
    RewriteRule (.*) public/$1 [L]
    
    

    path: public/.htaccess

    RewriteEngine On
    
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule .* index.php
    
    # This adds support for authorization header
    SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0
    
    question 
    opened by juanbautista0 1
  • Update Caddy reverse proxy config to exclude root path for static files

    Update Caddy reverse proxy config to exclude root path for static files

    Hey there 👋,

    first and foremost: thanks for Framework X! I'm currently developing a website from scratch and it's like a fresh breeze compared to the "heavy" frameworks I'm used to, and I'm having fun using and exploring it - a feeling I haven't had for a long time.

    While following the docs to let Caddy (also a new experience for me) serve the static assets on my local machine, the home page (/) didn't work for me until I excluded / in addition to *.php in the @static directive.

    I'm proposing the change in a PR instead of starting a discussion because I'm hopeful this change was the correct choice (and although it's just one added char) 😅.

    If the change tackles the problem from the wrong end, I'd be grateful for a hint in the right direction!

    :octocat:

    opened by jeromegamez 8
  • Prevent serving unparsed php files via nginx proxy.

    Prevent serving unparsed php files via nginx proxy.

    Currently, if using nginx as a reverse proxy with the described configuration, PHP files in the public folder are served as-it (unparsed) to the client, because the try_files instruction in the nginx configuration finds the file (e.g. index.php). To avoid this behavior we must instruct nginx to pass any file ending with .php as a route to X. That does not mean that X will parse this file, and as long as not appropriate route is defined (e.g. $app->get('/index.php', ...) X will just respond with a 404 error page, but at least no PHP code is leaked.

    documentation 
    opened by virtuelle-maschine 1
  • Allow Streaming Request

    Allow Streaming Request

    in respect to the underlying http-server component which will not allow to define the own middleware streaming handler. this code will give the opportunity to handle the 64KB request body problem. just assign your own 'StreamingRequestMiddleware' with custom allowed body size.

    opened by skydiablo 1
  • Documentation about 'nginx reverse proxy' is at least misleading

    Documentation about 'nginx reverse proxy' is at least misleading

    I have tried to build a setup with two services: one framework-x service and a nginx as reverse proxy. If I am using the nginx configuration that you are suggesting (https://framework-x.org/docs/best-practices/deployment/#nginx-reverse-proxy), all php files in the public folder are served "as-it" (unparsed) to the client (at least if nginx and framework-x are sharing the same public folder - but that is how I read your examples). Seems to me that using a different path for the the framework-x start script than /public/index.php is highly recommended. Or am I missing something?

    I have created an example in a branch of my test project: https://github.com/virtuelle-maschine/framework-x-test/tree/example-with-index An example that works as expected can be found in the main branch of that project.

    BTW, regarding Dockerfile: I am surprised you are using the ENTRYPOINT instruction to start the app - doesn't the CMD instruction makes more sense as you can run the container with a different command (e.g. composer) much easier?

    documentation 
    opened by virtuelle-maschine 2
  • Allow auto-wiring container-parameters without using factory-callback

    Allow auto-wiring container-parameters without using factory-callback

    Imagine you wanted to have a service with a constructor parameter of a string like this:

    class UserController
    {
        public function __construct(string $hostname)
        {
            // ...
        }
    }
    

    Prior to this change, you would have to do this.

    $container = new FrameworkX\Container([
        UserController::class => function (string $hostname): UserController {
            return new UserController($hostname);
        },
        'hostname' => 'Some string value',
    ]);
    

    After this change, you can do this:

    $container = new FrameworkX\Container([
        'hostname' => 'Some string value',
    ]);
    

    I am still relatively new to this framework, so I don't know whether this will break some anything.

    opened by jkrzefski 2
Owner
Christian Lück
@reactphp maintainer / Freelance Software Engineer, all things web, passionate about coaching others building awesome things… Reach out if you need help
Christian Lück
A powerful yet easy-to-use PHP micro-framework designed to help you build dynamic and robust Web applications - fast!

A powerful yet easy-to-use PHP micro-framework designed to help you build dynamic and robust Web applications - fast! Condensed in a single ~65KB file

Bong Cosca 2.6k Dec 30, 2022
A magic PHP framework. Build reactive web apps without writing HTML, CSS, or JavaScript! Powered by Tailwind, Alpine, Laravel, & Livewire.

Malzahar A magic PHP framework. Build reactive web apps without writing HTML, CSS, or JavaScript! Powered by Tailwind, Alpine, Laravel, & Livewire. Re

null 26 Nov 17, 2022
Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs.

Slim Framework Slim is a PHP micro-framework that helps you quickly write simple yet powerful web applications and APIs. Installation It's recommended

Slim Framework 11.5k Jan 4, 2023
FlyCubePHP is an MVC Web Framework developed in PHP and repeating the ideology and principles of building WEB applications, embedded in Ruby on Rails.

FlyCubePHP FlyCubePHP is an MVC Web Framework developed in PHP and repeating the ideology and principles of building WEB applications, embedded in Rub

Anton 1 Dec 21, 2021
Framework X is a simple and fast micro framework based on PHP

Framework X is a simple and fast micro framework based on PHP. I've created a simple CRUD application to understand how it works. I used twig and I created a custom middleware to handle PUT, DELETE methods.

Mahmut Bayri 6 Oct 14, 2022
An application for building micro-services in PHP ^8.

Restolia An application for building micro-services in PHP ^8. Install composer create-project restolia/restolia my-app Services Each service lives i

null 1 May 1, 2022
Lite & fast micro PHP framework that is **easy to learn**.

Utopia Framework is a PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development.

utopia 139 Dec 30, 2022
Lite & fast micro PHP abuse library that is **easy to use**.

Utopia Abuse Utopia framework abuse library is simple and lite library for managing application usage limits. This library is aiming to be as simple a

utopia 23 Dec 17, 2022
Framework for building extensible server-side progressive applications for modern PHP.

Chevere ?? Subscribe to the newsletter to don't miss any update regarding Chevere. Framework for building extensible server-side progressive applicati

Chevere 65 Jan 6, 2023
This component may look complex, weird and full of hacks but it is a game changer for how we run PHP applications.

PHP Runtimes In early 2021, Symfony created a "Runtime component". This component may look complex, weird and full of hacks but it is a game changer f

Runtime 321 Dec 25, 2022
A curated list of awesome tutorials and other resources for the Slim micro framework

Awesome Slim A curated list of awesome tutorials and other resources for the Slim micro framework Table of Contents Essentials Tutorials Packages and

Sawyer Charles 466 Dec 8, 2022
A tiny, yet powerful, PHP micro-framework.

Equip Framework A tiny and powerful PHP micro-framework created and maintained by the engineering team at When I Work. Attempts to be PSR-1, PSR-2, PS

Equip 118 Jun 24, 2022
An extensible micro-framework for PHP

What is Flight? Flight is a fast, simple, extensible framework for PHP. Flight enables you to quickly and easily build RESTful web applications. requi

Mike Cao 2.5k Dec 30, 2022
A resource-oriented micro PHP framework

Bullet Bullet is a resource-oriented micro PHP framework built around HTTP URIs. Bullet takes a unique functional-style approach to URL routing by par

Vance Lucas 415 Dec 27, 2022
a micro mvc framework for php

micro-mvc-php a micro mvc framework for php Config your Web url in .env . lifecycle All request proccess by index.php Autoload files include in bootst

Amiranbari 6 Jul 9, 2022
⚡ Micro API using Phalcon Framework

Micro App (Rest API) ⚡ Micro API using Phalcon PHP Framework. PHPDocs I. Requirements A Laptop ?? Docker (docker-compose*) Makefile (cli) II. Installa

Neutrapp 7 Aug 6, 2021
Mutexes for Micro-Framework HLEB

Use of mutexes in a project (including projects based on the HLEB micro framework) The use of mutexes is worthwhile in cases, when access to any code

Foma Tuturov 1 Oct 11, 2022
Plates Template Integration for Slim micro framework 3

Plates Template Integration for Slim micro framework 3 Render your Slim 3 application views using Plates template engine. Install Via Composer $ compo

Projek XYZ 26 Feb 5, 2022
The Slim PHP micro framework paired with Laravel's Illuminate Database toolkit.

Slim & Eloquent The Slim PHP micro framework paired with Laravel's Illuminate Database toolkit. Getting started # Download composer curl -s https://ge

Kyle Ladd 111 Jul 23, 2022