PageRenderTime 31ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/core/model/modx/modcontext.class.php

https://github.com/francisreboucas/revolution
PHP | 330 lines | 211 code | 16 blank | 103 comment | 66 complexity | 70f5cedc6906b95fc01af678d90b7a1c MD5 | raw file
  1. <?php
  2. /**
  3. * modContext
  4. *
  5. * @package modx
  6. */
  7. /**
  8. * Represents a virtual site context within a modX repository.
  9. *
  10. * @property string $key The key of the context
  11. * @property string $description The description of the context
  12. *
  13. * @package modx
  14. */
  15. class modContext extends modAccessibleObject {
  16. /**
  17. * An array of configuration options for this context
  18. * @var array $config
  19. */
  20. public $config= null;
  21. /**
  22. * The alias map for this context
  23. * @var array $aliasMap
  24. */
  25. public $aliasMap= null;
  26. /**
  27. * The resource map for all resources in this context
  28. * @var array $resourceMap
  29. */
  30. public $resourceMap= null;
  31. /**
  32. * The event map for all events being executed in this context
  33. * @var array $eventMap
  34. */
  35. public $eventMap= null;
  36. /**
  37. * The plugin cache array for all plugins being fired in this context
  38. * @var array $pluginCache
  39. */
  40. public $pluginCache= null;
  41. /**
  42. * The key for the cache for this context
  43. * @var string $_cacheKey
  44. */
  45. protected $_cacheKey= '[contextKey]/context';
  46. /**
  47. * Prepare a context for use.
  48. *
  49. * @uses modCacheManager::generateContext() This method is responsible for
  50. * preparing the context for use.
  51. * {@internal You can override this behavior here, but you will only need to
  52. * override the modCacheManager::generateContext() method in most cases}}
  53. * @access public
  54. * @param boolean $regenerate If true, the existing cache file will be ignored
  55. * and regenerated.
  56. * @return boolean Indicates if the context was successfully prepared.
  57. */
  58. public function prepare($regenerate= false) {
  59. $prepared= false;
  60. if ($this->config === null || $regenerate) {
  61. if ($this->xpdo->getCacheManager()) {
  62. $context = array();
  63. if ($regenerate || !($context = $this->xpdo->cacheManager->get($this->getCacheKey(), array(
  64. xPDO::OPT_CACHE_KEY => $this->xpdo->getOption('cache_context_settings_key', null, 'context_settings'),
  65. xPDO::OPT_CACHE_HANDLER => $this->xpdo->getOption('cache_context_settings_handler', null, $this->xpdo->getOption(xPDO::OPT_CACHE_HANDLER, null, 'cache.xPDOFileCache')),
  66. xPDO::OPT_CACHE_FORMAT => (integer) $this->xpdo->getOption('cache_context_settings_format', null, $this->xpdo->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)),
  67. )))) {
  68. $context = $this->xpdo->cacheManager->generateContext($this->get('key'));
  69. }
  70. if (!empty($context)) {
  71. foreach ($context as $var => $val) {
  72. if ($var === 'policies') {
  73. $this->setPolicies($val);
  74. continue;
  75. }
  76. $this->$var = $val;
  77. }
  78. $prepared= true;
  79. }
  80. }
  81. } else {
  82. $prepared= true;
  83. }
  84. return $prepared;
  85. }
  86. /**
  87. * Returns a context-specific setting value.
  88. *
  89. * @param string $key The option key to check.
  90. * @param string $default A default value to use if not found.
  91. * @param array $options An array of additional options to merge over top of
  92. * the context settings.
  93. * @return mixed The option value or the provided default.
  94. */
  95. public function getOption($key, $default = null, $options = null) {
  96. if (is_array($options)) {
  97. $options = array_merge($this->config, $options);
  98. } else {
  99. $options =& $this->config;
  100. }
  101. return $this->xpdo->getOption($key, $options, $default);
  102. }
  103. /**
  104. * Returns the file name representing this context in the cache.
  105. *
  106. * @access public
  107. * @return string The cache filename.
  108. */
  109. public function getCacheKey() {
  110. if ($this->get('key')) {
  111. $this->_cacheKey= str_replace('[contextKey]', $this->get('key'), $this->_cacheKey);
  112. } else {
  113. $this->_cacheKey= str_replace('[contextKey]', uniqid('ctx_'), $this->_cacheKey);
  114. }
  115. return $this->_cacheKey;
  116. }
  117. /**
  118. * Loads the access control policies applicable to this element.
  119. *
  120. * {@inheritdoc}
  121. */
  122. public function findPolicy($context = '') {
  123. $policy = array();
  124. $enabled = true;
  125. $context = !empty($context) ? $context : $this->xpdo->context->get('key');
  126. if (!is_object($this->xpdo->context) || $context === $this->xpdo->context->get('key')) {
  127. $enabled = (boolean) $this->xpdo->getOption('access_context_enabled', null, true);
  128. } elseif ($this->xpdo->getContext($context)) {
  129. $enabled = (boolean) $this->xpdo->contexts[$context]->getOption('access_context_enabled', true);
  130. }
  131. if ($enabled) {
  132. if (empty($this->_policies) || !isset($this->_policies[$context])) {
  133. $c = $this->xpdo->newQuery('modAccessContext');
  134. $c->leftJoin('modAccessPolicy','Policy');
  135. $c->select(array(
  136. 'modAccessContext.id',
  137. 'modAccessContext.target',
  138. 'modAccessContext.principal',
  139. 'modAccessContext.authority',
  140. 'modAccessContext.policy',
  141. 'Policy.data',
  142. ));
  143. $c->where(array(
  144. 'modAccessContext.principal_class' => 'modUserGroup',
  145. 'modAccessContext.target' => $this->get('key'),
  146. ));
  147. $c->sortby('modAccessContext.target,modAccessContext.principal,modAccessContext.authority,modAccessContext.policy');
  148. $acls = $this->xpdo->getCollection('modAccessContext',$c);
  149. foreach ($acls as $acl) {
  150. $policy['modAccessContext'][$acl->get('target')][] = array(
  151. 'principal' => $acl->get('principal'),
  152. 'authority' => $acl->get('authority'),
  153. 'policy' => $acl->get('data') ? $this->xpdo->fromJSON($acl->get('data'), true) : array(),
  154. );
  155. }
  156. $this->_policies[$context] = $policy;
  157. } else {
  158. $policy = $this->_policies[$context];
  159. }
  160. }
  161. return $policy;
  162. }
  163. /**
  164. * Generates a URL representing a specified resource in this context.
  165. *
  166. * Note that if this method is called from a context other than the one
  167. * initialized for the modX instance, and the scheme is not specified, an
  168. * empty string, or abs, the method will force the scheme to full.
  169. *
  170. * @access public
  171. * @param integer $id The id of a resource.
  172. * @param string $args A query string to append to the generated URL.
  173. * @param mixed $scheme The scheme indicates in what format the URL is generated.<br>
  174. * <pre>
  175. * -1 : (default value) URL is relative to site_url
  176. * 0 : see http
  177. * 1 : see https
  178. * full : URL is absolute, prepended with site_url from config
  179. * abs : URL is absolute, prepended with base_url from config
  180. * http : URL is absolute, forced to http scheme
  181. * https : URL is absolute, forced to https scheme
  182. * </pre>
  183. * @return string The URL for the resource.
  184. */
  185. public function makeUrl($id, $args = '', $scheme = -1) {
  186. $url = '';
  187. $found = false;
  188. if ($id= intval($id)) {
  189. if (is_object($this->xpdo->context) && $this->get('key') !== $this->xpdo->context->get('key')) {
  190. $config = array_merge($this->xpdo->_systemConfig, $this->config, $this->xpdo->_userConfig);
  191. if ($scheme === -1 || $scheme === '' || strpos($scheme, 'abs') !== false) {
  192. $scheme= 'full';
  193. }
  194. } else {
  195. $config = $this->xpdo->config;
  196. }
  197. if ($config['friendly_urls'] == 1) {
  198. if ($id == $config['site_start']) {
  199. $alias= ($scheme === '' || $scheme === -1) ? $config['base_url'] : '';
  200. $found= true;
  201. } else {
  202. $alias= array_search($id, $this->aliasMap);
  203. if (!$alias) {
  204. $alias= '';
  205. $this->xpdo->log(xPDO::LOG_LEVEL_WARN, '`' . $id . '` was requested but no alias was located.');
  206. } else {
  207. $found= true;
  208. }
  209. }
  210. } elseif (array_keys(array((string) $id), $this->resourceMap, true) !== false) {
  211. $found= true;
  212. }
  213. if ($found) {
  214. if (is_array($args)) {
  215. $args = modX::toQueryString($args);
  216. }
  217. if ($args != '' && $config['friendly_urls'] == 1) {
  218. /* add ? to $args if missing */
  219. $c= substr($args, 0, 1);
  220. if ($c == '&') {
  221. $args= '?' . substr($args, 1);
  222. } elseif ($c != '?') {
  223. $args= '?' . $args;
  224. }
  225. }
  226. elseif ($args != '') {
  227. /* add & to $args if missing */
  228. $c= substr($args, 0, 1);
  229. if ($c == '?')
  230. $args= '&' . substr($args, 1);
  231. elseif ($c != '&') $args= '&' . $args;
  232. }
  233. if ($config['friendly_urls'] == 1) {
  234. $url= $alias . $args;
  235. } else {
  236. $url= $config['request_controller'] . '?' . $config['request_param_id'] . '=' . $id . $args;
  237. }
  238. $host= '';
  239. if ($scheme !== -1 && $scheme !== '') {
  240. if ($scheme === 1 || $scheme === 0) {
  241. $https_port= $this->getOption('https_port',$config,443);
  242. $isSecure= ($_SERVER['SERVER_PORT'] == $https_port || (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS'])=='on')) ? 1 : 0;
  243. if ($scheme != $isSecure) {
  244. $scheme = $isSecure ? 'http' : 'https';
  245. }
  246. }
  247. switch ($scheme) {
  248. case 'full':
  249. $host= $config['site_url'];
  250. break;
  251. case 'abs':
  252. case 'absolute':
  253. $host= $config['base_url'];
  254. break;
  255. case 'https':
  256. case 'http':
  257. $host= $scheme . '://' . $config['http_host'] . $config['base_url'];
  258. break;
  259. }
  260. $url= $host . $url;
  261. }
  262. }
  263. }
  264. if ($this->xpdo->getDebug() === true) {
  265. $this->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "modContext[" . $this->get('key') . "]->makeUrl({$id}) = {$url}");
  266. }
  267. return $url;
  268. }
  269. /**
  270. * Overrides xPDOObject::remove to fire modX-specific events
  271. *
  272. * {@inheritDoc}
  273. */
  274. public function remove(array $ancestors = array()) {
  275. if ($this->xpdo instanceof modX) {
  276. $this->xpdo->invokeEvent('OnContextBeforeRemove',array(
  277. 'context' => &$this,
  278. 'ancestors' => $ancestors,
  279. ));
  280. }
  281. $removed = parent :: remove($ancestors);
  282. if ($removed && $this->xpdo instanceof modX) {
  283. $this->xpdo->invokeEvent('OnContextRemove',array(
  284. 'context' => &$this,
  285. 'ancestors' => $ancestors,
  286. ));
  287. }
  288. return $removed;
  289. }
  290. /**
  291. * Overrides xPDOObject::save to fire modX-specific events.
  292. *
  293. * {@inheritDoc}
  294. */
  295. public function save($cacheFlag= null) {
  296. $isNew = $this->isNew();
  297. if ($this->xpdo instanceof modX) {
  298. $this->xpdo->invokeEvent('OnContextBeforeSave',array(
  299. 'context' => &$this,
  300. 'mode' => $isNew ? modSystemEvent::MODE_NEW : modSystemEvent::MODE_UPD,
  301. 'cacheFlag' => $cacheFlag,
  302. ));
  303. }
  304. $saved = parent :: save($cacheFlag);
  305. if ($saved && $this->xpdo instanceof modX) {
  306. $this->xpdo->invokeEvent('OnContextSave',array(
  307. 'context' => &$this,
  308. 'mode' => $isNew ? modSystemEvent::MODE_NEW : modSystemEvent::MODE_UPD,
  309. 'cacheFlag' => $cacheFlag,
  310. ));
  311. }
  312. return $saved;
  313. }
  314. }