2017 © Pedro PelĆ”ez
 

library puppy-application

HTTP package for Puppy framework

image

raphhh/puppy-application

HTTP package for Puppy framework

  • Saturday, April 18, 2015
  • by raphhh
  • Repository
  • 1 Watchers
  • 0 Stars
  • 304 Installations
  • PHP
  • 5 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 5 Versions
  • 0 % Grown

The README.md

Puppy Application

HTTP package for Puppy framework, (*1)

Latest Stable Version Build Status Scrutinizer Quality Score Code Coverage Dependency Status Total Downloads Reference Status License, (*2)

Puppy Application is like an HTTP controller. It parses the current request and calls a matched controller., (*3)

Application basic logic:, (*4)

  • specify controllers for all specific requests
  • add services
  • manage services and controllers from modules
  • manage middlewares
  • pre/post-process
  • manage application error (todo)

Installation

$ composer require raphhh/puppy-application

Basic usage

Puppy needs a config and a request to run. Then you can add a controller., (*5)

use Puppy\Application;
use Puppy\Config\Config;
use Symfony\Component\HttpFoundation\Request;

$puppy = new Application(new Config(), Request::createFromGlobals());
$puppy->get('hello', function(){ 
    return 'Hello world!';
});
$puppy->run(); //good dog! :)

For the config, you can use any class implementing \ArrayAccess, instead of the Puppy Config., (*6)

Routes

A route simply matches a request to a controller. When you call this uri, that controller will be called., (*7)

How to add controller?

Puppy\Application has some simple methods to help you to declare your controllers., (*8)

$puppy->get($uri, $controller); //filter on GET http method
$puppy->post($uri, $controller); //filter on POST http method
$puppy->json($uri, $controller); //filter on JSON format
$puppy->any($uri, $controller); //filter only on the requested uri
$puppy->filter($filter, $controller); //specific filter as callable

How to define the route pattern?

A pattern of a route is a regex which will match with a specific request uri., (*9)

Only one of your controllers will be called when its pattern will match with the request uri. So, depending of the uri, the code of your controller will be executed., (*10)

$puppy->get('my/page/(\d)', $controller); 

To simplify your live and have more readable uri, you can define some binding. For example:, (*11)

$puppy->get('my/specific/:uri', $controller)->bind('uri'); 

By default, the binding will accept a pattern with string, numeric, '_' and '-'. But you can add a specific regex:, (*12)

$puppy->get('my/page/:index', $controller)->bind('index', '\d'); 

To simplify your life a little bit more, you can use predefined bindings. For example:, (*13)

$puppy->get(':all', $controller); //every uri
$puppy->get(':home', $controller); //home uri (empty or '/')
$puppy->get(':slug', $controller); //string uri, with numeric, '_' and '-'
$puppy->get(':id', $controller); //any unsigned int, except 0
$puppy->get(':index', $controller); //any unsigned int
$puppy->get(':lang', $controller); //two letters lower case, eventually followed by hyphen and two letters upper case (e.i. fr-FR)
$puppy->get(':datetime', $controller); //datetime with format yyyy-mm-ddThh:mm:ss or yyyy-mm-ddThh:mm:ss+hh:ss
$puppy->get(':date', $controller); //date with format yyyy-mm-dd
$puppy->get(':time', $controller); //time with format hh:mm:ss

How to specify other request constraints?

When you set controllers with the Puppy methods, you can continue to specify some other rules., (*14)

$puppy->get($uri, $controller)->content('xml/application');
$puppy->json($uri, $controller)->method('post');

All the constraints can be linked together for a same route., (*15)

$puppy->any('my/page/:index', $controller)
    ->bind('index', '\d')
    ->method('post')
    ->content('json/application');    

You can also restrict your route to a specific path namespace., (*16)

$puppy->get('users', $controller)->restrict('admin'); // this is accessible only with the request uri 'admin/users'

How to group routes?

You can also group several of your routes to process to some common actions., (*17)

$puppy->group([
             $puppy->get($uri1, $controller1),
             $puppy->get($uri2, $controller2),
        ])
      ->bind('index', '\d')
      ->method('post')
      ->restrict('admin');

Controllers

What is a controller?

A controller is any callable., (*18)

For example, a controller can be a closure:, (*19)

$puppy->get('hello', function(){
    ...
});

or it can be a class method:, (*20)

$puppy->get('hello', array($controller, 'method'));

or what you want that is callable..., (*21)

What will a controller return?

String

Your controller will return the response to send to the client. This can be a simple string., (*22)

$puppy->get('hello', function(){
    return '<h1>Hello world!</h1>';
});

Response

But more powerful, this can be also a Response, which will manage also the http header., (*23)

$puppy->get('hello', function(){
    return new Response('<h1>Hello world!</h1>');
});

To help you to manage some common actions, AppController has some cool methods for you. See AppController section., (*24)

Which arguments will receive the controller?

The controller receive two kinds of arguments, depending on what you want., (*25)

The pattern matches

If you want to receive the list of matches between pattern and uri, you must specify the param "array $args"., (*26)

$puppy->get('hello/:all', function(array $args){
    return $args['all']; //will return the value "world" for the uri "/hello/world"
});

If you use binding, the key of your matched arg is the alias without ":". For example, binding ":id" can be retrieved with the key "id"., (*27)

The Services

If you want to have the services container, you must specify the param "ArrayAccess $services"., (*28)

$puppy->get('hello', function(\ArrayAccess $services){
    ...
});

Of course, you can have the services with the matched args., (*29)

$puppy->get('hello', function(array $args, Container $services){
    ...
});

The order of params has no importance!, (*30)

You can also specify which service you want. You just have to name it in the params. (The name of the param must be exactly the name of your service.), (*31)

$puppy->get('hello', function(Request $request){
    return 'You ask for the uri "'.htmlentities($request->getRequestUri());
});

See services section to know which services are available by default., (*32)

What a controller can do?

A controller manages the HTTP response. So, to help you in common actions, you can use Puppy\Controller\AppController. This is a simple class that contains some utilities methods., (*33)

Which are the AppController methods?

Methods are for example:, (*34)

$appController->render($templateFile);
$appController->redirect($url);
$appController->call($uri);
$appController->abort();
$appController->flash()->get($myMessage);
$appController->retrieve($key);
$appController->getService($serviceName);

How to implement AppController?

There are three ways to use it., (*35)

As binded class

First, if you simply use a closure as controller, all the methods of AppController will be bound to your closure., (*36)

$puppy->get('hello', function(){
    return $this->abort();
});
As parent class

Second, you can create your Controller class which extends AppController., (*37)

use Puppy\Controller\AppController;

class MyController extends AppController 
{    
    public function myAction()
    {
        return $this->abort();
    }
} 
As service class

Third, you can ask for AppController as a service in the params., (*38)

$puppy->get('hello', function(AppController $appController){
    return $appController->abort();
});

See services section for more information., (*39)

Is there no dependencies?

Be careful, if you use AppController::flash(), you will need a service 'session'. And if your use AppController::rend(), you will need a service 'template'., (*40)

To simplify your life, you have two solutions., (*41)

Work with Puppy

Directly work with raphhh/puppy., (*42)

Include everything you need., (*43)

Work with Puppy/Service

You can work directly with Puppy\Service\Session and Puppy\Service\Template. These two services fit perfectly with the AppController., (*44)

First, you need to include their package to your project. Then, you just need to add these two services with Puppy\Application::addService(). See services section for more information., (*45)

Middlewares

What is a middleware?

A middleware is just a code executed before the controller. The middleware will trigger the call of its associated controller., (*46)

For example, imagine you want to call a controller only for users with admin rights. Then, your middleware can control this for you by filtering only accessible controllers., (*47)

How to implement a middleware?

Just by linking a callable to a controller., (*48)

$puppy->get($uri, $controller)->filter(function(){
    return true;
});

A middleware works like a controller: it can be any callable. The only difference is that a middleware must return a boolean indicating if we can call the controller., (*49)

You can also add any middleware you want. They will be executed in the same order. But, the chain will stop when a middleware returns false., (*50)

$puppy->get($uri, $controller)
      ->filter($middleware1)
      ->filter($middleware2)
      ->filter($middleware3);

Like a controller, a middleware works with the same system of dynamic params. You can retrieve any service you want. You just have to specify it in the params., (*51)

$puppy->get($uri, $controller)->filter(function(Request $request){
    ...
});

You can also apply middleware on a group of route. See route section for more information about group method., (*52)

$puppy->group($routes)
    ->filter($middleware1)
    ->filter($middleware2);

Pre and post processing

You can easily process on the HTTP request and response before and after the routing., (*53)

The method 'before' is called before the routing and receive the HTTP request., (*54)

$puppy->before(function(Request $request){
    ...
});

The method 'after' is called after the routing and receive the HTTP response., (*55)

$puppy->after(function(Response $response){
    ...
});

You can add as many processing as you want., (*56)

$puppy->before($callback1)
      ->before($callback2)
      ->after($callback3)
      ->after($callback4);

Note that if you give a Closure as process, the context will be bound with Application., (*57)

Mirrors

You can require that some uri be analysed like there were another ones. These uri will be like a mirror that points to a specific predefined route., (*58)

For example, you want your request uri "mail" points to "contact". "contact" is a real route, and "mail" must do exactly the same. So, if we the request uri is "mail", the route "contact" will be called., (*59)

$puppy->mirror('mail', 'contact'); //request uri "mail" will point to "contact"

Mirrors accept also dynamic params., (*60)

$puppy->mirror('mail/:id', 'contact/{id}');

Services

What is a service?

A service is a class which will be present in all your controllers., (*61)

By default, Puppy adds some services: * config (an object with the config according to your env) * request (an object with all the context of the current request. Just be aware that current request could be not the master request.) * requestStack (an object with all the requests used during the process. you can retrieve the current and the master request.) * router (an object which can analyse all the defined routes and controllers of your app) * frontController (instance of the class Puppy\Controller\AppController) * appController (instance of the class Puppy\Controller\AppController) * retriever (instance of the class Puppy\Helper\Retriever), (*62)

You can add any services you want, like for example a templating library, an ORM, ..., (*63)

How to add a service?

Because Puppy uses Pimple as services container, a service must be added from a callable., (*64)

$puppy->addService('serviceName', function(Container $services){
    return new MyService();
});

How to retrieve any services?

From Application

If you work with the Application object., (*65)

$puppy->getService('myService');

From AppController

If you work with the AppController object., (*66)

$appController->getService('myService');

See AppController section for more information about this class., (*67)

From any controller

The more powerful way is to retrieve dynamically your service in the params of the controller. You just have to specify a param with the same name as your service., (*68)


//you want the request? $puppy->get('hello', function(Request $request){ ... }); //you want the request and the config? $puppy->get('hello', function(Request $request, \ArrayAccess $config){ ... }); //you want the router and the appController? $puppy->get('hello', function(Router $router, AppController $appController){ ... });

The order of the params does not matter., (*69)

Modules

What is a module?

A module is a class that wraps a specific list of services an controllers. The module receives the Application in argument. So, your module class can add any services or controllers that are in your package., (*70)

//your module class
class MyModule implements \Puppy\Module\IModule{

    function init(\Puppy\Application $puppy){
        $puppy->get('my-module/:all', function(){
            return 'This is my module';
        });
    }

}

//add the module to the Application
$puppy->addModule(new MyModule());

How to load dynamically modules?

You can load dynamically all the modules of your project. You just have to create classes with two specifications: - The name of the class has to end with 'Module'. - The class must extend Puppy\Module\IModule., (*71)

Application::initModules(new ModulesLoader()) will load for you the modules of your project (by default modules in "src" and "vendor" dir). You can use a cache loader with ModulesLoaderProxy(). The search in the project will be done only on the first call and be cached into the filesystem., (*72)

Application error (todo)

You can add an error/exception handler which will be called for every error (event fatal error) and not caught exception., (*73)

$puppy->error(function(\Exception $exception){
    ...
});

If the script is interrupted because of a fatal error, you can specify a controller to send a correct HTTP header., (*74)

$puppy->die($controller);

It is recommended to display the error in the dev env only (display_error), but to intercept always the error (error_reporting). See the PHP doc for more information about the error., (*75)

Config options

  • 'module.directories' => define the directories where to find dynamically modules. (used by ModuleFactory)
  • 'module.cache.enable' => active the file cache of modules loader. (used by ModuleFactory)
  • 'module.cache.path' => set the path to save the cached files of the modules loader. (used by ModuleFactory)

The Versions

18/04 2015

dev-master

9999999-dev https://github.com/Raphhh/puppy

HTTP package for Puppy framework

  Sources   Download

MIT

The Requires

 

The Development Requires

by Raphaƫl Lefebvre

framework mvc

18/04 2015

1.2.0

1.2.0.0 https://github.com/Raphhh/puppy

HTTP package for Puppy framework

  Sources   Download

MIT

The Requires

 

The Development Requires

by Raphaƫl Lefebvre

framework mvc

14/04 2015

1.1.0

1.1.0.0 https://github.com/Raphhh/puppy

HTTP package for Puppy framework

  Sources   Download

MIT

The Requires

 

The Development Requires

by Raphaƫl Lefebvre

framework mvc

12/04 2015

1.0.1

1.0.1.0 https://github.com/Raphhh/puppy

HTTP package for Puppy framework

  Sources   Download

MIT

The Requires

 

The Development Requires

by Raphaƫl Lefebvre

framework mvc

11/04 2015

1.0.0

1.0.0.0 https://github.com/Raphhh/puppy

HTTP package for Puppy framework

  Sources   Download

MIT

The Requires

 

The Development Requires

by Raphaƫl Lefebvre

framework mvc