Compare commits

..

12 commits

Author SHA1 Message Date
f8e945bacd chore: drop EOL PHP versions
Seemed overdue to finally drop support for PHP 5.x, as well as 7.x as
the 7 series has also reached end of life.

Expanded testing to include both the soon to be released 8.3 and the
next development version 8.4.
2023-11-06 12:43:17 -06:00
15052790c5 feat: get previous workday
Added the ability to get the previous workday by passing in a negative
number of days along with the date to start from.

This update also includes some overhauling to allow for the library to
be more resilient to changes in the upstream API.
2022-04-05 18:02:30 -05:00
95bba75265 feat: add workdays endpoint
Added support for our new workdays endpoint that allows you to get the
number of working days for a country between two dates.
2021-06-14 18:01:47 -05:00
peter279k
c12f512f8a Add assertRegExp assertion checking 2021-06-10 23:01:28 -05:00
peter279k
b398ba5013 Add PHP8.0 and JSON & cURL extension checking 2020-12-29 16:26:42 -06:00
peter279k
b15f862193 Using PHPUnit ^4.8.36 and some PHPUnit stuffs 2020-12-22 16:17:12 -06:00
49d20e06a8 docs: fix build and coverage badges
Had the wrong URL in there, whoops.
2020-06-19 19:12:30 -05:00
45ca80d846 feat: add workday endpoint
Added support for our latest endpoint, which calculates the workday a
given number of business days into the future from the given date for
the given country.
2020-06-19 18:56:47 -05:00
b6fad34f19 build: swap travis for github actions 2020-06-13 10:19:15 -05:00
b9ceb5947c docs: improve syntax highlighting of code snippets
* Seems PHP snippets require the delimiter to function properly.
* Updated a bunch of dependencies.
2020-06-13 10:19:15 -05:00
12f1ea69f8 feat: filter out countries without public holidays
Fairly minor update, no code change, just added a new test to cover the
flag that was recently added to the API and expanded the documentation
to also include it.
2020-03-03 22:08:57 -06:00
054eab9c02 feat: pull country or language by code
* feat: pull country or language by code.

This differs from the existing `search` functionality in that it allows
you to explicitly pull back a single country or language instead of
anything that matches (which could result in more items returned than
expected).

* docs(readme): update to include examples for new functionality.
* test: expand tests to include new parameters.
* fix(client): dropped some commented out code that wasn't in use.
* docs(license): bump the year of the license.
2020-02-11 18:14:18 -06:00
11 changed files with 374 additions and 284 deletions

View file

@ -1 +0,0 @@
service_name: travis-ci

29
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: Test
on: [push, pull_request]
jobs:
test:
name: Test PHP ${{ matrix.php-version }}
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['8.0', '8.1', '8.2', '8.3', '8.4']
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
- name: PHP Version
run: php --version
- name: Composer Version
run: composer --version
- name: Install Dependencies
run: COMPOSER_MEMORY_LIMIT=-1 composer install
- name: Run Tests
run: vendor/bin/phpunit --coverage-clover ./coverage.xml
- name: Upload Coverage
if: ${{ matrix.php-version == '8.2' }}
uses: codecov/codecov-action@v1
with:
file: ./coverage.xml

View file

@ -1,40 +0,0 @@
language: php
dist: bionic
sudo: required
matrix:
include:
- php: 5.3
dist: precise
- php: 5.4
dist: trusty
- php: 5.5
dist: trusty
- php: 5.6
dist: trusty
- php: 7.0
dist: xenial
- php: 7.1
- php: 7.2
- php: 7.3
- php: 7.4
env: COVERAGE=true
- php: nightly
allow_failures:
- php: nightly
install:
- php --version
- composer install
before_script:
- mkdir -p build/logs
script:
- vendor/bin/phpunit --coverage-clover build/logs/clover.xml
after_success:
- |
if [[ $COVERAGE ]]; then
travis_retry php vendor/bin/php-coveralls --config .coveralls.yml -v
fi

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2016, 2017, 2018, 2019 Gravity Boulevard, LLC
Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Gravity Boulevard, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -2,25 +2,11 @@
[![License](https://img.shields.io/packagist/l/holidayapi/holidayapi-php?style=for-the-badge)](https://github.com/holidayapi/holidayapi-php/blob/master/LICENSE)
![PHP Version](https://img.shields.io/packagist/php-v/holidayapi/holidayapi-php?style=for-the-badge)
![Build Status](https://img.shields.io/travis/holidayapi/holidayapi-php/master?style=for-the-badge)
[![Coverage Status](https://img.shields.io/coveralls/github/holidayapi/holidayapi-php/master?style=for-the-badge)](https://coveralls.io/github/holidayapi/holidayapi-php?branch=master)
[![Code Coverage](https://img.shields.io/codecov/c/github/holidayapi/holidayapi-php?style=for-the-badge)](https://codecov.io/gh/holidayapi/holidayapi-php)
Official PHP library for [Holiday API](https://holidayapi.com) providing quick
and easy access to holiday information from applications written in PHP.
## Migrating from 1.x
Please note, version 2.x of this library is a full rewrite of the 1.x series.
The interfacing to the library has been simplified and existing applications
upgrading to 2.x will need to be updated.
| Version 1.x Syntax (Old) | Version 2.x Syntax (New) |
|--------------------------------------------|-----------------------------------------------------------|
| `$holiday_api = new \HolidayAPI\v1($key);` | `$holiday_api = new \HolidayAPI\Client(['key' => $key]);` |
Version 1.x of the library can still be found
[here](https://github.com/joshtronic/php-holidayapi).
## Documentation
Full documentation of the Holiday API endpoints is available
@ -35,6 +21,7 @@ composer require holidayapi/holidayapi-php
## Usage
```php
<?php
$key = 'Insert your API key here';
$holiday_api = new \HolidayAPI\Client(['key' => $key]);
@ -64,12 +51,32 @@ try {
#### Fetch all supported countries
```php
<?php
$holiday_api->countries();
```
#### Search for a country by code or name
#### Fetch only countries with public holidays
```php
<?php
$holiday_api->countries([
'public' => true,
]);
```
#### Fetch a supported country by code
```php
<?php
$holiday_api->countries([
'country' => 'NO',
]);
```
#### Search for countries by code or name
```php
<?php
$holiday_api->countries([
'search' => 'united',
]);
@ -80,12 +87,23 @@ $holiday_api->countries([
#### Fetch all supported languages
```php
<?php
$holiday_api->languages();
```
#### Search for a language by code or name
#### Fetch a supported language by code
```php
<?php
$holiday_api->languages([
'language' => 'es',
]);
```
#### Search for languages by code or name
```php
<?php
$holiday_api->languages([
'search' => 'Chinese',
]);
@ -96,6 +114,7 @@ $holiday_api->languages([
#### Fetch holidays for a specific year
```php
<?php
$holiday_api->holidays([
'country' => 'US',
'year' => 2019,
@ -105,6 +124,7 @@ $holiday_api->holidays([
#### Fetch holidays for a specific month
```php
<?php
$holiday_api->holidays([
'country' => 'US',
'year' => 2019,
@ -115,6 +135,7 @@ $holiday_api->holidays([
#### Fetch holidays for a specific day
```php
<?php
$holiday_api->holidays([
'country' => 'US',
'year' => 2019,
@ -126,6 +147,7 @@ $holiday_api->holidays([
#### Fetch upcoming holidays based on a specific date
```php
<?php
$holiday_api->holidays([
'country' => 'US',
'year' => 2019,
@ -138,6 +160,7 @@ $holiday_api->holidays([
#### Fetch previous holidays based on a specific date
```php
<?php
$holiday_api->holidays([
'country' => 'US',
'year' => 2019,
@ -150,6 +173,7 @@ $holiday_api->holidays([
#### Fetch only public holidays
```php
<?php
$holiday_api->holidays([
'country' => 'US',
'year' => 2019,
@ -160,6 +184,7 @@ $holiday_api->holidays([
#### Fetch holidays for a specific subdivision
```php
<?php
$holiday_api->holidays([
'country' => 'GB-ENG',
'year' => 2019,
@ -169,6 +194,7 @@ $holiday_api->holidays([
#### Include subdivision holidays with countrywide holidays
```php
<?php
$holiday_api->holidays([
'country' => 'US',
'year' => 2019,
@ -179,6 +205,7 @@ $holiday_api->holidays([
#### Search for a holiday by name
```php
<?php
$holiday_api->holidays([
'country' => 'US',
'year' => 2019,
@ -189,6 +216,7 @@ $holiday_api->holidays([
#### Translate holidays to another language
```php
<?php
$holiday_api->holidays([
'country' => 'US',
'year' => 2019,
@ -199,6 +227,7 @@ $holiday_api->holidays([
#### Fetch holidays for multiple countries
```php
<?php
$holiday_api->holidays([
'country' => 'US,GB,NZ',
'year' => 2019,
@ -209,3 +238,29 @@ $holiday_api->holidays([
'year' => 2019,
]);
```
### Workday
#### Fetch workday 7 business days after a date
```php
<?php
$holiday_api->workday([
'country' => 'US',
'start' => '2019-07-01',
'days' => 7,
]);
```
### Workdays
#### Fetch number of workdays between two dates
```php
<?php
$holiday_api->workdays([
'country' => 'US',
'start' => '2019-07-01',
'end' => '2019-07-10',
]);
```

20
codecov.yml Normal file
View file

@ -0,0 +1,20 @@
codecov:
require_ci_to_pass: yes
coverage:
precision: 2
round: down
range: "70...100"
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "reach,diff,flags,tree"
behavior: default
require_changes: no

View file

@ -1,7 +1,7 @@
{
"name": "holidayapi/holidayapi-php",
"description": "Official PHP library for Holiday API",
"version": "2.1.0",
"version": "4.0.0",
"type": "library",
"keywords": [
"calendar",
@ -17,13 +17,21 @@
"homepage": "https://holidayapi.com"
}],
"require": {
"php": ">=5.3"
"php": ">=8.0",
"ext-json": "*",
"ext-curl": "*"
},
"require-dev": {
"php-coveralls/php-coveralls": ">=1",
"phpunit/phpunit": ">=4"
"phpunit/phpunit": "^9.0"
},
"autoload": {
"psr-4": { "HolidayAPI\\": "src/" }
"psr-4": {
"HolidayAPI\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"HolidayAPI\\Tests\\": "tests/"
}
}
}

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
colors="true"
bootstrap="./vendor/autoload.php"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"

View file

@ -55,32 +55,6 @@ class Client
private function request($endpoint, $request)
{
return $this->handler->get($this->createUrl($endpoint, $request));
/*
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $this->createUrl($endpoint, $request),
CURLOPT_HEADER => false,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_RETURNTRANSFER => true,
));
$response = curl_exec($curl);
if ($error = curl_error($curl)) {
throw new \Exception($error);
}
curl_close($curl);
$response = json_decode($response, true);
if (!$response) {
throw new \Exception('Empty response received');
}
return $response;
*/
}
public function countries($request = array())
@ -90,17 +64,6 @@ class Client
public function holidays($request)
{
if (!isset($request['country'])) {
throw new \Exception('Missing country');
} elseif (!isset($request['year'])) {
throw new \Exception('Missing year');
} elseif (
isset($request['previous'], $request['upcoming'])
&& $request['previous'] && $request['upcoming']
) {
throw new \Exception('Previous and upcoming are mutually exclusive');
}
return $this->request('holidays', $request);
}
@ -108,5 +71,15 @@ class Client
{
return $this->request('languages', $request);
}
public function workday($request)
{
return $this->request('workday', $request);
}
public function workdays($request)
{
return $this->request('workdays', $request);
}
}

View file

@ -2,56 +2,72 @@
namespace HolidayAPI\Tests;
use HolidayAPI\Client;
use HolidayAPI\Request;
use PHPUnit\Framework\TestCase;
require __DIR__ . '/../vendor/autoload.php';
if (
!class_exists('\PHPUnit_Framework_TestCase')
&& class_exists('\PHPUnit\Framework\TestCase')
) {
class_alias('\PHPUnit\Framework\TestCase', '\PHPUnit_Framework_TestCase');
}
class ClientTest extends \PHPUnit_Framework_TestCase
class ClientTest extends TestCase
{
const BASE_URL = 'https://holidayapi.com/v1/';
const KEY = '8e4de28c-4b18-49f0-9aba-0bd6b424fc38';
public function testMissingKey()
{
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
$assertRegExp = 'assertMatchesRegularExpression';
} else {
$assertRegExp = 'assertRegExp';
}
try {
$client = new Client(array());
new Client(array());
} catch (\Exception $e) {
$this->assertRegExp('/missing api key/i', $e->getMessage());
$this->$assertRegExp('/missing api key/i', $e->getMessage());
}
}
public function testInvalidKey()
{
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
$assertRegExp = 'assertMatchesRegularExpression';
} else {
$assertRegExp = 'assertRegExp';
}
try {
$client = new Client(array(
new Client(array(
'key' => 'zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz',
));
} catch (\Exception $e) {
$this->assertRegExp('/invalid api key/i', $e->getMessage());
$this->$assertRegExp('/invalid api key/i', $e->getMessage());
}
}
public function testVersionTooLow()
{
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
$assertRegExp = 'assertMatchesRegularExpression';
} else {
$assertRegExp = 'assertRegExp';
}
try {
$client = new Client(array('key' => self::KEY, 'version' => 0));
new Client(array('key' => self::KEY, 'version' => 0));
} catch (\Exception $e) {
$this->assertRegExp('/invalid version/i', $e->getMessage());
$this->$assertRegExp('/invalid version/i', $e->getMessage());
}
}
public function testVersionTooHigh()
{
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
$assertRegExp = 'assertMatchesRegularExpression';
} else {
$assertRegExp = 'assertRegExp';
}
try {
$client = new Client(array('key' => self::KEY, 'version' => 2));
new Client(array('key' => self::KEY, 'version' => 2));
} catch (\Exception $e) {
$this->assertRegExp('/invalid version/i', $e->getMessage());
$this->$assertRegExp('/invalid version/i', $e->getMessage());
}
}
@ -97,40 +113,6 @@ class ClientTest extends \PHPUnit_Framework_TestCase
), $client->countries());
}
public function testSearchCountries()
{
$url = self::BASE_URL . 'countries?key=' . self::KEY . '&search=Sao';
$request = new Request(array(
'execute' => array(
$url => function ()
{
return json_encode(array(
'status' => 200,
'countries' => array(
array(
'code' => 'ST',
'name' => 'Sao Tome and Principle',
),
),
));
},
),
));
$client = new Client(array('key' => self::KEY, 'handler' => $request));
$this->assertEquals(array(
'status' => 200,
'countries' => array(
array(
'code' => 'ST',
'name' => 'Sao Tome and Principle',
),
),
), $client->countries(array('search' => 'Sao')));
}
public function testCountriesRaise4xxErrors()
{
$url = self::BASE_URL . 'countries?key=' . self::KEY;
@ -187,8 +169,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
public function testReturnHolidays()
{
$url = self::BASE_URL . 'holidays?key=' . self::KEY
. '&country=US&year=2015&month=7&day=4';
$url = self::BASE_URL . 'holidays?key=' . self::KEY . '&country=US&year=2015&month=7&day=4';
$request = new Request(array(
'execute' => array(
@ -229,89 +210,6 @@ class ClientTest extends \PHPUnit_Framework_TestCase
)));
}
public function testSearchHolidays()
{
$url = self::BASE_URL . 'holidays?key=' . self::KEY
. '&country=US&year=2015&search=Independence';
$request = new Request(array(
'execute' => array(
$url => function ()
{
return json_encode(array(
'status' => 200,
'holidays' => array(
array(
'name' => 'Independence Day',
'date' => '2015-07-04',
'observed' => '2015-07-03',
'public' => true,
),
),
));
},
),
));
$client = new Client(array('key' => self::KEY, 'handler' => $request));
$this->assertEquals(array(
'status' => 200,
'holidays' => array(
array(
'name' => 'Independence Day',
'date' => '2015-07-04',
'observed' => '2015-07-03',
'public' => true,
),
),
), $client->holidays(array(
'country' => 'US',
'year' => 2015,
'search' => 'Independence',
)));
}
public function testCountryMissing()
{
$client = new Client(array('key' => self::KEY));
try {
$client->holidays(array('year' => 2015));
} catch (\Exception $e) {
$this->assertRegExp('/missing country/i', $e->getMessage());
}
}
public function testYearMissing()
{
$client = new Client(array('key' => self::KEY));
try {
$client->holidays(array('country' => 'US'));
} catch (\Exception $e) {
$this->assertRegExp('/missing year/i', $e->getMessage());
}
}
public function testBothPreviousAndUpcoming()
{
$client = new Client(array('key' => self::KEY));
try {
$client->holidays(array(
'country' => 'US',
'year' => 2015,
'month' => 7,
'day' => 4,
'upcoming' => true,
'previous' => true,
));
} catch (\Exception $e) {
$this->assertRegExp('/previous and upcoming/i', $e->getMessage());
}
}
public function testHolidaysRaise4xxErrors()
{
$url = self::BASE_URL . 'holidays?key=' . self::KEY . '&country=US&year=2019';
@ -400,40 +298,6 @@ class ClientTest extends \PHPUnit_Framework_TestCase
), $client->languages());
}
public function testSearchLanguages()
{
$url = self::BASE_URL . 'languages?key=' . self::KEY . '&search=Eng';
$request = new Request(array(
'execute' => array(
$url => function ()
{
return json_encode(array(
'status' => 200,
'languages' => array(
array(
'code' => 'en',
'name' => 'English',
),
),
));
},
),
));
$client = new Client(array('key' => self::KEY, 'handler' => $request));
$this->assertEquals(array(
'status' => 200,
'languages' => array(
array(
'code' => 'en',
'name' => 'English',
),
),
), $client->languages(array('search' => 'Eng')));
}
public function testLanguagesRaise4xxErrors()
{
$url = self::BASE_URL . 'languages?key=' . self::KEY;
@ -487,5 +351,189 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$this->assertSame('Internal server error', $e->getMessage());
}
}
public function testReturnWorkday()
{
$url = self::BASE_URL . 'workday?key=' . self::KEY . '&country=US&start=2019-07-01&days=10';
$request = new Request(array(
'execute' => array(
$url => function ()
{
return json_encode(array(
'status' => 200,
'workday' => array(
'date' => '2019-07-16',
),
));
},
),
));
$client = new Client(array('key' => self::KEY, 'handler' => $request));
$this->assertEquals(array(
'status' => 200,
'workday' => array(
'date' => '2019-07-16',
),
), $client->workday(array(
'country' => 'US',
'start' => '2019-07-01',
'days' => 10,
)));
}
public function testWorkdayRaise4xxErrors()
{
$url = self::BASE_URL . 'workday?key=' . self::KEY . '&country=US&start=2019-07-01&days=10';
$request = new Request(array(
'execute' => array(
$url => function ()
{
return json_encode(array(
'status' => 429,
'error' => 'Rate limit exceeded',
));
},
),
));
$client = new Client(array('key' => self::KEY, 'handler' => $request));
try {
$client->workday(array(
'country' => 'US',
'start' => '2019-07-01',
'days' => 10,
));
} catch (\Exception $e) {
$this->assertSame(429, $e->getCode());
$this->assertSame('Rate limit exceeded', $e->getMessage());
}
}
public function testWorkdayRaise5xxErrors()
{
$url = self::BASE_URL . 'workday?key=' . self::KEY . '&country=US&start=2019-07-01&days=10';
$request = new Request(array(
'execute' => array(
$url => function ()
{
return false;
},
),
'error' => array(
$url => function ()
{
return 'Internal server error';
},
),
));
$client = new Client(array('key' => self::KEY, 'handler' => $request));
try {
$client->workday(array(
'country' => 'US',
'start' => '2019-07-01',
'days' => 10,
));
} catch (\Exception $e) {
$this->assertSame('Internal server error', $e->getMessage());
}
}
public function testReturnWorkdays()
{
$url = self::BASE_URL . 'workdays?key=' . self::KEY . '&country=US&start=2019-07-01&end=2019-07-10';
$request = new Request(array(
'execute' => array(
$url => function ()
{
return json_encode(array(
'status' => 200,
'workdays' => 7,
));
},
),
));
$client = new Client(array('key' => self::KEY, 'handler' => $request));
$this->assertEquals(array(
'status' => 200,
'workdays' => 7,
), $client->workdays(array(
'country' => 'US',
'start' => '2019-07-01',
'end' => '2019-07-10',
)));
}
public function testWorkdaysRaise4xxErrors()
{
$url = self::BASE_URL . 'workdays?key=' . self::KEY . '&country=US&start=2019-07-01&end=2019-07-10';
$request = new Request(array(
'execute' => array(
$url => function ()
{
return json_encode(array(
'status' => 429,
'error' => 'Rate limit exceeded',
));
},
),
));
$client = new Client(array('key' => self::KEY, 'handler' => $request));
try {
$client->workdays(array(
'country' => 'US',
'start' => '2019-07-01',
'end' => '2019-07-10',
));
} catch (\Exception $e) {
$this->assertSame(429, $e->getCode());
$this->assertSame('Rate limit exceeded', $e->getMessage());
}
}
public function testWorkdaysRaise5xxErrors()
{
$url = self::BASE_URL . 'workdays?key=' . self::KEY . '&country=US&start=2019-07-01&end=2019-07-10';
$request = new Request(array(
'execute' => array(
$url => function ()
{
return false;
},
),
'error' => array(
$url => function ()
{
return 'Internal server error';
},
),
));
$client = new Client(array('key' => self::KEY, 'handler' => $request));
try {
$client->workdays(array(
'country' => 'US',
'start' => '2019-07-01',
'end' => '2019-07-10',
));
} catch (\Exception $e) {
$this->assertSame('Internal server error', $e->getMessage());
}
}
}

View file

@ -1,18 +1,9 @@
<?php
namespace HolidayAPI\Tests;
use HolidayAPI\Client;
use HolidayAPI\Request;
use PHPUnit\Framework\TestCase;
require __DIR__ . '/../vendor/autoload.php';
if (
!class_exists('\PHPUnit_Framework_TestCase')
&& class_exists('\PHPUnit\Framework\TestCase')
) {
class_alias('\PHPUnit\Framework\TestCase', '\PHPUnit_Framework_TestCase');
}
class RequestTest extends \PHPUnit_Framework_TestCase
class RequestTest extends TestCase
{
public function testExecute()
{
@ -24,6 +15,12 @@ class RequestTest extends \PHPUnit_Framework_TestCase
public function testGet()
{
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
$assertRegExp = 'assertMatchesRegularExpression';
} else {
$assertRegExp = 'assertRegExp';
}
$url = 'https://holidayapi.com';
$request = new Request(array(
@ -38,7 +35,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
try {
$request->get($url);
} catch (\Exception $e) {
$this->assertRegExp('/empty response/i', $e->getMessage());
$this->$assertRegExp('/empty response/i', $e->getMessage());
}
}
}