This website uses Cookies to provide you with the best possible service. Please see our Privacy Policy for more information. Click the check box below to accept cookies. Then confirm with a click on "Save".  
Status: 2024-10-06

Policy


Enabling Policy Rules

Policies are bonded to a any/certain Controller::method.
And they are executed after all Routes are initialized by Emvicy.

Path to module's policy configuration files

module/{module}/etc/config/policy/*.php
module/{module}/etc/config/policy/policy.php

Set a single Rule

(assuming module is "Foo")

Set a single Rule to any (*) method of a controller

\MVC\Policy::set(
    '\Foo\Controller\Index', 
    '*', 
    '\Foo\Policy\Index::requestMethodHasToMatchRouteMethod'    
);
  • when any (*) method of controller \Foo\Controller\Index is being called
  • execute \Foo\Policy\Index::requestMethodHasToMatchRouteMethod

Set a single Rule to a certain method of a controller

\MVC\Policy::set(
    '\Foo\Controller\Index', 
    'index', 
    '\Foo\Policy\Index::requestMethodHasToMatchRouteMethod'
);
  • when method index of controller \Foo\Controller\Index is being called
  • execute \Foo\Policy\Index::requestMethodHasToMatchRouteMethod

Setting multiple Rules

simply wrap the rules into an array.

\MVC\Policy::set(
    '\Foo\Controller\Index', 
    '*', [
        '\Foo\Policy\Index::foo',
        '\Foo\Policy\Index::bar',
        '\Foo\Policy\Index::baz',
    ]
);

Bind Policy Rules to a Route

You can also bind a policy to a certain Route.

Example: bind policies checkUserRights and isAdmin to Route /foo/bar/

\MVC\Policy::bindOnRoute(
    \MVC\Route::$aRoute['/foo/bar/'], [
        '\Foo\Policy\Index::checkUserRights',
        '\Foo\Policy\Index::isAdmin'
    ]
);

Bind Policy Rules to multiple Routes

consider you have these following routes and you want to apply Policy Rules to /edit-Routes only.

/client/:number/contract/new
/client/:number/address/new
/client/:number/person/new
/client/:number/contract/:id/edit
/client/:number/address/:id/edit
/client/:number/person/:id/edit

All Route Indices you can get by \MVC\Route::getIndices().

Now all you have to do is to grep in those Indices for any match and then to apply your Policy Rules to that match.

Examples

Apply a regex to all routes
// iterate all '/edit' Routes ...
foreach (preg_grep('/^([\\p{L}\\p{M}\\p{Z}\\p{S}\\p{N}\\p{P}]*)\/edit/i', \MVC\Route::getIndices()) as $sRoute)
{
    // ... and bind 'isAdmin' Policy to those Routes  
    \MVC\Policy::bindOnRoute(
        \MVC\Route::$aRoute[$sRoute], ['\Foo\Policy\Index::isAdmin']
    );
}

Build a separate policy Ruleset array, then proceed the array
/*
 * Ruleset
 */
$aPolicyOnRoute = array(
    '/@/productroute/new'                                       => ['\Foo\Policy\Index::isUser'],
    '/@/productroute/:id/edit'                                  => ['\Foo\Policy\Index::isUser'],
    '/@/client/:number/credentials/new'                         => ['\Foo\Policy\Index::isUser'],
    '/@/client/:number/credentials/:id/edit'                    => ['\Foo\Policy\Index::isUser'],
    '/@/client/:number/credentialsproduct/new'                  => ['\Foo\Policy\Index::isUser'],
    '/@/client/:number/credentialsproduct/:id/edit'             => ['\Foo\Policy\Index::isUser'],
    '/@/client/:number/edit'                                    => ['\Foo\Policy\Index::isUser'],
    '^([\\p{L}\\p{M}\\p{Z}\\p{S}\\p{N}\\p{P}]*)/contract/new'   => ['\Foo\Policy\Index::isAdmin'],
);

/*
 * Implementation
 */
foreach ($aPolicyOnRoute as $sRoute => $aRule)
{
    $sRouteEscaped = str_replace('/', '\/', $sRoute);

    foreach (preg_grep('/^' . $sRouteEscaped . '/i', \MVC\Route::getIndices()) as $sRoute)
    {
        \MVC\Policy::bindOnRoute(
            \MVC\Route::$aRoute[$sRoute],
            $aRule
        );
    }
}

Disabling Policy Rules

Unset a single Rule

assuming module is "Foo"

Unset the single rule '\Foo\Policy\Index::requestMethodHasToMatchRouteMethod' set to controller \Foo\Controller\Index and method index

Policy::unset(
    '\Foo\Controller\Index', 
    'index', 
    '\Foo\Policy\Index::requestMethodHasToMatchRouteMethod'    
);

Unset multiple Rules

Unset certain, multiple rules set to controller \Foo\Controller\Index and method index

\MVC\Policy::unset(
    '\Foo\Controller\Index', 
    'index', [
        '\Foo\Policy\Index::foo',
        '\Foo\Policy\Index::bar',
        '\Foo\Policy\Index::baz',
    ]
);

Unset all rules set to controller \Foo\Controller\Index and method index

Policy::unset(
    '\Foo\Controller\Index', 
    'index'
);

Unset all rules set to controller '\Foo\Controller\Index'

Policy::unset(
    '\Foo\Controller\Index'
);

Unbind a Policy Rule from a Route

Unbind a certain policy rule

\MVC\Policy::unbindRoute(
    \MVC\Route::$aRoute['/foo/bar/'], [
        '\Blg\Policy\Index::checkUserRights'
    ]
);

Unbind all policy rules bonded to a route

\MVC\Policy::unbindRoute(
    \MVC\Route::$aRoute['/foo/bar/']
);

Write methods to be executed by policy

For a better overview, you note the required class::method not in "module/{module}/Model/" but in a separate folder.

Path to module's policy folder

module/{module}/Policy/

Example: file module/Foo/Policy/Index.php

<?php
/**
 * Index.php
 *
 * @package Emvicy
 * @copyright ueffing.net
 * @author Guido K.B.W. Üffing <info@ueffing.net>
 * @license GNU GENERAL PUBLIC LICENSE Version 3. See application/doc/COPYING
 */

/**
 * @name $FooPolicy
 */
namespace Foo\Policy;

use MVC\DataType\DTArrayObject;
use MVC\DataType\DTKeyValue;
use MVC\Event;

/**
 * Index
 */
class Index
{
    /**
     * @return void
     * @throws \ReflectionException
     */
    public static function requestMethodHasToMatchRouteMethod ()
    {
        $oDTArrayObject = DTArrayObject::create()
            ->add_aKeyValue(DTKeyValue::create()->set_sKey('sRequestmethod')->set_sValue(\MVC\Request::getCurrentRequest()->get_requestmethod()))
            ->add_aKeyValue(DTKeyValue::create()->set_sKey('aMethodsAssigned')->set_sValue(\MVC\Route::getCurrent()->get_methodsAssigned()))
            ->add_aKeyValue(DTKeyValue::create()->set_sKey('bGrant')->set_sValue(false))
            ->add_aKeyValue(DTKeyValue::create()->set_sKey('sMessage')->set_sValue('access denied'))
            ->add_aKeyValue(DTKeyValue::create()->set_sKey('sMethod')->set_sValue(__METHOD__))
            ->add_aKeyValue(DTKeyValue::create()->set_sKey('sRedirect')->set_sValue('/404/'))
            ->add_aKeyValue(DTKeyValue::create()->set_sKey('sClosure')->set_sValue(
                function(\MVC\DataType\DTArrayObject $oDTArrayObject) {
                    \MVC\Request::redirect($oDTArrayObject->getDTKeyValueByKey('sRedirect')->get_sValue());
                }
            ))
        ;

        // grant access
        if (
            // Route is of type ANY
            '*' === \MVC\Route::getCurrent()->get_method()
            OR
            // Request and Route methods do match
            true === in_array(\MVC\Request::getCurrentRequest()->get_requestmethod(), \MVC\Route::getCurrent()->get_methodsAssigned(), true)
        )
        {
            $oDTArrayObject->setDTKeyValueByKey(DTKeyValue::create()->set_sKey('bGrant')->set_sValue(true));
            $oDTArrayObject->setDTKeyValueByKey(DTKeyValue::create()->set_sKey('sMessage')->set_sValue('access granted'));
        }

        // give any middleware option to modify $oDTArrayObject
        Event::run('policy.index.requestMethodHasToMatchRouteMethod.after', $oDTArrayObject);

        // deny access; call closure
        if (false === $oDTArrayObject->getDTKeyValueByKey('bGrant')->get_sValue())
        {
            call_user_func($oDTArrayObject->getDTKeyValueByKey('sClosure')->get_sValue(), $oDTArrayObject);
        }
    }
}