7

GitHub - loskoderos/moo: Moo is a PHP micro framework to make life and debugging...

 1 year ago
source link: https://github.com/loskoderos/moo
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Question is not what is Moo, but why is Moo?

There is time that every PHP developer has to create its own framework. Most of them are crap, this one is no exception.

So, Moo, the framework, is a spawn of PHP evil created for making life and debugging miserable. It took a couple of hours to create, but can take days to find out what and why works or does not. Like most microframeworks, Moo is quite close to HTTP world, made of bunch of pure PHP classes with no external dependencies. Just router, request, response, boom done.

Of course, it would be easier, faster and wiser to just use any other off shelf framework, but there it is, Moo!

Why Moo?

Why not.

Why use Moo?

Seriously, for 99% of time you should not use this framework. Don't do it for sake of yours and other developers wellbeing and mental health.

The only exception to that I can think of, is when you consider using raw .php scripts somewhere on a server. If that is the case, Moo can actually be useful.

Looking for some decent PHP framework? Go learn Symfony, Laravel or anything that actually has any community around. This one does not have any. Actually, you can try writing your own micro framework, just like Moo to learn and validate your PHP skills.

Installation

If you really have to, here you go, just use composer.

composer config minimum-stability dev
composer require loskoderos/moo:dev-main

Hello World

Simplest Moo application.

<?php
$moo = new Moo\Moo();

$moo->get('/', function () {
    return "Hello, this is Moo!";
});

$moo();

Usage

This is the sample Moo app with more features presented like state container, plugins and parametrized routing.

<?php
$moo = new Moo\Moo();

// Use moo as service container, inject dependency.
$moo->bookService = new App\BookService();

// Override init to set Content-Type header.
$moo->init = function () use ($moo) {
    $moo->response->headers->set('Content-Type', 'application/json');
};

// Override finish to serialize output to JSON.
$moo->finish = function () use ($moo) {
    $moo->response->body = json_encode($moo->response->body);
}

// Custom plugin.
$moo->findBookById = function ($bookId) use ($moo) {
    return $moo->bookService->find($bookId);
}

// Define index handler.
$moo->get('/', function () {
    echo "Hello, this is Moo bookstore!";
});

// Define `GET /books/<id>` handler.
$moo->get('/books/(\d+)', function ($bookId) use ($moo) {
    return $moo->findBookById($bookId);
});

// Run Moo.
$moo();

Examples

There are some examples in the examples directory. To run them you can use builtin PHP server.

php -S 0.0.0.0:8080 examples/hello-world/index.php

Documentation

The goal of Moo is simplicity, flexibility and ease of use.

Concepts

Moo is written in PHP and is closure based. From design perspective it is a front controller, the Moo\Moo class exposes a set of standard HTTP methods to bind routing handlers as closures. Additionally, Moo acts as a state container and can be extended with plugins.

All Moo components reside in the PSR-4 Moo namespace. The main component is the Moo\Moo class. There are three models: Moo\Request, Moo\Response, Moo\Route and the Moo\Router that works as dispatcher.

Moo does output buffering, so you can simply output with echo or return a serializable value in the closure.

Lifecycle

Here is what happends when you call $moo(...):

Routing

You can bind handlers to standard HTTP methods:

  • GET: $moo->get(...)
  • HEAD: $moo->head(...)
  • POST: $moo->post(...)
  • PUT: $moo->put(...)
  • DELETE: $moo->delete(...)
  • CONNECT: $moo->connect(...)
  • OPTIONS: $moo->options(...)
  • TRACE: $moo->trace(...)
  • PATCH: $moo->patch(...)

You can match multiple methods using $moo->route(...).

Routes are matched from the first to the last. If no route matches the request, the error handler is called $moo->error(...).

Parameters

Route can be parametrized with regular expressions.

$moo->post('/orders/(\d+)/items/(\d+)', function ($orderId, $itemId) use ($moo) {
    return $moo->orderService->findOrderItem($orderId, $itemId);
});

Init & Finish

There are two handlers pre and post request, the init and the finish.

$moo->init = function () {
    echo "Hey I'm init";
};
$moo->finish = function () {
    echo "Hey I'm finish";
};
$moo();

Error Handling

By default exceptions are handled by the error handlers, that also works when no route matches request.

$moo->error = function(\Exception $exc) use ($moo) {
    $moo->response = new Response([
        'code' => $exc->getCode() > 0 ? $exc->getCode() : 500,
        'message' => StatusCode::message($exc->getCode()),
        'body' => $exc->getMessage()
    ]);
};

Request

The Moo\Request class consists of:

  • method
  • headers
  • query
  • files

Request object $moo->request is created before init with the values taken from PHP global variables, $_SERVER, $_GET, $_POST, $_FILES.

Request body is empty by default! You can override that with ini:

$moo->init = function () ($moo) {
    $moo->request->body = file_get_contents('php://input');
};

Response

The Moo\Response class consists of:

  • headers
  • message

Response object $moo->response is created before init and can be modified during the request lifecycle. Response body is not serialized, it is assumed you serialize it before flush in finish.

State

You can use Moo to keep your application state.

$moo->something = 123;
$moo->myState = [
    'config' => [
        'host' => 'localhost',
        'port' => 1234
    ]
];

Plugins

You can extend Moo with custom functions.

$moo->foobar = function () {
    return 123;
};
$moo->foobar();

Flush & Output Buffering

By default all output is buffered and then flushed at the end of $moo() execution. You can override that behaviour by setting custom flush handler.

$moo->flush = function () use ($moo) {
    header('HTTP/1.1 ' . $moo->response->code . ' ' . $moo->response->message);
    foreach ($moo->response->headers as $name => $value) {
        header($name.': '.$value, true);
    }
    echo $moo->response->body;
};

Testing

Moo is unit tested, just run make test.

Contributing

Contributions are welcome, please submit a pull request.

License


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK