MMOframework
Why AI Playground Libraries Documentation Search Agency
FR EN
Index

AccessController

MMO\oauth\controllers · 1 symbol · generated 27 Oct 2026

class

AccessController

AccessController.php:37
class MMO\oauth\controllers\AccessController extends MMO\core\classes\aController
Namespace
MMO\oauth\controllers
Extends
aController
Todo
implements route to get a token from a client and set the token in the authorization header

Index

CSRF_KEY
allowAnonymous
allowUserCreationWithCode
anonymousScopes
clients
codeAuthentifiers
dataControllers
heldScopes
holder
loginTpl
privateCollections
privateKey
publicKey
rightsCollections
rightsScope
route
superScope
user
carriesRights($entity)Tell if $entity carries rights: a role (any change), a client whose scopes or roles changed, a token, an entity of
checkCommitRights($entity)Check that the client of a data api request can write $entity, if it carries rights or is private (carriesRights, $privateCollections): it held $rightsScope (or it changes its own pr…
checkCommitScopes($entity)Check that the user can commit $entity's changes: its status, its creation, its changes or its removal
checkPrivatePaths($query)What a query returns tells the values it filters or sorts on: of the entities of a private collection ($privateCollections), a client without the rights filters and sorts only on what it reads…
collectionValue($values, $collection)
doLogin($route)
extractUser($route)
filterPrivate($query)Leave out of a data api listing what $privateCollections keep from a client without the rights: a collection none, the tokens of others, and opacify the other clients of a collection self,…
forgotPassword($route)
getCodeAuthentifier()
getRedirectUri($route, $default)
getUser()
hasUserScope($uid)Check if user or anonymous user has a given scope
hideRecursiveContent($contents, $required)Hide recursively the children content base on user scopes: pages.{path}, and the scopes the content and its parents ask besides (Content::$scopes: admin for a folder of administration pages)
holds($scope)Tell if the client of the request held $scope when the request started: what it changed since (its own role, its own scopes) is left aside
holdsRights()
isDataApi()Tell if the current route is one of the generic data api ($dataControllers), which serves any collection by its name and writes whatever properties its client sends
isLeftToItsModule($value)Tell if the rights on an entity, or on a collection, are its module's to check: everywhere but in the routes of the generic data api ($dataControllers), where the data.* scopes decide, as fo…
isOwn($entity)
isReadablePath($collection, $path)
isRequestQuery($query)
isUnserved($value)
isUserAllowed($uids)Check if user or anonymous user is allowed to do something
listRecursiveContentScope($request, $content, $required)
login($route)
loginJSON($route)
logout($route)
onCommit($commit)
onModeAccess($event)a mode with a scope is offered to whoever holds it (mmo.client's Modes)
onModesPreference($event)The modes the user saved (config.modes), else the ones their roles give (Role::$modes): the first role saying a level gives it, the layers of every role add up.
onNotificationRecipient($event)whose notifications the notification centre shows: the user's
onPageContents($pageContents)Filter content using scopes pages.*
onQuery($query)
onRoute($route)
onScopes($request)
onScopesListModes($request)a mode's scope is listed with the others, in the roles' editor
opacifyPrivateReferences($entity, $depth)Opacify the entities of a private collection ($privateCollections) that $entity references, but the client's own: a group listing its users shows their uid and title only.
privacyOf($collection)
readablePaths($collection)
refusing()
renderNoToken($route, $exception)
resetPassword($route)
restoreAccount($route)Leave a session opened by « Changer de compte » (doLogin's switchAccount) for one of the account that opened it, without its password: that account typed it to open this one.
routeCreateUser($route)
routeGetUserConfig($route)
routePutUserConfig($route)
routeScopes($route)
routeScopesCatalog($route)What the scopes' editor (<mmo-scopes>) needs to explain and check the rules of a role or a client - scopes: the scopes listed (ScopesList), id => text; - actions: scope => action => text…
scopeNames($uids, $open)
sendPasswordReset($login)Mail $login's account a link that logs it in to choose a new password (login?token=...&reset=true).

Constants1

CSRF_KEY

const CSRF_KEY = 'loginCSRF'

Properties17

allowAnonymous

bool $allowAnonymous = true
Type
bool

allowUserCreationWithCode

protected bool $allowUserCreationWithCode = false
Type
bool

anonymousScopes

array $anonymousScopes = []
Type
array

codeAuthentifiers

?MMO\core\entities\Collection $codeAuthentifiers = null
Type
null | Collection

dataControllers

array $dataControllers = […2 items]
Type
array

heldScopes

protected ?array $heldScopes = null
Type
null | array

holder

protected ?MMO\oauth\interfaces\iClient $holder = null
Type
null | iClient

loginTpl

string $loginTpl = 'login.phtml'
Type
string

privateCollections

array $privateCollections = []
Type
array

privateKey

MMO\oauth\keys\PrivateKey $privateKey
Type
PrivateKey

publicKey

MMO\oauth\keys\PublicKey $publicKey
Type
PublicKey

rightsCollections

array $rightsCollections = []
Type
array

rightsScope

string $rightsScope = 'sudo'
Type
string
See
$privateCollections in full. An application whose administrators hold another scope names it (admin)

route

protected ?MMO\core\server\Route $route = null
Type
null | Route

superScope

string $superScope = 'sudo'
Type
string

user

protected ?MMO\oauth\interfaces\iClient $user = null
Type
null | iClient

Methods50

carriesRights($entity)

AccessController.php:223

Tell if $entity carries rights: a role (any change), a client whose scopes or roles changed, a token, an entity of

protected function carriesRights(MMO\core\interfaces\iEntity $entity): bool
See
$rightsCollections
$entityiEntity
returnsbool

checkCommitRights($entity)

AccessController.php:239

Check that the client of a data api request can write $entity, if it carries rights or is private (carriesRights, $privateCollections): it held $rightsScope (or it changes its own private entity, but not its rights), and, without $superScope, it neither changes its own rights nor writes rights granting that scope.

protected function checkCommitRights(MMO\core\interfaces\iEntity $entity): voidNobody changes the status of its own account (archives itself), an administrator included
$entityiEntity
returnsvoid
throws(403) if it cannot: the attempt is logged
$this->checkCommitRights($role); // a client without `admin` that gave its own role `admin: true`: refused

checkCommitScopes($entity)

AccessController.php:623

Check that the user can commit $entity's changes: its status, its creation, its changes or its removal

protected function checkCommitScopes(MMO\core\interfaces\iEntity $entity): void
$entityiEntity
returnsvoid
throws(403) if it cannot: a right the user has not, not a malformed request
$this->checkCommitScopes($order); // an order created needs `data.main.orders.{id}#create`

checkPrivatePaths($query)

AccessController.php:315

What a query returns tells the values it filters or sorts on: of the entities of a private collection ($privateCollections), a client without the rights filters and sorts only on what it reads of them, opacified (readablePaths), its own included -- not ?filters[emails/default][$regex]=^a nor a full text search ($text), which found the others' e-mails or scopes out one character at a time (my.oviepro #90). Wherever they are: in the collection queried, or referenced by it (owner/emails/default)

protected function checkPrivatePaths(MMO\core\entities\Query $query): void
$queryQuery
returnsvoid
throws(403) for a filter or a sort on any other path
$this->checkPrivatePaths($users->query(['emails/default' => ['$regex' => '^a']])); // throws, without `admin`

collectionValue($values, $collection)

AccessController.php:203
protected function collectionValue(array $values, MMO\core\interfaces\iCollection $collection): mixed
$valuesarray
$collectioniCollection
returnsmixedthe value $values gives $collection, or null
$this->collectionValue(['data.main.users' => 'self'], $users); // 'self'

extractUser($route)

AccessController.php:381
#[MMO\core\attributes\APIRoute('**', order: -100, options: ['hidden' => true])] function extractUser(MMO\core\server\Route $route): void
$routeRoute
returnsvoid

filterPrivate($query)

AccessController.php:273

Leave out of a data api listing what $privateCollections keep from a client without the rights: a collection none, the tokens of others, and opacify the other clients of a collection self, wherever they are referenced

protected function filterPrivate(MMO\core\entities\Query $query): void
$queryQuery
returnsvoid
throws(403) for a collection none

forgotPassword($route)

AccessController.php:717
#[MMO\core\attributes\APIRoute('POST|login/forgot?login=email', 'reset password when forgotten', order: -300, mediaTypes: ['html'])] function forgotPassword(MMO\core\server\Route $route): void
$routeRoute
returnsvoid

hideRecursiveContent($contents, $required)

AccessController.php:496

Hide recursively the children content base on user scopes: pages.{path}, and the scopes the content and its parents ask besides (Content::$scopes: admin for a folder of administration pages)

protected function hideRecursiveContent(array $contents, string $required = ''): void
$contentsarray
$required = ''stringthe scopes its parents ask, space-separated
returnsvoid
$this->hideRecursiveContent($contents); // `admin/mongo` hidden to a role with `pages` but not `admin`

holds($scope)

AccessController.php:182

Tell if the client of the request held $scope when the request started: what it changed since (its own role, its own scopes) is left aside

function holds(string $scope): bool
$scopestring
returnsbool
$this->holds('admin'); // false for a client that gave itself `admin` in this request

isDataApi()

AccessController.php:167

Tell if the current route is one of the generic data api ($dataControllers), which serves any collection by its name and writes whatever properties its client sends

function isDataApi(): bool
returnsbool
$this->isDataApi(); // true in `PUT data/main/roles.json`, false in mmo.edms' upload

isLeftToItsModule($value)

AccessController.php:148
Tell if the rights on an entity, or on a collection, are its module's to check: everywhere but in the routes of the generic data api ([`$dataControllers`](https://mmoframework.fr/en/documentation/mmo.oauth/php/controllers/AccessController.md#accesscontroller-datacontrollers)), where the `data.*` scopes decide, as for any other. So are - an entity its module guards ([`iGuarded`](https://mmoframework.fr/en/documentation/mmo.oauth/php/interfaces/iGuarded.md#iguarded)); - the entities of a repository RepositoryController does not serve: no `data.{repository}` scope names them, since the data api cannot reach them -- a board kept in a file of its own, a GitHub project (mmo.admin's and mmo.git's kanban repositories), written by the module that holds them, which checks its own rights.function isLeftToItsModule(MMO\core\interfaces\iEntity|MMO\core\interfaces\iCollection $value): bool
$valueiEntity | iCollection
returnsbool
$this->isLeftToItsModule($file); // true in mmo.edms' routes, false in RepositoryController's `data/main/files.json`

isOwn($entity)

AccessController.php:213
protected function isOwn(MMO\core\interfaces\iEntity $entity): bool
$entityiEntity
returnsbooltrue if $entity is the client of the request, or one of its tokens

isReadablePath($collection, $path)

AccessController.php:333
protected function isReadablePath(MMO\core\interfaces\iCollection $collection, string $path): bool
$collectioniCollection
$pathstringa path a query of $collection filters or sorts on (owner/emails/default, or owner.emails.default)
returnsboolfalse if it reads, in a collection of $privateCollections, more than readablePaths
$this->isReadablePath($files, 'owner/username'); // true: an opacified user shows its title

isRequestQuery($query)

AccessController.php:300
protected function isRequestQuery(MMO\core\entities\Query $query): bool
$queryQuery
returnsbooltrue if $query is the one the client asked the data api for (its filters, sort and search): a listing's (RepositoryController::getQuery), any of the statistics'. Not those the request runs on its way (a @unique check of the account it saves), which are the server's

listRecursiveContentScope($request, $content, $required)

AccessController.php:644
protected function listRecursiveContentScope( MMO\oauth\events\ScopesList $request, MMO\client\entities\Content $content, string $required = '' ): void
$requestScopesList
$contentContent
$required = ''stringthe scopes the parents of $content ask besides their own (hideRecursiveContent)
returnsvoid

login($route)

AccessController.php:812
#[MMO\core\attributes\APIRoute('login', 'login a user using a password', order: -200, mediaTypes: ['html'])] function login(MMO\core\server\Route $route): void
$routeRoute
returnsvoid

loginJSON($route)

AccessController.php:806
#[MMO\core\attributes\APIRoute('GET|login.json?username={username}&password={password}', 'login a user using a password and get a token in a json file', order: -200, mediaTypes: ['json'])] function loginJSON(MMO\core\server\Route $route): MMO\core\server\Response
$routeRoute
returnsResponse

logout($route)

AccessController.php:686
#[MMO\core\attributes\APIRoute('logout', 'logout current user', order: -300, mediaTypes: ['html'])] function logout(MMO\core\server\Route $route): void
$routeRoute
returnsvoid

onCommit($commit)

AccessController.php:596
#[MMO\core\attributes\Listen('MMO\\core\\events\\Commit', order: 1000)] function onCommit(MMO\core\events\Commit $commit): void
$commitCommit
returnsvoid

onModeAccess($event)

AccessController.php:508

a mode with a scope is offered to whoever holds it (mmo.client's Modes)

#[MMO\core\attributes\Listen('MMO\\client\\events\\ModeAccess')] function onModeAccess(MMO\client\events\ModeAccess $event): void
$eventModeAccess
returnsvoid

onModesPreference($event)

AccessController.php:517

The modes the user saved (config.modes), else the ones their roles give (Role::$modes): the first role saying a level gives it, the layers of every role add up.

#[MMO\core\attributes\Listen('MMO\\client\\events\\ModesPreference')] function onModesPreference(MMO\client\events\ModesPreference $event): void
$eventModesPreference
returnsvoid

onNotificationRecipient($event)

AccessController.php:537

whose notifications the notification centre shows: the user's

#[MMO\core\attributes\Listen('MMO\\client\\events\\NotificationRecipient')] function onNotificationRecipient(MMO\client\events\NotificationRecipient $event): void

onPageContents($pageContents)

AccessController.php:558

Filter content using scopes pages.*

#[MMO\core\attributes\Listen('MMO\\client\\events\\PageContents', order: 1000)] function onPageContents(MMO\client\events\PageContents $pageContents): void
$pageContentsPageContents
returnsvoid

onQuery($query)

AccessController.php:565
#[MMO\core\attributes\Listen('MMO\\core\\entities\\Query', order: 1000)] function onQuery(MMO\core\entities\Query $query): void
$queryQuery
returnsvoid

onScopes($request)

AccessController.php:655
#[MMO\core\attributes\Listen('MMO\\oauth\\events\\ScopesList')] function onScopes(MMO\oauth\events\ScopesList $request): void
$requestScopesList
returnsvoid

onScopesListModes($request)

AccessController.php:543

a mode's scope is listed with the others, in the roles' editor

#[MMO\core\attributes\Listen('MMO\\oauth\\events\\ScopesList')] function onScopesListModes(MMO\oauth\events\ScopesList $request): void
$requestScopesList
returnsvoid

opacifyPrivateReferences($entity, $depth)

AccessController.php:361

Opacify the entities of a private collection ($privateCollections) that $entity references, but the client's own: a group listing its users shows their uid and title only. Embedded entities are looked into

protected function opacifyPrivateReferences(MMO\core\classes\aEntity $entity, int $depth = 3): void
$entityaEntity
$depth = 3inthow deep embedded entities are looked into
returnsvoid

refusing()

AccessController.php:104
protected function refusing(): MMO\core\server\Route
returnsRoutewhat a refusal answers: the request this controller routed, else the application's current one (a command of a script routing AdminController alone), else a request of the command line

resetPassword($route)

AccessController.php:759
#[MMO\core\attributes\APIRoute('POST|login/reset', 'endpoint to reset password', order: -300, mediaTypes: ['html'])] function resetPassword(MMO\core\server\Route $route): void
$routeRoute
returnsvoid

restoreAccount($route)

AccessController.php:696

Leave a session opened by « Changer de compte » (doLogin's switchAccount) for one of the account that opened it, without its password: that account typed it to open this one. The session left ends.

#[MMO\core\attributes\APIRoute('login/restore', 'return to the account that switched to this one', order: -300, mediaTypes: ['html'])] function restoreAccount(MMO\core\server\Route $route): void
$routeRoute
returnsvoid

routeCreateUser($route)

AccessController.php:901
#[MMO\core\attributes\APIRoute('POST|user/create', 'create a user', body: […8 items])] function routeCreateUser(MMO\core\server\Route $route): MMO\core\server\Response
$routeRoute
returnsResponse

routeGetUserConfig($route)

AccessController.php:934
#[MMO\core\attributes\APIRoute('GET|user/config.json', 'get user configuration', mediaTypes: ['json'])] function routeGetUserConfig(MMO\core\server\Route $route): MMO\core\server\Response
$routeRoute
returnsResponse

routePutUserConfig($route)

AccessController.php:919
#[MMO\core\attributes\APIRoute('PUT|user/config.json', 'set user configuration', mediaTypes: ['json'])] function routePutUserConfig(MMO\core\server\Route $route)
$routeRoute
returns

routeScopes($route)

AccessController.php:946
#[MMO\core\attributes\APIRoute('user/scopes.json?uid={?uid}', 'get scopes for current user', mediaTypes: ['json'])] function routeScopes(MMO\core\server\Route $route): array
$routeRoute
returnsarray

routeScopesCatalog($route)

AccessController.php:993
What the scopes' editor (`<mmo-scopes>`) needs to explain and check the rules of a role or a client - `scopes`: the scopes listed ([`ScopesList`](https://mmoframework.fr/en/documentation/mmo.oauth/php/events/ScopesList.md#scopeslist)), id => text; - `actions`: scope => action => text, the actions checked under a scope and the scopes below it; - `open`: the scopes whose children are ids (`data.main.orders.{id}`); - `needs`: scope => the scopes, space-separated, it also needs (a page whose folder asks `admin`); - `names`: the title of what a rule on an id names (`data.main.roles.{id}` => the role's label), for the rules of `uid` and of the roles; - `roles`: the roles, in their order, with their scopes: every role for a holder of [`$rightsScope`](https://mmoframework.fr/en/documentation/mmo.oauth/php/controllers/AccessController.md#accesscontroller-rightsscope), the client's own otherwise; - `target`: `uid`'s `{uid, kind: role|client, roles: [uid]}`, null without it.#[MMO\core\attributes\APIRoute('user/scopes/catalog.json?uid={?uid}', 'the scopes, their actions and the roles, for the scopes\' editor', mediaTypes: ['json'])] function routeScopesCatalog(MMO\core\server\Route $route): array
$routeRoute
returnsarray
GET user/scopes/catalog.json?uid=main/roles/67ce...

scopeNames($uids, $open)

AccessController.php:1040
protected function scopeNames(array $uids, array $open): array
$uidsarrayrules
$openarraythe scopes whose children are ids (data.main.roles)
returnsarraystring> scope => the title of the entity it names, for those naming one
$this->scopeNames(['data.main.roles.67ce...#edit'], ['data.main.roles']); // ['data.main.roles.67ce...' => 'admin']

sendPasswordReset($login)

AccessController.php:736

Mail $login's account a link that logs it in to choose a new password (login?token=...&reset=true).

protected function sendPasswordReset(string $login): bool
$loginstringa username, or an account's email.
returnsboolfalse when nothing was sent: no active account with an email answers to $login.
throwsif its tokens cannot be stored, or the mail cannot be sent (MailController::mail).
$this->sendPasswordReset('ada@example.com'); // true: the link went to ada's email
Inherited members (55)
ConstantsDeclared byDescription
ALERTiLogLevelAlert: Action must be taken immediately.
ALLiLogLevelMask for all
ALL_PLUSiLogLeveldebug everything
BACKTRACEiLogLevel
CRITICALiLogLevelCritical: Critical conditions.
DEBUGiLogLevelDebug: Detailed debug information.
DEEPiLogLeveldebug everything with arguments
EMERGENCYiLogLevelEmergency: System is unusable.
ERRORiLogLevelError: Runtime errors that do not require immediate action but should typically be logged and monitored.
ERROR_PLUSiLogLevelMask for all error
FATALiLogLevelMask for all fatal error
INFOiLogLevelInfo: Interesting events.
INFO_PLUSiLogLevelMask for all errors/warning/notices/info
MEMORYiLogLevelinclude backtrace object
NOTICEiLogLevelNotice: Normal but significant events.
NOTICE_PLUSiLogLevelMask for all errors/warning/notices/info
TRACEiLogLevelinclude backtrace as origins
WARNINGiLogLevelWarning: Exceptional occurrences that are not errors.
WARNING_PLUSiLogLevelMask for all errors and warnings
PropertiesDeclared byDescription
verbosityaModule
MethodsDeclared byDescription
alert($message, $context)aModuleAction must be taken immediately.
backtraces($message, $context)aModuleForce-log a message at INFO level together with a full stack trace/memory snapshot (iLogLevel::BACKTRACE), bypassing the verbosity mask entirely (any non-zero verbosity is enough to trigger it).
Configure($config)aModuleMerge $config into this module's configuration in the shared Configuration.
critical($message, $context)aModuleCritical conditions. No-op if CRITICAL is currently filtered out by the verbosity mask.
debug($message, $context)aModuleDetailed debug information.
debugName()aModuleHuman-readable identifier used as the default {origin} in this instance's log messages.
DefaultConfig()aModuleThe config a module starts from before anything loaded via Configuration is merged in.
emergency($message, $context)aModuleSystem is unusable. No-op if EMERGENCY is currently filtered out by the verbosity mask.
error($message, $context)aModuleRuntime errors that do not require immediate action but should typically be logged and monitored.
ExtractRoutes($config)aControllerExtract all the APIRoute from this class, regardless of the fact they are registered in the application
getVerbosity()aModule
HasRoutes()aControllerTells if any APIRoute are registered in the application
info($message, $context)aModuleInteresting events. No-op if INFO is currently filtered out by the verbosity mask.
Instantiate($config)aModule(Re)create the shared instance immediately, configured with $config merged into the class's existing config.
IsShared()aModule
Link($method, $data)aControllerBuild a Link (URL + label/icon/description/title, taken from the route's APIRoute metadata) for a registered route.
log($level, $message, $context)aModuleLogs with an arbitrary level.
notice($message, $context)aModuleNormal but significant events.
offsetExists($key)aModule\ArrayAccess::offsetExists -- tells whether $key is a declared property at all, regardless of whether it is currently readable/writable through array access.
offsetGet($key)aModule\ArrayAccess::offsetGet -- reads a property directly, unless it has a #[Serialize(serialize: 'methodName')] attribute, in which case that zero-argument method is called instead (e.g.
offsetSet($key, $value)aModule\ArrayAccess::offsetSet -- sets a property directly, unless it has a #[Serialize(unserialize: 'methodName')] attribute, in which case that method is called with $value instead (e.g.
offsetUnset($key)aModule\ArrayAccess::offsetUnset -- equivalent to $module[$key] = null.
Route($method)aControllerGet a registered APIRoute WARNING: if this class was not registered in the application, it will return null.
Routes()aControllerGet a list of registered APIRoutes (from this class) in the application WARNING: if this class was not registered in the application, it will return an empty array.
serialize($path, $serializer)aModule\MMO\core\interfaces\iSerializable::serialize -- exports every property (via
setVerbosity($verb)aModuleSet the current verbosity mask, replacing whatever it was before.
Shared()aModuleGet the shared instance, creating (and configuring) it on first call.
testVerbosity($level)aModuleTest whether a given level (or set of levels) is currently enabled by this instance's verbosity mask.
traitUnshare($serialize)aModuleRemove the shared instance, so the next Shared() call creates a fresh one.
unserialize($data, $path, $instances)aModule\MMO\core\interfaces\iSerializable::unserialize -- merges $data onto DefaultConfig, runs it through the (possibly overridden) constructor, then applies each resulting value to its property (via
Unshare($serialize)aModuleLike tSingleton::Unshare, but also disconnects this module's instance from every event it was listening to (via Event::DisconnectListeners) before dropping it.
Url($method, $data)aControllerBuild the URL for a registered route, filling in any {placeholder} from $data.
warning($message, $context)aModuleExceptional occurrences that are not errors.
__construct($config)aModuleprotected constructor, so it is not possible to do new Module(...) called by the serialization process just before being injected with data.
__wakeup()aControllerCalled automatically right after the controller's shared instance is built (aModule::unserialize): registers onRoute as a Route listener with a low priority (-10), so it…