noneOf filter

This commit is contained in:
yuri
2017-04-13 15:01:23 +03:00
parent a587efddde
commit 2d786d9660
5 changed files with 121 additions and 20 deletions

View File

@@ -742,7 +742,7 @@ class Base
$attribute = $w['attribute'];
}
if ($attribute) {
if (isset($w['type']) && in_array($w['type'], ['isLinked', 'isNotLinked', 'linkedWith', 'isUserFromTeams'])) {
if (isset($w['type']) && in_array($w['type'], ['isLinked', 'isNotLinked', 'linkedWith', 'notLinkedWith', 'isUserFromTeams'])) {
if (in_array($attribute, $this->getAcl()->getScopeForbiddenFieldList($this->getEntityType()))) {
throw new Forbidden();
}
@@ -958,6 +958,10 @@ class Base
$attribute = $item['attribute'];
}
if (!is_null($attribute) && !is_string($attribute)) {
throw new Error('Bad attribute in where statement');
}
if (!empty($attribute) && !empty($item['type'])) {
$methodName = 'getWherePart' . ucfirst($attribute) . ucfirst($item['type']);
if (method_exists($this, $methodName)) {
@@ -1159,14 +1163,14 @@ class Base
break;
case 'isNotLinked':
if (!$result) break;
$alias = $attribute . 'IsNotLinkedFilter';
$alias = $attribute . 'IsNotLinkedFilter' . strval(rand(10000, 99999));;
$part[$alias . '.id'] = null;
$this->setDistinct(true, $result);
$this->addLeftJoin([$attribute, $alias], $result);
break;
case 'isLinked':
if (!$result) break;
$alias = $attribute . 'IsLinkedFilter';
$alias = $attribute . 'IsLinkedFilter' . strval(rand(10000, 99999));;
$part[$alias . '.id!='] = null;
$this->setDistinct(true, $result);
$this->addLeftJoin([$attribute, $alias], $result);
@@ -1176,35 +1180,75 @@ class Base
$link = $attribute;
if (!$seed->hasRelation($link)) break;
$alias = $link . 'Filter' . strval(rand(10000, 99999));
$value = $item['value'];
if (is_null($value)) break;
$relationType = $seed->getRelationType($link);
if ($relationType == 'manyMany') {
$this->addLeftJoin([$link, $alias], $result);
$midKeys = $seed->getRelationParam($link, 'midKeys');
if (!empty($midKeys)) {
$key = $midKeys[1];
$part[$alias . 'Middle.' . $key] = $value;
}
} else if ($relationType == 'hasMany') {
$this->addLeftJoin([$link, $alias], $result);
$part[$alias . '.id'] = $value;
} else if ($relationType == 'belongsTo') {
$key = $seed->getRelationParam($link, 'key');
if (!empty($key)) {
$part[$key] = $value;
}
} else if ($relationType == 'hasOne') {
$this->addLeftJoin([$link, $alias], $result);
$part[$alias . '.id'] = $value;
} else {
break;;
}
$this->setDistinct(true, $result);
break;
case 'notLinkedWith':
$seed = $this->getSeed();
$link = $attribute;
if (!$seed->hasRelation($link)) break;
$value = $item['value'];
if (is_null($value)) break;
$relationType = $seed->getRelationType($link);
$alias = $link . 'NotLinkedFilter' . strval(rand(10000, 99999));
if ($relationType == 'manyMany') {
$this->addLeftJoin([$link, $link . 'Filter'], $result);
$this->addLeftJoin([$link, $alias], $result);
$midKeys = $seed->getRelationParam($link, 'midKeys');
if (!empty($midKeys)) {
$key = $midKeys[1];
$part[$link . 'Filter' . 'Middle.' . $key] = $value;
$result['joinConditions'][$alias] = [$key => $value];
$part[$alias . 'Middle.' . $key] = null;
}
} else if ($relationType == 'hasMany') {
$alias = $link . 'Filter';
$this->addLeftJoin([$link, $alias], $result);
$part[$alias . '.id'] = $value;
$result['joinConditions'][$alias] = ['id' => $value];
$part[$alias . '.id'] = null;
} else if ($relationType == 'belongsTo') {
$key = $seed->getRelationParam($link, 'key');
if (!empty($key)) {
$part[$key] = $value;
$part[$key . '!='] = $value;
}
} else if ($relationType == 'hasOne') {
$this->addLeftJoin([$link, $link . 'Filter'], $result);
$part[$link . 'Filter' . '.id'] = $value;
$this->addLeftJoin([$link, alias], $result);
$part[$alias . '.id!='] = $value;
} else {
return;
break;
}
$this->setDistinct(true, $result);
}

View File

@@ -850,6 +850,48 @@ abstract class Base
return implode(' ', $joinsArr);
}
protected function buildJoinConditionStatement($alias, $f, $v)
{
$join = '';
$operator = '=';
if (!preg_match('/^[a-z0-9]+$/i', $f)) {
foreach (self::$comparisonOperators as $op => $opDb) {
if (strpos($f, $op) !== false) {
$f = trim(str_replace($op, '', $f));
$operator = $opDb;
break;
}
}
}
$join .= " AND {$alias}." . $this->toDb($this->sanitize($f)) . "";
if (is_array($v)) {
$arr = [];
foreach ($v as $item) {
$arr[] = $this->pdo->quote($item);
}
$operator = "IN";
if ($operator == '<>') {
$operator = 'NOT IN';
}
if (count($arr)) {
$join .= " " . $operator . " (" . implode(', ', $arr) . ")";
} else {
if ($operator === 'IN') {
$join .= " IS NULL";
} else {
$join .= " IS NOT NULL";
}
}
} else {
$join .= " " . $operator . " " . $this->pdo->quote($v);
}
return $join;
}
protected function getJoinRelated(IEntity $entity, $relationName, $left = false, $conditions = array(), $joinAlias = null)
{
$relOpt = $entity->relations[$relationName];
@@ -890,7 +932,7 @@ abstract class Base
$conditions = array_merge($conditions, $relOpt['conditions']);
}
foreach ($conditions as $f => $v) {
$join .= " AND {$midAlias}." . $this->toDb($this->sanitize($f)) . " = " . $this->pdo->quote($v);
$join .= $this->buildJoinConditionStatement($midAlias, $f, $v);
}
$join .= " {$pre}JOIN `{$distantTable}` AS `{$alias}` ON {$alias}." . $this->toDb($foreignKey) . " = {$midAlias}." . $this->toDb($distantKey)
@@ -906,13 +948,15 @@ abstract class Base
$alias = $joinAlias;
// TODO conditions
$join =
"{$pre}JOIN `{$distantTable}` AS `{$alias}` ON {$this->toDb($entity->getEntityType())}." . $this->toDb('id') . " = {$alias}." . $this->toDb($foreignKey)
. " AND "
. "{$alias}.deleted = " . $this->pdo->quote(0) . "";
foreach ($conditions as $f => $v) {
$join .= $this->buildJoinConditionStatement($alias, $f, $v);
}
return $join;
case IEntity::HAS_CHILDREN:

View File

@@ -525,7 +525,8 @@
"isFromTeams": "Is From Team",
"isNot": "Is Not",
"isNotOneOf": "Is Not One Of",
"anyOf": "Any Of"
"anyOf": "Any Of",
"noneOf": "None Of"
},
"varcharSearchRanges": {
"equals": "Equals",

View File

@@ -58,7 +58,7 @@ Espo.define('views/fields/link-multiple', 'views/fields/base', function (Dep) {
sortable: false,
searchTypeList: ['anyOf', 'isEmpty', 'isNotEmpty'],
searchTypeList: ['anyOf', 'isEmpty', 'isNotEmpty', 'noneOf'],
data: function () {
var ids = this.model.get(this.idsName);
@@ -148,7 +148,7 @@ Espo.define('views/fields/link-multiple', 'views/fields/base', function (Dep) {
},
handleSearchType: function (type) {
if (~['anyOf'].indexOf(type)) {
if (~['anyOf', 'noneOf'].indexOf(type)) {
this.$el.find('div.link-group-container').removeClass('hidden');
} else {
this.$el.find('div.link-group-container').addClass('hidden');
@@ -349,6 +349,18 @@ Espo.define('views/fields/link-multiple', 'views/fields/base', function (Dep) {
}
};
return data;
} else if (type === 'noneOf') {
var values = this.ids || [];
var data = {
type: 'notLinkedWith',
value: this.ids || [],
nameHash: this.nameHash,
data: {
type: type
}
};
return data;
} else if (type === 'isEmpty') {
var data = {
type: 'isNotLinked',

View File

@@ -432,8 +432,8 @@ Espo.define('views/fields/link', 'views/fields/base', function (Dep) {
value: [
{
type: 'notIn',
attribute: this.searchData.oneOfIdList,
value: value
attribute: this.idName,
value: this.searchData.oneOfIdList
},
{
type: 'isNull',