11762 use doctrine for schema creation and update
[tine20] / tine20 / Tinebase / Controller / Abstract.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 Schuele <p.schuele@metaways.de>
9  * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
10  * 
11  */
12
13 /**
14  * controller abstract for applications
15  *
16  * @package     Tinebase
17  * @subpackage  Controller
18  */
19 abstract class Tinebase_Controller_Abstract extends Tinebase_Pluggable_Abstract implements Tinebase_Controller_Interface
20 {
21     /**
22      * default settings
23      * 
24      * @var array
25      */
26     protected $_defaultsSettings = array();
27
28     /**
29      * application models if given
30      *
31      * @var null
32      */
33     protected $_models = null;
34
35     /**
36      * holds the default Model of this application
37      * @var string
38      */
39     protected static $_defaultModel = NULL;
40     
41     /**
42      * application name (is needed in checkRight())
43      *
44      * @var string
45      */
46     protected $_applicationName = '';
47     
48     /**
49      * disable events on demand
50      * 
51      * @var mixed   false => no events filtered, true => all events filtered, array => disable only specific events
52      */
53     protected $_disabledEvents = false;
54
55     /**
56      * Models of this application that make use of Tinebase_Record_Path
57      *
58      * @var array|null
59      */
60     protected $_modelsUsingPath = null;
61     
62     /**
63      * generic check admin rights function
64      * rules: 
65      * - ADMIN right includes all other rights
66      * - MANAGE_* right includes VIEW_* right 
67      * - results are cached if caching is active (with cache tag 'rights')
68      * 
69      * @param   string  $_right to check
70      * @param   boolean $_throwException [optional]
71      * @param   boolean $_includeTinebaseAdmin [optional]
72      * @return  boolean
73      * @throws  Tinebase_Exception_UnexpectedValue
74      * @throws  Tinebase_Exception_AccessDenied
75      * @throws  Tinebase_Exception
76      * 
77      * @todo move that to *_Acl_Rights
78      * @todo include Tinebase admin? atm only the application admin right is checked
79      * @todo think about moving the caching to Tinebase_Acl_Roles and use only a class cache as it is difficult (and slow?) to invalidate
80      */
81     public function checkRight($_right, $_throwException = TRUE, $_includeTinebaseAdmin = TRUE) 
82     {
83         if (empty($this->_applicationName)) {
84             throw new Tinebase_Exception_UnexpectedValue('No application name defined!');
85         }
86         if (! is_object(Tinebase_Core::getUser())) {
87             throw new Tinebase_Exception('No user found for right check!');
88         }
89         
90         $right = strtoupper($_right);
91         
92         $cache = Tinebase_Core::getCache();
93         $cacheId = Tinebase_Helper::convertCacheId('checkRight' . Tinebase_Core::getUser()->getId() . $right . $this->_applicationName);
94         $result = $cache->load($cacheId);
95         
96         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . $cacheId);
97         
98         if (!$result) {
99             $applicationRightsClass = $this->_applicationName . '_Acl_Rights';
100             
101             // array with the rights that should be checked, ADMIN is in it per default
102             $rightsToCheck = ($_includeTinebaseAdmin) ? array(Tinebase_Acl_Rights::ADMIN) : array();
103             
104             if (preg_match("/VIEW_([A-Z_]*)/", $right, $matches)) {
105                 // manage right includes view right
106                 $rightsToCheck[] = constant($applicationRightsClass. '::MANAGE_' . $matches[1]);
107             } 
108             
109             $rightsToCheck[] = constant($applicationRightsClass. '::' . $right);
110             
111             $result = FALSE;
112             
113             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
114                 . ' Checking rights: ' . print_r($rightsToCheck, TRUE));
115             
116             foreach ($rightsToCheck as $rightToCheck) {
117                 if (Tinebase_Acl_Roles::getInstance()->hasRight($this->_applicationName, Tinebase_Core::getUser()->getId(), $rightToCheck)) {
118                     $result = TRUE;
119                     break;
120                 }
121             }
122             
123             $cache->save($result, $cacheId, array('rights'), 120);
124         }
125         
126         if (!$result && $_throwException) {
127             throw new Tinebase_Exception_AccessDenied("You are not allowed to $right in application $this->_applicationName !");
128         }
129         
130         return $result;
131     }
132     
133     /**
134      * Returns default settings for app
135      *
136      * @param boolean $_resolve if some values should be resolved
137      * @return  array settings data
138      */
139     public function getConfigSettings($_resolve = FALSE)
140     {
141         $appConfig = Tinebase_Config::getAppConfig($this->_applicationName);
142         if ($appConfig != NULL) {
143             $settings = $appConfig->get(
144                 Tinebase_Config::APPDEFAULTS, 
145                 new Tinebase_Config_Struct($this->_defaultsSettings)
146             )->toArray();
147         } else { 
148             $settings = $this->_defaultsSettings;
149         }
150         return ($_resolve) ? $this->_resolveConfigSettings($settings) : $settings;
151     }
152     
153     /**
154      * resolve some settings
155      * 
156      * @param array $_settings
157      */
158     protected function _resolveConfigSettings($_settings)
159     {
160         return $_settings;
161     }
162     
163     /**
164      * save settings
165      * 
166      * @param array $_settings
167      * @return void
168      */
169     public function saveConfigSettings($_settings)
170     {
171         // only admins are allowed to do this
172         $this->checkRight(Tinebase_Acl_Rights::ADMIN);
173         
174         $appConfig = Tinebase_Config::getAppConfig($this->_applicationName);
175         
176         if ($appConfig !== NULL) {
177             $appConfig->set(Tinebase_Config::APPDEFAULTS, $_settings);
178         }
179     }
180     
181     /**
182      * returns the default model of this application
183      * @return string
184      */
185     public static function getDefaultModel()
186     {
187         return static::$_defaultModel;
188     }
189     
190     /**
191      * returns controller instance for given $_controllerName
192      * 
193      * @param string $_controllerName
194      * @return Tinebase_Controller
195      */
196     public static function getController($_controllerName)
197     {
198         if (! class_exists($_controllerName)) {
199             throw new Exception("Controller" . $_controllerName . "not found.");
200         }
201         
202         if (!in_array('Tinebase_Controller_Interface', class_implements($_controllerName))) {
203             throw new Exception("Controller $_controllerName does not implement Tinebase_Controller_Interface.");
204         }
205         
206         return call_user_func(array($_controllerName, 'getInstance'));
207     }
208
209     /**
210      * delete all personal user folders and the content associated with these folders
211      *
212      * @param Tinebase_Model_User|string $_accountId the account object
213      */
214     public function deletePersonalFolder($_accountId, $model = '')
215     {
216         if ($_accountId instanceof Tinebase_Record_Abstract) {
217             $_accountId = $_accountId->getId();
218         }
219
220         if ('' === $model) {
221             $model = static::$_defaultModel;
222         }
223         // attention, currently everybody who has admin rights on a personal container is the owner of it
224         // even if multiple users have admin rights on that personal container! (=> multiple owners)
225         $containers = Tinebase_Container::getInstance()->getPersonalContainer($_accountId, $model, $_accountId, '*', true);
226
227         foreach ($containers as $container) {
228             //Tinebase_Container::getInstance()->deleteContainerContents($container, true);
229             Tinebase_Container::getInstance()->deleteContainer($container, true);
230         }
231     }
232
233     /**
234      * get core data for this application
235      *
236      * @return Tinebase_Record_RecordSet
237      *
238      * TODO add generic approach for fetching core data from config
239      */
240     public function getCoreDataForApplication()
241     {
242         $result = new Tinebase_Record_RecordSet('CoreData_Model_CoreData');
243
244         // TODO get configured core data
245
246         return $result;
247     }
248
249     /**
250      * get all models of this application that use tinebase_record_path
251      *
252      * @return array|null
253      */
254     public function getModelsUsingPaths()
255     {
256         return $this->_modelsUsingPath;
257     }
258
259     /**
260      * @return array
261      *
262      * @param bool $MCV2only filter for new modelconfig with doctrine schema tool
263      */
264     public function getModels($MCV2only = false)
265     {
266         if ($this->_models === null && ! empty($this->_applicationName)) {
267             try {
268                 $dir = new DirectoryIterator(dirname(dirname(dirname(__FILE__))) . '/' . $this->_applicationName . '/Model/');
269             } catch (Exception $e) {
270                 Tinebase_Exception::log($e);
271                 return null;
272             }
273
274             $models = array();
275             foreach ($dir as $fileinfo) {
276                 if (!$fileinfo->isDot() && !$fileinfo->isLink()) {
277                     if ($this->_isModelFile($fileinfo)) {
278                         $models[] = $this->_applicationName . '_Model_' . str_replace('.php', '', $fileinfo->getBasename());
279                     } else if ($fileinfo->isDir()) {
280                         // go (only) one level deeper
281                         $subdir = new DirectoryIterator($fileinfo->getPath() . '/' . $fileinfo->getFilename());
282                         foreach ($subdir as $subfileinfo) {
283                             if ($this->_isModelFile($subfileinfo)) {
284                                 $this->_applicationName . '_Model_' . $fileinfo->getBasename() . '_'
285                                 . str_replace('.php', '', $subfileinfo->getBasename());
286                             }
287                         }
288
289                     }
290                 }
291             }
292
293             $this->_models = $models;
294         }
295
296         if ($MCV2only) {
297             $md = new Tinebase_Record_DoctrineMappingDriver();
298             $MCv2Models = array();
299             foreach($models as $model) {
300                 if ($md->isTransient($model)) {
301                     $MCv2Models[] = $model;
302                 }
303             }
304
305             return $MCv2Models;
306         }
307
308         return $this->_models;
309     }
310
311     /**
312      * @param $fileinfo
313      * @return bool
314      */
315     protected function _isModelFile($fileinfo)
316     {
317         return (
318             ! $fileinfo->isDot() &&
319             ! $fileinfo->isLink() &&
320             $fileinfo->isFile() &&
321             ! preg_match('/filter\.php/i', $fileinfo->getBasename())
322         );
323     }
324 }