diff --git a/README.md b/README.md index 9799620..48056a1 100644 --- a/README.md +++ b/README.md @@ -109,17 +109,20 @@ It's how you can set your own holidays lists: Carbon::setHolidays('us-il', array_merge( Carbon::getHolidays('us-national'), array( - function ($year) { // Presidents' Day + // Presidents' Day + 'presidents-day' => function ($year) { $date = new DateTime("third monday of february $year"); return $date->format('d/m'); }, - function ($year) { // Columbus Day + // Columbus Day + 'columbus-day' => function ($year) { $date = new DateTime("second monday of october $year"); return $date->format('d/m'); }, - function ($year) { // Day after Thanksgiving + // Day after Thanksgiving + 'thanksgiving-next-day' => function ($year) { $date = new DateTime("fourth thursday of november $year +1 day"); return $date->format('d/m'); @@ -129,7 +132,8 @@ Carbon::setHolidays('us-il', array_merge( Carbon::setHolidays('my-enterprise', array_merge( Carbon::getHolidays('us-is'), array( - '12/02', // Lincoln's Birthday + // Lincoln's Birthday + 'lincolns-birthday' => '12/02', ) )); // Then when you select my-enterprise, all us-national, @@ -137,6 +141,21 @@ Carbon::setHolidays('my-enterprise', array_merge( Carbon::setHolidaysRegion('my-enterprise'); ``` +You can also pass deep array to `setHolidays` to set in the same call holidays dates and either observed flags, names +(in different languages) or both: +```php +Carbon::setHolidays('my-enterprise', array( + 'lincolns-birthday' => array( + 'date' => '12/02', + 'observed' => true, + 'name' => array( + 'en' => "Lincoln's Birthday", + 'fr' => 'Anniversaire du Président Lincoln', + ), + ), +)); +``` + #### addHolidays While setHolidays replace the whole holidays list for a given region, addHolidays @@ -144,16 +163,18 @@ append holidays to the current list. ```php Carbon::addHolidays('my-list', array( - '20/01', - '21/01', + 'poney' => '20/01', + 'swimmingpool' => '21/01', ))); Carbon::addHolidays('my-list', array( - '10/02', - '11/02', + 'boss-birthday' => '10/02', + 'boss-birthday-next-day' => '11/02', ))); Carbon::getHolidays('my-list') // contains 20/01, 21/01, 10/02 and 11/02 ``` +As for `setHolidays`, `addHolidays` handle deep arrays using date, observed and name keys. + #### resetHolidays Reset all holidays and region previously set. @@ -189,6 +210,36 @@ if ($nextWeekHoliday === 'easter' or $nextWeekHoliday === 'christmas') { } ``` +#### getHolidayName + +Returns the name of the holiday in the current locale (or English by default) or false if the day is not a holiday. + +```php +Carbon::setHolidaysRegion('fr-national'); +Carbon::parse('2018-12-25')->getHolidayName() // "Christmas" +Carbon::parse('2018-12-25')->getHolidayName('fr') // "Noël" + +Carbon::setLocale('nl'); +Carbon::parse('2018-01-15')->getHolidayName() // "Eerste Kerstdag" + +// If the name is not translated in business-day +Carbon::setLocale('de'); +Carbon::parse('2018-01-15')->getHolidayName() // "Christmas" + +// With Carbon 2, you can use local locale: +Carbon::parse('2018-01-15')->locale('sl')->getHolidayName() // "Božič" +``` + +#### setHolidayName + +Wanna rename a holiday name in a particular language? No problem: + +```php +Carbon::parse('2018-12-25')->getHolidayName() // "Christmas" +Carbon::setHolidayName('christmas', 'en', 'Christmas Day'); +Carbon::parse('2018-12-25')->getHolidayName() // "Christmas Day" +``` + #### isBusinessDay Returns `true` if the date (Carbon instance) is nor a week-end day neither diff --git a/src/Cmixin/BusinessDay/HolidaysList.php b/src/Cmixin/BusinessDay/HolidaysList.php index 20768e6..bf5da14 100644 --- a/src/Cmixin/BusinessDay/HolidaysList.php +++ b/src/Cmixin/BusinessDay/HolidaysList.php @@ -61,7 +61,9 @@ public function setHolidays() $mixin = $this; return function ($region, $holidays) use ($mixin) { - $mixin->holidays[$region] = $holidays; + $addHolidays = $mixin->addHolidays(); + $mixin->holidays[$region] = array(); + $addHolidays($region, $holidays); }; } @@ -93,9 +95,6 @@ public function initializeHolidaysRegion($region = null) if (!isset($this->holidays[$region])) { $this->holidays[$region] = array(); } - if ($this->holidays[$region] instanceof \Traversable) { - $this->holidays[$region] = iterator_to_array($this->holidays[$region]); - } return $this; } @@ -105,6 +104,140 @@ public function initializeHolidaysRegion($region = null) }; } + /** + * Push a holiday to the holidays list of a region. + * + * @return \Closure + */ + public function pushHoliday() + { + $mixin = $this; + + return function ($region, $holiday, $key = null) use ($mixin) { + $mixin->initializeHolidaysRegion($region); + + if (is_string($key)) { + $mixin->holidays[$region][$key] = $holiday; + + return isset($this) ? $this : null; + } + + $mixin->holidays[$region][] = $holiday; + + return isset($this) ? $this : null; + }; + } + + /** + * Set the name(s) of a holiday. + * + * @return \Closure + */ + public function setHolidayName() + { + $mixin = $this; + + return function ($holidayKey = null, $name = null, $value = null) use ($mixin) { + static $dictionary; + + if (($name = is_string($name) ? array($name => $value) : $name) && $mixin instanceof Holiday) { + if (!isset($dictionary)) { + $dictionary = $mixin->getHolidayNamesDictionary(); + } + foreach ($name as $language => $text) { + $dictionary($language); + $mixin->holidayNames[$language][$holidayKey] = $text; + } + } + + return isset($this) ? $this : null; + }; + } + + /** + * Add a holiday to the holidays list of a region then init name and observed state. + * + * @return \Closure + */ + public function addHoliday() + { + $mixin = $this; + $dictionary = $this->setHolidayName(); + + return function ($region, $holiday, $key = null, $name = null, $observed = null) use ($mixin, $dictionary) { + static $observer; + + $mixin->initializeHolidaysRegion($region); + $push = $mixin->pushHoliday(); + $push($region, $holiday, $key); + + $dictionary($key, $name); + + if (isset($observed) && $mixin instanceof HolidayObserver) { + if (!isset($observer)) { + $observer = $mixin->setHolidayObserveStatus(); + } + $observer($key, $observed); + } + + return isset($this) ? $this : null; + }; + } + + /** + * Unpack a holiday array definition. + * + * @return \Closure + */ + public function unpackHoliday() + { + return function (&$holiday, &$name = null, &$observed = null) { + if (!isset($holiday['date'])) { + throw new \InvalidArgumentException( + 'Holiday array definition should at least contains a "date" entry.' + ); + } + + if (isset($holiday['name'])) { + $name = $holiday['name']; + } + + if (isset($holiday['observed'])) { + $observed = $holiday['observed']; + } + + $holiday = $holiday['date']; + + return $holiday; + }; + } + + /** + * Check a holiday definition and unpack it if it's an array. + * + * @return \Closure + */ + public function checkHoliday() + { + $mixin = $this; + + return function (&$holiday, $key, &$name = null, &$observed = null) use ($mixin) { + $unpack = $mixin->unpackHoliday(); + + if (is_array($holiday)) { + if (is_int($key)) { + throw new \InvalidArgumentException( + 'Holiday array definition need a string identifier as main array key.' + ); + } + + $unpack($holiday, $name, $observed); + } + + return $holiday; + }; + } + /** * Add holidays to the holidays list. * @@ -116,9 +249,14 @@ public function addHolidays() return function ($region, $holidays) use ($mixin) { $mixin->initializeHolidaysRegion($region); + $add = $mixin->addHoliday(); + $check = $mixin->checkHoliday(); - foreach ($holidays as $holiday) { - $mixin->holidays[$region][] = $holiday; + foreach ($holidays as $key => $holiday) { + $name = null; + $observed = null; + $check($holiday, $key, $name, $observed); + $add($region, $holiday, $key, $name, $observed); } }; } diff --git a/tests/Cmixin/BusinessDayTest.php b/tests/Cmixin/BusinessDayTest.php index e3f3a78..f8ff058 100644 --- a/tests/Cmixin/BusinessDayTest.php +++ b/tests/Cmixin/BusinessDayTest.php @@ -78,6 +78,69 @@ public function testIsHoliday() } } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Holiday array definition should at least contains a "date" entry. + */ + public function testAddHolidaysArrayNotDate() + { + $carbon = static::CARBON_CLASS; + $carbon::addHolidays('fr-national', array( + 'foo-bar' => array( + 'observe' => true, + ), + )); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Holiday array definition need a string identifier as main array key. + */ + public function testAddHolidaysArrayIntKey() + { + $carbon = static::CARBON_CLASS; + $carbon::addHolidays('fr-national', array( + array( + 'date' => '15/11', + 'observe' => true, + ), + )); + } + + public function testAddHolidaysArray() + { + $carbon = static::CARBON_CLASS; + $carbon::addHolidays('fr-national', array( + 'foo-bar' => array( + 'date' => '15/11', + 'observed' => true, + 'name' => array( + 'en' => 'Foo bar', + 'fr' => 'Machin chose', + ), + ), + )); + self::assertFalse($carbon::parse('2010-11-15 03:30:40')->isHoliday()); + self::assertFalse($carbon::parse('2010-11-15 03:30:40')->isObservedHoliday()); + self::assertFalse($carbon::parse('2010-11-15 03:30:40')->getHolidayName()); + $carbon::setHolidaysRegion('fr-national'); + self::assertTrue($carbon::parse('2010-11-15 03:30:40')->isHoliday()); + self::assertTrue($carbon::parse('2010-11-15 03:30:40')->isObservedHoliday()); + self::assertSame('Foo bar', $carbon::parse('2010-11-15 03:30:40')->getHolidayName()); + self::assertSame('Machin chose', $carbon::parse('2010-11-15 03:30:40')->getHolidayName('fr')); + self::assertSame('Unknown', $carbon::parse('2010-11-15 03:30:40')->getHolidayName('nl')); + } + + public function testSetHolidayName() + { + $carbon = static::CARBON_CLASS; + $carbon::setHolidaysRegion('fr-national'); + self::assertSame('Christmas', $carbon::parse('2018-12-25')->getHolidayName()); + $carbon::setHolidayName('christmas', 'en', 'Christmas Day'); + self::assertSame('Christmas Day', $carbon::parse('2018-12-25')->getHolidayName()); + self::assertSame('Noël', $carbon::parse('2018-12-25')->getHolidayName('fr')); + } + public function testIsHolidayStatic() { $carbon = static::CARBON_CLASS;