Skip to content

Commit

Permalink
Update countrycity data
Browse files Browse the repository at this point in the history
Add search endpoints

Add CORS support

Support only PHP 7.4 or newer

Update example to use search endpoints
  • Loading branch information
shivammathur committed May 19, 2020
1 parent 0ecc4ef commit 400b682
Show file tree
Hide file tree
Showing 15 changed files with 1,282 additions and 672 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ jobs:
strategy:
matrix:
operating-system: [ubuntu-latest, windows-latest, macOS-latest]
php-versions: [7.2, 7.3, 7.4]
php-versions: [7.4]
runs-on: ${{ matrix.operating-system }}
steps:
- name: Checkout
Expand All @@ -14,8 +14,8 @@ jobs:
uses: shivammathur/setup-php@develop
with:
php-version: ${{ matrix.php-versions }}
extension-csv: 'mbstring'
ini-values-csv: 'pcov.directory=api'
extensions: 'mbstring'
ini-values: 'pcov.directory=api'
coverage: 'pcov'
- name: Install dependencies
run: composer install --no-progress --no-suggest --prefer-dist
Expand Down
36 changes: 27 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
[![Code Climate](https://codeclimate.com/github/shivammathur/countrycity/badges/gpa.svg)](https://codeclimate.com/github/shivammathur/countrycity)
[![codecov](https://codecov.io/gh/shivammathur/countrycity/branch/master/graph/badge.svg)](https://codecov.io/gh/shivammathur/countrycity)
[![License](https://poser.pugx.org/shivammathur/countrycity/license)](license.md)
[![Support me on Patreon](https://shivammathur.com/badges/patreon.svg)](https://www.patreon.com/shivammathur)
[![Support me on Paypal](https://shivammathur.com/badges/paypal.svg)](https://www.paypal.me/shivammathur)
[![Get Help on codementor](https://cdn.codementor.io/badges/get_help_github.svg)](https://www.codementor.io/shivammathur?utm_source=github&utm_medium=button&utm_term=shivammathur&utm_campaign=github)

This is geodata API built to get the data with countries in the world and cities in a particular country. This API is a plugin for creating drop-downs in a form which populate via an AJAX request. You can find a [select2](https://select2.org/) implementation [here](https://shivammathur.github.io/countrycity/). Code for this implementation is in [`example`](example) directory.
Geodata API to get the list of countries and cities in the world. This can be plugged in country and city picker drop-downs in forms. You can find a [select2](https://select2.org/) implementation [here](https://shivammathur.github.io/countrycity/). Code for this implementation is in [`example`](example) directory.

<p align="center">
<img src="https://shivammathur.com/countrycity/countrycity.gif">
</p>

### :zap: Installing the CountryCity API

- Make sure you have PHP 7.4 or newer.
```bash
$ php -v
```
- Download this API using [composer](https://getcomposer.org/download/) using the command below.
```bash
$ composer global require shivammathur/countrycity "master-dev"
Expand All @@ -37,12 +38,28 @@ All API responses are in `json` format.
/index.php/countries
```

- Get all cities in a country
- Get all countries containing a search keyword
```bash
/countries/{search_keyword}

# Without URL Rewriting
/index.php/countries/{search_keyword}
```

- Get all cities in a country
```bash
/cities/{country}

# Without URL Rewriting
/index.php/cities/{country}
```

- Get all cities in a country containing a search keyword
```bash
/cities/{countryName}
/cities/{country}/{search_keyword}

# Without URL Rewriting
/index.php/cities/{countryName}
/index.php/cities/{country}/{search_keyword}
```

### :sparkles: Rest API Features
Expand All @@ -53,6 +70,7 @@ All API responses are in `json` format.
- Last-Modified
- Fast and lightweight API
- PSR 7 Complaint
- CORS Middleware

### :cloud: Hosting configuration
Here are the [Configuration Instructions](http://www.slimframework.com/docs/v3/start/web-servers.html) if you want to host this on your server.
Expand All @@ -79,5 +97,5 @@ Contributions are welcome! See [Contributor's Guide](.github/CONTRIBUTING.md).

## :sparkling_heart: Support this project

- Please star the project and share it among your developer friends.
- Consider supporting on <a href="https://www.patreon.com/shivammathur"><img alt="Support me on Patreon" src="https://shivammathur.com/badges/patreon.svg"></a> and <a href="https://www.paypal.me/shivammathur"><img alt="Support me on Paypal" src="https://shivammathur.com/badges/paypal.svg"></a>.
- Please star the project and share it with the community.
- Support the project by sponsoring my work on <a href="https://www.patreon.com/shivammathur"><img alt="Support me on Patreon" src="https://shivammathur.com/badges/patreon.svg"></a> or sponsor using <a href="https://www.paypal.me/shivammathur"><img alt="Support me on Paypal" src="https://shivammathur.com/badges/paypal.svg"></a>.
75 changes: 46 additions & 29 deletions api/v1/Location.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

use JsonMachine\JsonMachine;
use Exception;
use function iconv;
use function mb_stripos;
use function preg_replace;

/**
* This class handles location data.
Expand All @@ -15,26 +18,21 @@
class Location
{
/**
* Location constructor.
* @param $filename
* @var string $file
*/
public function __construct($filename)
{
/** @var array $this ->data */
$this->file = $filename;
}
public static string $file = 'data/geo.json';

/**
* Return the json encoded list of all countries.
*
* @author Shivam Mathur <shivam_jpr@hotmail.com>
*
* @return string
* @param string|NULL $search
* @return false|string
*/
public function getAllCountries()
public function getCountries(string $search = NULL)
{
try {
$allCountries = $this->countries();
$allCountries = $this->countries($search);
} catch (Exception $exception) {
return json_encode(["error" => "true", "message" => $exception->getMessage()]);
}
Expand All @@ -46,16 +44,16 @@ public function getAllCountries()
* Return the json encoded list of all cities in a country.
*
* @author Shivam Mathur <shivam_jpr@hotmail.com>
*
* @param $countryName
* @return string
* @param string $countryName
* @param string|NULL $search
* @return false|string
*/
public function getAllCities($countryName)
public function getCities(string $countryName, string $search = NULL)
{
$countryName = trim(stripslashes(ucwords($countryName)));

try {
$allCities = $this->cities($countryName);
$allCities = $this->cities($countryName, $search);
} catch (Exception $exception) {
return json_encode(["error" => "true", "message" => $exception->getMessage()]);
}
Expand All @@ -67,19 +65,36 @@ public function getAllCities($countryName)
* Return the array containing all countries.
*
* @author Shivam Mathur <shivam_jpr@hotmail.com>
* @param string $haystack
* @param string $needle
* @return bool|false|int
*/
public function mb_search(string $haystack, string $needle)
{
$haystack = preg_replace('/[\'^`~\"]/', '', iconv('UTF-8', 'ASCII//TRANSLIT', $haystack));
$needle = preg_replace('/[\'^`~\"]/', '', iconv('UTF-8', 'ASCII//TRANSLIT', $needle));
return mb_stripos($haystack, $needle);
}

/**
* Return the array containing all countries.
*
* @author Shivam Mathur <shivam_jpr@hotmail.com>
* @param string|NULL $search
* @return array
* @throws Exception
*/
private function countries()
private function countries(string $search = NULL)
{
if (!$this->file) {
if (self::$file == '') {
throw new Exception('Invalid data filename');
}

$data = JsonMachine::fromFile($this->file);
$countries = array_keys(iterator_to_array($data, true));

$data = JsonMachine::fromFile(self::$file);
$countries = array_filter(
array_keys(iterator_to_array($data, true)),
fn (string $country) => !$search || $this->mb_search($country, $search) !== false
);
sort($countries);
return $countries;
}
Expand All @@ -88,25 +103,29 @@ private function countries()
* Returns the array containing all cities in a country.
*
* @author Shivam Mathur <shivam_jpr@hotmail.com>
*
* @param $countryName
* @param string $countryName
* @param string|NULL $search
* @return array
* @throws Exception
*/
private function cities($countryName)
private function cities(string $countryName, string $search = NULL)
{
if (!$this->file) {
if (self::$file == '') {
throw new Exception('Invalid data filename');
}

$data = JsonMachine::fromFile($this->file);
$data = JsonMachine::fromFile(self::$file);

$cities = [];
$found = false;
foreach ($data as $key => $value) {
if($countryName == ucwords($key)) {
$found = true;
$cities = $value;
$cities = array_filter(
$value,
fn (string $city) => !$search || $this->mb_search($city, $search) !== false
);
sort($cities);
break;
}
}
Expand All @@ -115,8 +134,6 @@ private function cities($countryName)
throw new Exception('Invalid country name: '. $countryName);
}

sort($cities);

return $cities;
}
}
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
}
],
"require": {
"php": "^7.2",
"php": "^7.4",
"ext-json": "*",
"ext-mbstring": "*",
"halaxa/json-machine": "*",
Expand All @@ -32,22 +32,23 @@
"symfony/event-dispatcher": "*",
"symfony/http-kernel": "*",
"symfony/lock": "*",
"symfony/polyfill-iconv": "^1.17",
"symfony/polyfill-mbstring": "^1.17",
"symfony/process": "*",
"zendframework/zend-httphandlerrunner": "*"
},
"require-dev": {
"php-coveralls/php-coveralls": "*",
"phpunit/php-timer": "dev-master",
"phpunit/phpunit": "dev-master",
"sebastian/type": "dev-master",
"squizlabs/php_codesniffer": "*"
},
"suggest": {
"ext-pcov": "*"
},
"config": {
"optimize-autoloader": true,
"platform": {
"php": "7.2.0"
},
"sort-packages": true
},
"autoload": {
Expand Down
Loading

0 comments on commit 400b682

Please sign in to comment.