Merge branch 'pu/2013.10-caldav' into 2014.09
authorPhilipp Schüle <p.schuele@metaways.de>
Thu, 9 Oct 2014 08:22:08 +0000 (10:22 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Thu, 9 Oct 2014 08:23:47 +0000 (10:23 +0200)
Conflicts:
tine20/Calendar/Backend/Sql.php
tine20/Tinebase/Backend/Sql/Abstract.php

Change-Id: I81f9d3e684152a0e77fe3fb1a70b56edcc066c79

13 files changed:
1  2 
tests/tine20/Calendar/Controller/MSEventFacadeTest.php
tests/tine20/Calendar/Frontend/WebDAV/EventTest.php
tests/tine20/Calendar/Frontend/iMIPTest.php
tests/tine20/Tinebase/AllTests.php
tine20/Calendar/Backend/Sql.php
tine20/Calendar/Controller/Event.php
tine20/Calendar/Convert/Event/VCalendar/Abstract.php
tine20/Calendar/Model/Attender.php
tine20/Calendar/js/Model.js
tine20/Tinebase/Backend/Sql/Abstract.php
tine20/Tinebase/Controller/Record/Abstract.php
tine20/Tinebase/Core.php
tine20/Tinebase/Record/RecordSet.php

@@@ -127,9 -129,9 +131,9 @@@ class Calendar_Controller_MSEventFacade
          $this->testCreate();
          
          $events = $this->_uit->search(new Calendar_Model_EventFilter(array(
 -            array('field' => 'container_id', 'operator' => 'in', 'value' => $this->_testCalendars->getId()),
 +            array('field' => 'container_id', 'operator' => 'in', 'value' => $this->_getTestCalendars()->getId()),
          )));
-         
          $this->assertEquals(1, $events->count());
          $this->_assertTestEvent($events->getFirstRecord());
      }
@@@ -248,12 -280,12 +280,12 @@@ class Calendar_Frontend_WebDAV_EventTes
          $event = Calendar_Frontend_WebDAV_Event::create($this->objects['initialContainer'], "$id.ics", $vcalendar);
          
          $event = Calendar_Controller_Event::getInstance()->get($id);
 -        $pwulf = $event->attendee->filter('user_id', $this->_personasContacts['pwulf']->getId())->getFirstRecord();
 +        $pwulf = $event->attendee->filter('user_id', $this->_getPersonasContacts('pwulf')->getId())->getFirstRecord();
          
          $this->assertTrue($pwulf !== null, 'could not find pwulf in attendee: ' . print_r($event->attendee->toArray(), true));
 -        $this->assertEquals($this->_personasDefaultCals['pwulf']->getId(), $pwulf->displaycontainer_id, 'event not in pwulfs personal calendar');
 +        $this->assertEquals($this->_getPersonasDefaultCals('pwulf')->getId(), $pwulf->displaycontainer_id, 'event not in pwulfs personal calendar');
      }
-     
      /**
       * _testEventMissingAttendee helper
       * 
Simple merge
@@@ -147,13 -152,10 +152,12 @@@ class Calendar_Backend_Sql extends Tine
       * @param  Tinebase_Model_Filter_FilterGroup    $_filter
       * @param  Tinebase_Model_Pagination            $_pagination
       * @param  boolean                              $_onlyIds
-      * @param  bool   $_getDeleted
       * @return Tinebase_Record_RecordSet|array
       */
-     public function search(Tinebase_Model_Filter_FilterGroup $_filter = NULL, Tinebase_Model_Pagination $_pagination = NULL, $_onlyIds = FALSE, $_getDeleted = FALSE)    
+     public function search(Tinebase_Model_Filter_FilterGroup $_filter = NULL, Tinebase_Model_Pagination $_pagination = NULL, $_onlyIds = FALSE)
      {
 +        if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Searching events ...');
 +        
          if ($_pagination === NULL) {
              $_pagination = new Tinebase_Model_Pagination();
          }
          $select->group($this->_tableName . '.' . 'id');
          Tinebase_Backend_Sql_Abstract::traitGroup($select);
          
 +        $period = $_filter->getFilter('period');
 +
 +        // filter out unnecessary YEARLY candidates for web client requests
 +        // periods < 40 days should be client web client requests.
 +        if ($period && $period->getFrom()->getClone()->addDay(40) > $period->getUntil()) {
 +            $this->_removeNonMatchingBaseEvents($select, $period);
 +        }
 +        
+         if ($calendarFilter) {
+             $select1 = clone $select;
+             $select2 = clone $select;
+             
+             $calendarFilter->appendFilterSql1($select1, $this);
+             $calendarFilter->appendFilterSql2($select2, $this);
+             
+             $select = $this->getAdapter()->select()->union(array(
+                 $select1,
+                 $select2
+             ));
+         }
+         
+         $_pagination->appendPaginationSql($select);
+         
          $stmt = $this->_db->query($select);
          $rows = (array)$stmt->fetchAll(Zend_Db::FETCH_ASSOC);
-         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
-                 . ' Event base rows fetched: ' . count($rows));
          
          $result = $this->_rawDataToRecordSet($rows);
 +        
 +        $this->_checkGrants($result, $grantsFilter);
 +        
 +        return $_onlyIds ? $result->{is_bool($_onlyIds) ? $this->_getRecordIdentifier() : $_onlyIds} : $result;
 +    }
 +    
 +    /**
 +     * removes non-matching rrule base events
 +     * 
 +     * @param Zend_Db_Select $select
 +     * @param Calendar_Model_PeriodFilter $period
 +     * 
 +     * TODO improve this by moving the rrules to a separate table to simplify SQL statment
 +     */
 +    protected function _removeNonMatchingBaseEvents($select, $period)
 +    {
 +        $gs = new Tinebase_Backend_Sql_Filter_GroupSelect($select);
 +        $from = $period->getFrom()->getClone()->subDay(1);
 +        $fromMonth = $from->format('n');
 +        $fromDay = $from->format('j');
 +        $until = $period->getUntil()->getClone()->addDay(1);
 +        $untilMonth = $until->format('n');
 +        $untilDay = $until->format('j');
 +        $quotedRrule = $this->_db->quoteIdentifier('rrule');
 +        
 +        $gs->where($quotedRrule . ' NOT LIKE ?', 'FREQ=YEARLY%')
 +        ->orWhere($quotedRrule . ' IS NULL');
 +        
 +        if ($fromMonth == $untilMonth && $untilDay-$fromDay <= 10) {
 +            // day|week view
 +            for($day=$fromDay; $day<=$untilDay; $day++) {
 +                $gs->orWhere($quotedRrule . ' LIKE ?', "FREQ=YEARLY;INTERVAL=1;BYMONTH={$fromMonth};BYMONTHDAY={$day}%");
 +            }
 +        } else {
 +            // monthview
 +            for ($month=$fromMonth; $month<=$untilMonth; $month++) {
 +                $gs->orWhere($quotedRrule . ' LIKE ?', "FREQ=YEARLY;INTERVAL=1;BYMONTH={$month};%");
 +            }
 +        }
 +        
 +        $gs->appendWhere(Zend_Db_Select::SQL_AND);
 +        //            Tinebase_Core::getLogger()->ERR($select);
 +    }
 +    
 +    /**
 +     * calculate event permissions and remove events that don't match
 +     * 
 +     * @param Tinebase_Record_RecordSet $result
 +     * @param Tinebase_Model_Filter_AclFilter $grantsFilter
 +     */
 +    protected function _checkGrants($result, $grantsFilter)
 +    {
          $clones = clone $result;
          
          Tinebase_Container::getInstance()->getGrantsOfRecords($clones, Tinebase_Core::getUser());
Simple merge
Simple merge
Simple merge
@@@ -480,22 -482,10 +482,24 @@@ abstract class Tinebase_Backend_Sql_Abs
          } else if ($_cols === FALSE) {
              $_cols = '*';
          }
 -        
 -        // (1) get ids or id/value pair
 +    
 +        // (1) eventually get only ids or id/value pair
          list($colsToFetch, $getIdValuePair) = $this->_getColumnsToFetch($_cols, $_filter, $_pagination);
 -        $select = $this->_getSelect($colsToFetch, $getDeleted);
++
 +        // check if we should do one or two queries
 +        $doSecondQuery = true;
 +        if (!$getIdValuePair && $_cols !== self::IDCOL)
 +        {
 +            if ($this->_compareRequiredJoins($_cols, $colsToFetch)) {
 +                $doSecondQuery = false;
 +            }
 +        }
 +        if ($doSecondQuery) {
-             $select = $this->_getSelect($colsToFetch);
++            $select = $this->_getSelect($colsToFetch, $getDeleted);
 +        } else {
-             $select = $this->_getSelect($_cols);
++            $select = $this->_getSelect($_cols, $getDeleted);
 +        }
++
          if ($_filter !== NULL) {
              $this->_addFilter($select, $_filter);
          }
          
          if ($getIdValuePair) {
              return $this->_fetch($select, self::FETCH_MODE_PAIR);
 -        } else {
 -            $ids = $this->_fetch($select);
 +        } elseif($_cols === self::IDCOL) {
 +            return $this->_fetch($select);
          }
          
 -        if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Fetched ' . count($ids) .' ids.');
 +        if (!$doSecondQuery) {
 +            $rows = $this->_fetch($select, self::FETCH_ALL);
 +            if (empty($rows)) {
 +                return new Tinebase_Record_RecordSet($this->_modelName);
 +            } else {
 +                return $this->_rawDataToRecordSet($rows);
 +            }
 +        }
          
 -        if ($_cols === self::IDCOL) {
 -            return $ids;
 -        } else if (empty($ids)) {
 +        // (2) get other columns and do joins
 +        $ids = $this->_fetch($select);
 +        if (empty($ids)) {
              return new Tinebase_Record_RecordSet($this->_modelName);
 -        } else {
 -            // (2) get other columns and do joins
 -            $select = $this->_getSelect($_cols, $getDeleted);
 -            $this->_addWhereIdIn($select, $ids);
 -            $_pagination->appendSort($select);
 -            
 -            $rows = $this->_fetch($select, self::FETCH_ALL);
 -            
 -            return $this->_rawDataToRecordSet($rows);
          }
-         $select = $this->_getSelect($_cols);
 +        
++        $select = $this->_getSelect($_cols, $getDeleted);
 +        $this->_addWhereIdIn($select, $ids);
 +        $_pagination->appendSort($select);
 +        
 +        $rows = $this->_fetch($select, self::FETCH_ALL);
 +        
 +        return $this->_rawDataToRecordSet($rows);
      }
  
      /**
       */
      public function create(Tinebase_Record_Interface $_record) 
      {
 -        $identifier = $_record->getIdProperty();
 -        
 -        if (!$_record instanceof $this->_modelName) {
 -            throw new Tinebase_Exception_InvalidArgument('invalid model type: $_record is instance of "' . get_class($_record) . '". but should be instance of ' . $this->_modelName);
 -        }
 -        
 -        // set uid if record has hash id and id is empty
 -        if ($this->_hasHashId() && empty($_record->$identifier)) {
 -            $newId = $_record->generateUID();
 -            $_record->setId($newId);
 -        }
 -        
 -        $recordArray = $this->_recordToRawData($_record);
 -        
 -        // unset id if autoincrement & still empty
 -        if (empty($_record->$identifier) || $_record->$identifier == 'NULL' ) {
 -            unset($recordArray['id']);
 -        }
 -        
 -        $recordArray = array_intersect_key($recordArray, $this->_schema);
 -
 -        $this->_prepareData($recordArray);
 -        if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
 -            . " Prepared data for INSERT: " . print_r($recordArray, true)
 -        );
 +        $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction($this->_db);
 +        try {
 +            $identifier = $_record->getIdProperty();
 +            
 +            if (!$_record instanceof $this->_modelName) {
 +                throw new Tinebase_Exception_InvalidArgument('invalid model type: $_record is instance of "' . get_class($_record) . '". but should be instance of ' . $this->_modelName);
 -        $this->_db->insert($this->_tablePrefix . $this->_tableName, $recordArray);
 -        
 -        if (!$this->_hasHashId()) {
 -            $newId = $this->_db->lastInsertId($this->getTablePrefix() . $this->getTableName(), $identifier);
 -            if(!$newId && isset($_record[$identifier])){
 -                $newId = $_record[$identifier];
              }
 -        }
 -
 -        // if we insert a record without an id, we need to get back one
 -        if (empty($_record->$identifier) && $newId == 0) {
 -            throw new Tinebase_Exception_UnexpectedValue("Returned record id is 0.");
 -        }
 -        
 -        // if the record had no id set, set the id now
 -        if ($_record->$identifier == NULL || $_record->$identifier == 'NULL') {
 -            $_record->$identifier = $newId;
 -        }
 -        
 -        // add custom fields
 -        if ($_record->has('customfields') && !empty($_record->customfields)) {
 -            Tinebase_CustomField::getInstance()->saveRecordCustomFields($_record);
 +            
 +            // set uid if record has hash id and id is empty
 +            if ($this->_hasHashId() && empty($_record->$identifier)) {
 +                $newId = $_record->generateUID();
 +                $_record->setId($newId);
 +            }
 +            
 +            $recordArray = $this->_recordToRawData($_record);
 +            
 +            // unset id if autoincrement & still empty
 +            if (empty($_record->$identifier) || $_record->$identifier == 'NULL' ) {
 +                unset($recordArray['id']);
 +            }
 +            
 +            $recordArray = array_intersect_key($recordArray, $this->_schema);
 +            
 +            $this->_prepareData($recordArray);
 +            if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
 +                    . " Prepared data for INSERT: " . print_r($recordArray, true)
 +            );
 +            
 +            $this->_db->insert($this->_tablePrefix . $this->_tableName, $recordArray);
 +            
 +            if (!$this->_hasHashId()) {
 +                $newId = $this->_db->lastInsertId($this->getTablePrefix() . $this->getTableName(), $identifier);
 +                if(!$newId && isset($_record[$identifier])){
 +                    $newId = $_record[$identifier];
 +                }
 +            }
 +            
 +            // if we insert a record without an id, we need to get back one
 +            if (empty($_record->$identifier) && $newId == 0) {
 +                throw new Tinebase_Exception_UnexpectedValue("Returned record id is 0.");
 +            }
 +            
 +            // if the record had no id set, set the id now
 +            if ($_record->$identifier == NULL || $_record->$identifier == 'NULL') {
 +                $_record->$identifier = $newId;
 +            }
 +            
 +            // add custom fields
 +            if ($_record->has('customfields') && !empty($_record->customfields)) {
 +                Tinebase_CustomField::getInstance()->saveRecordCustomFields($_record);
 +            }
 +            
 +            $this->_updateForeignKeys('create', $_record);
 +            
 +            $result = $this->get($_record->$identifier);
 +            
 +            $this->_inspectAfterCreate($result, $_record);
 +            
 +            Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId);
 +        } catch(Exception $e) {
 +            Tinebase_TransactionManager::getInstance()->rollBack();
 +            throw $e;
-         }       
+         }
          
 -        $this->_updateForeignKeys('create', $_record);
 -        
 -        $result = $this->get($_record->$identifier);
 -        
 -        $this->_inspectAfterCreate($result, $_record);
 -        
          return $result;
      }
      
Simple merge
Simple merge