Permissions
Office App has a built-in role-based access control (RBAC) system. You can control access at the model level, action level, and field level.
Model-Level: Permissive vs. Restrictive
In meta(), set the default access policy:
| public static function meta(): ?ModelMeta
{
return (new ModelMeta('Tasks', 'check-square'))
->enable()
->permissive(); // everyone can do everything (default)
}
|
| public static function meta(): ?ModelMeta
{
return (new ModelMeta('Contracts', 'file-text'))
->enable()
->restrictive(); // deny everything, then grant explicitly
}
|
| Policy |
Behavior |
permissive() |
All authenticated users can view, edit, create, delete. Grant/deny rules narrow access. |
restrictive() |
No access by default. You must explicitly grant permissions. |
Granting Permissions in Hooks
Set up permissions in App/Hooks.php:
| <?php
namespace App;
use System\HookContext;
use System\Permission;
use App\Model\Contracts\Contract;
use App\Model\Contracts\ContractType;
use App\Model\Contracts\ContractReminder;
class Hooks extends \System\Hooks
{
public function bootstrap(): void
{
$this->setupPermissions();
Permission::flush();
}
private function setupPermissions(): void
{
// Create groups and assign users
Permission::createGroup('Editors');
Permission::createGroup('Managers');
Permission::addUserToGroup('editor', 'Editors');
Permission::addUserToGroup('manager', 'Managers');
// Revoke all existing rules (start fresh)
Permission::revokeAll();
// Editors: can view and edit contracts, view-only for types
Permission::on(Contract::class)
->grant([Permission::VIEW, Permission::EDIT])
->to('Editors');
Permission::on(ContractType::class)
->grant([Permission::VIEW])
->to('Editors');
Permission::on(ContractReminder::class)
->grant(Permission::ALL_ACTIONS)
->to('Editors');
// Managers: full access to everything
Permission::on(Contract::class)
->grant(Permission::ALL_ACTIONS)
->to('Managers');
Permission::on(ContractType::class)
->grant(Permission::ALL_ACTIONS)
->to('Managers');
}
}
|
Available Permission Constants
| Constant |
Allows |
Permission::VIEW |
View records in list and detail |
Permission::CREATE |
Create new records |
Permission::EDIT |
Edit existing records |
Permission::DELETE |
Soft-delete and hard-delete |
Permission::ALL_ACTIONS |
All of the above |
Field-Level Visibility
Control which fields specific users can see using beforeRender():
| use System\Auth;
protected function beforeRender(): void
{
// Only superadmins see the admin notes field
$this->getProperty('admin_notes')?->setVisible(Auth::isSuperAdmin());
// Only admins can edit the status field
$this->getProperty('status')?->setReadonly(!Auth::isAdmin());
}
|
Action-Level Permissions
Control who can trigger specific actions:
| public function getActions(): array
{
return [
...parent::getActions(),
(new Action('approve', 'Approve'))
->withIcon('check')
->showWhen(fn($m) => Auth::isAdmin()) // only admins see it
->withEnabled(fn($m) => $m->status === 'review'), // only in review state
];
}
|
Record-Level Permissions
Override can*() methods to control access per record:
| // Only the creator can edit their own records
public function canSave(): bool
{
if ($this->isNew()) return true;
return $this->created_by === Auth::userId() || Auth::isAdmin();
}
// Only admins can permanently delete
public function canDelete(): bool
{
return Auth::isAdmin();
}
// Disable checkout for archived records
public function canCheckout(): bool
{
return $this->getState()?->name !== 'archived';
}
|
Custom Permission Checks
Use checkPermission() for model-wide access control:
| public static function checkPermission(): bool
{
return Auth::isSuperAdmin(); // entire model restricted to superadmins
}
|
User & Admin Checks
| use System\Auth;
use System\Model\User;
Auth::userId() // current user ID
Auth::user() // current User object
Auth::isSuperAdmin() // checks sys_user.is_superadmin flag
Auth::isAdmin() // superadmin OR member of admin group
User::isSuperAdmin() // instance method on User object
User::isAdmin() // instance method on User object
|