Role ‚XY‘ does not exist
- Bernard Williams
- Člen | 207
Nazdárek,
řeším právě dynamickou správu přístupových polích a zasekl jsem se na chybové hlášce: Role ‚XY‘ does not exist.
Hlavičku scriptu mám:
ob_start();
require './libs/Nette/loader.php';
Debug::enable();
require './libs/dibi/dibi.php';
require './libs/Acl.php';
require './libs/Login.php';
dibi::connect(array(
'driver' => 'postgre',
'host' => 'localhost',
'username' => 'root',
'password' => 'root',
'dbname' => 'bc',
'charset' => 'utf8',
));
Environment::setVariable('tempDir', dirname(__FILE__) . '/temp');
$user = Environment::getUser();
$user->setAuthenticationHandler(new Login);
$user->setAuthorizationHandler(new Acl);
a přístup testuji takto:
if ($user->isAllowed('admin', 'administration', 'show'))
Připomínám, že se nejedná o MVC model. Třída Acl je stejná jako zde. Tuto chybu mi to hází hned po spuštění scriptu – tj. před jakýmkoliv přihlášení. Role by měla být nastavena na Guest.
Děkuji
Bernard
- Bernard Williams
- Člen | 207
Tak už se mi podařilo najít chybu a taky ji odstranit. Je potřeba upravit třídy ze stránky Dynamická správa rolí a zdrojů. Konkrétně tedy hlavně metodu getRoles(), která sice vrací všechny role, ale nevrací je ve správném sledu. Je potřeba nejdřív vybrat role na nejvyšší úrovni a pak chronologicky postupovat níž. Docela mě překvapuje, že na to dosud nikdo nenarazil..
Třídy jsem upravil takto:
class AclModel extends Object {
const ACL_TABLE = 'nette_acl';
const PRIVILEGES_TABLE = 'nette_acl_privileges';
const RESOURCES_TABLE = 'nette_acl_resources';
const ROLES_TABLE = 'nette_acl_roles';
public function getParentRoles($parent_id, $parent_name, &$roles) {
$sql = dibi::query('SELECT id, name
FROM [' . self::ROLES_TABLE . ']
WHERE %and;', array('parent_id' => $parent_id));
$rows = $sql->fetchAll();
if (count($sql)) {
foreach ($rows as $row) {
$roles[] = array('name' => $row->name, 'parent_name' => $parent_name);
$this->getParentRoles($row->id, $row->name, $roles);
}
}
}
public function getRoles() {
$roles = array();
$this->getParentRoles(NULL, NULL, $roles);
return $roles;
}
public function getResources() {
return dibi::fetchAll('SELECT name FROM ['. self::RESOURCES_TABLE . '] ');
}
public function getRules() {
return dibi::fetchAll('
SELECT
a.allowed as allowed,
ro.name as role,
re.name as resource,
p.name as privilege
FROM [' . self::ACL_TABLE . '] a
JOIN [' . self::ROLES_TABLE . '] ro ON (a.role_id = ro.id)
LEFT JOIN [' . self::RESOURCES_TABLE . '] re ON (a.resource_id = re.id)
LEFT JOIN [' . self::PRIVILEGES_TABLE . '] p ON (a.privilege_id = p.id)
ORDER BY a.id ASC
');
}
}
class Acl extends Permission {
public function __construct() {
$model = new AclModel();
$roles = $model->getRoles();
foreach($roles as $role)
$this->addRole($role['name'], $role['parent_name']);
foreach($model->getResources() as $resource)
$this->addResource($resource->name);
foreach($model->getRules() as $rule)
$this->{$rule->allowed == 'Y' ? 'allow' : 'deny'}($rule->role, $rule->resource, $rule->privilege);
}
}
- Ondřej Mirtes
- Člen | 1536
Ten kód jsem psal já, na jaký problém tam narážíš? Docela hojně to používám, spoustu rolí dědím a na žádný problém jsem nenarazil.
- Bernard Williams
- Člen | 207
Uvedu příklad. Když budu mít v DB role:
guest | *NULL*
user | guest
a zavolám nad třídu Acl(), tak vše proběhne v pořádku. Pokud ale budu mít role v tomto pořadí:
user | guest
guest | *NULL*
tak mi třída Acl() skončí s chybou Role ‚guest‘ does not exist., protože role, kterou v prvním kroku používám jako rodičovskou, ještě nebyla vytvořena.
- Ondřej Mirtes
- Člen | 1536
Aha, to máš pravdu, to se dá považovat za bug. Při postupném plnění databáze na to člověk nemůže narazit (protože při plnění databáze záznamem s ID 1 ještě nemůžeš existovat záznam s ID 2, který by představoval rodiče toho prvního), ale pokud by se pak rozhodl role přeskupit, tak se může stát, že dřívější ID bude odkazovat na nějaké následující.
Zkusím vymyslet nějaké systematické řešení (nejlépe na jeden SQL dotaz :)) a dám vědět :) Díky!
- Bernard Williams
- Člen | 207
Já používám PostgreSQL a když nějaký záznam edituji, tak se ten záznam zařadí na konec a tím taky vznikla tato chyba.
Pokoušel jsem se najít řešení v podobě jednoho SQL dotazu, ale obávám se, že jinak než postupnou rekurzí to asi řešit nejde.