*/ class class_exception_policyreport extends \Exception { /** * @author Christian Fraß */ public function __construct( $messages ) { parent::__construct( ' | '.join($messages) ); } } /** * @author Christian Fraß */ abstract class class_policy { /** * @author Christian Fraß */ public function __construct( ) { } /** * @param record $environment * @return list * @author Christian Fraß */ abstract public function check( array $environment ) : array ; } /** * @author Christian Fraß */ class class_policy_none extends class_policy { /** * @author Christian Fraß */ public function __construct( ) { parent::__construct(); } /** * @implementation * @author Christian Fraß */ public function check( array $environment ) : array { return []; } } /** * @author Christian Fraß */ class class_policy_conjunction extends class_policy { /** * @author Christian Fraß */ public function __construct( array $subpolicies ) { parent::__construct(); $this->subpolicies = $subpolicies; } /** * @implementation * @author Christian Fraß */ public function check( array $environment ) : array { return ( \alveolata\list_\reduce( \alveolata\list_\map( $this->subpolicies, function ($policy) use ($environment) { return $policy->check($environment); } ), [], function ($x, $y) {return \alveolata\list_\concat($x, $y);} ) ); } } /** * @author Christian Fraß */ class class_policy_disjunction extends class_policy { /** * @author Christian Fraß */ public function __construct( array $subpolicies ) { parent::__construct(); $this->subpolicies = $subpolicies; } /** * @implementation * @author Christian Fraß */ public function check( array $environment ) : array { $some = \alveolata\list_\some( $this->subpolicies, function ($policy) use ($environment) { return $policy->check($environment); } ); return ($some ? [] : ['all alternatives failed']); } } /** * @author Christian Fraß */ class class_policy_logged_in extends class_policy { /** * @author Christian Fraß */ public function __construct( ) { parent::__construct(); } /** * @implementation * @author Christian Fraß */ public function check( array $environment ) : array { if (! array_key_exists('session_id', $environment)) { return ['session id not set']; } else { if (! \alveolata\session\has($environment['session_id'])) { return ['no session present']; } else { return []; } } } } /** * @param record> * @return class_policy * @author Christian Fraß */ function make( array $description ) : class_policy { switch ($description['kind']) { default: { throw ( new \Exception( \alveolata\string\coin('unhandled policy kind "{{kind}}"', ['kind' => $description['kind']]) ) ); break; } case 'none': { return ( new class_policy_none( ) ); break; } case 'logged_in': { return ( new class_policy_logged_in( ) ); break; } case 'conjunction': { return ( new class_policy_conjunction( \helper\list_\map( $description['parameters']['sub'] ?? [], function ($description_) { return make($description_); } ) ) ); break; } case 'disjunction': { return ( new class_policy_disjunction( \helper\list_\map( $description['parameters']['sub'] ?? [], function ($description_) { return make($description_); } ) ) ); break; } } } /** * @param class_policy $policy * @param function $function * @param record $environment * @return type_result * @throw \Exception if the policy check fails * @author Christian Fraß */ function wrap/**/( class_policy $policy, array $environment, \Closure $function )/* : type_result*/ { $messages = $policy->check($environment); if (count($messages) === 0) { $result = $function(); return $result; } else { throw (new class_exception_policyreport($messages)); } }