diff --git a/api/src/Storage.php b/api/src/Storage.php index f018bb3983..dda50433d1 100644 --- a/api/src/Storage.php +++ b/api/src/Storage.php @@ -407,31 +407,37 @@ class Storage extends Storage\Base } /** - * Return criteria array for a given search pattern + * Return SQL fragment to search custom-fields for given $pattern * - * Reimplemented to handle search in custom-fields by ORing with a sub-query - * returning all auto-ids of custom-fields matching the search-criteria + * To be or-ed to query for $_pattern in regular columns of main-table. * * @param string $_pattern search pattern incl. * or ? as wildcard, if no wildcards used we append and prepend one! - * @param string &$wildcard ='' on return wildcard char to use, if pattern does not already contain wildcards! - * @param string &$op ='AND' on return boolean operation to use, if pattern does not start with ! we use OR else AND - * @param string $extra_col =null extra column to search - * @param array $search_cols =array() List of columns to search. If not provided, all columns in $this->db_cols will be considered - * @return array or column => value pairs + * @return string with SQL fragment running on main table: "id IN (SELECT id FROM extra-table WHERE extra_value like '$pattern')" */ - public function search2criteria($_pattern,&$wildcard='',&$op='AND',$extra_col=null, $search_cols = array()) + public function cf_match($_pattern) { - $pattern = $wildcard.$_pattern.$wildcard; + static $private_cfs=null; - $criteria = parent::search2criteria($_pattern, $wildcard, $op, $extra_col, $search_cols); + if (!$this->customfields) return ''; // no custom-fields --> no search - $criteria[0] = '('.$criteria[0].' OR '. - $this->table_name.'.'.$this->autoinc_id.' IN (SELECT '.$this->autoinc_id. + $sql = ' OR '.$this->table_name.'.'.$this->autoinc_id.' IN (SELECT '.$this->autoinc_id. ' FROM '.$this->extra_table.' WHERE '.$this->extra_value.' '. $this->db->capabilities[Db::CAPABILITY_CASE_INSENSITIV_LIKE].' '. - $GLOBALS['egw']->db->quote($pattern).'))'; + $GLOBALS['egw']->db->quote($_pattern); - return $criteria; + // check if there are private cfs not available to current user --> filter by available cfs + if (!isset($private_cfs)) + { + $private_cfs = array_diff_key( + Storage\Customfields::get($this->app, true, null, $this->db), // true: get private cfs too + $this->customfields); + //error_log(__METHOD__."() private_cfs=".array2string($private_cfs)); + } + if ($private_cfs) + { + $sql .= ' AND '.$this->db->expression($this->extra_table, array($this->extra_key => array_keys($this->customfields))); + } + return $sql.')'; } /** diff --git a/api/src/Storage/Base.php b/api/src/Storage/Base.php index 639e944a2a..25d689e31f 100644 --- a/api/src/Storage/Base.php +++ b/api/src/Storage/Base.php @@ -1056,16 +1056,16 @@ class Base * Parse an array of search criteria into something that can be passed on * to the DB * - * @param array $criteria + * @param array $_criteria * @param string $wildcard ='' appended befor and after each criteria * @param boolean $empty =false False=empty criteria are ignored in query, True=empty have to be empty in row * @param string $op ='AND' defaults to 'AND', can be set to 'OR' too, then criteria's are OR'ed together * @return Array * @throws Api\Db\Exception */ - protected function parse_search(Array $criteria, $wildcard, $empty, $op) + protected function parse_search(Array $_criteria, $wildcard, $empty, $op) { - $criteria = $this->data2db($criteria); + $criteria = $this->data2db($_criteria); foreach($criteria as $col => $val) { if (is_int($col)) @@ -1351,9 +1351,17 @@ class Base $op = 'OR'; break; } + $search_token = $wildcard.str_replace(array('%','_','*','?'),array('\\%','\\_','%','_'),$token).$wildcard; $token_filter = ' '.call_user_func_array(array($GLOBALS['egw']->db,'concat'),$columns).' '. $this->db->capabilities['case_insensitive_like'] . ' ' . - $GLOBALS['egw']->db->quote($wildcard.str_replace(array('%','_','*','?'),array('\\%','\\_','%','_'),$token).$wildcard); + $GLOBALS['egw']->db->quote($search_token); + + // if we have customfields and this is Api\Storage (not Api\Storage\Base) + if (is_a($this, __NAMESPACE__)) + { + // add custom-field search: OR id IN (SELECT id FROM extra_table WHERE extra_value LIKE '$search_token') + $token_filter .= $this->cf_match($search_token); + } // Compare numeric token as equality for numeric columns // skip user-wildcards (*,?) in is_numeric test, but not SQL wildcards, which get escaped and give sql-error @@ -1376,10 +1384,10 @@ class Base } if(count($numeric_filter) > 0) { - $token_filter = '(' . $token_filter . ' OR ' . implode(' OR ', $numeric_filter) . ')'; + $token_filter .= ' OR ' . implode(' OR ', $numeric_filter); } } - $criteria[$op][] = $token_filter; + $criteria[$op][] = '('.$token_filter.')'; $token = strtok($break); }