adds directory scanning for apps as fallback
[tine20] / tine20 / Tinebase / ImportExportDefinition.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      Philipp Schüle <p.schuele@metaways.de>
9  * @copyright   Copyright (c) 2008-2011 Metaways Infosystems GmbH (http://www.metaways.de)
10  * 
11  */
12
13 /**
14  * backend for import/export definitions
15  *
16  * @package     Tinebase
17  * @subpackage  Controller
18  */
19 class Tinebase_ImportExportDefinition extends Tinebase_Controller_Record_Abstract
20 {
21     /**
22      * holds the instance of the singleton
23      *
24      * @var Tinebase_ImportExportDefinition
25      */
26     private static $_instance = NULL;
27         
28     /**
29      * the constructor
30      *
31      * don't use the constructor. use the singleton 
32      */
33     private function __construct() {
34         $this->_modelName = 'Tinebase_Model_ImportExportDefinition';
35         $this->_applicationName = 'Tinebase';
36         $this->_purgeRecords = FALSE;
37         $this->_doContainerACLChecks = FALSE;
38
39         // set backend with activated modlog
40         $this->_backend = new Tinebase_Backend_Sql(array(
41             'modelName'     => $this->_modelName,
42             'tableName'     => 'importexport_definition',
43             'modlogActive'  => TRUE,
44         ));
45     }
46     
47     /**
48      * the singleton pattern
49      *
50      * @return Tinebase_ImportExportDefinition
51      */
52     public static function getInstance()
53     {
54         if (self::$_instance === NULL) {
55             self::$_instance = new Tinebase_ImportExportDefinition();
56         }
57         return self::$_instance;
58     }
59     
60     /**
61      * get definition by name
62      * 
63      * @param string $_name
64      * @return Tinebase_Model_ImportExportDefinition
65      * 
66      * @todo replace this with search function
67      */
68     public function getByName($_name)
69     {
70         return $this->_backend->getByProperty($_name);
71     }
72     
73     /**
74      * get application export definitions
75      *
76      * @param Tinebase_Model_Application $_application
77      * @return Tinebase_Record_RecordSet of Tinebase_Model_ImportExportDefinition
78      */
79     public function getExportDefinitionsForApplication(Tinebase_Model_Application $_application)
80     {
81         $filter = new Tinebase_Model_ImportExportDefinitionFilter(array(
82             array('field' => 'application_id',  'operator' => 'equals',  'value' => $_application->getId()),
83             array('field' => 'type',            'operator' => 'equals',  'value' => 'export'),
84         ));
85         $result = $this->search($filter);
86         
87         return $result;
88     }
89     
90     /**
91      * get definition from file
92      *
93      * @param string $_filename
94      * @param string $_applicationId
95      * @param string $_name [optional]
96      * @return Tinebase_Model_ImportExportDefinition
97      * @throws Tinebase_Exception_NotFound
98      */
99     public function getFromFile($_filename, $_applicationId, $_name = NULL)
100     {
101         if (file_exists($_filename)) {
102             $basename = basename($_filename);
103             $content = file_get_contents($_filename);
104             $config = new Zend_Config_Xml($_filename);
105             
106             if ($_name === NULL) {
107                 $name = ($config->name) ? $config->name : preg_replace("/\.xml/", '', $basename);
108             } else {
109                 $name = $_name;
110             }
111             
112             $definition = new Tinebase_Model_ImportExportDefinition(array(
113                 'application_id'              => $_applicationId,
114                 'name'                        => $name,
115                 'label'                       => $config->label,
116                 'description'                 => $config->description,
117                 'type'                        => $config->type,
118                 'model'                       => $config->model,
119                 'plugin'                      => $config->plugin,
120                 'plugin_options'              => $content,
121                 'filename'                    => $basename,
122                 'mapUndefinedFieldsEnable'    => $config->mapUndefinedFieldsEnable,
123                 'mapUndefinedFieldsTo'        => $config->mapUndefinedFieldsTo,
124                 'postMappingHook'             => $config->postMappingHook
125             ));
126             
127             return $definition;
128         } else {
129             throw new Tinebase_Exception_NotFound('Definition file "' . $_filename . '" not found.');
130         }
131     }
132     
133     /**
134      * get config options as Zend_Config_Xml object
135      * 
136      * @param Tinebase_Model_ImportExportDefinition $_definition
137      * @param array $_additionalOptions additional options
138      * @return Zend_Config_Xml
139      */
140     public static function getOptionsAsZendConfigXml(Tinebase_Model_ImportExportDefinition $_definition, $_additionalOptions = array())
141     {
142         $cacheId = 'ZendConfigXml_' . md5($_definition);
143         $cache = Tinebase_Core::getCache();
144         if (! $cache->test($cacheId)) {
145             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
146                 . ' Generate new Zend_Config_Xml object' . $cacheId);
147             $config = new Zend_Config_Xml($_definition->plugin_options, /* section = */ null, /* runtime mods allowed = */ true);
148             $cache->save($config, $cacheId);
149         } else {
150             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
151                 . ' Get Zend_Config_Xml from cache' . $cacheId);
152             $config = $cache->load($cacheId);
153         }
154         
155         if (! empty($_additionalOptions)) {
156             $config->merge(new Zend_Config($_additionalOptions));
157         }
158         
159         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ 
160             . ' Config: ' . print_r($config->toArray(), true));
161         
162         return $config;
163     }
164     
165     /**
166      * update existing definition or create new from file
167      * - use backend functions (create/update) directly because we do not want any default controller handling here
168      * - calling function needs to make sure that user has admin right!
169      * 
170      * @param string $_filename
171      * @param Tinebase_Model_Application $_application
172      * @param string $_name
173      * @return Tinebase_Model_ImportExportDefinition
174      */
175     public function updateOrCreateFromFilename($_filename, $_application, $_name = NULL)
176     {
177         $definition = $this->getFromFile(
178             $_filename,
179             $_application->getId(),
180             $_name
181         );
182         
183         // try to get definition and update if it exists
184         try {
185             $existing = $this->getByName($definition->name);
186             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Updating definition: ' . $definition->name);
187             $copyFields = array('filename', 'plugin_options', 'description', 'label');
188             foreach ($copyFields as $field) {
189                 $existing->{$field} = $definition->{$field};
190             }
191             $result = $this->_backend->update($existing);
192             
193         } catch (Tinebase_Exception_NotFound $tenf) {
194             // does not exist
195             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Creating import/export definion from file: ' . $_filename);
196             $result = $this->_backend->create($definition);
197         }
198         
199         return $result;
200     }
201
202     /**
203      * repair definitions tables
204      * 
205      * - fixes application_ids
206      * 
207      * @todo should be moved to generic (?) backend
208      */
209     public function repairTable()
210     {
211         $definitions = $this->_backend->getAll();
212         
213         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
214             . ' Got ' . count($definitions) . ' definitions. Checking definitions table ...');
215         
216         foreach ($definitions as $definition) {
217             $appName = substr($definition->model, 0, strpos($definition->model, '_Model'));
218             echo $appName;
219             $application = Tinebase_Application::getInstance()->getApplicationByName($appName);
220             if ($application->getId() !== $definition->application_id) {
221                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
222                     . ' Fixing application_id for definition ' . $definition->name);
223                 $definition->application_id = $application->getId();
224                 $this->update($definition);
225             }
226         }
227     }
228 }