Skip to content

Instantly share code, notes, and snippets.

@jmwebservices
Last active July 19, 2018 23:01
Show Gist options
  • Save jmwebservices/fe317271e74c5f5f3a819b2c604053fd to your computer and use it in GitHub Desktop.
Save jmwebservices/fe317271e74c5f5f3a819b2c604053fd to your computer and use it in GitHub Desktop.
Apply filters over the iterable values of a DatePeriod object.
<?php
/**
* Apply filters over the iterable values of a DatePeriod object
*
* @method self monday Include Mondays while iterating the DatePeriod
* @method self tuesday Include Tuesdays while iterating the DatePeriod
* @method self wednesday Include Wednesdays while iterating the DatePeriod
* @method self thursday Include Thursdays while iterating the DatePeriod
* @method self friday Include Fridays while iterating the DatePeriod
* @method self saturday Include Saturdays while iterating the DatePeriod
* @method self sunday Include Sundays while iterating the DatePeriod
*
* @method self weekdays Include weekdays while iterating the DatePeriod
* @method self weekends Include weekends while iterating the DatePeriod
*
* @method self am Include AM DateTimes while iterating the DatePeriod
* @method self pm Include PM DateTimes while iterating the DatePeriod
*
* @method self january Include days in January while iterating the DatePeriod
* @method self february Include days in February while iterating the DatePeriod
* @method self march Include days in March while iterating the DatePeriod
* @method self april Include days in April while iterating the DatePeriod
* @method self may Include days in May while iterating the DatePeriod
* @method self june Include days in June while iterating the DatePeriod
* @method self july Include days in July while iterating the DatePeriod
* @method self august Include days in August while iterating the DatePeriod
* @method self september Include days in September while iterating the DatePeriod
* @method self october Include days in October while iterating the DatePeriod
* @method self november Include days in November while iterating the DatePeriod
* @method self december Include days in December while iterating the DatePeriod
*/
class DatePeriod_Filter extends FilterIterator
{
/**
* Array of days to filter
*
* @var array
* <ul>
* <li>@key string day => @type boolean true
* ...
* </ul>
*/
private $_dayFilter = [];
/**
* Array of ante/post meridiems to filter
*
* @var array
* <ul>
* <li>@key string 'am' => @type boolean true
* <li>@key string 'pm' => @type boolean true
* </ul>
*/
private $_meridiemFilter = [];
/**
* Array of months to filter
*
* @var array
* <ul>
* <li>@key string month => @type boolean true
* ...
* </ul>
*/
private $_monthFilter = [];
/**
* Array of user filters
*
* @var array
* <ul>
* <li>@type callable Invoked with the current DateTime object and is expected to return a boolean
* ...
* </ul>
*/
private $_userFilter = [];
/**
* @link http://php.net/manual/en/dateperiod.construct.php
* @see DatePeriod::__construct()
*/
public function __construct( ...$params )
{
parent::__construct( new IteratorIterator( new DatePeriod( ...$params ) ) );
}
/**
* Method overloading
*
* @throws BadMethodCallException
*
* @param string $name
* @param array $noop
* @return self
*/
public function __call( string $name, array $noop ) : self
{
switch( $name )
{
case 'monday' :
case 'tuesday' :
case 'wednesday':
case 'thursday' :
case 'friday' :
case 'saturday' :
case 'sunday' :
$this->_dayFilter[ ucfirst( $name ) ] = true;
break;
case 'weekdays':
$this->monday()->tuesday()->wednesday()->thursday()->friday();
break;
case 'weekends':
$this->saturday()->sunday();
break;
case 'am':
case 'pm':
$this->_meridiemFilter[ $name ] = true;
break;
case 'january' :
case 'february' :
case 'march' :
case 'april' :
case 'may' :
case 'june' :
case 'july' :
case 'august' :
case 'september' :
case 'october' :
case 'november' :
case 'december' :
$this->_monthFilter[ ucfirst( $name ) ] = true;
break;
default:
throw new BadMethodCallException( "Call to undefined method $name" );
}
return $this;
}
/**
* Given the current DateTime object, check if it matches a user filter
*
* @param DateTime $current
* @return bool
*/
private function _userFilterMatches( DateTime $current ) : bool
{
foreach( $this->_userFilter as $filter )
{
if( $filter( $current ) )
return true;
}
return false;
}
/**
* {@inheritDoc}
* @see FilterIterator::accept()
*/
public function accept() : bool
{
$current = $this->current();
if( $this->_dayFilter && !isset( $this->_dayFilter[ $current->format( 'l' ) ] ) ) return false;
if( $this->_meridiemFilter && !isset( $this->_meridiemFilter[ $current->format( 'a' ) ] ) ) return false;
if( $this->_monthFilter && !isset( $this->_monthFilter[ $current->format( 'F' ) ] ) ) return false;
if( $this->_userFilter && !$this->_userFilterMatches( $current ) ) return false;
return true;
}
/**
* Add one or more custom filters to control which DateTime
* objects of DatePeriod will be interated
*
* @param callable $filter
* <div>Invoked with the current DateTime object and is expected to return a boolean value to indicate whether it should be iterated.</div>
*
* @param callable ...$filters
* @return self
*/
public function filter( callable $filter, callable ...$filters ) : self
{
array_push( $this->_userFilter, $filter, ...$filters );
return $this;
}
/**
* Return the DatePeriod constructed during instantiation
*
* @return DatePeriod
*/
public function getDatePeriod() : DatePeriod
{
return $this->getInnerIterator()
->getInnerIterator()
;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment