Improved filtering capabilities
This commit is contained in:
		
					parent
					
						
							
								82772f4310
							
						
					
				
			
			
				commit
				
					
						1f433ff42e
					
				
			
		
					 3 changed files with 59 additions and 37 deletions
				
			
		|  | @ -168,6 +168,7 @@ GET http://localhost/api.php/categories?filter=name,sw,Inter | |||
| GET http://localhost/api.php/categories?filter=id,le,1 | ||||
| GET http://localhost/api.php/categories?filter=id,ngt,2 | ||||
| GET http://localhost/api.php/categories?filter=id,bt,1,1 | ||||
| GET http://localhost/api.php/categories?filter=categories.id,eq,1 | ||||
| ``` | ||||
| 
 | ||||
| Output: | ||||
|  | @ -176,6 +177,8 @@ Output: | |||
| {"categories":{"columns":["id","name"],"records":[["1","Internet"]]}} | ||||
| ``` | ||||
| 
 | ||||
| NB: You may specify table name before the field name, seperated with a dot. | ||||
| 
 | ||||
| ### List + Filter + Satisfy | ||||
| 
 | ||||
| Multiple filters can be applied by using "filter[]" instead of "filter" as a parameter name. Then the parameter "satisfy" is used to indicate whether "all" (default) or "any" filter should be satisfied to lead to a match: | ||||
|  | @ -183,6 +186,7 @@ Multiple filters can be applied by using "filter[]" instead of "filter" as a par | |||
| ``` | ||||
| GET http://localhost/api.php/categories?filter[]=id,eq,1&filter[]=id,eq,3&satisfy=any | ||||
| GET http://localhost/api.php/categories?filter[]=id,ge,1&filter[]=id,le,3&satisfy=all | ||||
| GET http://localhost/api.php/categories?filter[]=id,ge,1&filter[]=id,le,3&satisfy=categories.all | ||||
| GET http://localhost/api.php/categories?filter[]=id,ge,1&filter[]=id,le,3 | ||||
| ``` | ||||
| 
 | ||||
|  | @ -192,6 +196,8 @@ Output: | |||
| {"categories":{"columns":["id","name"],"records":[["1","Internet"],["3","Web development"]]}} | ||||
| ``` | ||||
| 
 | ||||
| NB: You may specify "satisfy=categories.all,posts.any" if you want to mix "and" and "or" for different tables. | ||||
| 
 | ||||
| ### List + Column selection | ||||
| 
 | ||||
| By default all columns are selected. With the "columns" parameter you can select specific columns. Multiple columns should be comma separated. An asterisk ("*") may be used as a wildcard to indicate "all columns": | ||||
|  |  | |||
							
								
								
									
										86
									
								
								api.php
									
										
									
									
									
								
							
							
						
						
									
										86
									
								
								api.php
									
										
									
									
									
								
							|  | @ -946,12 +946,7 @@ class PHP_CRUD_API { | |||
| 
 | ||||
| 	protected function applyRecordFilter($callback,$action,$database,$tables,&$filters) { | ||||
| 		if (is_callable($callback,true)) foreach ($tables as $i=>$table) { | ||||
| 			$f = $this->convertFilters($callback($action,$database,$table)); | ||||
| 			if ($f) { | ||||
| 				if (!isset($filters[$table])) $filters[$table] = array(); | ||||
| 				if (!isset($filters[$table]['and'])) $filters[$table]['and'] = array(); | ||||
| 				$filters[$table]['and'] = array_merge($filters[$table]['and'],$f); | ||||
| 			} | ||||
| 			$this->addFilters($filters,$table,array($table=>'and'),$callback($action,$database,$table)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -960,10 +955,8 @@ class PHP_CRUD_API { | |||
| 			foreach ($keys as $field) { | ||||
| 				$v = $callback($action,$database,$table,$field->name); | ||||
| 				if ($v!==null) { | ||||
| 					if (!isset($filters[$table])) $filters[$table] = array(); | ||||
| 					if (!isset($filters[$table]['and'])) $filters[$table]['and'] = array(); | ||||
| 					if (is_array($v)) $filters[$table]['and'][] = $this->convertFilter($field->name,'in',implode(',',$v)); | ||||
| 					else $filters[$table]['and'][] = $this->convertFilter($field->name,'eq',$v); | ||||
| 					if (is_array($v)) $this->addFilter($filters,$table,'and',$field->name,'in',implode(',',$v)); | ||||
| 					else $this->addFilter($filters,$table,'and',$field->name,'eq',$v); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | @ -1191,28 +1184,44 @@ class PHP_CRUD_API { | |||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	public function convertFilters($filters) { | ||||
| 		$result = array(); | ||||
| 		if ($filters) { | ||||
| 			for ($i=0;$i<count($filters);$i++) { | ||||
| 				$parts = explode(',',$filters[$i],3); | ||||
| 				if (count($parts)>=2) { | ||||
| 					$field = $parts[0]; | ||||
| 					$comparator = $parts[1]; | ||||
| 					$value = isset($parts[2])?$parts[2]:null; | ||||
| 	public function addFilter(&$filters,$table,$and,$field,$comparator,$value) { | ||||
| 		if (!isset($filters[$table])) $filters[$table] = array(); | ||||
| 		if (!isset($filters[$table][$and])) $filters[$table][$and] = array(); | ||||
| 		$filter = $this->convertFilter($field,$comparator,$value); | ||||
| 					if ($filter) $result[] = $filter; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return $result; | ||||
| 		if ($filter) $filters[$table][$and][] = $filter; | ||||
| 	} | ||||
| 
 | ||||
| 	protected function processFiltersParameter($tables,$satisfy,$filters) { | ||||
| 		$result = $this->convertFilters($filters); | ||||
| 		if (!$result) return array(); | ||||
| 		$and = ($satisfy && strtolower($satisfy)=='any')?'or':'and'; | ||||
| 		return array($tables[0]=>array($and=>$result)); | ||||
| 	public function addFilters(&$filters,$table,$satisfy,$filterStrings) { | ||||
| 		if ($filterStrings) { | ||||
| 			for ($i=0;$i<count($filterStrings);$i++) { | ||||
| 				$parts = explode(',',$filterStrings[$i],3); | ||||
| 				if (count($parts)>=2) { | ||||
| 					if (strpos($parts[0],'.')) list($t,$f) = explode('.',$parts[0],2); | ||||
| 					else list($t,$f) = array($table,$parts[0]); | ||||
| 					$comparator = $parts[1]; | ||||
| 					$value = isset($parts[2])?$parts[2]:null; | ||||
| 					$and = isset($satisfy[$t])?$satisfy[$t]:'and'; | ||||
| 					$this->addFilter($filters,$t,$and,$f,$comparator,$value); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	protected function processSatisfyParameter($tables,$satisfyString) { | ||||
| 		$satisfy = array(); | ||||
| 		foreach (explode(',',$satisfyString) as $str) { | ||||
| 			if (strpos($str,'.')) list($t,$s) = explode('.',$str,2); | ||||
| 			else list($t,$s) = array($tables[0],$str); | ||||
| 			$and = ($s && strtolower($s)=='any')?'or':'and'; | ||||
| 			$satisfy[$t] = $and; | ||||
| 		} | ||||
| 		return $satisfy; | ||||
| 	} | ||||
| 
 | ||||
| 	protected function processFiltersParameter($tables,$satisfy,$filterStrings) { | ||||
| 		$filters = array(); | ||||
| 		$this->addFilters($filters,$tables[0],$satisfy,$filterStrings); | ||||
| 		return $filters; | ||||
| 	} | ||||
| 
 | ||||
| 	protected function processPageParameter($page) { | ||||
|  | @ -1231,9 +1240,7 @@ class PHP_CRUD_API { | |||
| 		$this->convertOutputs($sql,$params,$fields[$table]); | ||||
| 		$sql .= ' FROM !'; | ||||
| 		$params[] = $table; | ||||
| 		if (!isset($filters[$table])) $filters[$table] = array(); | ||||
| 		if (!isset($filters[$table]['and'])) $filters[$table]['and'] = array(); | ||||
| 		$filters[$table]['and'][] = $this->convertFilter($key[1],'eq',$key[0]); | ||||
| 		$this->addFilter($filters,$table,'and',$key[1],'eq',$key[0]); | ||||
| 		$this->addWhereFromFilters($filters[$table],$sql,$params); | ||||
| 		$object = null; | ||||
| 		if ($result = $this->db->query($sql,$params)) { | ||||
|  | @ -1289,9 +1296,7 @@ class PHP_CRUD_API { | |||
| 			$params[] = $k; | ||||
| 			$params[] = $v; | ||||
| 		} | ||||
| 		if (!isset($filters[$table])) $filters[$table] = array(); | ||||
| 		if (!isset($filters[$table]['and'])) $filters[$table]['and'] = array(); | ||||
| 		$filters[$table]['and'][] = $this->convertFilter($key[1],'eq',$key[0]); | ||||
| 		$this->addFilter($filters,$table,'and',$key[1],'eq',$key[0]); | ||||
| 		$this->addWhereFromFilters($filters[$table],$sql,$params); | ||||
| 		$result = $this->db->query($sql,$params); | ||||
| 		if (!$result) return null; | ||||
|  | @ -1302,9 +1307,7 @@ class PHP_CRUD_API { | |||
| 		$table = $tables[0]; | ||||
| 		$sql = 'DELETE FROM !'; | ||||
| 		$params = array($table); | ||||
| 		if (!isset($filters[$table])) $filters[$table] = array(); | ||||
| 		if (!isset($filters[$table]['and'])) $filters[$table]['and'] = array(); | ||||
| 		$filters[$table]['and'][] = $this->convertFilter($key[1],'eq',$key[0]); | ||||
| 		$this->addFilter($filters,$table,'and',$key[1],'eq',$key[0]); | ||||
| 		$this->addWhereFromFilters($filters[$table],$sql,$params); | ||||
| 		$result = $this->db->query($sql,$params); | ||||
| 		if (!$result) return null; | ||||
|  | @ -1467,13 +1470,14 @@ class PHP_CRUD_API { | |||
| 		$callback  = $this->parseGetParameter($get, 'callback', 'a-zA-Z0-9\-_'); | ||||
| 		$page      = $this->parseGetParameter($get, 'page', '0-9,'); | ||||
| 		$filters   = $this->parseGetParameterArray($get, 'filter', false); | ||||
| 		$satisfy   = $this->parseGetParameter($get, 'satisfy', 'a-zA-Z'); | ||||
| 		$satisfy   = $this->parseGetParameter($get, 'satisfy', 'a-zA-Z0-9\-_,.'); | ||||
| 		$columns   = $this->parseGetParameter($get, 'columns', 'a-zA-Z0-9\-_,.*'); | ||||
| 		$order     = $this->parseGetParameter($get, 'order', 'a-zA-Z0-9\-_,'); | ||||
| 		$transform = $this->parseGetParameter($get, 'transform', 't1'); | ||||
| 
 | ||||
| 		$tables    = $this->processTableAndIncludeParameters($database,$table,$include,$action); | ||||
| 		$key       = $this->processKeyParameter($key,$tables,$database); | ||||
| 		$satisfy   = $this->processSatisfyParameter($tables,$satisfy); | ||||
| 		$filters   = $this->processFiltersParameter($tables,$satisfy,$filters); | ||||
| 		$page      = $this->processPageParameter($page); | ||||
| 		$order     = $this->processOrderParameter($order); | ||||
|  | @ -1608,9 +1612,7 @@ class PHP_CRUD_API { | |||
| 				foreach ($select[$table] as $field => $path) { | ||||
| 					$values = $collect[$path[0]][$path[1]]; | ||||
| 					if ($values) { | ||||
| 						if (!isset($filters[$table])) $filters[$table] = array(); | ||||
| 						if (!isset($filters[$table]['and'])) $filters[$table]['and'] = array(); | ||||
| 						$filters[$table]['and'][] = $this->convertFilter($field,'in',implode(',',$values)); | ||||
| 						$this->addFilter($filters,$table,'and',$field,'in',implode(',',$values)); | ||||
| 					} | ||||
| 					if ($first_row) $first_row = false; | ||||
| 					else echo ','; | ||||
|  |  | |||
|  | @ -569,6 +569,20 @@ class PHP_CRUD_API_Test extends PHPUnit_Framework_TestCase | |||
| 		$test->expect('{"posts":[{"category_id":"1","categories":[{"id":"1","name":"announcement"}]}]}'); | ||||
| 	} | ||||
| 
 | ||||
| 	public function testFilterOnRelationAnd() | ||||
| 	{ | ||||
| 		$test = new API($this); | ||||
| 		$test->get('/categories?include=posts&filter[]=id,ge,1&filter[]=id,le,1&filter[]=id,le,2&filter[]=posts.id,lt,8&filter[]=posts.id,gt,4'); | ||||
| 		$test->expect('{"categories":{"columns":["id","name","icon"],"records":[["1","announcement",null]]},"posts":{"relations":{"category_id":"categories.id"},"columns":["id","user_id","category_id","content"],"records":[["5","1","1","#1"],["6","1","1","#2"],["7","1","1","#3"]]}}'); | ||||
| 	} | ||||
| 
 | ||||
| 	public function testFilterOnRelationOr() | ||||
| 	{ | ||||
| 		$test = new API($this); | ||||
| 		$test->get('/categories?include=posts&filter[]=id,ge,1&filter[]=id,le,1&filter[]=posts.id,eq,5&filter[]=posts.id,eq,6&filter[]=posts.id,eq,7&satisfy=all,posts.any'); | ||||
| 		$test->expect('{"categories":{"columns":["id","name","icon"],"records":[["1","announcement",null]]},"posts":{"relations":{"category_id":"categories.id"},"columns":["id","user_id","category_id","content"],"records":[["5","1","1","#1"],["6","1","1","#2"],["7","1","1","#3"]]}}'); | ||||
| 	} | ||||
| 
 | ||||
| 	public function testColumnsOnWrongInclude() | ||||
| 	{ | ||||
| 		$test = new API($this); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Maurits van der Schee
				Maurits van der Schee