<commit_before><?php

namespace Ordermind\LogicalPermissions;

use Ordermind\LogicalPermissions\Exceptions\InvalidArgumentTypeException;
use Ordermind\LogicalPermissions\Exceptions\InvalidArgumentValueException;
use Ordermind\LogicalPermissions\Exceptions\InvalidReturnTypeException;
use Ordermind\LogicalPermissions\Exceptions\InvalidValueForLogicGateException;
use Ordermind\LogicalPermissions\Exceptions\PermissionTypeNotRegisteredException;

/**
 * Checks access based on registered permission types, a permission tree and a context.
 */
class AccessChecker implements AccessCheckerInterface
{
    /**
     * @var PermissionTypeCollectionInterface
     */
    protected $permissionTypeCollection;

    /**
     * @var BypassAccessCheckerInterface
     */
    protected $bypassAccessChecker;

    /**
     * @internal
     */
    public function __construct()
    {
        $this->setPermissionTypeCollection(new PermissionTypeCollection());
    }

    /**
     * {@inheritdoc}
     */
    public function setPermissionTypeCollection(PermissionTypeCollectionInterface $permissionTypeCollection)
    {
        $this->permissionTypeCollection = $permissionTypeCollection;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getPermissionTypeCollection()
    {
        return $this->permissionTypeCollection;
    }

    /**
     * {@inheritdoc}
     */
    public function setBypassAccessChecker(BypassAccessCheckerInterface $bypassAccessChecker)
    {
        $this->bypassAccessChecker = $bypassAccessChecker;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getBypassAccessChecker()
    {
        return $this->bypassAccessChecker;
    }

    /**
     * {@inheritdoc}
     */
    public function getValidPermissionKeys()
    {
        return array_merge(
            $this->getPermissionTypeCollection()->getReservedPermissionKeys(),
            array_keys($this->getPermissionTypeCollection()->toArray())
        );
    }

    /**
     * {@inheritdoc}
     */
    public function checkAccess($permissions, $context = null, $allowBypass = true)
    {
        if (!is_array($permissions) && !is_string($permissions) && !is_bool($permissions)) {
            throw new InvalidArgumentTypeException(
                'The permissions parameter must be an array or in certain cases a string or boolean.'
            );
        }
        if (!is_null($context) && !is_array($context) && !is_object($context)) {
            throw new InvalidArgumentTypeException('The context parameter must be an array or object.');
        }
        if (!is_bool($allowBypass)) {
            throw new InvalidArgumentTypeException('The allow_bypass parameter must be a boolean.');
        }

        if (is_array($permissions)) {
            // uppercasing of no_bypass key for backward compatibility
            if (is_array($permissions) && array_key_exists('no_bypass', $permissions)) {
                $permissions['NO_BYPASS'] = $permissions['no_bypass'];
                unset($permissions['no_bypass']);
            }

            $allowBypass = $this->checkAllowBypass($permissions, $context, $allowBypass);

            unset($permissions['NO_BYPASS']);
        }

        if ($allowBypass && $this->checkBypassAccess($context)) {
            return true;
        }

        if (is_array($permissions) && count($permissions)) {
            return $this->processOR($permissions, null, $context);
        }

        return $this->dispatch($permissions);
    }

    /**
     * @param array             $permissions
     * @param array|object|null $context
     * @param bool              $allowBypass
     * @internal
     *
     */
    protected function checkAllowBypass(array $permissions, $context, $allowBypass)
    {
        if (!$allowBypass) {
            return $allowBypass;
        }

        if (!array_key_exists('NO_BYPASS', $permissions)) {
            return $allowBypass;
        }

        if (is_bool($permissions['NO_BYPASS'])) {
            return !$permissions['NO_BYPASS'];
        }

        if (is_string($permissions['NO_BYPASS'])) {
            $noBypassUpper = strtoupper($permissions['NO_BYPASS']);
            if (!in_array($noBypassUpper, ['TRUE', 'FALSE'])) {
                throw new InvalidArgumentValueException(
                    'The NO_BYPASS value must be a boolean, a boolean string or an array. Current value: ' .
                    print_r($permissions['NO_BYPASS'], true)
                );
            }

            if ('TRUE' === $noBypassUpper) {
                return false;
            }
            if ('FALSE' === $noBypassUpper) {<commit_msg>Add return type in docblock<commit_after><?php

namespace Ordermind\LogicalPermissions;

use Ordermind\LogicalPermissions\Exceptions\InvalidArgumentTypeException;
use Ordermind\LogicalPermissions\Exceptions\InvalidArgumentValueException;
use Ordermind\LogicalPermissions\Exceptions\InvalidReturnTypeException;
use Ordermind\LogicalPermissions\Exceptions\InvalidValueForLogicGateException;
use Ordermind\LogicalPermissions\Exceptions\PermissionTypeNotRegisteredException;

/**
 * Checks access based on registered permission types, a permission tree and a context.
 */
class AccessChecker implements AccessCheckerInterface
{
    /**
     * @var PermissionTypeCollectionInterface
     */
    protected $permissionTypeCollection;

    /**
     * @var BypassAccessCheckerInterface
     */
    protected $bypassAccessChecker;

    /**
     * @internal
     */
    public function __construct()
    {
        $this->setPermissionTypeCollection(new PermissionTypeCollection());
    }

    /**
     * {@inheritdoc}
     */
    public function setPermissionTypeCollection(PermissionTypeCollectionInterface $permissionTypeCollection)
    {
        $this->permissionTypeCollection = $permissionTypeCollection;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getPermissionTypeCollection()
    {
        return $this->permissionTypeCollection;
    }

    /**
     * {@inheritdoc}
     */
    public function setBypassAccessChecker(BypassAccessCheckerInterface $bypassAccessChecker)
    {
        $this->bypassAccessChecker = $bypassAccessChecker;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getBypassAccessChecker()
    {
        return $this->bypassAccessChecker;
    }

    /**
     * {@inheritdoc}
     */
    public function getValidPermissionKeys()
    {
        return array_merge(
            $this->getPermissionTypeCollection()->getReservedPermissionKeys(),
            array_keys($this->getPermissionTypeCollection()->toArray())
        );
    }

    /**
     * {@inheritdoc}
     */
    public function checkAccess($permissions, $context = null, $allowBypass = true)
    {
        if (!is_array($permissions) && !is_string($permissions) && !is_bool($permissions)) {
            throw new InvalidArgumentTypeException(
                'The permissions parameter must be an array or in certain cases a string or boolean.'
            );
        }
        if (!is_null($context) && !is_array($context) && !is_object($context)) {
            throw new InvalidArgumentTypeException('The context parameter must be an array or object.');
        }
        if (!is_bool($allowBypass)) {
            throw new InvalidArgumentTypeException('The allow_bypass parameter must be a boolean.');
        }

        if (is_array($permissions)) {
            // uppercasing of no_bypass key for backward compatibility
            if (is_array($permissions) && array_key_exists('no_bypass', $permissions)) {
                $permissions['NO_BYPASS'] = $permissions['no_bypass'];
                unset($permissions['no_bypass']);
            }

            $allowBypass = $this->checkAllowBypass($permissions, $context, $allowBypass);

            unset($permissions['NO_BYPASS']);
        }

        if ($allowBypass && $this->checkBypassAccess($context)) {
            return true;
        }

        if (is_array($permissions) && count($permissions)) {
            return $this->processOR($permissions, null, $context);
        }

        return $this->dispatch($permissions);
    }

    /**
     * @param array             $permissions
     * @param array|object|null $context
     * @param bool              $allowBypass
     *
     * @return bool
     * @internal
     *
     */
    protected function checkAllowBypass(array $permissions, $context, $allowBypass)
    {
        if (!$allowBypass) {
            return $allowBypass;
        }

        if (!array_key_exists('NO_BYPASS', $permissions)) {
            return $allowBypass;
        }

        if (is_bool($permissions['NO_BYPASS'])) {
            return !$permissions['NO_BYPASS'];
        }

        if (is_string($permissions['NO_BYPASS'])) {
            $noBypassUpper = strtoupper($permissions['NO_BYPASS']);
            if (!in_array($noBypassUpper, ['TRUE', 'FALSE'])) {
                throw new InvalidArgumentValueException(
                    'The NO_BYPASS value must be a boolean, a boolean string or an array. Current value: ' .
                    print_r($permissions['NO_BYPASS'], true)
                );
            }

            if ('TRUE' === $noBypassUpper) {
                return false;
            }
            if ('FALSE' === $noBypassUpper) {
{'fraction_non_alphanumeric': 0.11168109436785295, 'fraction_numerical': 0.0, 'mean_word_length': 2.467210077806595, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7519103', 'n_tokens_mistral': 2523, 'n_tokens_neox': 2504, 'n_words': 482}