Browse Source

use AclQueryFeatures

Piotr Labudda 9 years ago
parent
commit
46f803f6ef

+ 11 - 0
SE/se-lib/ACL.php

@@ -372,4 +372,15 @@ SQL;
 		return $query;
 		return $query;
 	}
 	}
 
 
+	/**
+	 * @param mixed $object - Core_AclBase or string - namespace
+	 * @return Core_AclFields
+	 */
+	public static function getObjectFields($object) {
+		// TODO: try to get structure from `CRM_#CACHE_ACL_OBJECT_FIELD`
+		// if ($object is instance Core_AclBase) {
+		//   if ($object->isStructInstalled) then get structure from `CRM_#CACHE_ACL_OBJECT_FIELD` and put into Core_AclFields
+		//   else get from $object->getFields() and put into Core_AclFields
+	}
+
 }
 }

+ 30 - 4
SE/se-lib/AclQueryBuilder.php

@@ -10,6 +10,16 @@ class AclQueryBuilder {
   public $select;
   public $select;
   public $from;
   public $from;
   public $where;
   public $where;
+  /* where: array of [ $fieldName, $comparisonSign, $value ]
+   *   $fieldName - field name, TODO: xpath, null for groups (or, and)
+   *   $comparisonSign - @see where() to check allowed (implemented) signs or function names
+   *   $value - string or another $where if group (or, and)
+   * where examples: [ $fieldName, $comparisonSign, $value ]
+     [ 'ID', '=', '1' ] // where ID = '1'
+     [ 'LABEL', 'like', '%abc%' ] // where LABEL like '%abc%'
+     [ null, 'or',  [] $values ] // where ( $values[0] or  $values[1] or  ... ) // or where $values[0] when 1 === count($values)
+     [ null, 'and', [] $values ] // where ( $values[0] and $values[1] and ... ) // or where $values[0] when 1 === count($values)
+  */
   public $orderBy;
   public $orderBy;
   public $groupBy;
   public $groupBy;
   public $limit;
   public $limit;
@@ -58,9 +68,11 @@ class AclQueryBuilder {
     return $this;
     return $this;
   }
   }
 
 
-  public function where($fieldName, $comparisonSign = null, $value = null) {
-    if (!in_array($comparisonSign, [
-      '=', '>=', '<=', '<>', '!='
+  public function where($where) {
+    if (is_string($where)) return $this->whereRaw($where);
+    list($fieldName, $comparisonSign, $value) = $where;
+    if (!in_array($comparisonSign, [ // validation
+      '=', '<', '>', '<=', '>=', '<>', '!='
       , 'like', 'not like'
       , 'like', 'not like'
       , 'is not null', 'is null'
       , 'is not null', 'is null'
       , 'Intersects', 'GeometryType'
       , 'Intersects', 'GeometryType'
@@ -73,6 +85,7 @@ class AclQueryBuilder {
     return $this;
     return $this;
   }
   }
   public function _generateWhereMain($where) { // @returns string
   public function _generateWhereMain($where) { // @returns string
+    if (is_string($where)) return $where; // whereRaw
     list($fieldName, $comparisonSign, $value) = $where;
     list($fieldName, $comparisonSign, $value) = $where;
     $sqlFieldName = $fieldName; // TODO: getSqlFieldName // TODO: get sql field name with table prefix from join list to replace "{$this->_fromPrefix}.{$sqlFieldName}" below
     $sqlFieldName = $fieldName; // TODO: getSqlFieldName // TODO: get sql field name with table prefix from join list to replace "{$this->_fromPrefix}.{$sqlFieldName}" below
     switch ($comparisonSign) {
     switch ($comparisonSign) {
@@ -82,6 +95,17 @@ class AclQueryBuilder {
       case 'GeometryType': return "GeometryType({$this->_fromPrefix}.`{$sqlFieldName}`)='{$value}'";
       case 'GeometryType': return "GeometryType({$this->_fromPrefix}.`{$sqlFieldName}`)='{$value}'";
       case 'or': return $this->_generateWhereBlock($where);
       case 'or': return $this->_generateWhereBlock($where);
       case 'and': return $this->_generateWhereBlock($where);
       case 'and': return $this->_generateWhereBlock($where);
+      case 'UNIX_TIMESTAMP_LESS_THAN_NOW': return "
+        COALESCE(UNIX_TIMESTAMP({$this->_fromPrefix}.`{$sqlFieldName}`), 0) < UNIX_TIMESTAMP()
+        and {$this->_fromPrefix}.`{$sqlFieldName}` != ''
+        and {$this->_fromPrefix}.`{$sqlFieldName}` != '0000-00-00 00:00:00'
+      ";
+      case 'UNIX_TIMESTAMP_NOW_3600': return "
+        COALESCE(UNIX_TIMESTAMP({$this->_fromPrefix}.`{$sqlFieldName}`), 0) < UNIX_TIMESTAMP()+3600
+        and COALESCE(UNIX_TIMESTAMP({$this->_fromPrefix}.`{$sqlFieldName}`), 0) > UNIX_TIMESTAMP()-3600
+      ";
+      case 'UNIX_TIMESTAMP_GREATER_THAN': return " COALESCE(UNIX_TIMESTAMP({$this->_fromPrefix}.`{$sqlFieldName}`), 0) > '{$value}' ";
+      case 'UNIX_TIMESTAMP_LESS_THAN':    return " COALESCE(UNIX_TIMESTAMP({$this->_fromPrefix}.`{$sqlFieldName}`), 0) < '{$value}' ";
       default: return "{$this->_fromPrefix}.{$sqlFieldName} {$comparisonSign} " . DB::getPDO()->quote($value);
       default: return "{$this->_fromPrefix}.{$sqlFieldName} {$comparisonSign} " . DB::getPDO()->quote($value);
     }
     }
     return null;
     return null;
@@ -99,7 +123,8 @@ class AclQueryBuilder {
     $this->where[] = "{$this->_fromPrefix}.{$fieldName} is not null";
     $this->where[] = "{$this->_fromPrefix}.{$fieldName} is not null";
     return $this;
     return $this;
   }
   }
-  public function whereRaw($rawWhere) {
+  public function whereRaw($rawWhere) { // add where without validation
+    if (!$rawWhere) return $this;
     $this->where[] = $rawWhere;
     $this->where[] = $rawWhere;
     return $this;
     return $this;
   }
   }
@@ -254,6 +279,7 @@ class AclQueryBuilder {
 
 
     $sqlJoin = (!empty($sqlJoin)) ? implode("\n\t", $sqlJoin) : "";
     $sqlJoin = (!empty($sqlJoin)) ? implode("\n\t", $sqlJoin) : "";
 
 
+    DBG::log($this->where, 'array', "generateSql \$this->where");
     $sqlWhere = array_filter(
     $sqlWhere = array_filter(
       array_map([$this, '_generateWhereMain'], $this->where),
       array_map([$this, '_generateWhereMain'], $this->where),
       'is_string'
       'is_string'

+ 139 - 10
SE/se-lib/AclQueryFeatures.php

@@ -8,6 +8,9 @@ Lib::loadClass('SqlQueryWhereBuilder');
 //        (view): $total = $queryFeatures->getTotal();
 //        (view): $total = $queryFeatures->getTotal();
 //        (view): $items = $queryFeatures->getItems();
 //        (view): $items = $queryFeatures->getItems();
 // example: @see TableAcl, TableAjax
 // example: @see TableAcl, TableAjax
+
+// Special Filter Access - btns visible only if user don't have super access perms. If has, then will always see all rows.
+
 class AclQueryFeatures {
 class AclQueryFeatures {
 
 
   public $_params;
   public $_params;
@@ -16,12 +19,12 @@ class AclQueryFeatures {
   public $_total;
   public $_total;
   public $_legacyMode;
   public $_legacyMode;
 
 
-  public function __construct($acl, $params) {
+  public function __construct($acl, $params, $legacyMode = false) {
     $this->_acl = $acl;
     $this->_acl = $acl;
     $this->_params = $params;
     $this->_params = $params;
     $this->_query = null;
     $this->_query = null;
     $this->_total = null;
     $this->_total = null;
-    $this->_legacyMode = false;
+    $this->_legacyMode = $legacyMode;
     // TODO: _legacyMode = ($from instanceof simple schema or another programmed objects)
     // TODO: _legacyMode = ($from instanceof simple schema or another programmed objects)
   }
   }
 
 
@@ -64,7 +67,10 @@ class AclQueryFeatures {
       default: {
       default: {
         switch ($fieldType) {
         switch ($fieldType) {
           case 'xsd:number':
           case 'xsd:number':
-          case 'xsd:integer': return ['=', $searchQuery];
+          case 'xsd:integer': {
+            if (false !== strpos($searchQuery, '%')) return ['like', $searchQuery];
+            return ['=', $searchQuery];
+          }
           default: {
           default: {
             if (false !== strpos($searchQuery, '%')) return ['like', $searchQuery];
             if (false !== strpos($searchQuery, '%')) return ['like', $searchQuery];
             $queryWhereBuilder = new SqlQueryWhereBuilder();
             $queryWhereBuilder = new SqlQueryWhereBuilder();
@@ -129,6 +135,112 @@ class AclQueryFeatures {
     return $sqlFilter;
     return $sqlFilter;
   }
   }
 
 
+  public function parseSpecialFilterMsgs($type) {
+    $rootTableName = $this->_acl->getRootTableName();
+    DBG::log($rootTableName, 'string', "parse SpecialFilter Msgs({$type}), \$rootTableName");
+    $sqlHasFltrMsgs = "
+      select 1
+      from `CRM_UI_MSGS` m
+      where m.`uiTargetName`=CONCAT('{$rootTableName}.', t.`ID`)
+        and m.`uiTargetType`='default_db_table_record'
+        and m.`A_STATUS` not in('DELETED')
+      limit 1
+    ";
+    switch ($type) {
+      case 'HAS_MSGS': return " ({$sqlHasFltrMsgs})=1 ";
+      case 'NO_MSGS':  return " ({$sqlHasFltrMsgs}) is null ";
+      case 'NEW_MSGS': {
+        $sqlNewFltrMsgs = "
+          select 1
+          from `CRM_UI_MSGS` m
+          where m.`uiTargetName`=CONCAT('{$rootTableName}.', t.`ID`)
+            and m.`uiTargetType`='default_db_table_record'
+            and m.`A_STATUS` in('WAITING')
+          limit 1
+        ";
+        return " ({$sqlNewFltrMsgs})=1 ";
+      }
+    }
+    return null;
+  }
+
+  public function parseSpecialFilterProblemy($type) {
+    DBG::log($type, 'string', "parse SpecialFilter Problemy");
+    switch ($type) {
+      case 'PROBLEM': return ['A_PROBLEM', '!=', ''];
+      case 'WARNING': return ['A_PROBLEM', '=', 'WARNING'];
+      case 'NORMAL':  return ['A_PROBLEM', '=', 'NORMAL'];
+    }
+    return null;
+  }
+
+  public function parseSpecialFilterStatus($type) {
+    DBG::log($type, 'string', "parse SpecialFilter Status");
+    switch ($type) {
+      case 'WAITING': return ['A_STATUS', '=', 'WAITING'];
+      case 'AKTYWNI': return ['A_STATUS', 'or', [ // `A_STATUS` in('NORMAL', 'WARNING') ";
+        ['A_STATUS', '=', 'NORMAL'],
+        ['A_STATUS', '=', 'WARNING'],
+      ] ];
+    }
+    return null;
+  }
+
+  public function parseSpecialFilterSpotkania($type) {
+    DBG::log($type, 'string', "parse SpecialFilter Spotkania");
+    switch ($type) {
+      case 'OLD': return ['L_APPOITMENT_DATE', 'UNIX_TIMESTAMP_LESS_THAN_NOW'];
+      //           COALESCE(UNIX_TIMESTAMP(t.`L_APPOITMENT_DATE`), 0) < UNIX_TIMESTAMP()
+      //           and t.`L_APPOITMENT_DATE` != ''
+      //           and t.`L_APPOITMENT_DATE` != '0000-00-00 00:00:00'
+      case 'NOW': return ['L_APPOITMENT_DATE', 'UNIX_TIMESTAMP_NOW_3600'];
+      //           COALESCE(UNIX_TIMESTAMP(t.`L_APPOITMENT_DATE`), 0) < UNIX_TIMESTAMP()+3600
+      //           and COALESCE(UNIX_TIMESTAMP(t.`L_APPOITMENT_DATE`), 0) > UNIX_TIMESTAMP()-3600
+      case 'TODAY': return ['L_APPOITMENT_DATE', 'and', [
+        ['L_APPOITMENT_DATE', 'UNIX_TIMESTAMP_GREATER_THAN', mktime(0,0,0, date("m"), date("d"),     date("Y"))],
+        ['L_APPOITMENT_DATE', 'UNIX_TIMESTAMP_LESS_THAN',    mktime(0,0,0, date("m"), date("d") + 1, date("Y"))],
+      ] ];
+      //         $start = mktime(0,0,0, date("m"), date("d"), date("Y"));
+      //         $end = mktime(0,0,0, date("m"), date("d") + 1, date("Y"));
+      //         $sqlFltr = "
+      //           COALESCE(UNIX_TIMESTAMP(t.`L_APPOITMENT_DATE`), 0) > '{$start}'
+      //           and COALESCE(UNIX_TIMESTAMP(t.`L_APPOITMENT_DATE`), 0) < '{$end}'
+      //         ";
+      case 'TOMORROW': return ['L_APPOITMENT_DATE', 'and', [
+        ['L_APPOITMENT_DATE', 'UNIX_TIMESTAMP_GREATER_THAN', mktime(0,0,0, date("m"), date("d") + 1, date("Y"))],
+        ['L_APPOITMENT_DATE', 'UNIX_TIMESTAMP_LESS_THAN',    mktime(0,0,0, date("m"), date("d") + 2, date("Y"))],
+      ] ];
+      case 'YESTERDAY': return ['L_APPOITMENT_DATE', 'and', [
+        ['L_APPOITMENT_DATE', 'UNIX_TIMESTAMP_GREATER_THAN', mktime(0,0,0, date("m"), date("d") - 2, date("Y"))],
+        ['L_APPOITMENT_DATE', 'UNIX_TIMESTAMP_LESS_THAN',    mktime(0,0,0, date("m"), date("d") - 1, date("Y"))],
+      ] ];
+      case 'BRAK': return ['L_APPOITMENT_DATE', 'or', [
+        ['L_APPOITMENT_DATE', '=', ''],
+        ['L_APPOITMENT_DATE', '=', '0000-00-00 00:00:00'],
+      ] ];
+    }
+    return null;
+  }
+
+  public function parseSpecialFilterAccess() {
+    $userLogin = User::getLogin();
+    $usrAclGroups = User::getLdapGroupsNames();
+    DBG::log(['login'=>$userLogin, 'groups'=>$usrAclGroups, 'acl'=>$this->_acl], 'array', "parse SpecialFilter Access");
+    $orWhere = [];
+    if ($this->_acl->hasField('A_ADM_COMPANY')) {
+      $orWhere[] = ['A_ADM_COMPANY', '=', ''];// TODO: allow empty for everyone?
+      foreach ($usrAclGroups as $group) $orWhere[] = ['A_ADM_COMPANY', '=', $group];
+    }
+    if ($this->_acl->hasField('A_CLASSIFIED')) {
+      $orWhere[] = ['A_CLASSIFIED', '=', ''];// TODO: allow empty for everyone?
+      foreach ($usrAclGroups as $group) $orWhere[] = ['A_CLASSIFIED', '=', $group];
+    }
+    if ($this->_acl->hasField('L_APPOITMENT_USER')) {
+      $orWhere[] = ['L_APPOITMENT_USER', '=', $userLogin];
+    }
+    return (!empty($orWhere)) ? [null, 'or', $orWhere] : null;
+  }
+
   public function getQuery() {
   public function getQuery() {
     if ($this->_query) return $this->_query;
     if ($this->_query) return $this->_query;
     // $ds = $this->_acl->getDataSource(); // TODO: only for TableAcl // TODO: move _parseSqlWhere to this class
     // $ds = $this->_acl->getDataSource(); // TODO: only for TableAcl // TODO: move _parseSqlWhere to this class
@@ -138,21 +250,38 @@ class AclQueryFeatures {
       ->isInstance($filtrIsInstance)
       ->isInstance($filtrIsInstance)
       ->isNotInstance($filtrIsNotInstance);
       ->isNotInstance($filtrIsNotInstance);
     // ->join($instanceTable, 'i', [ 'rawJoin' => "i.pk = t.{$sqlPrimaryKey} and i.idInstance = {$idInstance}" ])
     // ->join($instanceTable, 'i', [ 'rawJoin' => "i.pk = t.{$sqlPrimaryKey} and i.idInstance = {$idInstance}" ])
-    // $this->_query->where([
-    //   'rawWhere' => $ds->_parseSqlWhere($params)
-    // ]);
+    // $this->_query->where($ds->_parseSqlWhere($params))
+    DBG::log($this->_params, 'array', "\$this->_params");
     foreach ($this->_params as $k => $v) {
     foreach ($this->_params as $k => $v) {
       if ('f_' === substr($k, 0, 2) && strlen($k) > 3) {
       if ('f_' === substr($k, 0, 2) && strlen($k) > 3) {
         $fieldName = substr($k, 2);
         $fieldName = substr($k, 2);
         $fieldType = $this->_acl->getXsdFieldType($fieldName);
         $fieldType = $this->_acl->getXsdFieldType($fieldName);
         list($comparisonSign, $value) = $this->parseQueryValue($fieldName, $v, $fieldType);
         list($comparisonSign, $value) = $this->parseQueryValue($fieldName, $v, $fieldType);
-        DBG::log([ $fieldName, $fieldType, $comparisonSign, $value ], 'array', "parseQueryValue");
-        $this->_query->where($fieldName, $comparisonSign, $value);
+        DBG::log([ $fieldName, $comparisonSign, $value, $fieldType ], 'array', "parseQueryValue");
+        $this->_query->where([$fieldName, $comparisonSign, $value]);
       } else if ('sf_' === substr($k, 0, 3) && strlen($k) > 4) {
       } else if ('sf_' === substr($k, 0, 3) && strlen($k) > 4) {
+        switch (substr($k, 3)) {
+          case 'Msgs': $this->_query->where($this->parseSpecialFilterMsgs($v)); break;
+          case 'Problemy': $this->_query->where($this->parseSpecialFilterProblemy($v)); break;
+          case 'Status': $this->_query->where($this->parseSpecialFilterStatus($v)); break;
+          case 'Spotkania': $this->_query->where($this->parseSpecialFilterSpotkania($v)); break;
+          case 'Access': break; // SKIP - used below
+          default: throw new Exception("Not Implemented special filter '".substr($k, 3)."'");
+        }
       } else if ('ogc:Filter' == $k) {
       } else if ('ogc:Filter' == $k) {
+        throw new Exception("Not Implemented ogc:Filter");
       } else if ('primaryKey' == $k) {
       } else if ('primaryKey' == $k) {
+        $fieldName = $this->_acl->getPrimaryKeyField();
+        $fieldType = $this->_acl->getXsdFieldType($fieldName);
+        list($comparisonSign, $value) = $this->parseQueryValue($fieldName, $v, $fieldType);
+        DBG::log([ $fieldName, $comparisonSign, $value, $fieldType ], 'array', "parseQueryValue");
+        $this->_query->where([$fieldName, $comparisonSign, $value]);
       }
       }
     }
     }
+
+    // sf_Access: if 'SHOW' then show all rows, but data with ***
+    if ('SHOW' !== V::get('sf_Access', '', $this->_params)) $this->_query->where($this->parseSpecialFilterAccess());
+
     return $this->_query;
     return $this->_query;
   }
   }
 
 
@@ -169,7 +298,7 @@ class AclQueryFeatures {
   public function getParam($key) { return V::get($key, '', $this->_params); }
   public function getParam($key) { return V::get($key, '', $this->_params); }
 
 
   public function getItems() {
   public function getItems() {
-    if ($this->_legacyMode) return $this->_acl->getTotal($this->_params);
+    if ($this->_legacyMode) return $this->_acl->getItems($this->_params);
     // 'limit' => 10,
     // 'limit' => 10,
     //  'limitstart' => 0,
     //  'limitstart' => 0,
     //  'order_by' => 'ID',
     //  'order_by' => 'ID',
@@ -188,7 +317,7 @@ class AclQueryFeatures {
     DBG::log(['params' => $this->_params, 'sortBy' => $sortBy, 'limit' => $limit, 'offset' => $offset], 'array', '$this->_params');
     DBG::log(['params' => $this->_params, 'sortBy' => $sortBy, 'limit' => $limit, 'offset' => $offset], 'array', '$this->_params');
     return $this->getQuery()
     return $this->getQuery()
       ->select([
       ->select([
-        'rawSelect' =>   $ds->_getSqlCols()
+        'rawSelect' => $ds->_getSqlCols()
       ]) // TODO: fields
       ]) // TODO: fields
       ->select(!empty($this->_params['@instances']) ? '@instances' : null)
       ->select(!empty($this->_params['@instances']) ? '@instances' : null)
       ->limit($limit)
       ->limit($limit)

+ 10 - 1
SE/se-lib/Core/AclBase.php

@@ -29,6 +29,12 @@ class Core_AclBase {
   public function getID() { return $this->_zasobID; }
   public function getID() { return $this->_zasobID; }
   public function init($force = false) { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }
   public function init($force = false) { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }
   public function isInitialized() { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }
   public function isInitialized() { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }
+  public function hasField($fieldName) {// TODO: fix use Core_AclFields or ACL::getObjectFields($namespace) - use cache - one place to store structure
+    foreach ($this->getFields() as $field) {
+      if ($fieldName === $field['name']) return true;
+    }
+    return false;
+  }
   public function getFields() {// @returns array - $this->_fields // TODO: mved to getFieldListByIdZasob
   public function getFields() {// @returns array - $this->_fields // TODO: mved to getFieldListByIdZasob
     /*
     /*
       $field = array();
       $field = array();
@@ -189,7 +195,10 @@ class Core_AclBase {
 
 
   public function getRawLabel($posLimit = 20) { return substr($this->getName(), 0, $posLimit); }
   public function getRawLabel($posLimit = 20) { return substr($this->getName(), 0, $posLimit); }
 
 
-  public function buildQuery($params = array()) { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }// TODO: use ParseOgcQuery
+  public function buildQuery($params = array()) {
+    Lib::loadClass('AclQueryFeatures');
+		return new AclQueryFeatures($this, $params, $legacyMode = true);
+  }
   public function getItems($params = array()) { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }// TODO: use ParseOgcQuery
   public function getItems($params = array()) { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }// TODO: use ParseOgcQuery
   public function getTotal($params = array()) { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }// TODO: use ParseOgcQuery
   public function getTotal($params = array()) { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }// TODO: use ParseOgcQuery
   public function getItem($primaryKey, $params = []) { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }
   public function getItem($primaryKey, $params = []) { throw new HttpException("Acl function " . __FUNCTION__ . " Not implemented", 501); }

+ 2 - 2
SE/se-lib/Schema/KorespondencjaStorageAcl.php

@@ -34,7 +34,7 @@ class Schema_KorespondencjaStorageAcl extends Core_AclBase {
 	}
 	}
   public function getFieldType($colName) { return null; }
   public function getFieldType($colName) { return null; }
   public function isAllowed($idZasob, $taskPerm, $record = null) {
   public function isAllowed($idZasob, $taskPerm, $record = null) {
-    if ($this->parentAcl->hasField($idZasob)) return $this->parentAcl->isAllowed($idZasob, $taskPerm, $record);
+    if ($this->parentAcl->hasFieldById($idZasob)) return $this->parentAcl->isAllowed($idZasob, $taskPerm, $record);
     $fields = $this->getRealFieldListByIdZasob();
     $fields = $this->getRealFieldListByIdZasob();
     if (array_key_exists($idZasob, $fields)) {
     if (array_key_exists($idZasob, $fields)) {
       if ('File' == $fields[$idZasob]) {
       if ('File' == $fields[$idZasob]) {
@@ -47,7 +47,7 @@ class Schema_KorespondencjaStorageAcl extends Core_AclBase {
     return false;
     return false;
   }
   }
   public function hasFieldPerm($idZasob, $taskPerm) {
   public function hasFieldPerm($idZasob, $taskPerm) {
-    if ($this->parentAcl->hasField($idZasob)) return $this->parentAcl->hasFieldPerm($idZasob, $taskPerm);
+    if ($this->parentAcl->hasFieldById($idZasob)) return $this->parentAcl->hasFieldPerm($idZasob, $taskPerm);
     $fields = $this->getRealFieldListByIdZasob();
     $fields = $this->getRealFieldListByIdZasob();
     if (array_key_exists($idZasob, $fields)) {
     if (array_key_exists($idZasob, $fields)) {
       if ('File' == $fields[$idZasob]) {
       if ('File' == $fields[$idZasob]) {

+ 46 - 12
SE/se-lib/TableAcl.php

@@ -43,6 +43,7 @@ class TableAcl extends Core_AclBase {
 
 
 	public function __construct($zasobID) { $this->_zasobID = $zasobID; }
 	public function __construct($zasobID) { $this->_zasobID = $zasobID; }
 	public function getNamespace() { return 'default_db/' . $this->getName(); }
 	public function getNamespace() { return 'default_db/' . $this->getName(); }
+	public function getRootNamespace() { return 'default_db/' . $this->getName(); }
 	public function getSourceName() { return 'default_db'; }
 	public function getSourceName() { return 'default_db'; }
 	public function getName() { return $this->_name; }
 	public function getName() { return $this->_name; }
 	public function getRootTableName() {
 	public function getRootTableName() {
@@ -58,7 +59,6 @@ class TableAcl extends Core_AclBase {
 				and t.TABLE_NAME LIKE '{$this->_name}'
 				and t.TABLE_NAME LIKE '{$this->_name}'
 		");
 		");
 		if (!$this->_rootTableName) return null;// throw new Exception("Table '{$this->_name}' not exists!");
 		if (!$this->_rootTableName) return null;// throw new Exception("Table '{$this->_name}' not exists!");
-		DBG::log("TableAcl({$this->_zasobID})->getRootTableName (\$this->_name='{$this->_name}', \$this->_rootTableName='{$this->_rootTableName}')");
 		if ($this->_rootTableName != $this->_name) {
 		if ($this->_rootTableName != $this->_name) {
 			if ($this->_zasobID) {
 			if ($this->_zasobID) {
 				$affected = DB::getPDO()->update('CRM_LISTA_ZASOBOW', 'ID', $this->_zasobID, [
 				$affected = DB::getPDO()->update('CRM_LISTA_ZASOBOW', 'ID', $this->_zasobID, [
@@ -72,6 +72,7 @@ class TableAcl extends Core_AclBase {
 		return $this->_rootTableName;
 		return $this->_rootTableName;
 	}
 	}
 	public function getID() { return $this->_zasobID; }
 	public function getID() { return $this->_zasobID; }
+	public function getSqlPrimaryKeyField() { return 'ID'; } // TODO: read from root object schema (_rootTableName)
 	public function setName($name) {// TODO: used only by setNameByTableId
 	public function setName($name) {// TODO: used only by setNameByTableId
 		DBG::log("setName('{$name}')");
 		DBG::log("setName('{$name}')");
 		$this->_name = $name;
 		$this->_name = $name;
@@ -163,7 +164,6 @@ class TableAcl extends Core_AclBase {
 		$this->_fields[$fieldID] = $field;
 		$this->_fields[$fieldID] = $field;
 	}
 	}
 
 
-
 	public function getTableDbId($tableID) {
 	public function getTableDbId($tableID) {
 		return $this->_db;
 		return $this->_db;
 	}
 	}
@@ -172,7 +172,7 @@ class TableAcl extends Core_AclBase {
 		return $this->_fields[$fieldID];
 		return $this->_fields[$fieldID];
 	}
 	}
 
 
-	public function hasField($fieldID) {
+	public function hasFieldById($fieldID) {
 		return array_key_exists($fieldID, $this->_fields);
 		return array_key_exists($fieldID, $this->_fields);
 	}
 	}
 
 
@@ -1061,12 +1061,12 @@ class TableAcl extends Core_AclBase {
 				trigger_error("BUG " . __CLASS__ . "->" . __FUNCTION__ . "(\$fieldsConfig) key must be integer - skipping '{$idField}'", E_USER_NOTICE);
 				trigger_error("BUG " . __CLASS__ . "->" . __FUNCTION__ . "(\$fieldsConfig) key must be integer - skipping '{$idField}'", E_USER_NOTICE);
 				continue;
 				continue;
 			}
 			}
-			//echo'<pre>INIT::$permField('.$vFieldConfig->ID_CELL.') hasFld('.$this->hasField($vFieldConfig->ID_CELL).') ';echo'</pre>';
-			if (!$this->hasField($vFieldConfig['ID_CELL'])) {
+			//echo'<pre>INIT::$permField('.$vFieldConfig->ID_CELL.') hasFld('.$this->hasFieldById($vFieldConfig->ID_CELL).') ';echo'</pre>';
+			if (!$this->hasFieldById($vFieldConfig['ID_CELL'])) {
 				//echo'<pre>INIT::$permField('.$vFieldConfig['ID_CELL'].') addFld('.$vFieldConfig['ID_CELL'] . ', ' . $vFieldConfig['CELL_NAME'] . ', ' . $vFieldConfig['CELL_DESC'] . ', ' . $vFieldConfig['SORT_PRIO'] . ', ' . $vFieldConfig['CELL_LABEL'].') ';echo'</pre>';
 				//echo'<pre>INIT::$permField('.$vFieldConfig['ID_CELL'].') addFld('.$vFieldConfig['ID_CELL'] . ', ' . $vFieldConfig['CELL_NAME'] . ', ' . $vFieldConfig['CELL_DESC'] . ', ' . $vFieldConfig['SORT_PRIO'] . ', ' . $vFieldConfig['CELL_LABEL'].') ';echo'</pre>';
 				$this->addField($vFieldConfig['ID_CELL'], $vFieldConfig['CELL_NAME'], $vFieldConfig['CELL_DESC'], $vFieldConfig['SORT_PRIO'], $vFieldConfig['CELL_LABEL']);
 				$this->addField($vFieldConfig['ID_CELL'], $vFieldConfig['CELL_NAME'], $vFieldConfig['CELL_DESC'], $vFieldConfig['SORT_PRIO'], $vFieldConfig['CELL_LABEL']);
 			}
 			}
-			//echo'<pre>INIT::$permField('.$vFieldConfig['ID_CELL'].') hasFld('.$this->hasField($vFieldConfig['ID_CELL']).') ';echo'</pre>';
+			//echo'<pre>INIT::$permField('.$vFieldConfig['ID_CELL'].') hasFld('.$this->hasFieldById($vFieldConfig['ID_CELL']).') ';echo'</pre>';
 			if (!isset($vFieldConfig['FORM_TREAT'])) {// TODO: convert to legacy perms
 			if (!isset($vFieldConfig['FORM_TREAT'])) {// TODO: convert to legacy perms
 				$vFieldConfig['FORM_TREAT'] = '';
 				$vFieldConfig['FORM_TREAT'] = '';
 				if ($vFieldConfig['PERM_R'] > 0) $vFieldConfig['FORM_TREAT'] .= 'R';
 				if ($vFieldConfig['PERM_R'] > 0) $vFieldConfig['FORM_TREAT'] .= 'R';
@@ -1467,19 +1467,53 @@ class TableAcl extends Core_AclBase {
 		return $value;
 		return $value;
 	}
 	}
 
 
+	public function buildQuery($params = []) {
+		Lib::loadClass('AclQueryFeatures');
+		return new AclQueryFeatures($this, $params);
+	}
+
 	public function getItem($primaryKey, $params = []) {
 	public function getItem($primaryKey, $params = []) {
 		$ds = $this->getDataSource();
 		$ds = $this->getDataSource();
 		return $ds->getItem($primaryKey);
 		return $ds->getItem($primaryKey);
 	}
 	}
 
 
-	public function getItems($params = array()) {// TODO: use ParseOgcQuery
+	public function prepareQuery($params = array()) {
+		DBG::log($params, 'array', 'TableAcl->prepareQuery $params');
 		$ds = $this->getDataSource();
 		$ds = $this->getDataSource();
-		return $ds->getItems($params);
+		$filtrIsInstance = []; // TODO: read instances from $params
+		$filtrIsNotInstance = [];
+		Lib::loadClass('ACL');
+		return ACL::query($this)
+			->isInstance($filtrIsInstance)
+			->isNotInstance($filtrIsNotInstance)
+			->whereRaw($ds->_parseSqlWhere($params));
+	}
+
+	public function getItems($params = array()) {
+		$orderBy = V::get('order_by', '', $params);
+		$orderDir = V::get('order_dir', '', $params);
+		$sortBy = (!empty($orderBy))
+			? ( !empty($orderDir) ? "{$orderBy} {$orderDir}" : $orderBy )
+			: '';
+		$limit = V::get('limit', 10, $params, 'int');
+		$offset = V::get('limitstart', 0, $params, 'int');
+		$ds = $this->getDataSource();
+
+		return $this->prepareQuery($params)
+			->select([
+				'rawSelect' => 	$ds->_getSqlCols()
+			])
+			->select(!empty($params['@instances']) ? '@instances' : '')
+			->limit($limit)
+			->offset($offset)
+			->orderBy($sortBy)
+			->fetchAll();
 	}
 	}
 
 
-	public function getTotal($params = array()) {// TODO: use ParseOgcQuery
-		$ds = $this->getDataSource();
-		return $ds->getTotal($params);
+	public function getTotal($params = array()) {
+		return $this->prepareQuery($params)
+			->select([ 'rawSelect' => "count(1) as cnt" ])
+			->fetchValue();
 	}
 	}
 
 
 	public function getColDefault($fieldName) {
 	public function getColDefault($fieldName) {
@@ -1682,7 +1716,7 @@ class TableAcl extends Core_AclBase {
 		$dsConfig['fields'] = $cols;
 		$dsConfig['fields'] = $cols;
 		$dsConfig['field_types'] = $this->getTypes();
 		$dsConfig['field_types'] = $this->getTypes();
 		$dsConfig['fields_virtual'] = $this->getVirtualFieldListByIdZasob();
 		$dsConfig['fields_virtual'] = $this->getVirtualFieldListByIdZasob();
-		$dsConfig['acl_fltr_allowed'] = !$this->hasSuperAccessPerms();
+		$dsConfig['acl_fltr_allowed'] = !$this->hasSuperAccessPerms(); // filtr Access is visible only if user dont have supe access perms. If has then see all rows
 		return DataSourceFactory::buildFromZasobInfo($dsConfig);
 		return DataSourceFactory::buildFromZasobInfo($dsConfig);
 	}
 	}
 
 

+ 13 - 5
SE/se-lib/TableAjax.php

@@ -6006,17 +6006,23 @@ jQuery(document).ready(function(){
 		$params['limitstart'] = $page * $params['limit'];
 		$params['limitstart'] = $page * $params['limit'];
 		$params['order_by'] = ($currSortCol)? $currSortCol : '';
 		$params['order_by'] = ($currSortCol)? $currSortCol : '';
 		$params['order_dir'] = $currSortFlip;
 		$params['order_dir'] = $currSortFlip;
+		foreach ($args as $k => $v) {
+			if (strlen($k) > 3 && substr($k, 0, 2) == 'f_' && strlen($v) > 0) {// filter prefix
+				$params[$k] = $v;
+			}
+			else if (strlen($k) > 4 && substr($k, 0, 3) == 'sf_' && strlen($v) > 0) {// special filter prefix
+				$params[$k] = $v;
+			}
+		}
 
 
 		$filters = new stdClass();
 		$filters = new stdClass();
 		$filters->currSortCol = $currSortCol;
 		$filters->currSortCol = $currSortCol;
 		$filters->currSortFlip = $currSortFlip;
 		$filters->currSortFlip = $currSortFlip;
 		foreach ($args as $k => $v) {
 		foreach ($args as $k => $v) {
 			if (strlen($k) > 3 && substr($k, 0, 2) == 'f_' && strlen($v) > 0) {// filter prefix
 			if (strlen($k) > 3 && substr($k, 0, 2) == 'f_' && strlen($v) > 0) {// filter prefix
-				$params[$k] = $v;
 				$filters->{$k} = $v;
 				$filters->{$k} = $v;
 			}
 			}
 			else if (strlen($k) > 4 && substr($k, 0, 3) == 'sf_' && strlen($v) > 0) {// special filter prefix
 			else if (strlen($k) > 4 && substr($k, 0, 3) == 'sf_' && strlen($v) > 0) {// special filter prefix
-				$params[$k] = $v;
 				$filters->{$k} = $v;
 				$filters->{$k} = $v;
 			}
 			}
 		}
 		}
@@ -6157,10 +6163,12 @@ jQuery(document).ready(function(){
 			$jsonData->cols->{$col} = $columnConfig;
 			$jsonData->cols->{$col} = $columnConfig;
 		}
 		}
 		$jsonData->rows = array();
 		$jsonData->rows = array();
-		$jsonData->total = $acl->getTotal($params);
+		$queryFeatures = $acl->buildQuery($params);
+		$jsonData->total = $queryFeatures->getTotal();
 		if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">get_total (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($jsonData->total);echo'</pre>';}
 		if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">get_total (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($jsonData->total);echo'</pre>';}
-		$items = $acl->getItems($params);
-		foreach ($items as $idx => $item) $items[$idx] = (array)$item;
+		$listItems = $queryFeatures->getItems();
+		$primaryKeyField = $acl->getPrimaryKeyField();
+		$items = []; foreach ($listItems as $item) $items[ $item[$primaryKeyField] ] = $item;
 		if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">items (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($items);echo'</pre>';}
 		if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">items (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($items);echo'</pre>';}
 		// TODO: add virtual data by Typespecial
 		// TODO: add virtual data by Typespecial
 		if (!empty($vCols) && !empty($items)) {
 		if (!empty($vCols) && !empty($items)) {