Skip to main content

Overview

The Restrictions class manages a collection of restrictions that limit entity access based on various criteria (date, location, entity relationships, etc.). It provides methods to check, retrieve, and register custom restriction types.

Constructor

Creates a new Restrictions instance with a restriction list.
public function __construct(array $list)
list
array
required
Nested array of restrictions organized by category and type, containing both personal (p) and global (g) restrictions
Typically, you don’t instantiate this directly. Use GAC::getRestrictions() instead.
// Retrieved from GAC
$restrictions = $gac->setEntity('user', 123)->getRestrictions();

Methods

has()

Checks if restrictions exist for a specific category.
public function has(string $categoryCode): bool
categoryCode
string
required
The restriction category code (e.g., 'by_date', 'by_branch', 'by_ip')
return
bool
Returns true if restrictions exist for the category, false otherwise
if ($restrictions->has('by_date')) {
    // Date restrictions are active
    echo "Date-based access control is enabled";
}

if ($restrictions->has('by_branch')) {
    // Branch restrictions are active
    echo "Branch-based access control is enabled";
}

get()

Retrieves a Restriction instance for a specific category.
public function get(string $categoryCode): mixed
categoryCode
string
required
The restriction category code
return
mixed
Returns an instance of the registered restriction class (e.g., ByDate, ByEntity), or null if no restrictions exist for that category
Throws:
  • Exception if restriction data is invalid
  • Exception if no handler is defined for the category
$dateRestriction = $restrictions->get('by_date');

if ($dateRestriction !== null) {
    // Validate against current date
    $isAllowed = $dateRestriction->run(['date' => time()]);
    
    if (!$isAllowed) {
        $error = $dateRestriction->getError();
        throw new Exception('Access denied: ' . $error['method']);
    }
}

getList()

Returns the complete restriction list.
public function getList(): array
return
array
Nested array of all restrictions indexed by category and type
$allRestrictions = $restrictions->getList();

foreach ($allRestrictions as $category => $types) {
    echo "Category: $category\n";
    foreach ($types as $type => $data) {
        echo "  Type: $type\n";
        if (isset($data['p'])) {
            echo "    Personal restriction ID: {$data['p']['i']}\n";
        }
        if (isset($data['g'])) {
            echo "    Global restriction ID: {$data['g']['i']}\n";
        }
    }
}

setList()

Replaces the entire restriction list.
public function setList(array $list): Restrictions
list
array
required
New restriction array to replace the current list
return
Restrictions
Returns the Restrictions instance for method chaining
$newRestrictions = [
    'by_date' => [
        'in_range' => [
            'p' => [
                'i' => 10,
                'd' => ['sd' => '2024-01-01', 'ed' => '2024-12-31']
            ]
        ]
    ]
];

$restrictions->setList($newRestrictions);

register()

Registers a custom restriction class.
public static function register(string $alias, string $className): void
alias
string
required
Alias/category code for the restriction type (e.g., 'by_ip', 'by_location')
className
string
required
Fully qualified class name that extends Restriction base class
Throws: InvalidArgumentException if class doesn’t extend Restriction
use DancasDev\GAC\Restrictions\Restrictions;
use App\Restrictions\ByIpAddress;

// Register custom restriction
Restrictions::register('by_ip', ByIpAddress::class);

// Now you can use it
$restrictions = $gac->getRestrictions();
if ($restrictions->has('by_ip')) {
    $ipRestriction = $restrictions->get('by_ip');
    $isAllowed = $ipRestriction->run(['ip' => $_SERVER['REMOTE_ADDR']]);
}

Built-in Restriction Types

GAC includes two built-in restriction handlers:
by_date
ByDate
Time-based access restrictions (before, after, in_range, out_range)
by_branch
ByEntity
Entity-based restrictions (allow, deny specific entities)

Restriction Data Structure

Each restriction category contains types with personal and/or global restrictions:
[
    'category_code' => [
        'type_code' => [
            'p' => [  // Personal restriction
                'i' => 123,  // Restriction ID
                'd' => [...]  // Restriction data
            ],
            'g' => [  // Global restriction
                'i' => 456,  // Restriction ID
                'd' => [...]  // Restriction data
            ]
        ]
    ]
]
p
array
Personal restrictions (entity-specific or role-based)
g
array
Global restrictions (apply to all entities)
i
int
Database ID of the restriction record
d
array
Restriction-specific data (varies by restriction type)

Usage Examples

Basic Restriction Check

$gac = new GAC();
$gac->setDatabase($pdo)
    ->setEntity('user', 456);

$restrictions = $gac->getRestrictions();

// Check if date restrictions apply
if ($restrictions->has('by_date')) {
    $dateRestriction = $restrictions->get('by_date');
    
    if (!$dateRestriction->run(['date' => time()])) {
        throw new Exception('Access denied: outside allowed time window');
    }
}

Multiple Restriction Validation

function validateAllRestrictions($restrictions, $context) {
    $categories = ['by_date', 'by_branch', 'by_ip'];
    
    foreach ($categories as $category) {
        if (!$restrictions->has($category)) {
            continue;
        }
        
        $restriction = $restrictions->get($category);
        if (!$restriction->run($context)) {
            $error = $restriction->getError();
            return [
                'allowed' => false,
                'reason' => "Restricted by {$category}",
                'method' => $error['method'] ?? 'unknown'
            ];
        }
    }
    
    return ['allowed' => true];
}

// Usage
$result = validateAllRestrictions($restrictions, [
    'date' => time(),
    'entity' => $branchId,
    'ip' => $_SERVER['REMOTE_ADDR']
]);

if (!$result['allowed']) {
    die('Access denied: ' . $result['reason']);
}

Custom Restriction Implementation

use DancasDev\GAC\Restrictions\Restriction;

class ByIpAddress extends Restriction {
    protected array $methods = [
        'whitelist' => 'whitelist',
        'blacklist' => 'blacklist',
    ];
    
    public function whitelist(array $internalData, array $externalData): bool {
        if (!$this->validateDataIntegrity($internalData, ['ips' => ['array']])) {
            return false;
        }
        
        if (!$this->validateDataIntegrity($externalData, ['ip' => ['string']])) {
            return false;
        }
        
        return in_array($externalData['ip'], $internalData['ips']);
    }
    
    public function blacklist(array $internalData, array $externalData): bool {
        if (!$this->validateDataIntegrity($internalData, ['ips' => ['array']])) {
            return false;
        }
        
        if (!$this->validateDataIntegrity($externalData, ['ip' => ['string']])) {
            return false;
        }
        
        return !in_array($externalData['ip'], $internalData['ips']);
    }
}

// Register and use
Restrictions::register('by_ip', ByIpAddress::class);

$restrictions = $gac->getRestrictions();
if ($restrictions->has('by_ip')) {
    $ipRestriction = $restrictions->get('by_ip');
    $allowed = $ipRestriction->run(['ip' => $_SERVER['REMOTE_ADDR']]);
}

Date Restriction Example

// Check if user can access during business hours
$restrictions = $gac->getRestrictions();

if ($restrictions->has('by_date')) {
    $dateRestriction = $restrictions->get('by_date');
    
    // Current timestamp
    $now = time();
    
    if (!$dateRestriction->run(['date' => $now])) {
        $error = $dateRestriction->getError();
        
        switch ($error['method']) {
            case 'before':
                die('Access not yet available');
            case 'after':
                die('Access period has ended');
            case 'in_range':
                die('Access only allowed during specific dates');
            case 'out_range':
                die('Access blocked during this period');
        }
    }
}

Entity/Branch Restriction Example

// Check if user can access specific branch
$restrictions = $gac->getRestrictions();

if ($restrictions->has('by_branch')) {
    $branchRestriction = $restrictions->get('by_branch');
    
    $requestedBranch = $_GET['branch_id'];
    
    if (!$branchRestriction->run(['entity' => $requestedBranch])) {
        throw new Exception('You do not have access to this branch');
    }
}

Combining with Permissions

function checkFullAccess($gac, $moduleCode, $branchId) {
    // Check permissions first
    $permissions = $gac->getPermissions();
    if (!$permissions->has($moduleCode)) {
        return ['allowed' => false, 'reason' => 'No permission'];
    }
    
    // Check restrictions
    $restrictions = $gac->getRestrictions();
    
    // Date restriction
    if ($restrictions->has('by_date')) {
        $dateRestriction = $restrictions->get('by_date');
        if (!$dateRestriction->run(['date' => time()])) {
            return ['allowed' => false, 'reason' => 'Time restriction'];
        }
    }
    
    // Branch restriction
    if ($restrictions->has('by_branch')) {
        $branchRestriction = $restrictions->get('by_branch');
        if (!$branchRestriction->run(['entity' => $branchId])) {
            return ['allowed' => false, 'reason' => 'Branch restriction'];
        }
    }
    
    return ['allowed' => true];
}

// Usage
$result = checkFullAccess($gac, 'invoices', 'branch-123');
if (!$result['allowed']) {
    die('Access denied: ' . $result['reason']);
}

See Also

Build docs developers (and LLMs) love