Network Operators Query scope Laravel
Mua Rachmann
@muarachmann
Before diving 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.
// scope for network operatorspublic 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
Client::networkOperator('mtn')->get();
However for scalability and readability, and the fact I worried about dial codes which wasn't a problem at this moment because I had this separated this 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 satisfied. So I began playing with some regex. Yes regex. If you haven't 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 and 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.
// NetworkOperator.phpclass 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
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 scenarios 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
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
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 dial code prefix and its operators number and you are good to go. Feel free to tweak the regex if your database is not using numbers in international formats. I hope this be of help to you someday :)