golden hour
/home/doctorbruno/public_html/taeionline.com/support/include
⬆️ Go Up
Upload
File/Folder
Size
Actions
.MANIFEST
194.97 KB
Del
OK
.htaccess
14 B
Del
OK
JSON.php
33.13 KB
Del
OK
PasswordHash.php
6.92 KB
Del
OK
Spyc.php
31.74 KB
Del
OK
UniversalClassLoader.php
8.61 KB
Del
OK
ajax.admin.php
7.29 KB
Del
OK
ajax.config.php
4.61 KB
Del
OK
ajax.content.php
9.76 KB
Del
OK
ajax.draft.php
13.03 KB
Del
OK
ajax.email.php
2.33 KB
Del
OK
ajax.export.php
1006 B
Del
OK
ajax.filter.php
874 B
Del
OK
ajax.forms.php
13.84 KB
Del
OK
ajax.i18n.php
5.1 KB
Del
OK
ajax.kbase.php
2.93 KB
Del
OK
ajax.note.php
2.05 KB
Del
OK
ajax.orgs.php
11.73 KB
Del
OK
ajax.plugins.php
2.15 KB
Del
OK
ajax.schedule.php
4.29 KB
Del
OK
ajax.search.php
12.72 KB
Del
OK
ajax.sequence.php
3.2 KB
Del
OK
ajax.staff.php
11.62 KB
Del
OK
ajax.tasks.php
33.87 KB
Del
OK
ajax.thread.php
8.81 KB
Del
OK
ajax.tickets.php
79.7 KB
Del
OK
ajax.tips.php
1.66 KB
Del
OK
ajax.upgrader.php
2.24 KB
Del
OK
ajax.users.php
18.33 KB
Del
OK
api.cron.php
1.06 KB
Del
OK
api.tickets.php
10.36 KB
Del
OK
class.2fa.php
7.76 KB
Del
OK
class.ajax.php
1.45 KB
Del
OK
class.api.php
15.31 KB
Del
OK
class.app.php
1.49 KB
Del
OK
class.attachment.php
6.95 KB
Del
OK
class.auth.php
50.73 KB
Del
OK
class.avatar.php
6.44 KB
Del
OK
class.banlist.php
2.58 KB
Del
OK
class.base32.php
4.07 KB
Del
OK
class.businesshours.php
7.08 KB
Del
OK
class.canned.php
9.05 KB
Del
OK
class.captcha.php
1.73 KB
Del
OK
class.category.php
11.14 KB
Del
OK
class.charset.php
3.41 KB
Del
OK
class.cli.php
9.48 KB
Del
OK
class.client.php
15.39 KB
Del
OK
class.collaborator.php
5.65 KB
Del
OK
class.company.php
2.65 KB
Del
OK
class.config.php
60.36 KB
Del
OK
class.controller.php
1.15 KB
Del
OK
class.cron.php
3.6 KB
Del
OK
class.crypto.php
18.92 KB
Del
OK
class.csrf.php
2.38 KB
Del
OK
class.dept.php
33.21 KB
Del
OK
class.dispatcher.php
7.12 KB
Del
OK
class.draft.php
6.23 KB
Del
OK
class.dynamic_forms.php
64.98 KB
Del
OK
class.email.php
49 KB
Del
OK
class.error.php
1.69 KB
Del
OK
class.export.php
32.92 KB
Del
OK
class.faq.php
15.05 KB
Del
OK
class.file.php
34.59 KB
Del
OK
class.filter.php
31.9 KB
Del
OK
class.filter_action.php
23.67 KB
Del
OK
class.format.php
44.3 KB
Del
OK
class.forms.php
195.58 KB
Del
OK
class.http.php
7.16 KB
Del
OK
class.i18n.php
24.28 KB
Del
OK
class.import.php
6.9 KB
Del
OK
class.json.php
2.71 KB
Del
OK
class.knowledgebase.php
5.8 KB
Del
OK
class.list.php
42 KB
Del
OK
class.lock.php
4.05 KB
Del
OK
class.log.php
1.55 KB
Del
OK
class.mail.php
35.76 KB
Del
OK
class.mailer.php
25.75 KB
Del
OK
class.mailfetch.php
9.72 KB
Del
OK
class.mailparse.php
30.99 KB
Del
OK
class.message.php
6.42 KB
Del
OK
class.migrater.php
5.2 KB
Del
OK
class.misc.php
7.5 KB
Del
OK
class.model.php
2.3 KB
Del
OK
class.nav.php
14.15 KB
Del
OK
class.note.php
2.39 KB
Del
OK
class.oauth2.php
4.04 KB
Del
OK
class.organization.php
22.45 KB
Del
OK
class.orm.php
120.9 KB
Del
OK
class.osticket.php
20.64 KB
Del
OK
class.ostsession.php
21.86 KB
Del
OK
class.page.php
10.59 KB
Del
OK
class.pagenate.php
5.53 KB
Del
OK
class.passwd.php
1.21 KB
Del
OK
class.pdf.php
3.83 KB
Del
OK
class.plugin.php
36.13 KB
Del
OK
class.priority.php
1.81 KB
Del
OK
class.queue.php
103.51 KB
Del
OK
class.report.php
11.76 KB
Del
OK
class.role.php
11.27 KB
Del
OK
class.schedule.php
46.28 KB
Del
OK
class.search.php
61.66 KB
Del
OK
class.sequence.php
7.27 KB
Del
OK
class.session.php
19.25 KB
Del
OK
class.setup.php
3.55 KB
Del
OK
class.signal.php
4.16 KB
Del
OK
class.sla.php
9.11 KB
Del
OK
class.staff.php
60.21 KB
Del
OK
class.task.php
56.21 KB
Del
OK
class.team.php
12.31 KB
Del
OK
class.template.php
23.45 KB
Del
OK
class.thread.php
108.96 KB
Del
OK
class.thread_actions.php
17.08 KB
Del
OK
class.ticket.php
167.39 KB
Del
OK
class.timezone.php
21.94 KB
Del
OK
class.topic.php
20.06 KB
Del
OK
class.translation.php
34.79 KB
Del
OK
class.upgrader.php
13.76 KB
Del
OK
class.user.php
43.4 KB
Del
OK
class.usersession.php
7.55 KB
Del
OK
class.util.php
10.07 KB
Del
OK
class.validator.php
12.94 KB
Del
OK
class.variable.php
11.93 KB
Del
OK
class.xml.php
3.23 KB
Del
OK
class.yaml.php
1.15 KB
Del
OK
cli
-
Del
OK
client
-
Del
OK
config
-
Del
OK
fpdf
-
Del
OK
htmLawed.php
53.53 KB
Del
OK
html2text.php
33.71 KB
Del
OK
i18n
-
Del
OK
index.php
37 B
Del
OK
laminas-mail
-
Del
OK
mpdf
-
Del
OK
mysqli.php
9.55 KB
Del
OK
ost-config.php
5.63 KB
Del
OK
ost-sampleconfig.php
6.24 KB
Del
OK
pear
-
Del
OK
plugins
-
Del
OK
staff
-
Del
OK
tnef_decoder.php
19.82 KB
Del
OK
upgrader
-
Del
OK
Edit: class.schedule.php
<?php /********************************************************************* class.schedule.php Peter Rotich <peter@osticket.com> Copyright (c) 2019 osTicket http://www.osticket.com Released under the GNU General Public License WITHOUT ANY WARRANTY. See LICENSE.TXT for details. vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ /** * Schedule * */ class Schedule extends VerySimpleModel { static $meta = array( 'table' => SCHEDULE_TABLE, 'ordering' => array('name'), 'pk' => array('id'), 'joins' => array( 'entries' => array( 'reverse' => 'ScheduleEntry.schedule', ), ), ); // Supported Schedule types based on flags. protected static $types = array( 'bizhrs' => /* @trans */ 'Business Hours', 'hdays' => /* @trans */ 'Holiday Hours', ); // Supported Flags // FLAG_BIZHRS: Schedule type of Business Hours otherwise Holiday Hours // is assumed. const FLAG_BIZHRS = 0x0001; protected $_entries; protected $_holidays; protected $_form; protected $_config; public function setFlag($flag, $val) { if ($val) $this->flags |= $flag; else $this->flags &= ~$flag; } function get($field, $default=false) { try { return parent::get($field, $default); } catch (Exception $e) {} if (!isset($this->_config)) $this->getConfig(); if (isset($this->_config[$field])) return $this->_config[$field]; } function getConfig() { if (!isset($this->_config) && $this->getId()) { $_config = new Config('schedule.'.$this->getId()); $this->_config = $_config->getInfo(); } return $this->_config; } function getId() { return $this->get('id'); } function getName() { return $this->getLocal('name'); } function getType() { return ($this->flags & self::FLAG_BIZHRS) ? 'bizhrs' : 'hdays'; } function getTypeDesc() { $types = self::getTypes(); return $types[$this->getType()]; } function getTimezone() { global $cfg; return $this->get('timezone') ?: $cfg->getTimezone(); } function getDatetimeZone() { return new DatetimeZone($this->getTimezone()); } function getCreated() { return $this->get('created'); } function getUpdated() { return $this->get('updated'); } function getInfo() { $info = $this->ht; $info['type'] = $this->getType(); return $info; } function getNumEntries() { return $this->getEntries()->count(); } function getEntries() { if (!$this->_entries) { $this->_entries = ScheduleEntry::objects() ->filter(array('schedule_id' => $this->getId())); } return $this->_entries; } function getEntry($id) { return $this->entries->findFirst(array('id' => $id)); } function addEntry(ScheduleEntryForm $form, &$errors) { if (!($vars=$form->process())) return false; if (!$this->isEntryUnique($vars, $errors)) $errors['error'] = $errors['error'] ?: __('Entry must be unique'); if ($errors) return false; $vars['schedule_id'] = $this->getId(); if (!($entry = ScheduleEntry::create($vars))) return false; $this->_entries = false; return $entry; } function isEntryNameUnique($name, $id=0) { $entry = $this->entries->findFirst(array('name' => $name)); return !($entry && $entry->getId() != $id); } function isEntryUnique($vars, &$errors) { // Make sure name is inique if (!$vars['name'] || !$this->isEntryNameUnique($vars['name'], $vars['id'] ?: 0)) $errors['name'] = __('Name must be unique'); switch ($vars['repeats']) { case 'weekly': if ($vars['day'] < 6 ) { // Weekday if ($this->entries->findFirst(['repeats' => 'weekdays'])) $errors['error'] = __('Weekdays entry already exists'); } elseif ($vars['day'] > 5) { //Weekend if ($this->entries->findFirst(['repeats' => 'weekends'])) $errors['error'] = __('Weekends entry already exists'); } break; case 'weekdays': if ($this->entries->findFirst(['repeats' => 'weekly', 'day__lt' => 6])) $errors['error'] = __('Week day entry already exists'); break; case 'weekends': if ($this->entries->findFirst(['repeats' => 'weekly', 'day__gt' => 5])) $errors['error'] = __('Weekend day entry already exists'); break; case 'daily': if (!$vars['id'] && $this->entries->count()) $errors['error'] = __('Other entries already exists'); break; } // Daily entry cannot coexist with other entries - mf is selfish af. if (!$errors['error'] && strcasecmp($vars['repeats'], 'daily')) if ($this->entries->findFirst(['repeats' => 'daily'])) $errors['error'] = __('Daily entry already exists'); if (!$errors['error']) { $keys = array_intersect_key($vars, array_flip( ['repeats', 'day', 'week', 'month'])); $keys['schedule_id'] = $this->getId(); // Once entries can repeat on different dates if ($keys['repeats'] == 'never') $keys['starts_on'] = $vars['starts_on']; $entries= ScheduleEntry::objects() ->filter($keys); if ($vars['id']) $entries->exclude(['id' => $vars['id']]); if ($entries->count()) $errors['error'] = __('Entry matching the selection already exists'); } return !count($errors); } function isHolidays() { return !$this->isBusinessHours(); } function isBusinessHours() { return ($this->flags & self::FLAG_BIZHRS); } function getForm($source=null) { if (!isset($this->_form)) $this->_form = self::basicForm($source ?: $this->getInfo()); return $this->_form; } function getTranslateTag($subtag) { return _H(sprintf('schedule.%s.%s', $subtag, $this->id)); } function getLocal($subtag) { $tag = $this->getTranslateTag($subtag); $T = CustomDataTranslation::translate($tag); return $T != $tag ? $T : $this->get($subtag); } function getHolidays() { if (!$this->isBusinessHours()) return false; if (!isset($this->_holidays)) { $config = $this->getConfiguration(); $this->_holidays = $config['holidays'] ?: array(); } return $this->_holidays; } function getNumHolidaysSchedules() { return count($this->getHolidays() ?: array()); } function getConfiguration() { $config = $this->getConfig(); return JsonDataParser::decode($config['configuration']); } function saveConfiguration($vars) { $config = new Config('schedule.'.$this->getId()); return $config->updateAll(array( 'configuration' => JsonDataEncoder::encode([ 'holidays' => $vars['holidays'] ?: array() ]), ) ); } function update($vars, &$errors) { $form = $this->getForm($vars); if (!$form->isValid()) return false; $data = $form->getClean(); foreach (['name', 'timezone', 'description'] as $f) $this->set($f, $data[$f]); // Set Schedule type flag only on create. if (!$this->getId() && isset($data['type'])) $this->setFlag(self::FLAG_BIZHRS, ($data['type'] == 'bizhrs')); if (!$this->save(true)) return false; // Update the config information $this->saveConfiguration(array( 'holidays' => $vars['holidays'])); // Update sorting foreach ($this->getEntries() as $e) { $id = $e->getId(); if (isset($_POST["sort-{$id}"])) { $e->sort = $_POST["sort-$id"]; $e->save(true); } } // Reset the form so we don't cache old data unset($this->_form); return true; } function save($refetch=false) { if (count($this->dirty)) $this->set('updated', new SqlFunction('NOW')); if (isset($this->dirty['description'])) $this->description = Format::sanitize($this->description); return parent::save($refetch); } function cloneEntries($schedule) { if (!$schedule) return; foreach ($schedule->getEntries() as $entry) { $vars = $entry->ht; unset($vars['id']); $vars['schedule_id'] = $this->getId(); ScheduleEntry::create($vars); } } function delete() { // TODO: Deny delete for in-use schedules if (!parent::delete()) return false; $this->entries->delete(); return true; } function getEntryForm($source=null) { return new ScheduleEntryForm($source, array( 'timezone' => $this->getTimezone(), 'holidays' => !$this->isBusinessHours(), )); } function getDiagnosticForm($source=null) { if (!$source) $source = ['date' => time(), 'hours' => 24]; return new ScheduleDiagnosticForm($source, array( 'timezone' => $this->getTimezone(), )); } static function create($ht=false, &$errors=array()) { $inst = new static($ht); $inst->set('created', new SqlFunction('NOW')); if ($inst->save()) return $inst; } static function __create($vars) { $s = static::create($vars); $s->set('created', new SqlFunction('NOW')); $s->set('updated', new SqlFunction('NOW')); $s->save(true); foreach ($vars['entries'] ?: array() as $info) { $entry = new ScheduleEntry($info); $entry->schedule_id = $s->getId(); $entry->save(); } if (isset($vars['configuration'])) $s->saveConfiguration($vars['configuration']); return $s; } static function getIdByName($name, $pid=0) { $schedule = self::objects()->filter(array( 'name' => $name, ))->values_flat('id')->first(); return $schedule ? $schedule[0] : 0; } static function lookup($id) { if (!($schedule = parent::lookup($id))) return null; return $schedule; } static function getSchedules($criteria=array()) { $schedules = self::objects(); if ($criteria) $schedules->filter($criteria); $schedules->order_by('name'); return $schedules; } static function getTypes() { static $translated = false; if (!$translated) { foreach (self::$types as $k => $v) self::$types[$k] = __($v); } return self::$types; } static function basicForm($source=null) { return new SimpleForm(array( 'name' => new TextboxField(array( 'required' => true, 'label' => __('Name'), 'configuration' => array( 'size' => 60, 'length' => 0, 'autofocus' => true, ), )), 'type' => new ChoiceField(array( 'required' => true, 'editable' => false, 'label' => __('Type'), 'validator-error' => __('Selection required'), 'choices' => self::getTypes(), 'configuration' => array( 'mode' => 'view', ), )), 'timezone' => new TimezoneField(array( 'required'=>false, 'label'=>__('Timezone'), 'hint' => __('Leave selection empty for Floating Timezone'), 'configuration' => array( 'autodetect'=>false, 'prompt' => __("Schedule's timezone") ), )), 'description' => new TextareaField(array( 'label'=> 'Description', 'required'=>false, 'default'=>'', 'configuration' => array( 'html' => true, 'size' => 'small', 'placeholder' => __('Brief description of the schedule'), ), )), ), $source); } } /* * BusinessHoursSchedule - extension of schedule * */ class BusinessHoursSchedule extends Schedule { // Holidays schedules applicable to this schedule protected $holidays; public function addWorkingHours(Datetime $date, $hours, &$timeline=array()) { // Delegate adding working hours to Business Hours utility class $bhrs = new BusinessHours($this); if (!$bhrs->addWorkingHours($date, $hours)) return false; $timeline = $bhrs->getTimeline(); return $date; } public function getHolidaysSchedules() { if (!isset($this->holidays)) { $this->holidays = array(); foreach ($this->getHolidays() ?:array() as $id) { if (($s=HolidaysSchedule::lookup($id))) $this->holidays[] = $s; } } return $this->holidays; } static function getSchedules($criteria=array()) { return parent::getSchedules($criteria + array( 'flags__hasbit' => Schedule::FLAG_BIZHRS)); } static function lookup($id) { return parent::lookup(array( 'id' => $id, 'flags__hasbit' => Schedule::FLAG_BIZHRS)); } } /* * HolidaysSchedule * */ class HolidaysSchedule extends Schedule { static function getSchedules($criteria=array()) { return parent::getSchedules($criteria) ->exclude(array('flags__hasbit' => Schedule::FLAG_BIZHRS)); } static function lookup($id) { return parent::lookup($id); } } /** * ScheduleEntry: An entry in a schedule. * */ class ScheduleEntry extends VerySimpleModel { static $meta = array( 'table' => SCHEDULE_ENTRY_TABLE, 'pk' => array('id'), 'joins' => array( 'schedule' => array( 'null' => true, 'constraint' => array('schedule_id' => 'Schedule.id'), ), ), ); var $_form; protected static $frequencies = array( 'never' => /* @trans */ 'Once', 'daily' => /* @trans */ 'Daily', 'weekly' => /* @trans */ 'Weekly', 'monthly' => /* @trans */ 'Monthly', 'yearly' => /* @trans */ 'Yearly', ); protected static $days = array( 1 => /* @trans */ 'Monday', 2 => /* @trans */ 'Tuesday', 3 => /* @trans */ 'Wednesday', 4 => /* @trans */ 'Thursday', 5 => /* @trans */ 'Friday', 6 => /* @trans */ 'Saturday', 7 => /* @trans */ 'Sunday', ); protected static $weeks = array( 1 => /* @trans */ 'First', 2 => /* @trans */ 'Second', 3 => /* @trans */ 'Third', 4 => /* @trans */ 'Fourth', 5 => /* @trans */ 'Fifth', -1 => /* @trans */ 'Last', ); protected static $months = array( 1 => /* @trans */ 'January', /* @trans */ 'February', /* @trans */ 'March', /* @trans */ 'April', /* @trans */ 'May', /* @trans */ 'June', /* @trans */ 'July', /* @trans */ 'August', /* @trans */ 'September', /* @trans */ 'October', /* @trans */ 'November', /* @trans */ 'December' ); protected $_timezone; protected $_starts; protected $_ends; protected $_stops; function getId() { return $this->get('id'); } function getSchedule() { return $this->schedule; } function getScheduleId() { return $this->get('schedule_id'); } function getCreated() { return $this->get('created'); } function getUpdated() { return $this->get('updated'); } function getTimezone() { if (!isset($this->_timezone)) $this->_timezone = $this->getSchedule()->getTimezone(); return $this->_timezone; } function getDatetimeZone() { return new DatetimeZone($this->getTimezone()); } function diffTime(Datetime $date) { // Set the time based on datetime given $start = clone $this->getStartsDatetime(); list($h, $m, $s) = explode(':', $date->format('H:i:s')); $start->setTime($h, $m, $s); return $this->getEndsDatetime()->getTimestamp() - $start->getTimestamp(); } function diff() { return ($this->getEndsDatetime()->getTimestamp() - $this->getStartsDatetime()->getTimestamp()); } function getHours() { return ($this->diff()+1)/3600; } function getMinutes() { return $this->diff()/60; } function isFullDay() { return ($this->getHours() >= 24); } function isWithinHours(Datetime $dt) { return !($this->isAfterHours($dt) || $this->isBeforeHours($dt)); } function isBeforeHours(Datetime $dt) { return strtotime($dt->format('H:i:s')) < strtotime($this->getStartsTime()); } function isAfterHours(Datetime $dt) { return strtotime($dt->format('H:i:s')) > strtotime($this->getEndsTime()); } function isOneTime() { return !strcasecmp($this->getRepeats(), 'never'); } function getStartsDatetime() { if (!isset($this->_starts)) $this->_starts = new Datetime(sprintf('%s %s', $this->ht['starts_on'], $this->ht['starts_at']), $this->getDatetimeZone()); return $this->_starts; } function getStartsTime() { return $this->getStartsDatetime()->format('H:i:s'); } function getEndsDatetime() { if (!isset($this->_ends)) $this->_ends = new Datetime(sprintf('%s %s', $this->ht['ends_on'], $this->ht['ends_at']), $this->getDatetimeZone()); return $this->_ends; } function getEndsTime() { return $this->getEndsDatetime()->format('H:i:s'); } function getStopsDatetime() { if (!isset($this->_stops)) { if ($this->ht['stops_on']) $this->_stops = new Datetime($this->ht['stops_on'], $this->getDatetimeZone()); elseif ($this->isOneTime()) $this->_stops = $this->getEndsDatetime(); } return $this->_stops; } function getIntervalSpec(Datetime $dt) { $info = $this->getInfo(); switch ($info['repeats']) { case 'never': $starts = $this->getStartsDatetime(); return $starts->format('Y-m-d'); break; case 'daily': return sprintf('%s %s', 'today', $dt->format('Y-m-d')); break; case 'weekdays': if ($dt->format('N') > 5) return 'weekday'; else return sprintf('%s %s', 'today', $dt->format('Y-m-d')); break; case 'weekends': if ($dt->format('N') > 5) return sprintf('%s %s', 'today', $dt->format('Y-m-d')); else return sprintf('Next Saturday %s', $dt->format('Y-m-d')); break; case 'weekly': return sprintf('%s %s', self::$days[$info['day']], $dt->format('Y-m-d')); break; case 'monthly': if (!$info['week'] && $info['day']> 0) return sprintf('%s-%s', $dt->format('Y-m'), $info['day']); else return sprintf('%s %s of %s %d', self::$weeks[$info['week']], self::$days[$info['day']], $dt->format('F'), $dt->format('Y')); break; case 'yearly': if ($info['week'] > 0) { return sprintf('%s %s %s %s', self::$months[$info['month']], $dt->format('Y'), self::$weeks[$info['week']], self::$days[$info['day']]); } elseif ($info['week'] == -1) { return sprintf('last %s of %s %s', self::$days[$info['day']], self::$months[$info['month']], $dt->format('Y')); } else { return sprintf('%s %d %d', self::$months[$info['month']], $info['day'], $dt->format('Y')); } break; } } function getCurrent($from=null) { if (!isset($this->_current) || $from) { // Figure out starting point (from) $from = is_object($from) ? clone $from : Format::parseDateTime($from ?: 'now'); $start = $this->getStartsDatetime(); if ($start->getTimestamp() > $from->getTimestamp()) $from = clone $start; // Check to make sure we're still in scope $stop = $this->getStopsDatetime(); if ($stop && $stop->getTimestamp() < $from->getTimestamp()) return null; // Figure out start time for the entry. $from->modify($this->getIntervalSpec($from)); $this->_current = clone $from; } return $this->_current; } function next() { if (!($current=$this->getCurrent())) return null; // Advance the interval based on frequencry switch ($this->ht['repeats']) { case 'daily': $current->modify('+1 day'); break; case 'weekly': $current->modify('+1 week'); break; case 'weekdays': $current->modify('+1 weekday'); break; case 'weekends': // Heavy lifting done in getIntervalSpec $current->modify('+1 day'); break; case 'monthly': $current->modify('+1 month'); break; case 'yearly': $current->modify('+1 year'); break; case 'never': return null; } // Set interval spec for specific day/week/month $current->modify($this->getIntervalSpec($current)); // Make sure we're still in scope $stops = $this->getStopsDatetime(); if ($stops && $stops->getTimestamp() < $current->getTimestamp()) return null; // Advance current position $this->_current = $current; return $current; } function getOccurrences($start=null, $end=null, $num=5) { $occurrences = array(); if (($current = $this->getCurrent($start))) { $start = $start ?: $current; while (count($occurrences) < $num) { $date = $current->format('Y-m-d'); if ($end && strtotime($date) > strtotime($end)) break; if (strtotime($date) >= strtotime($start->format('Y-m-d'))) $occurrences[$date] = $this; if (!($current=$this->next())) break; } } return $occurrences; } function getName() { return $this->getLocal('name'); } function getRepeats() { return $this->get('repeats'); } function getDesc() { $info = $this->getInfo(); $repeats = $this->getRepeats(); $days = self::getDays(); $weeks = self::getWeeks(); $months = self::getMonths(); $frequencies = self::getFrequencies(); $starts = $this->getStartsDatetime(); $ends = $this->getEndsDatetime(); $when = ''; $desc = $frequencies[$info['repeats']]; switch ($info['repeats']) { case 'weekly': $when = $days[$info['day']]; break; case 'weekdays': $desc = sprintf('%s (%s)', __('Weekdays'), __('Mon-Fri')); break; case 'weekends': $desc = sprintf('%s (%s)', __('Weekends'), __('Sat-Sun')); break; case 'monthly': if (!$info['week']) $when = sprintf(__('%s of the Month'), Format::ordinalsuffix($info['day'])); else $when = sprintf('the %s %s', $weeks[$info['week']], $days[$info['day']]); break; case 'yearly': if (!$info['week']) { $when =sprintf('%s %s', $months[$info['month']], Format::ordinalsuffix($info['day'])); } else { $when = sprintf('the %s %s in %s', $weeks[$info['week']], $days[$info['day']], $months[$info['month']]); } break; case 'never': $when = $starts->format('F jS, Y'); break; } if ($when) $desc .=' '.sprintf(__('on %s'), $when); if (!$this->isFullDay()) { $desc .= sprintf(' <small>(%s - %s)</small>', $starts->format('h:i a'), $ends->format('h:i a')); } return $desc; } function getSortOrder() { return $this->get('sort'); } function getInfo() { return $this->ht; } function getForm($source=null) { if (!$this->_form) { if (!$source) { $source = $this->getInfo(); $starts = $this->getStartsDatetime(); $source['starts_on'] = $starts->getTimestamp(); $source['starts_at'] = $starts->format('h:i a'); $ends = $this->getEndsDatetime(); // TODO: Add support for 'ends_on' - We don't support date // range at the moment - assuming ends on the same day. $source['ends_at'] = $ends->format('h:i a'); if (($stops=$this->getStopsDatetime())) $source['stops_on'] = $stops->getTimestamp(); // See if time spans all day. if ($this->isFullDay()) $source['allday'] = true; // Map UI fields switch ($source['repeats']) { case 'weekly': $source['weekly_day'] = $source['day']; break; case 'weekdays': case 'weekends': // Keep the UI dumb af $source['weekly_day'] = $source['repeats']; $source['repeats'] = 'weekly'; break; case 'monthly': $source['monthly'] = $source['week'] ?: 'day'; $source['monthly_week'] = $source['week']; $source['monthly_day'] = $source['day']; break; case 'yearly': $source['yearly'] = $source['week'] ?: 'date'; $source['yearly_month'] = $source['month']; $source['yearly_week'] = $source['week']; $source['yearly_day'] = $source['day']; break; } } $this->_form = new ScheduleEntryForm($source); } return $this->_form; } function getFields() { return $this->getForm()->getFields(); } function getTranslateTag($subtag) { return _H(sprintf('schedulentry.%s.%s', $subtag, $this->id)); } function getLocal($subtag) { $tag = $this->getTranslateTag($subtag); $T = CustomDataTranslation::translate($tag); return $T != $tag ? $T : $this->get($subtag); } function toString() { return $this->getName(); } function __toString() { return $this->toString(); } function update(ScheduleEntryForm $form, &$errors=array()) { if (!($vars=$form->process())) return false; $vars['id'] = $this->getId(); if (!$this->getSchedule()->isEntryUnique($vars, $errors)) return false; foreach ($vars as $k => $v) $this->set($k, $v); return $this->save(); } function delete() { return parent::delete(); } function save($refetch=false) { if (count($this->dirty)) $this->set('updated', new SqlFunction('NOW')); return parent::save($refetch); } static function getFrequencies() { static $translated = false; if (!$translated) { foreach (static::$frequencies as $k=>$v) static::$frequencies[$k] = __($v); } return static::$frequencies; } static function getDays() { return self::$days; } static function getTranslatedDays() { static $translated = null; if (!isset($translated)) $translated = array_map(function ($d) { return __($d); }, static::getDays()); return $translated; } static function getWeeks() { static $translated = false; if (!$translated) { foreach (static::$weeks as $k=>$v) static::$weeks[$k] = __($v); } return static::$weeks; } static function getMonths() { static $translated = false; if (!$translated) { foreach (static::$months as $k=>$v) static::$months[$k] = __($v); } return static::$months; } static function create($ht=false) { $inst = new static($ht); $inst->set('created', new SqlFunction('NOW')); if ($inst->save()) return $inst; } } class ScheduleEntryForm extends AbstractForm { static $layout = 'GridFormLayout'; function buildFields() { $timezone = $this->options['timezone']; $allday = ($this->options['holidays']); $fields = array( 'name' => new TextboxField(array( 'required' => true, 'layout' => new GridFluidCell(8), 'label' => __('Name'), 'configuration' => array( // 'translatable' => $item ? $item->getTranslateTag('value') : false, 'size' => 60, 'length' => 0, 'autofocus' => true, ), )), 'starts_on' => new DatetimeField(array( 'label' => __('Starts on'), 'required' => true, 'layout' => new GridFluidCell(6), 'configuration' => array( 'time' => false, 'gmt' => false, 'future' => true, 'showtimezone' => false, ), )), 'allday' => new BooleanField(array( 'required' => false, 'default' => $allday, 'label' => __('All Day'), 'layout' => new GridFluidCell(6), 'configuration'=>array( 'desc'=>__('Full 24-hour day')) )), 'starts_at' => new TimeField(array( 'required' => true, 'default' => $allday ? '12:00 am' : '8:00 am', 'label' => __('Starts at'), 'layout' => new GridFluidCell(6), 'configuration' => array( 'timezone' => $timezone, 'showtimezone' => false, ), 'visibility' => new VisibilityConstraint( new Q(array('allday__eq'=>false)), VisibilityConstraint::HIDDEN), )), 'ends_at' => new TimeField(array( 'required' => true, 'default' => $allday ? '11:59 pm' : '5:00 pm', 'label' => __('Ends at'), 'layout' => new GridFluidCell(6), 'configuration' => array( 'timezone' => $timezone, 'showtimezone' => false, ), 'visibility' => new VisibilityConstraint( new Q(array('allday__eq'=>false)), VisibilityConstraint::HIDDEN), )), 'repeats' => new ChoiceField(array( 'required' => true, 'layout' => new GridFluidCell(6), 'label' => __('Repeats'), 'validator-error' => __('Selection required'), 'choices' => ScheduleEntry::getFrequencies(), )), 'stops_on' => new DatetimeField(array( 'label' => __('Until'), 'required' => false, 'layout' => new GridFluidCell(4), 'configuration' => array( 'time' => false, 'gmt' => false, 'future' => true, 'placeholder' => __('Forever'), 'showtimezone' => false, ), 'visibility' => new VisibilityConstraint( new Q(array('repeats__eq' => 'daily|weekly|monthly|yearly')), VisibilityConstraint::VISIBLE ), )), 'weekly_day' => new ChoiceField(array( 'required' => true, 'default' => "", 'layout' => new GridFluidCell(6), 'label' => __('Day of the Week'), 'choices' => ScheduleEntry::getTranslatedDays() + array( 'weekdays' => sprintf('%s (%s)', __('Weekdays'), __('Mon-Fri')), 'weekends' => sprintf('%s (%s)', __('Weekends'), __('Sat-Sun'))), 'validator-error' => __('Selection required'), 'configuration'=>array('prompt'=>__('Select Day of the Week')), 'visibility' => new VisibilityConstraint( new Q(array('repeats__eq'=>'weekly')), VisibilityConstraint::HIDDEN ), )), 'monthly' => new ChoiceField(array( 'required' => true, 'default' => 'day', 'layout' => new GridFluidCell(6, array( 'break' => true)), 'label' => __('On the'), 'validator-error' => __('Selection required'), 'choices' => array( 'day' => __('Day of the Month Entered'), '1' => __('First'), '2' => __('Second'), '3' => __('Third'), '4' => __('Fourth'), '5' => __('Fifth'), '-1' => __('Last'), ), 'visibility' => new VisibilityConstraint( new Q(array('repeats__eq'=>'monthly')), VisibilityConstraint::HIDDEN ), )), 'monthly_day' => new ChoiceField(array( 'required' => true, 'default' => "", 'layout' => new GridFluidCell(6), 'label' => __('Day'), 'choices' => ScheduleEntry::getTranslatedDays(), 'validator-error' => __('Selection required'), 'visibility' => new VisibilityConstraint( new Q(array('monthly__neq'=>'day')), VisibilityConstraint::HIDDEN ), )), 'yearly' => new ChoiceField(array( 'required' => true, 'layout' => new GridFluidCell(4), 'label' => __('On the'), 'validator-error' => __('Selection required'), 'choices' => array( 'date' => __('Date Entered'), '1' => __('First'), '2' => __('Second'), '3' => __('Third'), '4' => __('Fourth'), '5' => __('Fifth'), '-1' => __('Last'), ), 'visibility' => new VisibilityConstraint( new Q(array('repeats__eq'=>'yearly')), VisibilityConstraint::HIDDEN ), )), 'yearly_day' => new ChoiceField(array( 'required' => true, 'default' => '', 'layout' => new GridFluidCell(4), 'label' => __('Day'), 'choices' => ScheduleEntry::getTranslatedDays(), 'validator-error' => __('Selection required'), 'configuration'=>array('prompt'=>__('Day')), 'visibility' => new VisibilityConstraint( new Q(array('yearly__neq'=>'date')), VisibilityConstraint::HIDDEN ), )), 'yearly_month' => new ChoiceField(array( 'required' => true, 'default' => 0, 'layout' => new GridFluidCell(4), 'label' => __('In'), 'choices' => ScheduleEntry::getMonths(), 'validator-error' => __('Selection required'), 'configuration'=>array('prompt'=>__('Month')), 'visibility' => new VisibilityConstraint( new Q(array('yearly__neq'=>'date')), VisibilityConstraint::HIDDEN ), )), ); return $fields; } function process($validate=true) { if (!$this->isValid()) return false; // Parse && validate data $errors = array(); $data = $this->getClean($validate); $vars = array('name' => $data['name'], 'repeats' => $data['repeats']); if (($startsOn=Format::parseDateTime($data['starts_on']))) $vars['starts_on'] = $startsOn->format('Y-m-d'); else $errors['starts_on'] = __('Valid Start Date required'); if ($data['stops_on'] && $startsOn && ($stopsOn = Format::parseDateTime($data['stops_on']))) { if ($stopsOn->getTimestamp() <= $startsOn->getTimestamp()) $errors['ends_on'] = __('Must be in the future'); } if ($data['allday']) { $data['starts_at'] = '00:00:00'; $data['ends_at'] = '23:59:59'; } else { $data['starts_at'] = date('H:i:s', strtotime($data['starts_at'])); $data['ends_at'] = date('H:i:s', strtotime($data['ends_at'])); $startsAt = strtotime($vars['starts_on'].' '.$data['starts_at']); $endsAt = strtotime($vars['starts_on'] .' '.$data['ends_at'])+59; if ($startsAt >= $endsAt) $errors['ends_at'] = __('Invalid time span'); } if ($errors) { // Replay any errors back on the form fields $this->addErrors($errors); return false; } $dt = DateTimeImmutable::createFromMutable($startsOn); // Start time list($h,$m,$s) = explode(':', $data['starts_at']); $starts = $dt->setTime($h, $m, 00); $vars['starts_on'] = $starts->format('Y-m-d'); $vars['starts_at'] = $starts->format('H:i:s'); // end time list($h,$m,$s) = explode(':', $data['ends_at']); $ends = $dt->setTime($h, $m, $m == '00' ? 00 : 59); $vars['ends_on'] = $ends->format('Y-m-d'); $vars['ends_at'] = $ends->format('H:i:s'); // Stop date if ($stopsOn) $vars['stops_on'] = $stopsOn->format('Y-m-d H:i:s'); switch ($data['repeats']) { case 'weekly': switch ($data['weekly_day']) { // Under the hood we're overloading repeats on weekdays & // weekends to keep the UI stupid and simple. case 'weekdays': case 'weekends': $vars['repeats'] = $data['weekly_day']; break; default: $vars['day'] = $data['weekly_day']; break; } break; case 'monthly': $vars['day'] = $data['monthly_day'] ?: null; if ($data['monthly'] == 'day') $vars['day'] = $startsOn->format('d'); else $vars['week'] = $data['monthly']; break; case 'yearly': if ($data['yearly'] == 'date') { $vars['week'] = null; $vars['day'] = $startsOn->format('d'); $vars['month'] = $startsOn->format('m'); } else { $vars['week'] = $data['yearly']; $vars['day'] = $data['yearly_day']; $vars['month'] = $data['yearly_month']; } break; } return $vars; } function emitJavascript($options=array()) { if (!($starts=$this->getField('starts_on'))) return; $keys = array(); foreach (array('weekly_day' => 'day', 'monthly_day' => 'day', 'yearly_day' => 'day', 'yearly_week' => 'week', 'yearly_month' => 'month') as $k => $v) { if (($f=$this->getField($k))) $keys[$f->getWidget()->id] = $v; } $id = $starts->getWidget()->id; ?> <script type="text/javascript"> $(function() { $('#<?php echo $id; ?>').on('change', function() { var keys = <?php echo JsonDataEncoder::encode($keys); ?>; var d = $(this).datepicker('getDate'); if (d) { var a = new Array(); a['month'] = d.getMonth()+1; a['week'] = Math.ceil(d.getDate() / 7); a['day'] = d.getDay() || 7; console.log(a); $.each(keys, function(key, value) { $sel = $('#'+key); $val = $('#'+key+' option:selected').val(); console.log(key, value, $val, a[value]); $sel.removeClass('error'); if ($val.length == 0) $sel.val(a[value]); else if ($val != a[value]) $sel.addClass('error') .bind('change fucus', function() { $(this).removeClass('error'); }); }); } }); }); </script> <?php parent::emitJavascript($options); } } class ScheduleDiagnosticForm extends AbstractForm { static $layout = 'GridFormLayout'; function buildFields() { $fields = array( 'date' => new DatetimeField(array( 'label' => __('Date Time'), 'required' => true, 'layout' => new GridFluidCell(6), 'configuration' => array( 'time' => true, 'gmt' => false, 'future' => false, 'max' => time(), 'showtimezone' => true, ), )), 'hours' => new TextboxField(array( 'label' => __('Hours'), 'required' => true, 'layout' => new GridFluidCell(3), 'validator' => 'number', 'configuration' => ['size'=>10, 'length'=>10], )), ); return $fields; } function emitJavascript($options=array()) { $date = $this->getField('date')->getWidget()->id; $hours = $this->getField('hours')->getWidget()->id; ?> <script type="text/javascript"> $(function() { $('#<?php echo $date; ?>, #<?php echo $hours; ?>').on('change', function() { $('#diagnostic-results').hide(); }); }); </script> <?php parent::emitJavascript($options); } } ?>
Save