/**
  * Get a new criterion to filter a SQL query by ACL rules
  *
  * @param Criteria $criteria
  * @param mixed $root - root object for list
  * @return Criterion
  */
 public static function getFilterCriterion($criteria, $root, $action)
 {
     $user = sfContext::getInstance()->user;
     $rootClass = get_class($root);
     if ('createTerm' != $action) {
         $permissions = self::getUserPermissionsByAction($user, $rootClass, $action);
     } else {
         $permissions = self::getUserPermissionsByAction($user, 'QubitTerm', 'create');
     }
     // Build access control list
     $allows = $bans = $ids = array();
     $forceBan = false;
     if (0 < count($permissions)) {
         foreach ($permissions as $permission) {
             switch ($action) {
                 case 'createTerm':
                     if (null === ($id = $permission->getConstants(array('name' => 'taxonomyId')))) {
                         $ids[] = QubitTaxonomy::ROOT_ID;
                     }
                     break;
                 case 'viewDraft':
                     if (null !== ($repoId = $permission->getConstants(array('name' => 'repositoryId')))) {
                         $criteria2 = new Criteria();
                         $criteria2->add(QubitInformationObject::REPOSITORY_ID, $repoId);
                         if (0 < count($results = QubitInformationObject::get($criteria2))) {
                             foreach ($results as $item) {
                                 $ids[] = $item->id;
                             }
                             // Special case because isAllowed() on ROOT will return true if
                             // user has grant permission on ANY repository. This will force
                             // showing ONLY resources in allowed repositories
                             $forceBan = true;
                         }
                     }
                     break;
                 default:
                     $ids[] = $permission->objectId;
             }
         }
         foreach ($ids as $id) {
             if (!isset($resourceAccess[$id])) {
                 $resource = call_user_func(array($rootClass, 'getById'), $id);
                 $resourceAccess[$id] = self::isAllowed($user, $resource, $action);
                 if ($resourceAccess[$id]) {
                     $allows[] = $id;
                 } else {
                     $bans[] = $id;
                 }
             }
         }
     }
     // Special cases - avoid adding unnecessary criteria
     if (0 == count($allows) && !QubitAcl::isAllowed($user, $root, $action)) {
         return false;
         // No allows, always false
     } else {
         if (!$forceBan && 0 == count($bans) && QubitAcl::isAllowed($user, $root, $action)) {
             return true;
             // No bans, always true
         }
     }
     // If more allows then bans, then add list of allowed resources
     $criterion = null;
     if (count($allows) >= count($bans)) {
         while ($resourceId = array_shift($allows)) {
             $resource = call_user_func(array($rootClass, 'getById'), $resourceId);
             // If object has no children include it by id
             if (1 == $resource->rgt - $resource->lft) {
                 $subCriterion = $criteria->getNewCriterion(constant("{$rootClass}::ID"), $resourceId);
             } else {
                 $subCriterion = $criteria->getNewCriterion(constant("{$rootClass}::LFT"), $resource->lft, Criteria::GREATER_EQUAL);
                 $subCriterion2 = $criteria->getNewCriterion(constant("{$rootClass}::RGT"), $resource->rgt, Criteria::LESS_EQUAL);
                 $subCriterion->addAnd($subCriterion2);
             }
             if (isset($criterion)) {
                 $criterion->addOr($subCriterion);
             } else {
                 $criterion = $subCriterion;
             }
         }
     } else {
         while ($resourceId = array_shift($bans)) {
             $resource = call_user_func(array($rootClass, 'getById'), $resourceId);
             // If object has no children, remove it by id
             if (1 == $resource->rgt - $resource->lft) {
                 $subCriterion = $criteria->getNewCriterion(constant("{$rootClass}::ID"), $resourceId, Criteria::NOT_EQUAL);
             } else {
                 $subCriterion = $criteria->getNewCriterion(constant("{$rootClass}::LFT"), $resource->lft, Criteria::LESS_THAN);
                 $subCriterion2 = $criteria->getNewCriterion(constant("{$rootClass}::RGT"), $resource->rgt, Criteria::GREATER_THAN);
                 $subCriterion->addOr($subCriterion2);
             }
             if (isset($criterion)) {
                 $criterion->addAnd($subCriterion);
             } else {
                 $criterion = $subCriterion;
             }
         }
     }
     return $criterion;
 }