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)
14 * controller abstract for applications
17 * @subpackage Controller
19 abstract class Tinebase_Controller_Abstract extends Tinebase_Pluggable_Abstract implements Tinebase_Controller_Interface
26 protected $_defaultsSettings = array();
29 * application models if given
33 protected $_models = null;
36 * holds the default Model of this application
39 protected static $_defaultModel = NULL;
42 * application name (is needed in checkRight())
46 protected $_applicationName = '';
49 * disable events on demand
51 * @var mixed false => no events filtered, true => all events filtered, array => disable only specific events
53 protected $_disabledEvents = false;
56 * Models of this application that make use of Tinebase_Record_Path
60 protected $_modelsUsingPath = null;
63 * request context information
67 protected $_requestContext = null;
69 public function setRequestContext(array $context)
71 $this->_requestContext = $context;
77 public function getRequestContext()
79 return $this->_requestContext;
83 * generic check admin rights function
85 * - ADMIN right includes all other rights
86 * - MANAGE_* right includes VIEW_* right
87 * - results are cached if caching is active (with cache tag 'rights')
89 * @param string $_right to check
90 * @param boolean $_throwException [optional]
91 * @param boolean $_includeTinebaseAdmin [optional]
93 * @throws Tinebase_Exception_UnexpectedValue
94 * @throws Tinebase_Exception_AccessDenied
95 * @throws Tinebase_Exception
97 * @todo move that to *_Acl_Rights
98 * @todo include Tinebase admin? atm only the application admin right is checked
99 * @todo think about moving the caching to Tinebase_Acl_Roles and use only a class cache as it is difficult (and slow?) to invalidate
101 public function checkRight($_right, $_throwException = TRUE, $_includeTinebaseAdmin = TRUE)
103 if (empty($this->_applicationName)) {
104 throw new Tinebase_Exception_UnexpectedValue('No application name defined!');
106 if (! is_object(Tinebase_Core::getUser())) {
107 throw new Tinebase_Exception('No user found for right check!');
110 $right = strtoupper($_right);
112 $cache = Tinebase_Core::getCache();
113 $cacheId = Tinebase_Helper::convertCacheId('checkRight' . Tinebase_Core::getUser()->getId() . $right . $this->_applicationName);
114 $result = $cache->load($cacheId);
116 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . $cacheId);
119 $applicationRightsClass = $this->_applicationName . '_Acl_Rights';
121 // array with the rights that should be checked, ADMIN is in it per default
122 $rightsToCheck = ($_includeTinebaseAdmin) ? array(Tinebase_Acl_Rights::ADMIN) : array();
124 if (preg_match("/VIEW_([A-Z_]*)/", $right, $matches)) {
125 // manage right includes view right
126 $rightsToCheck[] = constant($applicationRightsClass. '::MANAGE_' . $matches[1]);
129 $rightsToCheck[] = constant($applicationRightsClass. '::' . $right);
133 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
134 . ' Checking rights: ' . print_r($rightsToCheck, TRUE));
136 foreach ($rightsToCheck as $rightToCheck) {
137 if (Tinebase_Acl_Roles::getInstance()->hasRight($this->_applicationName, Tinebase_Core::getUser()->getId(), $rightToCheck)) {
143 $cache->save($result, $cacheId, array('rights'), 120);
146 if (!$result && $_throwException) {
147 throw new Tinebase_Exception_AccessDenied("You are not allowed to $right in application $this->_applicationName !");
154 * Returns default settings for app
156 * @param boolean $_resolve if some values should be resolved
157 * @return array settings data
159 public function getConfigSettings($_resolve = FALSE)
161 $appConfig = Tinebase_Config::getAppConfig($this->_applicationName);
162 if ($appConfig != NULL) {
163 $settings = $appConfig->get(
164 Tinebase_Config::APPDEFAULTS,
165 new Tinebase_Config_Struct($this->_defaultsSettings)
168 $settings = $this->_defaultsSettings;
170 return ($_resolve) ? $this->_resolveConfigSettings($settings) : $settings;
174 * resolve some settings
176 * @param array $_settings
178 protected function _resolveConfigSettings($_settings)
186 * @param array $_settings
189 public function saveConfigSettings($_settings)
191 // only admins are allowed to do this
192 $this->checkRight(Tinebase_Acl_Rights::ADMIN);
194 $appConfig = Tinebase_Config::getAppConfig($this->_applicationName);
196 if ($appConfig !== NULL) {
197 $appConfig->set(Tinebase_Config::APPDEFAULTS, $_settings);
202 * returns the default model of this application
206 public function getDefaultModel()
208 if (static::$_defaultModel !== null) {
209 return static::$_defaultModel;
212 // no default model defined, using first model of app...
213 $models = $this->getModels();
214 return (count($models) > 0) ? $models[0] : null;
218 * returns controller instance for given $_controllerName
220 * @param string $_controllerName
221 * @return Tinebase_Controller
223 public static function getController($_controllerName)
225 if (! class_exists($_controllerName)) {
226 throw new Exception("Controller" . $_controllerName . "not found.");
229 if (!in_array('Tinebase_Controller_Interface', class_implements($_controllerName))) {
230 throw new Exception("Controller $_controllerName does not implement Tinebase_Controller_Interface.");
233 return call_user_func(array($_controllerName, 'getInstance'));
237 * delete all personal user folders and the content associated with these folders
239 * @param Tinebase_Model_User|string $_accountId the account object
241 public function deletePersonalFolder($_accountId, $model = '')
243 if ($_accountId instanceof Tinebase_Record_Abstract) {
244 $_accountId = $_accountId->getId();
248 $model = static::$_defaultModel;
250 // attention, currently everybody who has admin rights on a personal container is the owner of it
251 // even if multiple users have admin rights on that personal container! (=> multiple owners)
252 $containers = Tinebase_Container::getInstance()->getPersonalContainer($_accountId, $model, $_accountId, '*', true);
254 foreach ($containers as $container) {
255 //Tinebase_Container::getInstance()->deleteContainerContents($container, true);
256 Tinebase_Container::getInstance()->deleteContainer($container, true);
261 * get core data for this application
263 * @return Tinebase_Record_RecordSet
265 * TODO add generic approach for fetching core data from config
267 public function getCoreDataForApplication()
269 $result = new Tinebase_Record_RecordSet('CoreData_Model_CoreData');
271 // TODO get configured core data
277 * get all models of this application that use tinebase_record_path
281 public function getModelsUsingPaths()
283 return $this->_modelsUsingPath;
289 * @param bool $MCV2only filter for new modelconfig with doctrine schema tool
291 public function getModels($MCV2only = false)
293 if ($this->_models === null && ! empty($this->_applicationName)) {
295 $cache = Tinebase_Core::getCache();
296 $cacheId = Tinebase_Helper::convertCacheId('getModels' . $this->_applicationName);
297 $models = $cache->load($cacheId);
300 $models = $this->_getModelsFromAppDir();
301 // cache for a long time only on prod
302 $cache->save($models, $cacheId, array(), TINE20_BUILDTYPE === 'DEVELOPMENT' ? 1 : 3600);
305 $this->_models = $models;
309 $md = new Tinebase_Record_DoctrineMappingDriver();
310 $MCv2Models = array();
311 foreach ((array)$this->_models as $model) {
312 if ($md->isTransient($model)) {
313 $MCv2Models[] = $model;
320 return $this->_models;
324 * get models from application directory
328 protected function _getModelsFromAppDir()
331 $dir = new DirectoryIterator(dirname(dirname(dirname(__FILE__))) . '/' . $this->_applicationName . '/Model/');
332 } catch (Exception $e) {
333 Tinebase_Exception::log($e);
338 foreach ($dir as $fileinfo) {
339 if (!$fileinfo->isDot() && !$fileinfo->isLink()) {
340 if ($this->_isModelFile($fileinfo)) {
341 $models[] = $this->_applicationName . '_Model_' . str_replace('.php', '', $fileinfo->getBasename());
342 } else if ($fileinfo->isDir()) {
343 // go (only) one level deeper
344 $subdir = new DirectoryIterator($fileinfo->getPath() . '/' . $fileinfo->getFilename());
345 foreach ($subdir as $subfileinfo) {
346 if ($this->_isModelFile($subfileinfo)) {
347 $models[] = $this->_applicationName . '_Model_' . $fileinfo->getBasename() . '_'
348 . str_replace('.php', '', $subfileinfo->getBasename());
356 foreach ($models as $key => $model) {
357 if (class_exists($model)) {
358 $reflection = new ReflectionClass($model);
359 $interfaces = $reflection->getInterfaceNames();
360 if (! in_array('Tinebase_Record_Interface', $interfaces)) {
361 unset($models[$key]);
364 // interface, no php class, ...
365 unset($models[$key]);
373 * returns true if $fileinfo describes a model file
378 protected function _isModelFile($fileinfo)
381 ! $fileinfo->isDot() &&
382 ! $fileinfo->isLink() &&
383 $fileinfo->isFile() &&
384 ! preg_match('/filter\.php/i', $fileinfo->getBasename()) &&
385 ! preg_match('/abstract\.php/i', $fileinfo->getBasename())