The Framework Code

class/framework/ajax/ajax.php

File List

<?php
/**
 * Base class for AJax operations
 *
 * @author Lindsay Marshall <lindsay.marshall@ncl.ac.uk>
 * @copyright 2020-2021 Newcastle University
 * @package Framework\Framework\Ajax
 */
    namespace Framework\Ajax;

    use \Framework\Exception\Forbidden;
    use \Support\Context;
/**
 * Ajax operation base class
 */
    abstract class Ajax
    {
        protected \Framework\Ajax $controller;
        protected Context $context;
/**
 * Constructor
 */
        public function __construct(Context $context, \Framework\Ajax $controller)
        {
            $this->context = $context;
            $this->controller = $controller;
            [$login, $perms] = $this->requires();
            if ($login && !$context->hasUser())
            {
                throw new Forbidden('Access denied');
            }
            $this->checkPerms($context->user(), $perms);
        }
/**
 * Check that a bean has a field. Do not allow id field to be manipulated unless flag is set.
 *
 * @param string $type   The type of bean
 * @param string $field  The field name
 * @param bool   $idok   Allow the id field to be tested
 *
 * @throws \Framework\Exception\BadValue
 */
        final protected function fieldExists(string $type, string $field, bool $idok = FALSE) : bool
        {
            if (!\Support\SiteInfo::hasField($type, $field) || (!$idok && $field === 'id'))
            {
                throw new \Framework\Exception\BadValue('Bad field: '.$field);
            }
            return TRUE;
        }
/**
 * Check access to a bean
 *
 * @throws Forbidden
 */
        final protected function checkAccess(?\RedBeanPHP\OODBBean $user, array $permissions, string $beanType, string $field = '', bool $idOK = FALSE) : void
        {
            if (isset($permissions[$beanType]))
            { // there are some permissions
                $access = $permissions[$beanType];
                if (\is_object($user) || !$access[0])
                { // either we have a user or no login required
                    $checks = count($access) == 2 ? $access[1] : [ [$access[1], $access[2]] ];
                    foreach ($checks as $check)
                    {
                        $this->checkPerms($user, $check[0]); // check user plays the right roles
                        if ($field === '' || empty($check[1]) || (\in_array($field, $check[1]) && ($field != 'id' || $idOK)))
                        {
                            return;
                        }
                    }
                }
            }
            throw new Forbidden('Permission denied: '.$beanType);
        }
/**
 * Check that user has the permissions that are specified in an array
 *
 * @throws Forbidden
 * @psalm-suppress PossiblyNullReference
 */
        private function checkPerms(?\RedBeanPHP\OODBBean $user, array $pairs) : void
        {
            if (!empty($pairs) && $user === NULL)
            { // you can't have permissions without a user
                throw new Forbidden('Permission denied');
            }
            foreach ($pairs as [$cname, $rname])
            {
                if (!\is_object($user->hasRole($cname, $rname)))
                {
                    throw new Forbidden('Permission denied');
                }
            }
        }
/**
 * Check URL string for n parameter values and pull them out
 *
 * Returns the parameter values in an array indexed from 0 with last parameter, anything left in an array
 * The value in $rest[0] is assumed to be an opcode so we always start at $rest[1]
 *
 * @param int $count  The number of parameters to check for
 *
 * @throws \Framework\Exception\ParameterCount
 */
        protected function restCheck(int $count) : array
        {
            $rest = $this->context->rest();
            if (\count($rest) <= $count) // there is always the AJAX op in there as well as its parameters
            {
                throw new \Framework\Exception\ParameterCount('Missing parameter');
            }
            $res = \array_slice($rest, 1, $count);
            $res[] = \array_slice($rest, $count + 1); // return anything left - there might be optional parameters.
            return $res;
        }
/**
 * Return permission requirements
 */
        public function requires() : array
        {
            return [TRUE, []]; // default to requiring login but no specific context/role
        }
/**
 * Handle AJAX operations
 */
        abstract public function handle() : void;
    }
?>