case 'REGEXP':
case 'NOT REGEXP':
- $pattern = '/' . str_replace('/', '\\/', $expected) . '/';
- return !preg_match($pattern, $value) == ($operator != 'REGEXP');
+ case 'REGEXP BINARY':
+ case 'NOT REGEXP BINARY':
+ // Perform case-sensitive matching for BINARY operator, otherwise insensitive
+ $i = str_ends_with($operator, 'BINARY') ? '' : 'i';
+ $pattern = '/' . str_replace('/', '\\/', $expected) . "/$i";
+ return !preg_match($pattern, $value) == str_starts_with($operator, 'NOT');
case 'IN':
return in_array($value, $expected);
* * '=', '<=', '>=', '>', '<', 'LIKE', "<>", "!=",
* * 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN',
* * 'IS NOT NULL', 'IS NULL', 'CONTAINS', 'NOT CONTAINS',
- * * 'IS EMPTY', 'IS NOT EMPTY', 'REGEXP', 'NOT REGEXP'.
+ * * 'IS EMPTY', 'IS NOT EMPTY', 'REGEXP', 'NOT REGEXP'
+ * * 'REGEXP BINARY', 'NOT REGEXP BINARY'
*/
abstract class Api4Query {
}
}
- if ($operator == 'REGEXP' || $operator == 'NOT REGEXP') {
+ if ($operator == 'REGEXP' || $operator == 'NOT REGEXP' || $operator == 'REGEXP BINARY' || $operator == 'NOT REGEXP BINARY') {
return sprintf('%s %s "%s"', $fieldAlias, $operator, \CRM_Core_DAO::escapeString($value));
}
$operators[] = 'IS NOT EMPTY';
$operators[] = 'REGEXP';
$operators[] = 'NOT REGEXP';
+ $operators[] = 'REGEXP BINARY';
+ $operators[] = 'NOT REGEXP BINARY';
return $operators;
}
'NOT LIKE' => E::ts('Not Like'),
'REGEXP' => E::ts('Matches Pattern'),
'NOT REGEXP' => E::ts("Doesn't Match Pattern"),
+ 'REGEXP BINARY' => E::ts('Matches Pattern (case-sensitive)'),
+ 'NOT REGEXP BINARY' => E::ts("Doesn't Match Pattern (case-sensitive)"),
];
}
'NOT LIKE' => E::ts('Not Like'),
'REGEXP' => E::ts('Matches Pattern'),
'NOT REGEXP' => E::ts("Doesn't Match Pattern"),
+ 'REGEXP BINARY' => E::ts('Matches Pattern (case-sensitive)'),
+ 'NOT REGEXP BINARY' => E::ts("Doesn't Match Pattern (case-sensitive)"),
'BETWEEN' => E::ts('Is Between'),
'NOT BETWEEN' => E::ts('Not Between'),
'IS EMPTY' => E::ts('Is Empty'),
this.getTemplate = function() {
var field = ctrl.field || {};
- if (_.includes(['LIKE', 'NOT LIKE', 'REGEXP', 'NOT REGEXP'], ctrl.op)) {
+ if (_.includes(['LIKE', 'NOT LIKE', 'REGEXP', 'NOT REGEXP', 'REGEXP BINARY', 'NOT REGEXP BINARY'], ctrl.op)) {
return '~/crmSearchTasks/crmSearchInput/text.html';
}
}
#bootstrap-theme.crm-search .api4-operator {
- width: 110px;
+ width: 235px;
}
#bootstrap-theme.crm-search input[type=number] {
->setValues(['first_name' => 'Jane', 'last_name' => $last_name])
->execute()->first();
+ $holly = Contact::create()
+ ->setValues(['first_name' => 'holly', 'last_name' => $last_name])
+ ->execute()->first();
+
+ $meg = Contact::create()
+ ->setValues(['first_name' => 'meg', 'last_name' => $last_name])
+ ->execute()->first();
+
+ $jess = Contact::create()
+ ->setValues(['first_name' => 'jess', 'last_name' => $last_name])
+ ->execute()->first();
+
+ $amy = Contact::create()
+ ->setValues(['first_name' => 'amy', 'last_name' => $last_name])
+ ->execute()->first();
+
$result = Contact::get(FALSE)
->addWhere('last_name', '=', $last_name)
->addWhere('first_name', 'REGEXP', '^A')
->execute()->indexBy('id');
- $this->assertCount(2, $result);
+ $this->assertCount(3, $result);
$this->assertArrayHasKey($alice['id'], (array) $result);
$this->assertArrayHasKey($alex['id'], (array) $result);
+ $this->assertArrayHasKey($amy['id'], (array) $result);
$result = Contact::get(FALSE)
->addWhere('last_name', '=', $last_name)
->addWhere('first_name', 'NOT REGEXP', '^A')
->execute()->indexBy('id');
- $this->assertCount(1, $result);
+ $this->assertCount(4, $result);
+ $this->assertArrayHasKey($jane['id'], (array) $result);
+ $this->assertArrayHasKey($holly['id'], (array) $result);
+ $this->assertArrayHasKey($meg['id'], (array) $result);
+ $this->assertArrayHasKey($jess['id'], (array) $result);
+
+ $result = Contact::get(FALSE)
+ ->addWhere('last_name', '=', $last_name)
+ ->addWhere('first_name', 'REGEXP BINARY', '^[A-Z]')
+ ->execute()->indexBy('id');
+ $this->assertCount(3, $result);
+ $this->assertArrayHasKey($alice['id'], (array) $result);
+ $this->assertArrayHasKey($alex['id'], (array) $result);
+ $this->assertArrayHasKey($jane['id'], (array) $result);
+
+ $result = Contact::get(FALSE)
+ ->addWhere('last_name', '=', $last_name)
+ ->addWhere('first_name', 'REGEXP BINARY', '^[a-z]')
+ ->execute()->indexBy('id');
+ $this->assertCount(4, $result);
+ $this->assertArrayHasKey($holly['id'], (array) $result);
+ $this->assertArrayHasKey($meg['id'], (array) $result);
+ $this->assertArrayHasKey($jess['id'], (array) $result);
+ $this->assertArrayHasKey($amy['id'], (array) $result);
+
+ $result = Contact::get(FALSE)
+ ->addWhere('last_name', '=', $last_name)
+ ->addWhere('first_name', 'NOT REGEXP BINARY', '^[A-Z]')
+ ->execute()->indexBy('id');
+ $this->assertCount(4, $result);
+ $this->assertArrayHasKey($holly['id'], (array) $result);
+ $this->assertArrayHasKey($meg['id'], (array) $result);
+ $this->assertArrayHasKey($jess['id'], (array) $result);
+ $this->assertArrayHasKey($amy['id'], (array) $result);
+
+ $result = Contact::get(FALSE)
+ ->addWhere('last_name', '=', $last_name)
+ ->addWhere('first_name', 'NOT REGEXP BINARY', '^[a-z]')
+ ->execute()->indexBy('id');
+ $this->assertCount(3, $result);
+ $this->assertArrayHasKey($alice['id'], (array) $result);
+ $this->assertArrayHasKey($alex['id'], (array) $result);
$this->assertArrayHasKey($jane['id'], (array) $result);
}
// The object's count() method will account for all results, ignoring limit, while the array results are limited
$this->assertCount(2, (array) $result);
- $this->assertCount(5, $result);
+ $this->assertCount(6, $result);
}
public function testArrayGetWithSort(): void {
$result = MockArrayEntity::get()
->addOrderBy('field1', 'DESC')
->execute();
- $this->assertEquals([5, 4, 3, 2, 1], array_column((array) $result, 'field1'));
+ $this->assertEquals([6, 5, 4, 3, 2, 1], array_column((array) $result, 'field1'));
$result = MockArrayEntity::get()
->addOrderBy('field5', 'DESC')
->addOrderBy('field2', 'ASC')
->execute();
- $this->assertEquals([3, 2, 5, 4, 1], array_column((array) $result, 'field1'));
+ $this->assertEquals([3, 2, 5, 4, 1, 6], array_column((array) $result, 'field1'));
$result = MockArrayEntity::get()
->addOrderBy('field3', 'ASC')
->addOrderBy('field2', 'ASC')
->execute();
- $this->assertEquals([3, 1, 2, 5, 4], array_column((array) $result, 'field1'));
+ $this->assertEquals([3, 1, 2, 5, 4, 6], array_column((array) $result, 'field1'));
}
public function testArrayGetWithSelect(): void {
->addWhere('field5', '!=', 'banana')
->addWhere('field3', 'IS NOT NULL')
->execute();
- $this->assertEquals([4, 5], array_column((array) $result, 'field1'));
+ $this->assertEquals([4, 5, 6], array_column((array) $result, 'field1'));
$result = MockArrayEntity::get()
->addWhere('field1', '>=', '4')
->execute();
- $this->assertEquals([4, 5], array_column((array) $result, 'field1'));
+ $this->assertEquals([4, 5, 6], array_column((array) $result, 'field1'));
$result = MockArrayEntity::get()
->addWhere('field1', '<', '2')
$result = MockArrayEntity::get()
->addWhere('field2', 'REGEXP', '(zebra|yac[a-z]|something/else)')
->execute();
- $this->assertEquals([1, 2], array_column((array) $result, 'field1'));
+ $this->assertEquals([1, 2, 6], array_column((array) $result, 'field1'));
$result = MockArrayEntity::get()
->addWhere('field2', 'NOT REGEXP', '^[x|y|z]')
->execute();
$this->assertEquals([4, 5], array_column((array) $result, 'field1'));
+ $result = MockArrayEntity::get()
+ ->addWhere('field2', 'REGEXP BINARY', 'Yack')
+ ->execute();
+ $this->assertEquals([6], array_column((array) $result, 'field1'));
+
+ $result = MockArrayEntity::get()
+ ->addWhere('field5', 'NOT REGEXP BINARY', 'Apple')
+ ->execute();
+ $this->assertEquals([1, 2, 3, 4, 5], array_column((array) $result, 'field1'));
+
$result = MockArrayEntity::get()
->addWhere('field3', 'IS NULL')
->execute();
$result = MockArrayEntity::get()
->addWhere('field2', 'NOT LIKE', '%ra%')
->execute();
- $this->assertEquals([2, 4, 5], array_column((array) $result, 'field1'));
+ $this->assertEquals([2, 4, 5, 6], array_column((array) $result, 'field1'));
$result = MockArrayEntity::get()
->addWhere('field6', '=', '0')
->execute();
- $this->assertEquals([3, 4, 5], array_column((array) $result, 'field1'));
-
- $result = MockArrayEntity::get()
- ->addWhere('field6', '=', 0)
- ->execute();
- $this->assertEquals([3, 4, 5], array_column((array) $result, 'field1'));
+ $this->assertEquals([3, 4, 5, 6], array_column((array) $result, 'field1'));
$result = MockArrayEntity::get()
->addWhere('field1', 'BETWEEN', [3, 5])
$result = MockArrayEntity::get()
->addWhere('field1', 'NOT BETWEEN', [3, 4])
->execute();
- $this->assertEquals([1, 2, 5], array_column((array) $result, 'field1'));
+ $this->assertEquals([1, 2, 5, 6], array_column((array) $result, 'field1'));
}
public function testArrayGetWithNestedWhereClauses(): void {
'field5' => 'apple',
'field6' => 0,
],
+ [
+ 'field1' => 6,
+ 'field2' => 'Yack',
+ 'field3' => 1,
+ 'field4' => [4, 5, 6],
+ 'field5' => 'Apple',
+ 'field6' => 0,
+ ],
];
}