summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEgor <elazarovich@xbsoftware.com>2015-03-06 11:58:17 +0300
committerEgor <elazarovich@xbsoftware.com>2015-03-06 11:58:17 +0300
commitc84f7d0038fa9bc1c6569bc7e4d73da17fb414fd (patch)
treed9ac8a6ee2f0b457e388dfe3579770dcc02cf5e5
downloadscheduler-helper-php-c84f7d0038fa9bc1c6569bc7e4d73da17fb414fd.zip
scheduler-helper-php-c84f7d0038fa9bc1c6569bc7e4d73da17fb414fd.tar.gz
scheduler-helper-php-c84f7d0038fa9bc1c6569bc7e4d73da17fb414fd.tar.bz2
Added.
-rw-r--r--RecurringType.php383
-rw-r--r--SchedulerDate.php99
-rw-r--r--SchedulerHelper.php391
-rw-r--r--SchedulerHelperConnector.php105
4 files changed, 978 insertions, 0 deletions
diff --git a/RecurringType.php b/RecurringType.php
new file mode 100644
index 0000000..b5ff1de
--- /dev/null
+++ b/RecurringType.php
@@ -0,0 +1,383 @@
+<?php
+namespace Scheduler;
+use Exception;
+
+class RecurringType {
+
+ //RECURRING DATA FIELDS
+ const FLD_REC_TYPE = "type";
+ const FLD_REC_TYPE_STEP = "count";
+ const FLD_WEEK_DAY = "day";
+ const FLD_WEEK_NUMBER = "count2";
+ const FLD_WEEK_DAYS_LIST = "days";
+ const FLD_REPEAT = "repeat";
+
+ //RECURRING TYPES
+ const REC_TYPE_DAY = "day";
+ const REC_TYPE_WEEK = "week";
+ const REC_TYPE_MONTH = "month";
+ const REC_TYPE_YEAR = "year";
+
+ //RECURRING VALUES
+ const IS_RECURRING_EXCEPTION = "";
+ const IS_RECURRING_BREAK = "none";
+
+ private $_fields_values = array();
+ private $_recurring_start_date_stamp;
+ private $_recurring_end_date_stamp;
+
+ public function __construct($recurringType, $recurringStartDateStamp, $recurringEndDateStamp)
+ {
+ if(is_array($recurringType))
+ $recurringType = self::parseRecurringDataArrayToString($recurringType);
+
+ $this->_fields_values = self::_parseRecurringDataString($recurringType);
+ $this->_recurring_start_date_stamp = $recurringStartDateStamp;
+ $this->_recurring_end_date_stamp = $recurringEndDateStamp;
+ }
+
+ public static function getInstance($recurringTypeString, $recurringStartDateStamp, $recurringEndDateStamp) {
+ return new self($recurringTypeString, $recurringStartDateStamp, $recurringEndDateStamp);
+ }
+
+ /**
+ * Get field value.
+ * @param $fieldName
+ * @return mixed
+ * @throws Exception
+ */
+ private function _getFieldValue($fieldName)
+ {
+ if(!isset($this->_fields_values[$fieldName]))
+ throw new Exception("Field '{$fieldName}' not found.");
+
+ return $this->_fields_values[$fieldName];
+ }
+
+ /**
+ * Parse recurring data from array to string.
+ * @param $dataArray
+ * @return string
+ * @throws Exception
+ */
+ static function parseRecurringDataArrayToString($dataArray)
+ {
+ $dataFields = array(
+ self::FLD_REC_TYPE => "each",
+ self::FLD_REC_TYPE_STEP => "step",
+// self::FLD_WEEK_DAY => "day_of_week",//ToDo: delete.
+ self::FLD_WEEK_NUMBER => "week_number",
+ self::FLD_WEEK_DAYS_LIST => "days_of_week",
+ self::FLD_REPEAT => "repeat"
+ );
+
+ $recurringTypes = array(self::REC_TYPE_DAY, self::REC_TYPE_WEEK, self::REC_TYPE_MONTH, self::REC_TYPE_YEAR);
+ $daysOfWeek = array("sunday" => 0, "monday" => 1, "tuesday" => 2, "wednesday" => 3, "thursday" => 4, "friday" => 5, "saturday" => 6);
+ $dataFieldsValues = array();
+
+ foreach($dataArray as $field => $value) {
+ switch($field) {
+ case $dataFields[self::FLD_REC_TYPE_STEP]:
+ case $dataFields[self::FLD_REPEAT]:
+ $value = str_replace(" ", "", $value);
+ $dataFieldsValues[$field] = $value;
+ break;
+
+ case $dataFields[self::FLD_REC_TYPE]:
+ $value = str_replace(" ", "", $value);
+ if(!in_array($value, $recurringTypes))
+ throw new Exception("Field '{$field}' will contains value of ".join(", ", $recurringTypes));
+
+ $dataFieldsValues[$field] = $value;
+ break;
+
+
+ case $dataFields[self::FLD_WEEK_NUMBER]:
+ $value = str_replace(" ", "", $value);
+ if(count(explode(",", $dataArray[$dataFields[self::FLD_WEEK_DAYS_LIST]])) > 1)
+ throw new Exception("If field {$field} not null, then field ".$dataFields[self::FLD_WEEK_DAYS_LIST]." will contains only one value of ".join(", ", array_keys($daysOfWeek)));
+
+ if(!in_array($value, $daysOfWeek))
+ throw new Exception("Field {$field} will contains value of ".join(",", array_keys($daysOfWeek)));
+
+ $dataFieldsValues[$field] = $value;
+ break;
+
+ case $dataFields[self::FLD_WEEK_DAYS_LIST]:
+ $weekDaysToRecurring = explode(",", $value);
+ $days = array();
+ foreach($weekDaysToRecurring as $day) {
+ $day = str_replace(" ", "", $day);
+ if(!in_array($day, $daysOfWeek))
+ throw new Exception("Field {$field} will contains data like 'monday,tuesday,wednesday'.");
+
+ array_push($days, $daysOfWeek[$day]);
+ }
+
+ $dataFieldsValues[$field] = join("," ,$days);
+ break;
+
+ default:
+ $dataFieldsValues[$field] = "";
+ break;
+ }
+ }
+
+ //Check required data and fill gaps of data.
+ $requiredFields = array(
+ self::FLD_REC_TYPE,
+ self::FLD_REC_TYPE_STEP
+ );
+
+ foreach($dataFields as $fieldKey => $fieldName) {
+ if(isset($dataFieldsValues[$fieldName]))
+ continue;
+
+ if(in_array($fieldKey, $requiredFields))
+ throw new Exception("Field '{$fieldName}' is required");
+
+ $dataFieldsValues[$fieldName] = "";
+ }
+
+ $recurringFormat = "%s_%s_%s_%s_%s#%s";
+ return sprintf(
+ $recurringFormat,
+ $dataFieldsValues[$dataFields[self::FLD_REC_TYPE]],
+ $dataFieldsValues[$dataFields[self::FLD_REC_TYPE_STEP]],
+ (!empty($dataFieldsValues[$dataFields[self::FLD_WEEK_NUMBER]])) ? $dataFieldsValues[$dataFields[self::FLD_WEEK_DAYS_LIST]] : "",
+ $dataFieldsValues[$dataFields[self::FLD_WEEK_NUMBER]],
+ (empty($dataFieldsValues[$dataFields[self::FLD_WEEK_NUMBER]])) ? $dataFieldsValues[$dataFields[self::FLD_WEEK_DAYS_LIST]] : "",
+ $dataFieldsValues[$dataFields[self::FLD_REPEAT]]
+ );
+ }
+
+ /**
+ * Parse recurring data from string.
+ * @param $dataStr
+ * @return array
+ */
+ static private function _parseRecurringDataString($dataStr)
+ {
+ $formatPartsReg = "/(_|#)/";
+ $formatDaysListPartReg = "/,/";
+ $parsedData = array();
+
+ list(
+ $parsedData[self::FLD_REC_TYPE],
+ $parsedData[self::FLD_REC_TYPE_STEP],
+ $parsedData[self::FLD_WEEK_DAY],
+ $parsedData[self::FLD_WEEK_NUMBER],
+ $parsedData[self::FLD_WEEK_DAYS_LIST],
+ $parsedData[self::FLD_REPEAT]
+ ) = preg_split($formatPartsReg, $dataStr);
+
+ $parsedData[self::FLD_WEEK_DAYS_LIST] = ($parsedData[self::FLD_WEEK_DAYS_LIST]) ?
+ preg_split($formatDaysListPartReg, $parsedData[self::FLD_WEEK_DAYS_LIST]) : array();
+
+ return $parsedData;
+ }
+
+ public function getRecurringTypeValue()
+ {
+ return $this->_getFieldValue(self::FLD_REC_TYPE);
+ }
+
+ public function getRecurringTypeStepValue()
+ {
+ return $this->_getFieldValue(self::FLD_REC_TYPE_STEP);
+ }
+
+ public function getWeekNumberValue()
+ {
+ return $this->_getFieldValue(self::FLD_WEEK_NUMBER);
+ }
+
+ public function getWeekDayValue()
+ {
+ return $this->_getFieldValue(self::FLD_WEEK_DAY);
+ }
+
+ public function getWeekDaysListValue()
+ {
+ return $this->_getFieldValue(self::FLD_WEEK_DAYS_LIST);
+ }
+
+ public function getRepeatValue()
+ {
+ return $this->_getFieldValue(self::FLD_REPEAT);
+ }
+
+ /**
+ * Correcting interval by recurring start($this->_recurring_start_date_stamp)
+ * and end($this->_recurring_end_date_stamp) dates.
+ * @param $intervalStartDateStamp
+ * @param $intervalEndDateStamp
+ * @return array
+ */
+ private function _getCorrectedRecurringInterval($intervalStartDateStamp, $intervalEndDateStamp)
+ {
+ $recurringStartDateStamp = $this->_recurring_start_date_stamp;
+ $recurringEndDateStamp = $this->_recurring_end_date_stamp;
+
+ $recurringInterval = array(
+ "start_date_stamp" => $intervalStartDateStamp,
+ "end_date_stamp" => $intervalEndDateStamp
+ );
+
+ //Return recurring interval without correcting if it not belongs to assigned interval.
+ if(($intervalStartDateStamp >= $recurringEndDateStamp) || ($intervalEndDateStamp <= $recurringStartDateStamp))
+ return $recurringInterval;
+
+ //Correct start date interval if it smaller then recurring start date.
+ if($intervalStartDateStamp < $recurringStartDateStamp)
+ $intervalStartDateStamp = $recurringStartDateStamp;
+
+ //Correct end date interval if it smaller then recurring end date.
+ if($intervalEndDateStamp > $recurringEndDateStamp)
+ $intervalEndDateStamp = $recurringEndDateStamp;
+
+ $differenceStartDates = SchedulerDate::differenceBetweenDates($intervalStartDateStamp, $recurringStartDateStamp);
+ $differenceEndDates = SchedulerDate::differenceBetweenDates($intervalEndDateStamp, $recurringEndDateStamp);
+ $dateUnits = SchedulerDate::$DATE_UNITS;
+
+ //Add years.
+ $recurringInterval["start_date_stamp"] = SchedulerDate::addYears($recurringStartDateStamp, $differenceStartDates[$dateUnits["year"]]);
+ $recurringInterval["end_date_stamp"] = SchedulerDate::addYears($recurringEndDateStamp, -$differenceEndDates[$dateUnits["year"]]);
+
+ //If recurring type is "year" then exit, else add months.
+ if($this->getRecurringTypeValue() == self::REC_TYPE_YEAR)
+ return $recurringInterval;
+
+ //Add months.
+ $recurringInterval["start_date_stamp"] = SchedulerDate::addMonths($recurringInterval["start_date_stamp"], $differenceStartDates[$dateUnits["month"]]);
+ $recurringInterval["end_date_stamp"] = SchedulerDate::addMonths($recurringInterval["end_date_stamp"], -$differenceEndDates[$dateUnits["month"]]);
+ return $recurringInterval;
+ }
+
+ /**
+ * Get step to recurring day from current day of week in date.
+ * @param $dateStamp
+ * @param $recurringWeekDay
+ * @return int
+ */
+ private function _getRecurringDayStep($dateStamp, $recurringWeekDay)
+ {
+ $weekDay = SchedulerDate::getDayOfWeek($dateStamp);
+ $dayStep = $recurringWeekDay - $weekDay;
+ $dayStep = ($dayStep < 0) ? (SchedulerDate::DAYS_IN_WEEK - (-$dayStep)) : $dayStep;
+ return $dayStep;
+ }
+
+ /**
+ * Get recurring days for date.
+ * @param $dateStamp
+ * @return array
+ */
+ private function _getRecurringDays($dateStamp)
+ {
+ $recurringDays = array();
+
+ //If recurring type has list of days, then get those days.
+ $recurringWeekDays = $this->getWeekDaysListValue();
+ if($recurringWeekDays) {
+ for($i = 0; $i < count($recurringWeekDays); $i++) {
+ $dayStep = $this->_getRecurringDayStep($dateStamp, $recurringWeekDays[$i]);
+ array_push($recurringDays, SchedulerDate::addDays($dateStamp, $dayStep));
+ }
+ }
+ //Else if recurring type has day of week and step for it, then get this day.
+ elseif($this->getWeekDayValue() && $this->getWeekNumberValue()) {
+ $dayStep = $this->_getRecurringDayStep($dateStamp, $this->getWeekDayValue());
+ $dayStep += (SchedulerDate::DAYS_IN_WEEK * ($this->getWeekNumberValue() - 1));
+ array_push($recurringDays, SchedulerDate::addDays($dateStamp, $dayStep));
+ }
+ //Else return recurring date without change.
+ else
+ array_push($recurringDays, $dateStamp);
+
+ return $recurringDays;
+ }
+
+ /**
+ * Get recurring dates by interval or $intervalStartDateStamp and $countDates.
+ * @param $intervalStartDateStamp
+ * @param $intervalEndDateStamp
+ * @param null $countDates
+ * @return array|bool
+ */
+ public function getRecurringDates($intervalStartDateStamp, $intervalEndDateStamp, $countDates = NULL)
+ {
+ if(!($this->getRecurringTypeStepValue() && $this->getRecurringTypeValue()))
+ return false;
+
+ //Correct interval by recurring interval.
+ $correctedInterval = $this->_getCorrectedRecurringInterval($intervalStartDateStamp, $intervalEndDateStamp);
+ $intervalStartDateStamp = $correctedInterval["start_date_stamp"];
+ $intervalEndDateStamp = $correctedInterval["end_date_stamp"];
+ $currentRecurringStartDateStamp = $intervalStartDateStamp;
+ $recurringDates = array();
+
+ //Generate dates wile next recurring date belongs to interval.
+ $countRecurringCycles = 0;
+ while(
+ (!is_null($countDates) && ($countRecurringCycles <= $countDates))
+ || (
+ ($intervalStartDateStamp <= $currentRecurringStartDateStamp)
+ && ($currentRecurringStartDateStamp <= $intervalEndDateStamp)
+ )
+ ) {
+ $countRecurringCycles++;
+ $recurringDays = $this->_getRecurringDays($currentRecurringStartDateStamp);
+ $recurringDates = array_merge($recurringDates, $recurringDays);
+
+ $recurringTypeStep = $this->getRecurringTypeStepValue();
+ switch($this->getRecurringTypeValue()) {
+ case self::REC_TYPE_DAY:
+ $currentRecurringStartDateStamp = SchedulerDate::addDays($currentRecurringStartDateStamp, $recurringTypeStep);
+ break;
+
+ case self::REC_TYPE_WEEK:
+ $currentRecurringStartDateStamp = SchedulerDate::addWeeks($currentRecurringStartDateStamp, $recurringTypeStep);
+ break;
+
+ case self::REC_TYPE_MONTH:
+ $currentRecurringStartDateStamp = SchedulerDate::addMonths($currentRecurringStartDateStamp, $recurringTypeStep);
+ break;
+
+ case self::REC_TYPE_YEAR:
+ $currentRecurringStartDateStamp = SchedulerDate::addYears($currentRecurringStartDateStamp, $recurringTypeStep);
+ break;
+ }
+ }
+
+ return (!is_null($countDates))
+ ? array_splice($recurringDates, (count($recurringDates) - $countDates))
+ : $recurringDates;
+ }
+
+ /**
+ * @param $recurringType
+ * @param $startDateStamp
+ * @param $eventLength
+ * @return int|NULL
+ */
+ public static function getRecurringEndDate($recurringType, $startDateStamp, $eventLength)
+ {
+ $recurringTypeObj = self::getInstance($recurringType, $startDateStamp, NULL);
+
+ $repeatValue = $recurringTypeObj->getRepeatValue();
+ if(empty($repeatValue))
+ return ($startDateStamp + $eventLength);
+
+ $recurringStartDatesStamps = $recurringTypeObj->getRecurringDates($startDateStamp, NULL, $repeatValue);
+
+ $maxEndDateStamp = NULL;
+ foreach($recurringStartDatesStamps as $startDateStamp) {
+ $endDateStamp = $startDateStamp + $eventLength;
+ $maxEndDateStamp = ($endDateStamp > $maxEndDateStamp) ? $endDateStamp : $maxEndDateStamp;
+ }
+
+ return $maxEndDateStamp;
+ }
+
+} \ No newline at end of file
diff --git a/SchedulerDate.php b/SchedulerDate.php
new file mode 100644
index 0000000..52d342f
--- /dev/null
+++ b/SchedulerDate.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace Scheduler;
+use DateTime;
+
+interface ISchedulerDate
+{
+ static public function getDateTimestamp($date);
+}
+
+class SchedulerDate implements ISchedulerDate
+{
+ const SECONDS_IN_DAY = 86400;
+ const DAYS_IN_WEEK = 7;
+ const MONTHS_IN_YEAR = 12;
+
+ const FORMAT_DEFAULT = "Y-m-d H:i:s";
+
+ static $DATE_UNITS = array(
+ "hour" => "H",
+ "minute" => "i",
+ "second" => "s",
+ "month" => "m",
+ "day" => "d",
+ "year" => "Y"
+ );
+
+ static public function differenceBetweenDates($firstDateStamp, $secondDateStamp) {
+ $firstDate = new DateTime(date(self::FORMAT_DEFAULT, $firstDateStamp));
+ $secondDate = new DateTime(date(self::FORMAT_DEFAULT, $secondDateStamp));
+ $dateUnits = self::$DATE_UNITS;
+ $differenceArray = array();
+
+ foreach($dateUnits as $dateUnit)
+ $differenceArray[$dateUnit] = $firstDate->diff($secondDate, true)->format("%".$dateUnit);
+
+ return $differenceArray;
+ }
+
+ static public function getDateTimestamp($date)
+ {
+ $parsedDate = date_parse($date);
+ return mktime(
+ $parsedDate["hour"],
+ $parsedDate["minute"],
+ $parsedDate["second"],
+ $parsedDate["month"],
+ $parsedDate["day"],
+ $parsedDate["year"]
+ );
+ }
+
+ static public function getDayOfWeek($timestamp) {
+ $weekDay = getdate($timestamp)["wday"];
+ return $weekDay;
+ }
+
+ static public function addDate($timestamp, $unit, $count) {
+ $dateUnits = self::$DATE_UNITS;
+ $units = array(
+ $dateUnits["hour"],
+ $dateUnits["minute"],
+ $dateUnits["second"],
+ $dateUnits["month"],
+ $dateUnits["day"],
+ $dateUnits["year"]
+ );
+ $args = array();
+
+ for($i = 0; $i < count($units); $i++){
+ $time_part = $units[$i];
+ $param = date($time_part, $timestamp);
+ if($unit == $time_part)
+ $param += $count;
+
+ array_push($args, $param);
+
+ }
+
+ return call_user_func_array("mktime", $args);
+ }
+
+ static public function addDays($timestamp, $count) {
+ return self::addDate($timestamp, self::$DATE_UNITS["day"], $count);
+ }
+
+ static public function addWeeks($timestamp, $count) {
+ return self::addDate($timestamp, self::$DATE_UNITS["day"], ($count * self::DAYS_IN_WEEK));
+ }
+
+ static public function addMonths($timestamp, $count) {
+ return self::addDate($timestamp, self::$DATE_UNITS["month"], $count);
+ }
+
+ static public function addYears($timestamp, $count) {
+ return self::addDate($timestamp, self::$DATE_UNITS["year"], $count);
+ }
+
+} \ No newline at end of file
diff --git a/SchedulerHelper.php b/SchedulerHelper.php
new file mode 100644
index 0000000..2387dbe
--- /dev/null
+++ b/SchedulerHelper.php
@@ -0,0 +1,391 @@
+<?php
+
+namespace Scheduler;
+require_once "SchedulerDate.php";
+require_once "SchedulerHelperConnector.php";
+require_once "RecurringType.php";
+
+use PDO, Exception;
+
+abstract class DHelper extends Connector
+{
+ const FLD_ID = "id";
+ const FLD_START_DATE = "start_date";
+ const FLD_END_DATE = "end_date";
+ const FLD_TEXT = "text";
+ const FLD_RECURRING_TYPE = "recurring_type";
+ const FLD_PARENT_ID = "parent_id";
+ const FLD_LENGTH = "length";
+
+ private $_fields_names = array(
+ self::FLD_ID => "event_id",
+ self::FLD_START_DATE => "start_date",
+ self::FLD_END_DATE => "end_date",
+ self::FLD_TEXT => "text",
+ self::FLD_RECURRING_TYPE => "rec_type",
+ self::FLD_PARENT_ID => "event_pid",
+ self::FLD_LENGTH => "event_length"
+ );
+
+ private $_connect_configs;
+ private $_fields_values = array();
+
+ public $config = array(
+ "debug" => true
+ );
+
+ protected function getIdFieldName()
+ {
+ return $this->getFieldsNames(self::FLD_ID);
+ }
+
+ protected function getStartDateFieldName()
+ {
+ return $this->getFieldsNames(self::FLD_START_DATE);
+ }
+
+ protected function getEndDateFieldName()
+ {
+ return $this->getFieldsNames(self::FLD_END_DATE);
+ }
+
+ protected function getTextFieldName()
+ {
+ return $this->getFieldsNames(self::FLD_TEXT);
+ }
+
+ protected function getRecurringTypeFieldName()
+ {
+ return $this->getFieldsNames(self::FLD_RECURRING_TYPE);
+ }
+
+ protected function getParentIdFieldName()
+ {
+ return $this->getFieldsNames(self::FLD_PARENT_ID);
+ }
+
+ protected function getLengthFieldName()
+ {
+ return $this->getFieldsNames(self::FLD_LENGTH);
+ }
+
+ protected function getConnectConfigs()
+ {
+ return $this->_connect_configs;
+ }
+
+ protected function setConnectConfigs($connectConfigs)
+ {
+ $this->_connect_configs = $connectConfigs;
+ return $this;
+ }
+
+ protected function getFieldsNames($field = NULL)
+ {
+ if(is_null($field))
+ return $this->_fields_names;
+
+ if(!isset($this->_fields_names[$field]))
+ throw new Exception("Field {$field} not found.");
+
+ return $this->_fields_names[$field];
+ }
+
+ public function setFieldsNames($fieldsDataArray)
+ {
+ if(!is_array($fieldsDataArray))
+ throw new Exception("Fields data must be array.");
+
+ foreach($fieldsDataArray as $fieldKey => $fieldValue) {
+ //If field name is numeric, then made same field key and field value.
+ if(is_numeric($fieldKey))
+ $fieldKey = $fieldValue;
+
+ $this->_fields_names[$fieldKey] = $fieldValue;
+ }
+
+ return $this;
+ }
+
+ protected function setFieldsValues($dataArray)
+ {
+ foreach($dataArray as $fieldKey => $fieldValue)
+ $this->_fields_values[$this->_fields_names[$fieldKey]] = $fieldValue;
+
+ return $this;
+ }
+
+ protected function getFieldsValues($field = NULL)
+ {
+ if(is_null($field))
+ return $this->_fields_values;
+
+ if(isset($this->_fields_values[$this->_fields_names[$field]]))
+ return $this->_fields_values[$this->_fields_names[$field]];
+
+ return NULL;
+ }
+}
+
+interface IHelper
+{
+ public function getData($startDate, $endDate);
+ public function saveData($dataArray);
+ public function deleteById($id);
+}
+
+class Helper extends DHelper implements IHelper
+{
+ public function __construct($connectConfigs = NULL)
+ {
+ $this->setConnectConfigs($connectConfigs);
+ parent::__construct($connectConfigs);
+ }
+
+ public static function getInstance($connectConfigs = NULL)
+ {
+ return new self($connectConfigs);
+ }
+
+ /**
+ * Get recurring events data exceptions. And prepare data to format: []
+ * @return array
+ */
+ private function _getRecurringEventsExceptions()
+ {
+ $getEventsSql = "
+ SELECT
+ *
+ FROM
+ ".$this->getTableName()."
+ WHERE
+ ".$this->getRecurringTypeFieldName()." = '".RecurringType::IS_RECURRING_BREAK."'
+ OR (
+ ".$this->getRecurringTypeFieldName()." = '".RecurringType::IS_RECURRING_EXCEPTION."'
+ AND ".$this->getLengthFieldName()." != '0'
+ )
+ ";
+
+ $query = $this->getPDO()->prepare($getEventsSql);
+ $query->execute();
+ $events = array();
+
+ while($eventData = $query->fetch(PDO::FETCH_ASSOC))
+ {
+ $eventParentId = $eventData[$this->getParentIdFieldName()];
+ if(!isset($events[$eventParentId]))
+ $events[$eventParentId] = array();
+
+ $eventLength = $eventData[$this->getLengthFieldName()];
+ $events[$eventParentId][$eventLength] = $eventData;
+ }
+
+ return $events;
+ }
+
+ /**
+ * Get recurring events data by interval.
+ * @param $startDate
+ * @param $endDate
+ * @return array
+ */
+ private function _getRecurringEventsByInterval($startDate, $endDate)
+ {
+ $getEventsSql = "
+ SELECT
+ *
+ FROM
+ ".$this->getTablename()."
+ WHERE
+ ".$this->getStartDateFieldName()." <= '{$endDate}'
+ AND ".$this->getEndDateFieldName()." >= '{$startDate}'
+ AND (
+ ".$this->getParentIdFieldName()." = '0'
+ OR (
+ ".$this->getParentIdFieldName()." != '0'
+ AND ".$this->getLengthFieldName()." < '".SchedulerDate::getDateTimestamp($startDate)."'
+ )
+ )";
+
+ $query = $this->getPDO()->prepare($getEventsSql);
+ $query->execute();
+ return $query->fetchAll();
+ }
+
+ /**
+ * Exclude event extra data.
+ * @param $eventDataArray
+ * @return array
+ */
+ private function _filterEventDataToResponse($eventDataArray)
+ {
+ $filteredEventData = array();
+ foreach($eventDataArray as $dataKey => $dataValue) {
+ switch($dataKey) {
+ case $this->getIdFieldName():
+ case $this->getRecurringTypeFieldName():
+ case $this->getParentIdFieldName():
+ case $this->getLengthFieldName():
+ continue;
+ break;
+
+ default:
+ $filteredEventData[$dataKey] = $dataValue;
+ break;
+ }
+ }
+
+ return $filteredEventData;
+ }
+
+ /**
+ * Exclude recurring exceptions from dates and prepare events data.
+ * @param $recurringDatesStamps
+ * @param $recurringEventData
+ * @param array $recurringEventExceptionsData
+ * @return array
+ */
+ private function _prepareRecurringDataWithoutExceptions($recurringDatesStamps, $recurringEventData, $recurringEventExceptionsData = array())
+ {
+ $recurringData = array();
+
+ $parentRecurringExceptions = array();
+ if(isset($recurringEventExceptionsData[$recurringEventData[$this->getIdFieldName()]]))
+ $parentRecurringExceptions = $recurringEventExceptionsData[$recurringEventData[$this->getIdFieldName()]];
+
+ for($i = 0; $i < count($recurringDatesStamps); $i++) {
+ $preparedEventData = $recurringEventData;
+ $eventStartDateStamp = $recurringDatesStamps[$i];
+ $preparedEventData[$this->getStartDateFieldName()] = date(SchedulerDate::FORMAT_DEFAULT, $eventStartDateStamp);
+
+ $eventEndDateStamp = $eventStartDateStamp + $recurringEventData[$this->getLengthFieldName()];
+ $preparedEventData[$this->getEndDateFieldName()] = date(SchedulerDate::FORMAT_DEFAULT, $eventEndDateStamp);
+
+ if(isset($parentRecurringExceptions[$eventStartDateStamp])) {
+ $eventExceptionData = $parentRecurringExceptions[$eventStartDateStamp];
+ if($eventExceptionData[$this->getRecurringTypeFieldName()] != RecurringType::IS_RECURRING_BREAK)
+ $preparedEventData = $eventExceptionData;
+ else
+ continue;
+ }
+
+ $preparedEventData = $this->_filterEventDataToResponse($preparedEventData);
+ array_push($recurringData, $preparedEventData);
+ }
+
+ return $recurringData;
+ }
+
+ /**
+ * Get recurring events data by interval.
+ * @param $startDate
+ * @param $endDate
+ * @return array
+ */
+ public function getData($startDate, $endDate)
+ {
+ $recurringData = array();
+ $recurringEventsExceptions = $this->_getRecurringEventsExceptions();
+ $recurringEvents = $this->_getRecurringEventsByInterval($startDate, $endDate);
+
+ $intervalStartDateStamp = SchedulerDate::getDateTimestamp($startDate);
+ $intervalEndDateStamp = SchedulerDate::getDateTimestamp($endDate);
+
+ for($i = 0; $i < count($recurringEvents); $i++) {
+ $eventData = $recurringEvents[$i];
+
+ //Parse recurring data format.
+ $recurringTypeData = $eventData[$this->getRecurringTypeFieldName()];
+ $recurringStartDateStamp = SchedulerDate::getDateTimestamp($eventData[$this->getStartDateFieldName()]);
+ $recurringEndDateStamp = SchedulerDate::getDateTimestamp($eventData[$this->getEndDateFieldName()]);
+ $recurringTypeObj = new RecurringType($recurringTypeData, $recurringStartDateStamp, $recurringEndDateStamp);
+
+ //Get recurring dates by parsed format.
+ $recurringDatesStamps = $recurringTypeObj->getRecurringDates($intervalStartDateStamp, $intervalEndDateStamp);
+
+ //Exclude recurring exceptions by dates and prepare events data.
+ $recurringEventData = $this->_prepareRecurringDataWithoutExceptions($recurringDatesStamps, $eventData, $recurringEventsExceptions);
+ $recurringData = array_merge($recurringData, $recurringEventData);
+ }
+
+ //Leave events that belongs to interval.
+ $resultData = array();
+ for($i = 0; $i < count($recurringData); $i++) {
+ $recurringEvent = $recurringData[$i];
+ $recurringStartDateStamp = SchedulerDate::getDateTimestamp($recurringEvent[$this->getStartDateFieldName()]);
+ $recurringEndDateStamp = SchedulerDate::getDateTimestamp($recurringEvent[$this->getEndDateFieldName()]);
+
+ if(
+ (($intervalStartDateStamp <= $recurringStartDateStamp) && ($recurringStartDateStamp <= $intervalEndDateStamp))
+ || (($intervalStartDateStamp <= $recurringEndDateStamp) && ($recurringEndDateStamp <= $intervalEndDateStamp))
+ ) {
+ array_push($resultData, $recurringEvent);
+ }
+
+ }
+
+ return $resultData;
+ }
+
+ /**
+ * Save recurring events data.
+ * @param $dataArray
+ * @throws Exception
+ */
+ public function saveData($dataArray)
+ {
+ //If exist recurring type field and this array, then parse this to string.
+ if((isset($dataArray[self::FLD_RECURRING_TYPE])) && is_array($dataArray[self::FLD_RECURRING_TYPE]))
+ $dataArray[self::FLD_RECURRING_TYPE] = RecurringType::parseRecurringDataArrayToString($dataArray[self::FLD_RECURRING_TYPE]);
+
+ $PDO = $this->getPDO();
+ $PDO->beginTransaction();
+ try {
+ self::getInstance($this->getConnectConfigs())
+ ->setFieldsNames($this->getFieldsNames())
+ ->setFieldsValues($dataArray)
+ ->save();
+
+ $PDO->commit();
+ }
+ catch(Exception $error) {
+ $PDO->rollBack();
+ throw new Exception("Data not saved.");
+ }
+ }
+
+ /**
+ * Delete data event by id.
+ * @param $id
+ * @throws Exception
+ */
+ public function deleteById($id)
+ {
+ $PDO = $this->getPDO();
+ $PDO->beginTransaction();
+ try {
+ self::getInstance($this->getConnectConfigs())
+ ->setFieldsNames($this->getFieldsNames())
+ ->setFieldsValues(array(self::FLD_ID => $id))
+ ->delete();
+
+ $PDO->commit();
+ }
+ catch(Exception $error) {
+ $PDO->rollBack();
+ throw new Exception("Data not deleted.");
+ }
+ }
+
+ /**
+ * Get max recurring end date for recurring type.
+ * @param $recurringType
+ * @param $startDateStr
+ * @param $eventLength
+ * @return int
+ */
+ public function getRecurringEndDateStr($recurringType, $startDateStr, $eventLength) {
+ $endDateStamp = RecurringType::getRecurringEndDate($recurringType, SchedulerDate::getDateTimestamp($startDateStr), $eventLength);
+ return date(SchedulerDate::FORMAT_DEFAULT, $endDateStamp);
+ }
+} \ No newline at end of file
diff --git a/SchedulerHelperConnector.php b/SchedulerHelperConnector.php
new file mode 100644
index 0000000..88e8203
--- /dev/null
+++ b/SchedulerHelperConnector.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace Scheduler;
+use PDO, Exception;
+
+class Connector
+{
+ private $_dbsm, $_host, $_db_name, $_user, $_password, $_table_name;
+ private $_PDO;
+
+ protected function __construct($configs = array())
+ {
+ $this->_dbsm = isset($configs["dbsm"]) ? $configs["dbsm"] : "mysql";
+ $this->_host = isset($configs["host"]) ? $configs["host"] : "localhost";
+ $this->_db_name = $configs["db_name"];
+ $this->_user = $configs["user"];
+ $this->_password = $configs["password"];
+ $this->_table_name = $configs["table_name"];
+ }
+
+ protected function getTableName()
+ {
+ return $this->_table_name;
+ }
+
+ private function getConfigStringPDO()
+ {
+ return "{$this->_dbsm}:host={$this->_host};dbname={$this->_db_name}";
+ }
+
+ public function getPDO()
+ {
+ $PDO_options = array(
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
+ );
+
+ $this->_PDO = ($this->_PDO) ? $this->_PDO : new PDO($this->getConfigStringPDO(), $this->_user, $this->_password, $PDO_options);
+ return $this->_PDO;
+ }
+
+ protected function save()
+ {
+ if(!is_null($this->getFieldsValues(Helper::FLD_ID)))
+ $this->update();
+ else
+ $this->insert();
+ }
+
+ protected function update()
+ {
+ if(is_null($this->getFieldsValues(Helper::FLD_ID)))
+ throw new Exception("For updating data needs value of field Helper::FLD_ID");
+
+ $fieldsValues = $this->getFieldsValues();
+ $sqlSetPart = [];
+ foreach($fieldsValues as $field => $value)
+ array_push($sqlSetPart, "{$field}='{$value}'");
+
+ $sql = "
+ UPDATE
+ {$this->_table_name}
+ SET
+ ".join("," ,$sqlSetPart)."
+ WHERE
+ ".$this->getIdFieldName()." = ".$this->getFieldsValues(Helper::FLD_ID)."
+ ";
+
+ if($this->config["debug"])
+ echo("Update operation sql: ".$sql."<BR>");
+
+ $this->getPDO()->prepare($sql)->execute();
+ }
+
+ protected function insert()
+ {
+ $fieldsValues = $this->getFieldsValues();
+ $sqlFields = join(",", array_keys($fieldsValues));
+ $sqlValues = "'".join("','", array_values($fieldsValues))."'";
+ $sql = "INSERT INTO {$this->_table_name} ({$sqlFields}) values ({$sqlValues})";
+
+ if($this->config["debug"])
+ echo("Insert operation sql: ".$sql."<BR>");
+
+ $this->getPDO()->prepare($sql)->execute();
+ }
+
+ protected function delete()
+ {
+ $dataId = $this->getFieldsValues(Helper::FLD_ID);
+ if(is_null($dataId))
+ throw new Exception("For deleting needs value of FLD_ID");
+
+ $sql = "
+ DELETE FROM
+ ".$this->_table_name."
+ WHERE
+ ".$this->getIdFieldName()." = '{$dataId}'";
+
+ if($this->config["debug"])
+ echo("Delete operation sql: ".$sql."<BR>");
+
+ $this->getPDO()->prepare($sql)->execute();
+ }
+} \ No newline at end of file