wbond / flourish (http://flourishlib.com/)

Flourish is a PHP unframework — a general-purpose, object-oriented library. It's architecture is modular and thus not strictly MVC. It focuses on being secure, broadly compatible, portable, well documented and easy to use.

Clone this repository (size: 2.3 MB): HTTPS / SSH
$ hg clone http://bitbucket.org/wbond/flourish/
commit 733: 718fe2bd60fe
parent 732: 6f3e97513957
branch: trunk
[svn r734] Fixed ticket #347 - fRecordSet::build() can now compare columns by using the =:, !=:, <:, <=:, >:, >=: operators
Will Bond / wbond
3 months ago

Changed (Δ3.5 KB):

raw changeset »

classes/fORMDatabase.php (66 lines added, 32 lines removed)

classes/fRecordSet.php (20 lines added, 2 lines removed)

Up to file-list classes/fORMDatabase.php:

10
10
 * @package    Flourish
11
11
 * @link       http://flourishlib.com/fORMDatabase
12
12
 * 
13
 * @version    1.0.0b18
13
 * @version    1.0.0b19
14
 * @changes    1.0.0b19  Added the ability to compare columns with the `=:`, `!:`, `<:`, `<=:`, `>:` and `>=:` operators [wb, 2009-12-08]
14
15
 * @changes    1.0.0b18  Fixed a bug affecting where conditions with columns that are not null but have a default value [wb, 2009-11-03]
15
16
 * @changes    1.0.0b17  Added support for multiple databases [wb, 2009-10-28]
16
17
 * @changes    1.0.0b16  Internal Backwards Compatibility Break - Renamed methods and significantly changed parameters and functionality for SQL statements to use value placeholders, identifier escaping and to handle schemas [wb, 2009-10-22]
@@ -133,9 +134,9 @@ class fORMDatabase
133
134
		}
134
135
		
135
136
		list($table, $column) = self::getTableAndColumn($schema, $table, $column);
136
		
137
		if ($placeholder === NULL) {
138
			$placeholder = $schema->getColumnInfo($table, $column, 'placeholder');	
137
								 
138
		if ($placeholder === NULL && !in_array($operator, array('=:', '!=:', '<:', '<=:', '>:', '>=:'))) {
139
			$placeholder = $schema->getColumnInfo($table, $column, 'placeholder');
139
140
		}
140
141
		
141
142
		// More than one value
@@ -225,6 +226,29 @@ class fORMDatabase
225
226
			}
226
227
								  
227
228
			switch ($operator) {
229
				case '!:':
230
					$operator = '<>:';
231
				case '=:':
232
				case '<:':
233
				case '<=:':
234
				case '>:':
235
				case '>=:':
236
					$params[0] .= $escaped_column . ' ';
237
					$params[0] .= substr($operator, 0, -1) . ' ';
238
					
239
					// If the column to match is a function, split the function
240
					// name off so we can escape the column name
241
					$prefix = '';
242
					$suffix = '';
243
					if (preg_match('#^([^(]+\()\s*([^\s]+)\s*(\))$#D', $value, $parts)) {
244
						 $prefix = $parts[1];
245
						 $value  = $parts[2];
246
						 $suffix = $parts[3];
247
					}
248
					
249
					$params[0] .= $prefix . $db->escape('%r', (strpos($value, '.') === FALSE) ? $table . '.' . $value : $value) . $suffix;
250
					break;
251
				
228
252
				case '=':
229
253
					if ($value === NULL) {
230
254
						$operator = 'IS';	
@@ -299,13 +323,16 @@ class fORMDatabase
299
323
			}
300
324
			
301
325
			// Splits the operator off of the end of the expression
302
			if (in_array(substr($expression, -2), array('<=', '>=', '!=', '<>'))) {
326
			if (in_array(substr($expression, -3), array('!=:', '>=:', '<=:', '<>:'))) {
327
				$operator = strtr(
328
					substr($expression, -3),
329
					array('<>:' => '!:', '!=:' => '!:')
330
				);
331
				$expression = substr($expression, 0, -3);
332
			} elseif (in_array(substr($expression, -2), array('<=', '>=', '!=', '<>', '=:', '!:', '<:', '>:'))) {
303
333
				$operator   = strtr(
304
334
					substr($expression, -2),
305
					array(
306
						'<>' => '!',
307
						'!=' => '!'
308
					)
335
					array('<>' => '!', '!=' => '!')
309
336
				);
310
337
				$expression = substr($expression, 0, -2);
311
338
			} else {
@@ -463,13 +490,16 @@ class fORMDatabase
463
490
				$params[0] .= ' AND ';	
464
491
			}
465
492
			
466
			if (in_array(substr($column, -2), array('<=', '>=', '!=', '<>', '!~', '&~', '><'))) {
493
			if (in_array(substr($column, -3), array('!=:', '>=:', '<=:', '<>:'))) {
494
				$operator = strtr(
495
					substr($column, -3),
496
					array('<>:' => '!:', '!=:' => '!:')
497
				);
498
				$column   = substr($column, 0, -3);
499
			} elseif (in_array(substr($column, -2), array('<=', '>=', '!=', '<>', '!~', '&~', '><', '=:', '!:', '<:', '>:'))) {
467
500
				$operator = strtr(
468
501
					substr($column, -2),
469
					array(
470
						'<>' => '!',
471
						'!=' => '!'
472
					)
502
					array('<>' => '!', '!=' => '!')
473
503
				);
474
504
				$column   = substr($column, 0, -2);
475
505
			} else {
@@ -501,13 +531,16 @@ class fORMDatabase
501
531
				$operators = array();
502
532
				
503
533
				foreach ($columns as &$_column) {
504
					if (in_array(substr($_column, -2), array('<=', '>=', '!=', '<>', '!~', '&~'))) {
534
					if (in_array(substr($_column, -3), array('!=:', '>=:', '<=:', '<>:'))) {
535
						$operators[] = strtr(
536
							substr($_column, -3),
537
							array('<>:' => '!:', '!=:' => '!:')
538
						);
539
						$_column     = substr($_column, 0, -3);
540
					} elseif (in_array(substr($_column, -2), array('<=', '>=', '!=', '<>', '!~', '&~', '=:', '!:', '<:', '>:'))) {
505
541
						$operators[] = strtr(
506
542
							substr($_column, -2),
507
							array(
508
								'<>' => '!',
509
								'!=' => '!'
510
							)
543
							array('<>' => '!', '!=' => '!')
511
544
						);
512
545
						$_column     = substr($_column, 0, -2);
513
546
					} elseif (!ctype_alnum(substr($_column, -1))) {
@@ -517,17 +550,17 @@ class fORMDatabase
517
550
				}
518
551
				$operators[] = $operator;
519
552
				
520
				// Make sure every column is qualified by a table name
521
				$new_columns = array();
522
				foreach ($columns as $column) {
523
					if (strpos($column, '.') === FALSE) {
524
						$column = $table . '.' . $column;
553
				if (sizeof($operators) == 1) {
554
					
555
					// Make sure every column is qualified by a table name
556
					$new_columns = array();
557
					foreach ($columns as $column) {
558
						if (strpos($column, '.') === FALSE) {
559
							$column = $table . '.' . $column;
560
						}
561
						$new_columns[] = $column;	
525
562
					}
526
					$new_columns[] = $column;	
527
				}
528
				$columns = $new_columns;
529
				
530
				if (sizeof($operators) == 1) {
563
					$columns = $new_columns;
531
564
					
532
565
					// Handle fuzzy searches
533
566
					if ($operator == '~') {
@@ -1216,9 +1249,10 @@ class fORMDatabase
1216
1249
	{
1217
1250
		$having_conditions = array();
1218
1251
		
1219
		foreach ($where_conditions as $column => $value)
1220
		{
1221
			if (preg_match('#^(count\(|max\(|avg\(|min\(|sum\()#i', $column)) {
1252
		foreach ($where_conditions as $column => $value) {
1253
			$column_has_aggregate             = preg_match('#^(count\(|max\(|avg\(|min\(|sum\()#i', $column);
1254
			$is_column_compare_with_aggregate = substr($column, -1) == ':' && preg_match('#^(count\(|max\(|avg\(|min\(|sum\()#i', $value);
1255
			if ($column_has_aggregate || $is_column_compare_with_aggregate) {
1222
1256
				$having_conditions[$column] = $value;
1223
1257
				unset($where_conditions[$column]);
1224
1258
			}	

Up to file-list classes/fRecordSet.php:

9
9
 * @package    Flourish
10
10
 * @link       http://flourishlib.com/fRecordSet
11
11
 * 
12
 * @version    1.0.0b30
12
 * @version    1.0.0b31
13
 * @changes    1.0.0b31  Added the ability to compare columns in ::build() with the `=:`, `!:`, `<:`, `<=:`, `>:` and `>=:` operators [wb, 2009-12-08]
13
14
 * @changes    1.0.0b30  Fixed a bug affecting where conditions with columns that are not null but have a default value [wb, 2009-11-03]
14
15
 * @changes    1.0.0b29  Updated code for the new fORMDatabase and fORMSchema APIs [wb, 2009-10-28]
15
16
 * @changes    1.0.0b28  Fixed ::prebuild() and ::precount() to work across all databases, changed SQL statements to use value placeholders, identifier escaping and schema support [wb, 2009-10-22]
@@ -66,6 +67,14 @@ class fRecordSet implements Iterator, Co
66
67
	 * 'column<='                   => VALUE                        // column <= VALUE
67
68
	 * 'column>'                    => VALUE                        // column > VALUE
68
69
	 * 'column>='                   => VALUE                        // column >= VALUE
70
	 * 'column=:'                   => 'other_column'               // column = other_column
71
	 * 'column!:'                   => 'other_column'               // column <> other_column
72
	 * 'column!=:'                  => 'other_column'               // column <> other_column
73
	 * 'column<>:'                  => 'other_column'               // column <> other_column
74
	 * 'column<:'                   => 'other_column'               // column < other_column
75
	 * 'column<=:'                  => 'other_column'               // column <= other_column
76
	 * 'column>:'                   => 'other_column'               // column > other_column
77
	 * 'column>=:'                  => 'other_column'               // column >= other_column
69
78
	 * 'column='                    => array(VALUE, VALUE2, ... )   // column IN (VALUE, VALUE2, ... )
70
79
	 * 'column!'                    => array(VALUE, VALUE2, ... )   // column NOT IN (VALUE, VALUE2, ... )
71
80
	 * 'column!='                   => array(VALUE, VALUE2, ... )   // column NOT IN (VALUE, VALUE2, ... )
@@ -113,7 +122,8 @@ class fRecordSet implements Iterator, Co
113
122
	 * 
114
123
	 * In addition to using plain column names for where conditions, it is also
115
124
	 * possible to pass an aggregate function wrapped around a column in place
116
	 * of a column name, but only for certain comparison types:
125
	 * of a column name, but only for certain comparison types. //Note that for
126
	 * column comparisons, the function may be placed on either column or both.//
117
127
	 * 
118
128
	 * {{{
119
129
	 * 'function(column)='   => VALUE,                       // function(column) = VALUE
@@ -126,6 +136,14 @@ class fRecordSet implements Iterator, Co
126
136
	 * 'function(column)<='  => VALUE                        // function(column) <= VALUE
127
137
	 * 'function(column)>'   => VALUE                        // function(column) > VALUE
128
138
	 * 'function(column)>='  => VALUE                        // function(column) >= VALUE
139
	 * 'function(column)=:'  => 'other_column'               // function(column) = other_column
140
	 * 'function(column)!:'  => 'other_column'               // function(column) <> other_column
141
	 * 'function(column)!=:' => 'other_column'               // function(column) <> other_column
142
	 * 'function(column)<>:' => 'other_column'               // function(column) <> other_column
143
	 * 'function(column)<:'  => 'other_column'               // function(column) < other_column
144
	 * 'function(column)<=:' => 'other_column'               // function(column) <= other_column
145
	 * 'function(column)>:'  => 'other_column'               // function(column) > other_column
146
	 * 'function(column)>=:' => 'other_column'               // function(column) >= other_column
129
147
	 * 'function(column)='   => array(VALUE, VALUE2, ... )   // function(column) IN (VALUE, VALUE2, ... )
130
148
	 * 'function(column)!'   => array(VALUE, VALUE2, ... )   // function(column) NOT IN (VALUE, VALUE2, ... )
131
149
	 * 'function(column)!='  => array(VALUE, VALUE2, ... )   // function(column) NOT IN (VALUE, VALUE2, ... )