2017 © Pedro Peláez
 

library tale-controller

A controller middleware for talesoft/tale-app

image

talesoft/tale-controller

A controller middleware for talesoft/tale-app

  • Wednesday, March 2, 2016
  • by TorbenKoehn
  • Repository
  • 3 Watchers
  • 0 Stars
  • 5 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 2 Versions
  • 0 % Grown

The README.md

Tale Controller

A Tale Framework Component, (*1)

What is Tale Controller?

A middleware for talesoft/tale-app that allows easy instanciation and handling of controllers., (*2)

You can either use single, static controllers or use a dispatcher that automatically handles everything., (*3)

Installation

Install via Composer, (*4)

composer require "talesoft/tale-controller:*"
composer install

Usage

Single usage

A single controller can make up a whole website. This is really useful for small websites with 5-10 sub-pages. No configuration needed., (*5)


use Tale\App; use Tale\Controller; //Define a controller of some kind class MyController extends Controller { //GET|POST / public function indexAction() { $res = $this->getResponse(); $res->getBody()->write('Hello index!'); return $res; } //GET|POST /?action=about-us public function aboutUsAction() { $res = $this->getResponse(); $res->getBody()->write('About us!'); return $res; } //GET /?action=contact public function getContactAction() { $res = $this->getResponse(); $res->getBody()->write('Contact form!'); return $res; } //POST /?action=contact public function postContactAction() { //Handle contact form $res = $this->getResponse(); $res->getBody()->write('Success!'); return $res; } } //Create a new app context $app = new App(); //Make sure we can target the "action" somehow. //Normally you'd use a router, we use a simple GET-variable in this case //"index.php?action=about-us" would dispatch "MyController->aboutUsAction" //This is a simple middleware mapping query's "action" to the required request attribute "action" $app->append(function($req, $res, $next) { $params = $req->getQueryParams(); $action = isset($params['action']) ? $params['action'] : null; if ($action) $req = $req->withAttribute('action', $action); return $next($req, $res); }); //Append our controller middleware $app->append(MyController::class); //Display the app $app->display();

Using the Dispatcher

When apps get larger, you want to split functionality into single modules. With the Dispatcher you can control an automatic controller dispatching mechanism., (*6)

Imagine the following controller structure:, (*7)

/
    /index.php
    /app
        /controllers
            IndexController.php
            ContactController.php
            PortfolioController.php
            /Admin
                /IndexController.php

This is a common case that the dispatcher can handle with a low configuration profile., (*8)


use Tale\App; use Tale\Controller\Dispatcher; //Create a new app context $app = new App([ 'controller' => [ 'nameSpace' => 'My\\Controllers', 'loader' => ['path' => __DIR__.'/app/controllers'] ] ]); //This is a middleware mapping "module", "controller" and "action" GET-values to //ServerRequestInterface-attributes $app->append(function($req, $res, $next) { $params = $req->getQueryParams(); $module = isset($params['module']) ? $params['module'] : null; $controller = isset($params['controller']) ? $params['controller'] : null; $action = isset($params['action']) ? $params['action'] : null; if ($module) $req = $req->withAttribute('module', $module); if ($controller) $req = $req->withAttribute('controller', $controller); if ($action) $req = $req->withAttribute('action', $action); return $next($req, $res); }); //Append our dispatcher middleware $app->append(Dispatcher::class); //Display the app $app->display();

Now you could call the editAction of the Admin\IndexController by requesting index.php?module=admin&action=edit, (*9)

Notice that all values are completely optional., (*10)

ServerRequestInterface attributes

The following attributes are handled by the dispatcher:, (*11)

module (Default: null)

Tells the dispatcher which namespace to find controllers in. The controller.nameSpace option will be prepended in any case., (*12)

controller (Default: index)

Tells the dispatcher, which controller to load. my-blog will be parsed to MyBlogController, (*13)

The following attributes are handled by the controllers:, (*14)

action (Default: index)

Tells the controller which action to call. edit-user will be parsed to editUserAction, (*15)

If there's an getEditUserAction-method, that one will only listen to GET-requests The same goes for POST-requests with postEditUserAction. Not prefixing will handle all request methods., (*16)

id (Default: null)

Specifies the first parameter given to the action. Allowed values are numerical values and canonical strings (some-user-name), (*17)

format (Default: html)

Specifies the format the result should appear in. This mostly equals the file extension of the called URI (/some-file.xml will yield format xml), (*18)

This format is to be used by some kind of output formatter/renderer., (*19)

Handle 404-errors

What if there's no fitting controller/it doesn't extend the correct class/the input is malformed etc., (*20)

That's all checked by tale-controller. Upon any kind of failure, control will be passed on to the next middleware., (*21)

Handling 404 is as simple as adding an "end"-middleware that results in said 404-error, (*22)


$app->append(Dispatcher::class) ->append(function($req, $res) { $res->getBody()->write('<h1>404 - Not found!</h1>'); return $res->withStatus(404); });

Shorten things up

This module is specially designed to work with the Tale\Router. You can use it stand-alone, but it will require extra-work (but is still really cool!), (*23)

Here's an example of how it could look like by installing talesoft/tale-router via composer, (*24)

env.json, (*25)

{
    "middlewares": ["Tale\\Router"],
    "routes": {
        "/blog/:action?/:id?": "My\\Controller\\BlogController",
        "/:controller?/:action?/:id?.:format?": "Tale\\Controller\\Dispatcher"
    },
    "controller": {
        "nameSpace": "My\\Controller",
        "loader": {
            "path": "{{path}}/app/controllers"
        }
    }
}
```php

**index.php**
```php

use Tale\App;

$app = new App(['path' => __DIR__]);
$app->display();

Configuration options

All configuration options., (*26)

controller.defaultModule            The default module to use (Default: null)
controller.defaultController        The default controller to use (Default: index)
controller.defaultAction            The default action to use (Default: index)
controller.defaultId                The default ID to use (Default: null)
controller.defaultFormat            The default format to use (Default: html)

controller.nameSpace                The namespace where controllers reside in (Default: null)
controller.modules                  A map [module-name => namespace] for module mapping

controller.controllerPattern        The pattern for controllers (Default: %sController)
controller.controllerInflection     How to inflect the controller name (Default: [Tale\Inflector, camelize]

controller.actionPattern            The pattern for actions (Default: %sAction)
controller.actonInflection          How to inflect the action name (Default: [Tale\Inflector, variablize]
controller.getActionPattern         The pattern for GET actions (Default: get%sAction)
controller.getActonInflection       How to inflect the GET action name (Default: [Tale\Inflector, camelize]
controller.postActionPattern        The pattern for POST actions (Default: post%sAction)
controller.postActonInflection      How to inflect the POST action name (Default: [Tale\Inflector, camelize]

controller.loader.enabled           Enable an auto-loader for controllers (Default: true)
controller.loader.path              The path for controller classes (Default: getcwd()/controllers)
controller.loader.pattern           The pattern for controller loading (Default: %s.php)

Using multiple dispatchers

Using multiple dispatchers is as easy as extending the dispatcher. You can set an option namespace to load different configuration values., (*27)


class FirstDispatcher { public function getOptionNameSpace() { return 'firstDispatcher'; } } class SecondDispatcher { public function getOptionNameSpace() { return 'secondDispatcher'; } } $app->get(Router::class) ->all('/:controller?/:action?', FirstDispatcher::class) ->all('/sub-module/:controller?/:action?', SecondDispatcher::class); $app->display();

The Versions