Xataface Calendar Module 0.1
Full Calendar for Xataface
/Applications/XAMPP/xamppfiles/htdocs/nanofabrication/modules/calendar/classes/RepeatEvent.class.php
Go to the documentation of this file.
00001 <?php
00007 class modules_calendar_RepeatEvent {
00008 
00012         public static $EX_INVALID_FREQUENCY = 501;
00013         
00017         public static $EX_INVALID_REPEAT_ID=502;
00018         
00019 
00024         private static $REPEAT_TABLE='dataface__calendar_repeats';
00025         
00030         private static $module = null;
00031         
00036         private $sourceRecord;
00037         
00043         private $startDate;
00044         
00050         private $expiryDate;
00051         
00052         
00064         private $frequency;
00065         private $frequencyChanged=false;
00066         
00071         private $_isSaved;
00072         
00079         private $startAtt;
00080         
00087         private $endAtt;
00088         
00094         private $repeatAtt;
00095         
00096         
00100         public static function createRepeatTable(){
00101                 $tname = self::$REPEAT_TABLE;
00102                 $sql = "create table if not exists `$tname` (
00103                         tablename varchar(200) not null,
00104                         repeat_id int(11) not null,
00105                         repeat_type enum('Daily','Weekly','Biweekly','Weekdays','Monthly','Yearly') default 'Weekly',
00106                         repeat_start_date datetime,
00107                         repeat_expire_date datetime,
00108                         primary key (tablename,repeat_id)
00109                         )
00110                         ";
00111                         
00112                 return self::query($sql);
00113                 
00114                 
00115                 
00116                 
00117         }
00118         
00119         
00120         public static function dropRepeatTable(){
00121                 $tname = self::$REPEAT_TABLE;
00122                 $sql = "drop table if exists `$tname`";
00123                 return self::query($sql);
00124         }
00125         
00132         private static function query($sql){
00133                 $res = mysql_query($sql, df_db());
00134                 if ( !$res ){
00135                         throw new Exception(mysql_error(df_db()));
00136                 }
00137                 return $res;
00138         }
00139         
00140         private static function cleanIdent($val){
00141                 return str_replace('`','',$val);
00142         }
00143         
00152         private static function queryRepeats($sql){
00153         
00154                 try {
00155                         return self::query($sql);
00156                 } catch (Exception $ex){
00157                         self::createRepeatTable();
00158                         
00159                 }
00160                 return self::query($sql);
00161         }
00162         
00167         public static function getModule(){
00168                 if ( !isset(self::$module) ){
00169                         self::$module = Dataface_ModuleTool::getInstance()->loadModule('modules_calendar');
00170                 }
00171                 return self::$module;
00172         }
00173         
00190         private function getAtt($name){
00191                 $att = self::getModule()
00192                         ->loadOntology($this->sourceRecord->table()->tablename)
00193                         ->getFieldname($name);
00194                         
00195                 if ( PEAR::isError($att) ){
00196                         throw new Exception("No start attribute found for table.");
00197                 }
00198                 return $att;
00199         }
00200         
00208         public function getStartAtt(){
00209                 return $this->getAtt('start');
00210         }
00211         
00212         
00220         public function getEndAtt(){
00221                 return $this->getAtt('end');
00222         }
00223         
00231         public function getRepeatAtt(){
00232                 return $this->getAtt('repeat');
00233         }
00234         
00235         public function getRepeatSeedAtt(){
00236                 return $this->getAtt('repeat_seed');
00237         }
00238         
00244         public function getSourceStart(){
00245                 return $this->sourceRecord->strval($this->getStartAtt());
00246         }
00247         
00253         public function getSourceEnd(){
00254                 return $this->sourceRecord->strval($this->getEndAtt());
00255         }
00256         
00263         public function getRepeatID(){
00264                 return $this->sourceRecord->val($this->getRepeatAtt());
00265         }
00266         
00272         public function __construct(Dataface_Record $source){
00273                 $this->sourceRecord = $source;
00274                 $this->loadRepeatInfo();
00275         }
00276         
00277         
00278         
00285         public function loadRepeatInfo(){
00286                 if ( !$this->getRepeatID() ){
00287                         
00288                         return;
00289                 }
00290                 $sql = sprintf("select * from `%s` where `tablename`='%s' and `repeat_id`=%d",
00291                         self::cleanIdent(self::$REPEAT_TABLE),
00292                         addslashes($this->sourceRecord->table()->tablename),
00293                         intval($this->getRepeatID())
00294                 );
00295                 $this->_isSaved = false;
00296                 $res = self::queryRepeats($sql);
00297                 
00298                 while ($row = mysql_fetch_assoc($res) ){
00299                         $this->expiryDate = $row['repeat_expire_date'];
00300                         $this->frequency = $row['repeat_type'];
00301                         $this->startDate = $row['repeat_start_date'];
00302                         $this->_isSaved = true;
00303                 }
00304                 @mysql_free_result($res);
00305         }
00306         
00307         
00308         public function getDefaultExpiryDifferential(){
00309                 $defaultDiff = '+90 days';
00310                 $settingsField = $this->getModule()->getRepeatSettingsField($this->sourceRecord->table()->tablename);
00311                 if ( $settingsField ){
00312                         $settingsFieldDef =& $this->sourceRecord->table()->getField($settingsField);
00313                         if ( isset($settingsFieldDef['widget']['default_expiry']) ){
00314                                 $defaultDiff = $settingsFieldDef['widget']['default_expiry'];
00315                         }
00316                 }
00317                 return $defaultDiff;
00318         
00319         }
00320         
00331         public function saveRepeatInfo(){
00332         
00333                 if ( !$this->frequency ){
00334                         throw new Exception('Frequency is not set for this repeat.', self::$EX_INVALID_FREQUENCY);
00335                 }
00336         
00337                 if ( !$this->startDate ){
00338                         $this->startDate = $this->getSourceStart();
00339                 }
00340                 
00341                 
00342                 
00343                 if ( !$this->expiryDate ){
00344                         $this->expiryDate = date(
00345                                 'Y-m-d H:i:s'
00346                                 , strtotime(
00347                                         $this->getDefaultExpiryDifferential()
00348                                         , strtotime(
00349                                                 $this->getSourceStart()
00350                                         )
00351                                 )
00352                         );
00353                         
00354                 }
00355                 
00356                 $repeatID = $this->getRepeatID();
00357                 if ( !$repeatID ){
00358                         // The repeat ID hasn't been set yet
00359                         $seedField = $this->getRepeatSeedAtt();
00360                         $this->sourceRecord->setValue(
00361                                 $this->getRepeatAtt(),
00362                                 $this->sourceRecord->val($seedField)
00363                         );
00364                         $res = $this->sourceRecord->save(null, $secure);
00365                         if ( PEAR::isError($res) ){
00366                                 throw new Exception($res->getMessage(), $res->getCode());
00367                         }
00368                         $repeatID = $this->getRepeatID();
00369                 }
00370                 if ( !isset($repeatID) ){
00371                         throw new Exception("Could not commit repeat sequence because it doesn't have a valid repeat id.", self::$EX_INVALID_REPEAT_ID);
00372                         
00373                 }
00374                 
00375                 
00376         
00377                 $isql = sprintf("insert into `%s` (`tablename`,`repeat_id`,`repeat_type`, `repeat_start_date`, `repeat_expire_date`)
00378                         values
00379                                 ('%s',%d,'%s','%s','%s')"
00380                                 , self::cleanIdent(self::$REPEAT_TABLE)
00381                                 , addslashes($this->sourceRecord->table()->tablename)
00382                                 , intval($this->getRepeatID())
00383                                 , addslashes($this->frequency)
00384                                 , addslashes($this->startDate)
00385                                 , addslashes($this->expiryDate)
00386                         );
00387                 $usql = sprintf("update `%s` set
00388                         `repeat_type`='%s',
00389                         `repeat_start_date`='%s',
00390                         `repeat_expire_date`='%s'
00391                         where
00392                                 `tablename`='%s' and `repeat_id`=%d"
00393                                 , self::cleanIdent(self::$REPEAT_TABLE)
00394                                 , addslashes($this->frequency)
00395                                 , addslashes($this->startDate)
00396                                 , addslashes($this->expiryDate)
00397                                 , addslashes($this->sourceRecord->table()->tablename)
00398                                 , intval($this->getRepeatID())
00399                         );
00400                         
00401                 if ( $this->isSaved() ){
00402                         self::queryRepeats($usql);
00403                 } else {
00404                         self::queryRepeats($isql);      
00405                 }
00406                                 
00407         }
00408         
00415         public function getRepeatRecords($limit=250, $query=array()){
00416                 
00417                 $query[$this->getRepeatAtt()] = '='.$this->getRepeatID();
00418                 $query['-limit'] = $limit;
00419                 
00420                 if ( !isset($query[$this->getStartAtt()] ) ){
00421                         $query[$this->getStartAtt()] = '>'.$this->getSourceStart();
00422                 }
00423                 return df_get_records_array($this->sourceRecord->table()->tablename, $query);
00424         }
00425         
00426         
00444         public function updateRepeats(array $changes, $startDiffSeconds, $endDiffSeconds, $secure=false){
00445                 
00446                 $repeats = $this->getRepeatRecords(999);
00447                 $errors = array();
00448                 $del = $this->sourceRecord->table()->getDelegate();
00449                 
00450                 $beforeUpdateExists = (isset($del) and method_exists($del, 'beforeUpdateRepeat'));
00451                 $afterUpdateExists = (isset($del) and method_exists($del, 'afterUpdateRepeat') );
00452                 $beforeSaveRepeatExists = (isset($del) and method_exists($del, 'beforeSafeRepeat'));
00453                 $afterSaveRepeatExists = (isset($del) and method_exists($del, 'afterSaveRepeat'));
00454                 
00455                 foreach ($repeats as $event){
00456                         try {
00457                                 $oldStart = $event->strval($this->getStartAtt());
00458                                 $oldEnd = $event->strval($this->getEndAtt());
00459                                 
00460                                 $newStartTime = strtotime('+'.$startDiffSeconds.' seconds', strtotime($oldStart));
00461                                 $newEndTime = strtotime('+'.$endDiffSeconds.' seconds', strtotime($oldEnd));
00462                                 
00463                                 $changes[$this->getStartAtt()] = date('Y-m-d H:i:s', $newStartTime);
00464                                 $changes[$this->getEndAtt()] = date('Y-m-d H:i:s', $newEndTime);
00465                                 
00466                                 $event->setValues($changes);
00467                                 
00468                                 if ( $beforeSaveRepeatExists ){
00469                                         $del->beforeSaveRepeat($event, $this, $changes);
00470                                 }
00471                                 
00472                                 if ( $beforeUpdateExists ){
00473                                         $del->beforeUpdateRepeat($event, $this, $changes);
00474                                         
00475                                 }
00476                                 $res = $event->save(null, $secure);
00477                                 if ( PEAR::isError($res) ){
00478                                         throw new Exception($res->getMessage(), $res->getCode());
00479                                         
00480                                 }
00481                                 
00482                                 
00483                                 if ( $afterUpdateExists ){
00484                                         $del->afterUpdateRepeat($event, $this, $changes);
00485                                 
00486                                 }
00487                                 
00488                                 if ( $afterSaveRepeatExists ){
00489                                         $del->afterSaveRepeat($event, $this, $changes);
00490                                 }
00491                                 
00492                         } catch (Exception $ex){
00493                                 $errors[] = $ex;
00494                         }
00495                                 
00496                 }
00497                 
00498                 return $errors;
00499                 
00500                 
00501         }
00502         
00503         
00513         public function clearRepeats($secure=false, $query=array()){
00514                 $del = $this->sourceRecord->table()->getDelegate();
00515                 $repeats = $this->getRepeatRecords(999, $query);
00516                 $errors = array();
00517                 $beforeDeleteExists = (isset($del) and method_exists($del, 'beforeDeleteRepeat'));
00518                 $afterDeleteExists = (isset($del) and method_exists($del, 'afterDeleteRepeat'));
00519                 
00520                 foreach ($repeats as $event){
00521                         try {
00522                                 if ( $beforeDeleteExists ){
00523                                         
00524                                         $del->beforeDeleteRepeat($event, $this);
00525                                                 
00526                                         
00527                                 }
00528                                         
00529                                 $res = $event->delete($secure);
00530                                 if ( PEAR::isError($res) ){
00531                                         throw new Exception($res->getMessage(), $res->getCode());
00532                                 }
00533                                         
00534                                 if ( $afterDeleteExists ){
00535                                         $res = $del->afterDeleteRepeat($event, $this);
00536                                         
00537                                 }
00538                         } catch (Exception $ex){
00539                                 $errors[] = $ex;
00540                         }
00541                         
00542                 }
00543                 
00544                 return $errors;
00545         }
00546         
00556         public function fillRepeats($secure=false){
00557                 $del = $this->sourceRecord->table()->getDelegate();
00558                 $errors = array();
00559                 $beforeAddRepeatExists = (isset($del) and method_exists($del, 'beforeAddRepeat'));
00560                 $afterAddRepeatExists = (isset($del) and method_exists($del, 'afterAddRepeat'));
00561                 $beforeSaveRepeatExists = (isset($del) and method_exists($del, 'beforeSafeRepeat'));
00562                 $afterSaveRepeatExists = (isset($del) and method_exists($del, 'afterSaveRepeat'));
00563                 
00564                 
00565                 // Let's get the last existing event in this repeat sequence
00566                 $lastEvent = df_get_record($this->sourceRecord->table()->tablename,
00567                         array(
00568                                 $this->getRepeatAtt() => $this->getRepeatID(),
00569                                 '-sort' => $this->getStartAtt().' desc'
00570                         )
00571                 );
00572                 
00573                 if ( !$lastEvent ){
00574                         throw new Exception("Could not find last event in repeat sequence.  Please check that the source record of this event sequence has a valid repeat id.");
00575                         
00576                 }
00577                 
00578                 
00579                 /*
00580                 $currTime = strtotime($this->getSourceStart());
00581                 $maxTime = strtotime($this->getExpiryDate());
00582                 $currEnd = strtotime($this->getSourceEnd());
00583                 */
00584                 $currTime = strtotime(
00585                         date('Y-m-d', 
00586                                 strtotime(
00587                                         $lastEvent->strval($this->getStartAtt())
00588                                 )
00589                         )
00590                         . ' '
00591                         . date('H:i:s', 
00592                                 strtotime(
00593                                         $this->getSourceStart()
00594                                 )
00595                         )
00596                 );
00597                 
00598                 $maxTime = strtotime($this->getExpiryDate());
00599                 $currEnd = strtotime(
00600                         date('Y-m-d', 
00601                                 strtotime(
00602                                         $lastEvent->strval($this->getEndAtt())
00603                                 )
00604                         )
00605                         . ' '
00606                         . date('H:i:s', 
00607                                 strtotime(
00608                                         $this->getSourceEnd()
00609                                 )
00610                         )
00611                 );
00612                 
00613                 $stepsize = null;
00614                 switch ($this->getFrequency()){
00615                 
00616                         case 'Daily': $stepsize = '+1 day';break;
00617                         case 'Weekly': $stepsize = '+1 week';break;
00618                         case 'Biweekly': $stepsize = '+2 week'; break;
00619                         case 'Monthly': $stepsize = '+1 month'; break;
00620                         case 'Yearly': $stepsize = '+1 year'; break;
00621                         case 'Weekdays':
00622                                 if ( date('N', $currtime) == 5 ){
00623                                         $stepsize = '+3 day';
00624                                 } else {
00625                                         $stepsize = '+1 day';
00626                                 }
00627                                 break;
00628                 }
00629                 
00630                 if ( !$stepsize ){
00631                         throw new Exception("Invalid frequency '".$this->getFrequency()."' in repeat.");
00632                 }
00633                 
00634                 $baseVals = $this->sourceRecord->vals();
00635                 $autoField = $this->sourceRecord->table()->getAutoIncrementField();
00636                 if ( !$autoField ){
00637                         throw new Exception("Repeat tables require an auto increment field.");
00638                 }
00639                 unset($baseVals[$autoField]);
00640                 
00641                 $errors = array();
00642                 while ( $currTime < $maxTime ){
00643                         //echo "[Adding $currTime]";
00644                         try {
00645                                 $currTime = strtotime($stepsize, $currTime);
00646                                 $currEnd = strtotime($stepsize, $currEnd);
00647                                 
00648                                 $event = new Dataface_Record($this->sourceRecord->table()->tablename, array());
00649                                 $event->setValues($baseVals);
00650                                 $event->setValue($this->getStartAtt(), date('Y-m-d H:i:s', $currTime));
00651                                 $event->setValue($this->getEndAtt(), date('Y-m-d H:i:s', $currEnd));
00652                                 
00653                                 if ( $beforeSaveRepeatExists ){
00654                                         $del->beforeSaveRepeat($event, $this);
00655                                 }
00656                                 
00657                                 if ( $beforeAddRepeatExists ){
00658                                         $del->beforeAddRepeat($event, $this);
00659                                 }
00660                                 
00661                                 $res = $event->save(null, $secure);
00662                                 if ( PEAR::isError($res) ){
00663                                         throw new Exception($res->getMessage(), $res->getCode());
00664                                 }
00665                                 
00666                                 if ( $afterAddRepeatExists ){
00667                                         $del->afterAddRepeat($event, $this);
00668                                 }
00669                                 
00670                                 if ( $afterSaveRepeatExists ){
00671                                         $del->afterSaveRepeat($event, $this);
00672                                 }
00673                                 
00674                         } catch (Exception $ex){
00675                                 $errors[] = $ex;
00676                         }
00677                         
00678                         
00679                         
00680                         
00681                         
00682                 }
00683                 
00684                 
00685                 return $errors;
00686         }
00687         
00688         
00689         
00695         public function isSaved(){
00696                 if ( !$this->getRepeatID() ) return false;
00697                 if ( !isset($this->_isSaved) ){
00698                         $this->loadRepeatInfo();
00699                 }
00700                 return $this->_isSaved;
00701         }
00702         
00703         
00704         
00713         public function setSourceRecord(Dataface_Record $record){
00714                 $this->expiryDate = null;
00715                 $this->startDate = null;
00716                 $this->frequency = null;
00717                 $this->sourceRecord = $record;
00718                 $this->_isSaved = null;
00719         }
00720         
00728         public function getSourceRecord(){
00729                 return $this->sourceRecord;
00730         }
00731         
00742         public function setFrequency($freq){
00743                 if ( $freq != $this->frequency ){
00744                         $this->frequency = $freq;
00745                         $this->frequencyChanged = true;
00746                 }
00747         }
00748         
00760         public function getFrequency(){ return $this->frequency;}
00761         
00767         public function setStartDate($date){ $this->startDate = $date;}
00768         
00769         public function getStartDate(){ return $this->startDate; }
00770         
00775         public function setExpiryDate($d){ $this->expiryDate = $d;}
00776         
00781         public function getExpiryDate(){ return $this->expiryDate;}
00782         
00783         
00784         public function commit(array $changes, $startDiffSeconds, $endDiffSeconds, $secure=false ){
00785                 
00786                 
00787                 
00788         
00789                 $this->saveRepeatInfo();
00790                 $errors = array();
00791                 if ( $this->frequencyChanged ){
00792                         //If the frequency has changed, we need to clear all of the existing repeat
00793                         // events and build them anew.
00794                         $errors = array_merge($errors, $this->clearRepeats($secure));
00795                         $this->frequencyChanged = false;
00796                 } else {
00797                         // Let's clear all of the repeats that come after the expiry date
00798                         $errors = array_merge($errors, $this->clearRepeats($secure, array(
00799                                 $this->getStartAtt()=>'>'.$this->getExpiryDate()
00800                         )));
00801                 }
00802                 
00803                 // Now let's fill all of the repeats
00804                 $errors = array_merge($errors,$this->fillRepeats($secure));
00805                 
00806                 // Now let's update the repeat records.
00807                 // Will be redundant the first time the repeats are filled, but that's ok
00808                 // we may optimize this later.
00809                 if ( $changes or $startDiffSeconds or $endDiffSeconds ){
00810                         $errors = array_merge($errors,
00811                                 $this->updateRepeats($changes, $startDiffSeconds, $endDiffSeconds, $secure)
00812                         );
00813                 }
00814                 
00815                 return $errors;
00816                 
00817                 
00818         }
00819         
00820         
00821 }
 All Data Structures Files Functions Variables