Giter VIP home page Giter VIP logo

lucille's Introduction

Lucille HTTP Abstraction

Lucille is a lightweight HTTP abstraction layer based on the principles of CQRS. It is designed to quickly create restful services and web services/websites that require dynamic request handling.

Integrate

Type Coverage

Requirements

  • PHP 7.2+
    • ext/dom (when using the XML/XHTML component)
    • ext/xsl (when using the XSL component)

Basic Concepts

Request processing workflow

The Lucille HTTP Abstraction Framework follows in general the principles of CQRS. The regular processing of a request is done in six steps:

  1. The Request, separated by its HTTP request method (GET, POST, ...) is routed through an explicit RoutingChain to ensure separation from other request types
  2. Each router in the chain must decide to either be responsible to handle the request or have to decline it by forwarding it to the next router in the chain
  3. The matching router in the chain (the router that decides to be responsible to handle the current request) always returns a valid Command or Query object
  4. The Query or Command is executed
  5. The result of the execution is always a Result object
  6. The Result object is finally routed through a ResultRouterChain, which composes the final Response object which is sent to the client

The processing in short, for example for a GetRequest:

  1. GetRequest
  2. GetRoutingChain returns Query
  3. Query is executed and returns a QueryResult object
  4. The result routing chain is invoked and builds the final Response object

Supported HTTP Request Types

Currently the following http request methods are supported

  • GET
  • POST
  • PUT
  • PATCH
  • DELETE

Usage

Full Example using the internal RequestProcessor

The easiest way is to use the provided RequestProcessor. When creating HTTP services you probably want to implement your own request processing mechanism to properly implement your own Logging and Exception handling.

namespace Website;

use Lucille\Factory;

require_once '/lucille/autoload.php';

// create the factory, which helps getting the core features
$factory = new Factory();

// register stream wrapper
$factory->registerStream('xhtml', __DIR__.'/parts');
$factory->registerStream('xsl',   __DIR__.'/xsl');

// create the GET routing chain add a GET router
$chainGet = $factory->createGetRoutingChain();
$chainGet->addRouter(new IndexRouter());

// create the POST routing chain and add a POST router
$chainPost = $factory->createPostRoutingChain();
$chainPost->addRouter(new FormVerifyRouter());

// create an instance of the default request processor
$processor = $factory->createRequestProcessor();

// enable verbose error output for debugging purposes
//$processor->enableVerboseErrors();

// add routing chains to the processor
$processor->addRoutingChain($chainGet);
$processor->addRoutingChain($chainPost);

// create request (based on the request method, headers and parameters)
$request = $factory->createRequestFactory()->createRequest();

// build a response by running the processor with the created request
$response = $processor->run($request);


// dump/send the response to the client
$response->send();

Implementing Routers, Commands and Queries

Example Router (GET Request)

namespace Website;

use Lucille\Query;
use Lucille\Request\GetRequest;
use Lucille\Request\Uri;
use Lucille\Routing\GetRouter;

class IndexRouter extends GetRouter {
    
    public function route(GetRequest $request): Query {
        if (!$request->getUri()->isEqual(new Uri('/'))) {
            return $this->getNext()->route($request);
        }
        
        return new IndexQuery();
    }
    
}

Example Query

namespace Website;
    
use Lucille\Components\Xml\XhtmlContent;
use Lucille\Filename;
use Lucille\Query;
use Lucille\Result\Result;

class IndexQuery implements Query {
    
    public function execute(): Result {
        // load main page
        $page = new XhtmlContent(new Filename('xhtml://design.xhtml'));
        
        // load a part and append it to the html <body> tag (which has the id attribute 'content')
        $part1 = new XhtmlContent(new Filename('xhtml://part1.xhtml'));
        $page->append('content', $part1);
        
        return $page;
    }
    
}

URI Matching and Usage Examples

// request URI equals another URI
if ($request->getUri()->isEqual( new Uri('/contact') ) {
    ...
}

// check if request URI matches a specified regular expression
// - example request uri: /articles/my-first-article/view.xml
if ($request->getUri()->beginsWith( new Uri('/articles/') ) {
    ...
}

// check if request URI matches a specified regular expression
// - example request uri: /articles/2020/demo-article/
if ($request->getUri()->matchesRegEx( new UriRegEx('#^/articles/[0-9]{4}/.*#') )) {
    ...
}

// check for a specific URI segment
// - example request uri: /articles/2020/demo-article/
$request->getUri()->getPart(0);    // returns 'articles'
$request->getUri()->getPart(1);    // returns '2020'
$request->getUri()->getPart(2);    // returns 'demo-article'

Request Parameter Examples

URI parameter by name

example request uri: /article?id=123

// cast to string
echo $request->getParam('id')->asString();

// cast to int
echo $request->getParam('id')->asInt();

// cast to float
echo $request->getParam('id')->asFloat();

Working with Parameter Collections

// example request uri: /article?id=123&limit=20
$collection = $request->getParameterCollection();
if (count($collection) > 0) {
    foreach ($collection as $param) {
        echo $param->getName()->asString();     // parameter name
        echo $param->asString();                // parameter value
    }
}

// example request uri: /article?list[]=foo&list[]=bar
$collection = $request->getParameterCollection('list');
if (count($collection) > 0) {
    foreach ($collection as $value) {
        echo $value->asString();
    }
}

Components and Helper

Lucille comes with some handy ready-to-use components to solve some daily problems. Most of these components are simply a lightweight wrapper for standard functionality. So when building complex websites or API projects these components may not fit your extended needs and should be implemented based on your current project scope.

Contributing

Lucille and its Components are open source projects released under the BSD license. You are welcome to join the development team!

lucille's People

Contributors

ahabel avatar localheinz avatar szepeviktor avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.