Merge branch 'pu/2013.10-icsimport'
[tine20] / tine20 / Tinebase / Controller / ScheduledImport.php
1 <?php
2 /**
3  * Tine 2.0
4  * 
5  * @package     Tinebase
6  * @subpackage  Controller
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @author      Michael Spahn <m.spahn@metaways.de>
9  * @copyright   Copyright (c) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
10  */
11
12 /**
13  * Tinebase Import Controller
14  * 
15  * @package Tinebase
16  * @subpackage  Controller
17  */
18 class Tinebase_Controller_ScheduledImport extends Tinebase_Controller_Record_Abstract
19 {
20     /**
21      * holds the instance of the singleton
22      *
23      * @var Tinebase_Controller_ScheduledImport
24      */
25     private static $instance = null;
26     
27     /**
28      * the constructor
29      *
30      * don't use the constructor. use the singleton 
31      */
32     private function __construct()
33     {
34         $this->_applicationName = 'Tinebase';
35         $this->_modelName = 'Tinebase_Model_Import';
36         $this->_backend = new Tinebase_Backend_Sql(array(
37             'modelName' => $this->_modelName, 
38             'tableName' => 'import',
39         ));
40         $this->_purgeRecords = false;
41         // activate this if you want to use containers
42         $this->_doContainerACLChecks = false;
43         $this->_resolveCustomFields = false;
44     }
45     
46     /**
47      * the singleton pattern
48      *
49      * @return Tinebase_Controller_ScheduledImport
50      */
51     public static function getInstance() 
52     {
53         if (self::$instance === null) {
54             self::$instance = new self();
55         }
56         return self::$instance;
57     }
58     
59     /**
60      * Search and executed the next scheduled import
61      * 
62      * @return null|array
63      */
64     public function runNextScheduledImport()
65     {
66         if ($record = $this->_getNextScheduledImport()) {
67             return $this->_doScheduledImport($record)->toArray();
68         }
69         
70         return NULL;
71     }
72     
73     /**
74      * Get the next scheduled import
75      * 
76      * @param interval
77      * @param recursive
78      * @return Object
79      */
80     protected function _getNextScheduledImport()
81     {
82         $timestampBefore = null;
83         
84         $now = new Tinebase_DateTime();
85         
86         $anHourAgo = clone $now;
87         $anHourAgo->subHour(1);
88         
89         $aDayAgo = clone $now;
90         $aDayAgo->subDay(1);
91         
92         $aWeekAgo = clone $now;
93         $aWeekAgo->subWeek(1);
94         
95         $filter = new Tinebase_Model_ImportFilter(array(), 'OR');
96         
97         $filter0 = new Tinebase_Model_ImportFilter(array(
98                 array('field' => 'interval', 'operator' => 'equals', 'value' => Tinebase_Model_Import::INTERVAL_ONCE),
99                 array('field' => 'timestamp', 'operator' => 'isnull', 'value' => null),
100         ), 'AND');
101         
102         $filter1 = new Tinebase_Model_ImportFilter(array(
103             array('field' => 'interval', 'operator' => 'equals', 'value' => Tinebase_Model_Import::INTERVAL_HOURLY),
104             array('field' => 'timestamp', 'operator' => 'before', 'value' => $anHourAgo),
105         ), 'AND');
106         
107         $filter2 = new Tinebase_Model_ImportFilter(array(
108                 array('field' => 'interval', 'operator' => 'equals', 'value' => Tinebase_Model_Import::INTERVAL_DAILY),
109                 array('field' => 'timestamp', 'operator' => 'before', 'value' => $aDayAgo),
110         ), 'AND');
111         
112         $filter3 = new Tinebase_Model_ImportFilter(array(
113                 array('field' => 'interval', 'operator' => 'equals', 'value' => Tinebase_Model_Import::INTERVAL_WEEKLY),
114                 array('field' => 'timestamp', 'operator' => 'before', 'value' => $aWeekAgo),
115         ), 'AND');
116         
117         $filter->addFilterGroup($filter0);
118         $filter->addFilterGroup($filter1);
119         $filter->addFilterGroup($filter2);
120         $filter->addFilterGroup($filter3);
121         
122         // Always sort by creation timestamp to ensure first in first out
123         $pagination = new Tinebase_Model_Pagination(array(
124             'limit'     => 1,
125             'sort'      => 'timestamp',
126             'dir'       => 'DESC'
127         ));
128         
129         $record = $this->search($filter, $pagination)->getFirstRecord();
130         
131         if (! $record) {
132             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
133                 Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' No ScheduledImport could be found.');
134             }
135             
136             return NULL;
137         }
138         return $record;
139     }
140     
141     /**
142      * Execute scheduled import
143      * @param Tinebase_Model_Import $record
144      * @return Tinebase_Model_Import
145      */
146     protected function _doScheduledImport(Tinebase_Model_Import $record)
147     {
148         $currentUser = Tinebase_Core::getUser();
149         // set user who created the import job
150         $importUser = Tinebase_User::getInstance()->getUserByPropertyFromSqlBackend('accountId', $record->user_id, 'Tinebase_Model_FullUser');
151         Tinebase_Core::set(Tinebase_Core::USER, $importUser);
152         
153         $importer = $record->getOption('plugin');
154         
155         $options = array(
156             'container_id' => $record->container_id,
157             // legacy
158             'importContainerId' => $record->container_id,
159         );
160         
161         if (strpos($record->source, 'http') === 0) {
162             $client = new Zend_Http_Client($record->source);
163             $toImport = $client->request()->getBody();
164         } else {
165             $toImport = file_get_contents($record->source);
166         }
167         
168         $importer = new $importer($options);
169         
170         if ($toImport) {
171             // do import
172             $importer->import($toImport);
173             
174             if ($record->interval === Tinebase_Model_Import::INTERVAL_ONCE || ! $record->timestamp instanceof Tinebase_DateTime) {
175                 $record->timestamp = Tinebase_DateTime::now();
176             }
177             
178             switch ($record->interval) {
179                 case Tinebase_Model_Import::INTERVAL_DAILY:
180                     $record->timestamp->addDay(1);
181                     break;
182                 case Tinebase_Model_Import::INTERVAL_WEEKLY:
183                     $record->timestamp->addWeek(1);
184                     break;
185                 case Tinebase_Model_Import::INTERVAL_HOURLY:
186                     $record->timestamp->addHour(1);
187                     break;
188             }
189             
190             // update record
191             $record = $this->update($record);
192             
193         } else {
194             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
195                 Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__ . ' The source could not be loaded: "' . $record->source . '"');
196             }
197         }
198         
199         Tinebase_Core::set(Tinebase_Core::USER, $currentUser);
200         
201         return $record;
202     }
203     
204     /**
205      * Creates a remote import for events
206      * 
207      * @param string $remoteUrl
208      * @param string $interval
209      * @param array $importOptions
210      * @throws Calendar_Exception_InvalidUrl
211      * @return Tinebase_Record_Interface
212      */
213     public function createRemoteImportEvent($data)
214     {
215         $possibleIntervals = array(
216             Tinebase_Model_Import::INTERVAL_DAILY,
217             Tinebase_Model_Import::INTERVAL_HOURLY,
218             Tinebase_Model_Import::INTERVAL_ONCE,
219             Tinebase_Model_Import::INTERVAL_WEEKLY
220         );
221         
222         if (! in_array($data['interval'], $possibleIntervals)) {
223             $data['interval'] = Tinebase_Model_Import::INTERVAL_ONCE;
224         }
225         
226         $url = filter_var($data['source'], FILTER_VALIDATE_URL);
227         if ($url) {
228             if (strpos($data['source'], 'http') === 0) {
229                 $client = new Zend_Http_Client($data['source']);
230                 $toImport = $client->request()->getBody();
231             } else {
232                 $toImport = file_get_contents($data['source']);
233             }
234         } else {
235             throw new Calendar_Exception_InvalidUrl();
236         }
237         
238         // find container or create a new one
239         $containerId = $data['options']['container_id'];
240         
241         try {
242             $container = Tinebase_Container::getInstance()->getContainerById($containerId);
243         } catch (Tinebase_Exception_InvalidArgument $e) {
244             $container = new Tinebase_Model_Container(array(
245                 'name'              => $data['options']['container_id'],
246                 'type'              => Tinebase_Model_Container::TYPE_PERSONAL,
247                 'backend'           => Tinebase_User::SQL,
248                 'color'             => '#ffffff',
249                 'application_id'    => $data['application_id'],
250                 'owner_id'          => $data['user_id'],
251                 'model'             => $data['model'],
252             ));
253
254             $container = Tinebase_Container::getInstance()->addContainer($container);
255         }
256         
257         $data['options'] = json_encode(array_replace(array(
258             'forceUpdateExisting' => TRUE,
259             'import_defintion' => NULL,
260         ), $data['options']));
261         
262         $record = new Tinebase_Model_Import(array_replace(array(
263             'id'                => Tinebase_Record_Abstract::generateUID(),
264             'user_id'           => Tinebase_Core::getUser()->getId(),
265             'sourcetype'        => Tinebase_Model_Import::SOURCETYPE_REMOTE,
266             'container_id'      => $container->getId(),
267         ), $data));
268         
269         return $this->create($record);
270     }
271 }