ソースを参照

fixed generate select in acl query

Piotr Labudda 9 年 前
コミット
c13a239fac
3 ファイル変更80 行追加25 行削除
  1. 69 21
      SE/se-lib/AclQueryBuilder.php
  2. 6 4
      SE/se-lib/AclQueryFeatures.php
  3. 5 0
      SE/se-lib/AntAclBase.php

+ 69 - 21
SE/se-lib/AclQueryBuilder.php

@@ -29,6 +29,8 @@ class AclQueryBuilder {
   public $_joinParams;
   public $isInstances;
   public $isNotInstances;
+  public $_hasSelectRemoteFields;
+  public $_hasQueryRemoteFields;
 
   public function __construct() {
     $this->select = [];
@@ -43,6 +45,9 @@ class AclQueryBuilder {
     $this->_joinParams = []; // prefx => params
     $this->isInstances = [];
     $this->isNotInstances = [];
+
+    $this->_hasSelectRemoteFields = false;
+    $this->_hasQueryRemoteFields = false;
   }
 
   public function from($from, $prefix = 't') {
@@ -136,6 +141,33 @@ class AclQueryBuilder {
     return $this;
   }
 
+  public function _generateSelectMain($select, $key) {
+    if ('__rawSelect__' === $key) return $select;
+    $sqlPk = 'ID';
+    if ($this->from instanceof Core_AclBase) $sqlPk = $this->from->getSqlPrimaryKeyField();
+    if ('@instnces' === $select) {
+      if (!($this->from instanceof Core_AclBase)) throw new Exception("select @instances allowed only for Acl object");
+      $instanceTable = ACL::getInstanceTable($this->from->getNamespace());
+      return "
+        (
+          select GROUP_CONCAT(inst_conf.namespace)
+          from `{$instanceTable}` inst_tbl
+          join `CRM_INSTANCE_CONFIG` inst_conf on (inst_conf.id = inst_tbl.idInstance)
+          where inst_tbl.pk = {$this->_fromPrefix}.{$sqlPk}
+        ) as `@instances`
+      ";
+    }
+    if (is_array($select)) {
+      // TODO: [ '__backRef' => [ ... ] ]
+      DBG::log($select, 'array', "TODO: select array");
+    } else {
+      // TODO: only real table field
+      // TODO: if geometry type then `AsWKT(t.`{$fieldName}`) as {$fieldName}`
+      return $this->parseSelectFieldValueToSql($select, $this->_fromPrefix);
+    }
+    return null;
+  }
+
   public function join($join, $prefix, $params) {
     if (array_key_exists($prefix, $this->_joinPrefix)) throw new Exception("Prefix already used!");
     $this->_joinPrefix[$prefix] = $join;
@@ -223,7 +255,7 @@ class AclQueryBuilder {
 
   public function fetchValue() {
     $sql = $this->generateSql();
-    DBG::log((array)$this, 'array', "AclQueryBuilder::fetchValue");
+    DBG::log(['sql'=>$sql,'this'=>(array)$this], 'array', "AclQueryBuilder::fetchValue");
     return DB::getPDO()->fetchValue($sql);
   }
 
@@ -291,27 +323,21 @@ class AclQueryBuilder {
     $offset = ($this->offset < 0) ? 0 : $this->offset;
     $sqlLimit = ($limit > 0) ? "limit {$limit} offset {$offset}" : '';
 
-    $sqlSelect = [];
-    if (!empty($this->select['__rawSelect__'])) {
-      $sqlSelect[] = $this->select['__rawSelect__'];
-    } else {
-      $sqlSelect[] = "{$this->_fromPrefix}.{$sqlPk}";
-      if (in_array('*', $this->select)) $sqlSelect[] = "{$this->_fromPrefix}.*";
-    }
-    if (in_array('@instances', $this->select)) {
-      if (!($this->from instanceof Core_AclBase)) throw new Exception("select @instances allowed only for Acl object");
-      $instanceTable = ACL::getInstanceTable($this->from->getNamespace());
-      $sqlSelect[] = "
-        (
-          select GROUP_CONCAT(inst_conf.namespace)
-          from `{$instanceTable}` inst_tbl
-            join `CRM_INSTANCE_CONFIG` inst_conf on (inst_conf.id = inst_tbl.idInstance)
-          where inst_tbl.pk = {$this->_fromPrefix}.{$sqlPk}
-        ) as `@instances`
-      ";
-    }
+    // TODO: split select to local and remote (use field isLocal)
+    // TODO: $this->_hasSelectRemoteFields = false;
+    // TODO: $this->_hasQueryRemoteFields = false;
+
+    // TODO: select must contain primaryKey
+    $sqlSelect = array_filter(
+      array_map([$this, '_generateSelectMain'], $this->select, array_keys($this->select)),
+      'is_string'
+    );
+    $sqlSelect = (!empty($sqlSelect))
+      ? implode("\n\t and ", $sqlSelect)
+      : "{$this->_fromPrefix}.*"
+    ;
+
     $sqlOrderBy = $this->generateOrderBySql();
-    $sqlSelect = (!empty($sqlSelect)) ? implode(", ", $sqlSelect) : "{$this->_fromPrefix}.*";
     return "
       select {$sqlSelect}
       from `{$tableName}` {$this->_fromPrefix}
@@ -322,4 +348,26 @@ class AclQueryBuilder {
     ";
   }
 
+  public function parseSelectFieldValueToSql($fieldName, $prefix = 't') {
+    if (false !== strpos($fieldName, '/')) {
+      DBG::log($fieldName, 'string', "TODO: select by xpath");
+      throw new Exception("Not implemented select by xpath ('{$fieldName}')");
+    }
+
+    $fieldType = $this->from->getXsdFieldType($fieldName);
+    if ('xsd:' === substr($fieldType, 0, 4)) {
+      return "{$prefix}.`{$fieldName}`";
+    }
+    switch ($fieldType) {
+      case 'gml:PolygonPropertyType':
+      case 'gml:PointPropertyType':
+      case 'gml:LineStringPropertyType':
+      case 'gml:GeometryPropertyType': return "AsWKT({$prefix}.`{$fieldName}`) as `{$fieldName}`";
+      case 'p5:enum': { // TODO: check if local or remote
+        return "{$prefix}.`{$fieldName}`";
+      }
+    }
+    return null;
+  }
+
 }

+ 6 - 4
SE/se-lib/AclQueryFeatures.php

@@ -3,6 +3,7 @@
 Lib::loadClass('ACL');
 Lib::loadClass('SqlQueryWhereBuilder');
 Lib::loadClass('ParseOgcFilter');
+Lib::loadClass('TableAcl');
 
 // usage: (Acl class)::buildQuery($params): return new AclQueryFeatures($this, $params);
 //        (view): $queryFeatures = $acl->buildQuery($params);
@@ -297,7 +298,7 @@ class AclQueryFeatures {
     if ($this->_legacyMode) return $this->_acl->getTotal($this->_params);
     if (null !== $this->_total) return $this->_total;
     $this->_total = $this->getQuery()
-      ->select([ 'rawSelect' => "count(1) as cnt" ])
+      ->select([ 'rawSelect' => "count(1) as cnt" ]) // TODO: fetchTotal() ? a// TODO: add AclQueryBuilder::fetchTotal()
       ->fetchValue();
     return $this->_total;
   }
@@ -320,13 +321,14 @@ class AclQueryFeatures {
       : '';
     $limit = V::get('limit', 10, $this->_params, 'int');
     $offset = V::get('limitstart', 0, $this->_params, 'int');
-    $ds = $this->_acl->getDataSource(); // TODO: only for TableAcl // TODO: move _parseSqlWhere to this class
 
     DBG::log(['params' => $this->_params, 'sortBy' => $sortBy, 'limit' => $limit, 'offset' => $offset], 'array', '$this->_params');
     return $this->getQuery()
       ->select([
-        'rawSelect' => $ds->_getSqlCols()
-      ]) // TODO: fields
+        'rawSelect' => ($this->_acl instanceof TableAcl)
+          ? $this->_acl->getDataSource()->_getSqlCols()
+          : '*'
+      ])
       ->select(!empty($this->_params['@instances']) ? '@instances' : null)
       ->limit($limit)
       ->offset($offset)

+ 5 - 0
SE/se-lib/AntAclBase.php

@@ -210,6 +210,11 @@ class AntAclBase extends Core_AclBase {
     return $_cache[$idZasob];
   }
 
+  public function buildQuery($params = array()) {
+    Lib::loadClass('AclQueryFeatures');
+		return new AclQueryFeatures($this, $params, $legacyMode = false);
+  }
+
   public function getInstanceList() {
     $rootTableName = $this->_rootTableName;
     return array_map(function ($row) use ($rootTableName) {