Skip to content

Instantly share code, notes, and snippets.

@muarachmann
Last active February 25, 2022 09:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save muarachmann/edc30f43e067ef6007a1c162c6f0941b to your computer and use it in GitHub Desktop.
Save muarachmann/edc30f43e067ef6007a1c162c6f0941b to your computer and use it in GitHub Desktop.
network-operators-query-scope-laravel
Before diviing into the hassle of creating this post, I had one big concern dealing with tons of telephone data (numbers), I had to filter these based on Cameroonian network operators (MTN, ORANGE, CAMTEL & NEXTTEL). While this was an easy thing to do with the `'LIKE'` functionality of mysql. However, I didn't like my solution as shown below.
```php
// scope for network operators
public function scopeNetworkOperator($query, string $operator = null)
{
switch ($operator) {
case "mtn":
return $query->where('phone', 'like', '67%')
->orWhere('phone', 'like', '650%')
->orWhere('phone', 'like', '651%')
->orWhere('phone', 'like', '652%')
->orWhere('phone', 'like', '653%')
->orWhere('phone', 'like', '654%')
->orWhere('phone', 'like', '680%')
->orWhere('phone', 'like', '681%')
->orWhere('phone', 'like', '682%')
->orWhere('phone', 'like', '683%');
case "orange":
return $query->where('phone', 'like', '69%')
->orWhere('phone', 'like', '655%')
->orWhere('phone', 'like', '656%')
->orWhere('phone', 'like', '657%')
->orWhere('phone', 'like', '658%')
->orWhere('phone', 'like', '659%');
case "camtel":
return $query->where('phone', 'like', '233%')
->orWhere('phone', 'like', '222%')
->orWhere('phone', 'like', '242%')
->orWhere('phone', 'like', '243%');
case "nexttel":
return $query->where('phone', 'like', '66%');
default:
return $query;
}
}
```
With this we can then get them all with
```php
// Client::networkOperator('mtn')->get();
```
However for scalability and readability, I wasn't pleased with my solution though it worked but I worried about dial codes though I had this separated for my database, so actually phone numbers where in standard format and not international formats and I kept the dail code in another column. Yet I wasn't still satistfied. So I began playing with some regex. Yes regex. If you havent heard about regex, a nice place to start will be here https://regexlearn.com/learn and you can test them here https://regex101.com/
For simplicity I made it as a helper function. You can go ahead an make it as a trait, class, package whatever.
Enough talk, lets dive into action...
We first create a helper function to match produce our regex given the operator.
```php
// NetworkOperator.php
class NetworkOperator
{
/**
* Country Prefix.
*/
const PREFIX = '237';
/**
* Operator Prefixes.
*/
const OPERATOR_PREFIXES = [
'mtn' => [
67, 650, 651, 652, 653, 654, 680, 681, 682, 683,
],
'orange' => [
69, 655, 656, 657, 658, 659,
],
'nexttel' => [
66,
],
'camtel' => [
233, 222, 242, 243,
],
];
/**
* Match Regex to Operator.
* @param string|null $operator
* @return string
*/
public static function getRegex(string $operator = null): ?string
{
if (!$operator || !array_key_exists($operator, self::OPERATOR_PREFIXES)) return 'null';
$operator_prefixes = trim(implode('|', self::OPERATOR_PREFIXES[$operator]), '|');
return "((|(0{2}))?" . self::PREFIX . ")?(("."$operator_prefixes".")([0-9]{6,7}))$";
}
}
```
With this, I can get the regex of a particular operator by simply performing
```php
NetworkOperator::getRegex('mtn')
// results
((|(0{2}))?237)?((67|650|651|652|653|654|680|681|682|683)([0-9]{6,7}))$
```
With this I was very pleased cause this takes care of all senarios and even international standards. Again if you don't know about regex, please make sure to get the basics to understand what is going on in the **getRegex()** method.
With this, I refactored my queryScope with the following code
```php
public function scopeNetworkOperator($query, string $operator = null)
{
$regex = NetworkOperator::getRegex($operator);
return $query->whereRaw("phone regexp '$regex'");
}
```
Then I can call this anywhere within my controller via my model
```php
Client::networkOperator('mtn')->get()
User::networkOperator('mtn')->get()
...
etc
```
I like this solution because it is scalable and can work for any country/dial code, you just need to modify the country dialcode prefix and its operators number and you are good to go. I hope this be of help to you someday.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment