resource.class.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. <?php
  2. /*
  3. * This file is part of MODX Revolution.
  4. *
  5. * Copyright (c) MODX, LLC. All Rights Reserved.
  6. *
  7. * For complete copyright and license information, see the COPYRIGHT and LICENSE
  8. * files found in the top-level directory of this distribution.
  9. */
  10. /**
  11. * Base controller class for Resources
  12. *
  13. * @package modx
  14. * @subpackage manager.controllers
  15. */
  16. abstract class ResourceManagerController extends modManagerController {
  17. public $resourceArray = array();
  18. public $onDocFormRender = '';
  19. public $ctx = 'web';
  20. /** @var modContext $context */
  21. public $context;
  22. /** @var modResource $resource */
  23. public $resource;
  24. /** @var modResource $resource */
  25. public $parent = null;
  26. /** @var string $resourceClass */
  27. public $resourceClass = 'modDocument';
  28. /** @var array $tvCounts */
  29. public $tvCounts = array();
  30. /** @var array $rteFields */
  31. public $rteFields = array();
  32. /** @var modRegister $reg */
  33. protected $reg;
  34. public $canPublish = true;
  35. public $canSave = true;
  36. public $canDuplicate = true;
  37. public $canDelete = true;
  38. public $canEdit = true;
  39. public $canCreate = true;
  40. public $canCreateRoot = true;
  41. /**
  42. * Return the appropriate Resource controller class based on the class_key request parameter
  43. *
  44. * @static
  45. * @param modX $modx A reference to the modX instance
  46. * @param string $className The controller class name that is attempting to be loaded
  47. * @param array $config An array of configuration options for the action
  48. * @return modManagerController The proper controller class
  49. */
  50. public static function getInstance(modX &$modx,$className,array $config = array()) {
  51. $resourceClass = 'modDocument';
  52. $isDerivative = false;
  53. if (!empty($_REQUEST['class_key'])) {
  54. $isDerivative = true;
  55. $resourceClass = in_array($_REQUEST['class_key'],array('modDocument','modResource')) ? 'modDocument' : $_REQUEST['class_key'];
  56. if ($resourceClass == 'modResource') $resourceClass = 'modDocument';
  57. } else if (!empty($_REQUEST['id']) && $_REQUEST['id'] != 'undefined' && strlen($_REQUEST['id']) === strlen((integer)$_REQUEST['id'])) {
  58. /** @var modResource $resource */
  59. $resource = $modx->getObject('modResource', array('id' => $_REQUEST['id']));
  60. if ($resource && !in_array($resource->get('class_key'),array('modDocument','modResource'))) {
  61. $isDerivative = true;
  62. $resourceClass = $resource->get('class_key');
  63. } else if ($resource && $resource->get('class_key') == 'modResource') { /* fix improper class key */
  64. $resource->set('class_key','modDocument');
  65. $resource->save();
  66. }
  67. }
  68. if ($isDerivative) {
  69. $resourceClass = str_replace(array('../','..','/','\\'),'',$resourceClass);
  70. if (!class_exists($resourceClass) && !$modx->loadClass($resourceClass)) {
  71. $resourceClass = 'modDocument';
  72. }
  73. $delegateView = $modx->call($resourceClass,'getControllerPath',array(&$modx));
  74. $action = strtolower(str_replace(array('Resource','ManagerController'),'',$className));
  75. $className = str_replace('mod','',$resourceClass).ucfirst($action).'ManagerController';
  76. $controllerFile = $delegateView.$action.'.class.php';
  77. if (!file_exists($controllerFile)) {
  78. // We more than likely are using a custom manager theme without overridden controller, let's try with the default theme
  79. $theme = $modx->getOption('manager_theme', null, 'default');
  80. $modx->setOption('manager_theme', 'default');
  81. $delegateView = $modx->call($resourceClass, 'getControllerPath', array(&$modx));
  82. $controllerFile = $delegateView.$action.'.class.php';
  83. // Restore custom theme (so we don't process/use default theme assets)
  84. $modx->setOption('manager_theme', $theme);
  85. }
  86. require_once $controllerFile;
  87. }
  88. $controller = new $className($modx,$config);
  89. $controller->resourceClass = $resourceClass;
  90. return $controller;
  91. }
  92. /**
  93. * Used to set values on the resource record sent to the template for derivative classes
  94. *
  95. * @return void
  96. */
  97. public function prepareResource() {}
  98. /**
  99. * Specify the language topics to load
  100. * @return array
  101. */
  102. public function getLanguageTopics() {
  103. return array('resource');
  104. }
  105. /**
  106. * Setup permissions for this page
  107. * @return void
  108. */
  109. public function setPermissions() {
  110. if ($this->canSave) {
  111. $this->canSave = $this->resource->checkPolicy('save');
  112. }
  113. $this->canEdit = $this->modx->hasPermission('edit_document');
  114. $this->canCreate = $this->modx->hasPermission('new_document');
  115. $this->canPublish = $this->modx->hasPermission('publish_document');
  116. $this->canDelete = ($this->modx->hasPermission('delete_document') && $this->resource->checkPolicy(array('save' => true, 'delete' => true)));
  117. $this->canDuplicate = ($this->modx->hasPermission('resource_duplicate') && $this->resource->checkPolicy('save'));
  118. $this->canCreateRoot = $this->modx->hasPermission('new_document_in_root');
  119. }
  120. /**
  121. * Get and set the parent for this resource
  122. * @return string The pagetitle of the parent
  123. */
  124. public function setParent() {
  125. /* handle default parent */
  126. $parentName = $this->context->getOption('site_name', '', $this->modx->_userConfig);
  127. $parentId = !empty($this->scriptProperties['parent']) ? $this->scriptProperties['parent'] : $this->resource->get('parent');
  128. if ($parentId == 0) {
  129. $parentName = $this->context->getOption('site_name', '', $this->modx->_userConfig);
  130. } else {
  131. $this->parent = $this->modx->getObject('modResource',$parentId);
  132. if ($this->parent !== null) {
  133. $parentName = $this->parent->get('pagetitle');
  134. $this->resource->set('parent',$parentId);
  135. }
  136. }
  137. if ($this->parent === null) {
  138. $this->parent = $this->modx->newObject($this->resourceClass);
  139. $this->parent->set('id',0);
  140. $this->parent->set('parent',0);
  141. }
  142. return $parentName;
  143. }
  144. /**
  145. * Fire any pre-render events
  146. * @return array|bool|string
  147. */
  148. public function firePreRenderEvents() {
  149. $resourceId = !empty($this->resource) && ($this->resource instanceof $this->resourceClass) ? $this->resource->get('id') : (!empty($this->scriptProperties['id']) ? $this->scriptProperties['id'] : 0);
  150. $properties = array(
  151. 'id' => $resourceId,
  152. 'mode' => !empty($resourceId) ? modSystemEvent::MODE_UPD : modSystemEvent::MODE_NEW,
  153. );
  154. if (!empty($resourceId)) {
  155. $properties['resource'] =& $this->resource;
  156. }
  157. $onDocFormPrerender = $this->modx->invokeEvent('OnDocFormPrerender',$properties);
  158. if (is_array($onDocFormPrerender)) {
  159. $onDocFormPrerender = implode('',$onDocFormPrerender);
  160. }
  161. $this->setPlaceholder('onDocFormPrerender',$onDocFormPrerender);
  162. return $onDocFormPrerender;
  163. }
  164. /**
  165. * Fire any render events
  166. * @return string
  167. */
  168. public function fireOnRenderEvent() {
  169. $resourceId = $this->resource->get('id');
  170. $this->onDocFormRender = $this->modx->invokeEvent('OnDocFormRender',array(
  171. 'id' => $resourceId,
  172. 'resource' => &$this->resource,
  173. 'mode' => !empty($resourceId) ? modSystemEvent::MODE_UPD : modSystemEvent::MODE_NEW,
  174. ));
  175. if (is_array($this->onDocFormRender)) $this->onDocFormRender = implode('',$this->onDocFormRender);
  176. $this->onDocFormRender = str_replace(array('"',"\n","\r"),array('\"','',''),$this->onDocFormRender);
  177. $this->setPlaceholder('onDocFormRender',$this->onDocFormRender);
  178. return $this->onDocFormRender;
  179. }
  180. /**
  181. * Initialize a RichText Editor, if set
  182. *
  183. * @return void
  184. */
  185. public function loadRichTextEditor() {
  186. /* register JS scripts */
  187. $rte = isset($this->scriptProperties['which_editor']) ? $this->scriptProperties['which_editor'] : $this->context->getOption('which_editor', '', $this->modx->_userConfig);
  188. $this->setPlaceholder('which_editor',$rte);
  189. /* Set which RTE if not core */
  190. if ($this->context->getOption('use_editor', false, $this->modx->_userConfig) && !empty($rte)) {
  191. /* invoke OnRichTextEditorRegister event */
  192. $textEditors = $this->modx->invokeEvent('OnRichTextEditorRegister');
  193. $this->setPlaceholder('text_editors',$textEditors);
  194. $this->rteFields = array('ta');
  195. $this->setPlaceholder('replace_richtexteditor',$this->rteFields);
  196. /* invoke OnRichTextEditorInit event */
  197. $resourceId = $this->resource->get('id');
  198. $onRichTextEditorInit = $this->modx->invokeEvent('OnRichTextEditorInit',array(
  199. 'editor' => $rte,
  200. 'elements' => $this->rteFields,
  201. 'id' => $resourceId,
  202. 'resource' => &$this->resource,
  203. 'mode' => !empty($resourceId) ? modSystemEvent::MODE_UPD : modSystemEvent::MODE_NEW,
  204. ));
  205. if (is_array($onRichTextEditorInit)) {
  206. $onRichTextEditorInit = implode('',$onRichTextEditorInit);
  207. $this->setPlaceholder('onRichTextEditorInit',$onRichTextEditorInit);
  208. }
  209. }
  210. }
  211. /**
  212. * Get and set the context for this resource
  213. *
  214. * @return modContext
  215. */
  216. public function setContext() {
  217. if(!empty($this->scriptProperties['context_key'])) {
  218. $this->ctx = $this->modx->stripTags($this->scriptProperties['context_key']);
  219. } else {
  220. $this->ctx = !empty($this->resource) ? $this->resource->get('context_key') : $this->modx->getOption('default_context');
  221. }
  222. $this->context = $this->modx->getContext($this->ctx);
  223. if (!$this->context) {
  224. $this->ctx = '';
  225. }
  226. $this->setPlaceholder('_ctx',$this->ctx);
  227. return $this->context;
  228. }
  229. /**
  230. * Load the TVs for the Resource
  231. *
  232. * @param array $reloadData resource data passed if reloading
  233. * @return string The TV editing form
  234. */
  235. public function loadTVs($reloadData = array()) {
  236. $this->setPlaceholder('wctx',$this->resource->get('context_key'));
  237. $_GET['wctx'] = $this->resource->get('context_key');
  238. $this->fireOnTVFormRender();
  239. /* get categories */
  240. $c = $this->modx->newQuery('modCategory');
  241. $c->sortby($this->modx->escape('rank'), 'ASC');
  242. $c->sortby($this->modx->escape('category'),'ASC');
  243. $cats = $this->modx->getCollection('modCategory',$c);
  244. $categories = array();
  245. /** @var modCategory $cat */
  246. foreach ($cats as $cat) {
  247. $categories[$cat->get('id')] = $cat->toArray();
  248. $categories[$cat->get('id')]['tvs'] = array();
  249. $categories[$cat->get('id')]['tvCount'] = 0;
  250. }
  251. $categories[0] = array(
  252. 'id' => 0,
  253. 'category' => ucfirst($this->modx->lexicon('uncategorized')),
  254. 'tvs' => array(),
  255. 'tvCount' => 0,
  256. );
  257. $tvMap = array();
  258. $hidden = array();
  259. $templateId = $this->resource->get('template');
  260. if ($templateId && ($template = $this->modx->getObject('modTemplate', $templateId))) {
  261. if ($template) {
  262. $c = $this->modx->newQuery('modTemplateVar');
  263. $c->query['distinct'] = 'DISTINCT';
  264. $c->leftJoin('modCategory','Category');
  265. $c->innerJoin('modTemplateVarTemplate','TemplateVarTemplate',array(
  266. 'TemplateVarTemplate.tmplvarid = modTemplateVar.id',
  267. 'TemplateVarTemplate.templateid' => $templateId,
  268. ));
  269. $c->leftJoin('modTemplateVarResource','TemplateVarResource',array(
  270. 'TemplateVarResource.tmplvarid = modTemplateVar.id',
  271. 'TemplateVarResource.contentid' => $this->resource->get('id'),
  272. ));
  273. $c->select($this->modx->getSelectColumns('modTemplateVar', 'modTemplateVar'));
  274. $c->select($this->modx->getSelectColumns('modCategory', 'Category', 'cat_', array('category')));
  275. if(empty($reloadData)) {
  276. $c->select($this->modx->getSelectColumns('modTemplateVarResource', 'TemplateVarResource', '', array('value')));
  277. }
  278. $c->select($this->modx->getSelectColumns('modTemplateVarTemplate', 'TemplateVarTemplate', '', array('rank')));
  279. $c->sortby('cat_category,TemplateVarTemplate.rank,modTemplateVar.rank','ASC');
  280. $tvs = $this->modx->getCollection('modTemplateVar',$c);
  281. $reloading = !empty($reloadData) && count($reloadData) > 0;
  282. $this->setPlaceholder('tvcount',count($tvs));
  283. /** @var modTemplateVar $tv */
  284. foreach ($tvs as $tv) {
  285. if (!$tv->checkResourceGroupAccess(null,'mgr')) {
  286. continue;
  287. }
  288. $v = '';
  289. $tv->set('inherited', false);
  290. /** @var int $cat */
  291. $cat = (int)$tv->get('category');
  292. $tvid = $tv->get('id');
  293. if($reloading && array_key_exists('tv'.$tvid, $reloadData)) {
  294. $v = $reloadData['tv'.$tvid];
  295. $tv->set('value', $v);
  296. } else {
  297. $default = $tv->processBindings($tv->get('default_text'),$this->resource->get('id'));
  298. if (strpos($tv->get('default_text'),'@INHERIT') > -1 && (strcmp($default,$tv->get('value')) === 0 || $tv->get('value') === null)) {
  299. $tv->set('inherited',true);
  300. }
  301. if ($tv->get('value') === null) {
  302. $v = $default;
  303. $tv->set('value',$v);
  304. }
  305. }
  306. if ($tv->get('type') == 'richtext') {
  307. $this->rteFields = array_merge($this->rteFields,array(
  308. 'tv' . $tv->get('id'),
  309. ));
  310. }
  311. $inputForm = $tv->renderInput($this->resource, array('value'=> $v));
  312. if (empty($inputForm)) continue;
  313. $tv->set('formElement',$inputForm);
  314. if ($tv->get('type') != 'hidden') {
  315. if (!isset($categories[$cat]['tvs']) || !is_array($categories[$cat]['tvs'])) {
  316. $categories[$cat]['tvs'] = array();
  317. $categories[$cat]['tvCount'] = 0;
  318. }
  319. /* add to tv/category map */
  320. $tvMap[$tv->get('id')] = $tv->category;
  321. /* add TV to category array */
  322. $categories[$cat]['tvs'][] = $tv;
  323. if ($tv->get('type') != 'hidden') {
  324. $categories[$cat]['tvCount']++;
  325. }
  326. } else {
  327. $hidden[] = $tv;
  328. }
  329. }
  330. }
  331. }
  332. $finalCategories = array();
  333. /** @var modCategory $category */
  334. foreach ($categories as $n => $category) {
  335. if (is_array($category)) {
  336. $category['hidden'] = empty($category['tvCount']) ? true : false;
  337. $ct = isset($category['tvs']) ? count($category['tvs']) : 0;
  338. if ($ct > 0) {
  339. $finalCategories[$category['id']] = $category;
  340. $this->tvCounts[$n] = $ct;
  341. }
  342. }
  343. }
  344. $onResourceTVFormRender = $this->modx->invokeEvent('OnResourceTVFormRender',array(
  345. 'categories' => &$finalCategories,
  346. 'template' => $templateId,
  347. 'resource' => $this->resource->get('id'),
  348. 'tvCounts' => &$this->tvCounts,
  349. 'hidden' => &$hidden,
  350. ));
  351. if (is_array($onResourceTVFormRender)) {
  352. $onResourceTVFormRender = implode('',$onResourceTVFormRender);
  353. }
  354. $this->setPlaceholder('OnResourceTVFormRender',$onResourceTVFormRender);
  355. $this->setPlaceholder('categories',$finalCategories);
  356. $this->setPlaceholder('tvCounts',$this->modx->toJSON($this->tvCounts));
  357. $this->setPlaceholder('tvMap',$this->modx->toJSON($tvMap));
  358. $this->setPlaceholder('hidden',$hidden);
  359. if (!empty($this->scriptProperties['showCheckbox'])) {
  360. $this->setPlaceholder('showCheckbox',1);
  361. }
  362. $tvOutput = $this->fetchTemplate('resource/sections/tvs.tpl');
  363. if (!empty($this->tvCounts)) {
  364. $this->setPlaceholder('tvOutput',$tvOutput);
  365. }
  366. return $tvOutput;
  367. }
  368. /**
  369. * Set token for validating a request
  370. *
  371. * @return void
  372. */
  373. public function setResourceToken() {
  374. if(!isset($_SESSION['newResourceTokens']) || !is_array($_SESSION['newResourceTokens'])) {
  375. $_SESSION['newResourceTokens'] = array();
  376. }
  377. $this->resourceArray['create_resource_token'] = uniqid('', true);
  378. $_SESSION['newResourceTokens'][] = $this->resourceArray['create_resource_token'];
  379. }
  380. /**
  381. * Fire the TV Form Render event
  382. * @return mixed
  383. */
  384. public function fireOnTVFormRender() {
  385. $onResourceTVFormPrerender = $this->modx->invokeEvent('OnResourceTVFormPrerender',array(
  386. 'resource' => $this->resource->get('id'),
  387. ));
  388. if (is_array($onResourceTVFormPrerender)) {
  389. $onResourceTVFormPrerender = implode('',$onResourceTVFormPrerender);
  390. }
  391. $this->setPlaceholder('OnResourceTVFormPrerender',$onResourceTVFormPrerender);
  392. return $onResourceTVFormPrerender;
  393. }
  394. protected function getReloadData() {
  395. $modx =& $this->modx;
  396. $scriptProperties =& $this->scriptProperties;
  397. $reloadData = array();
  398. // get reload data if reload token found in registry
  399. if (array_key_exists('reload', $scriptProperties) && !empty($scriptProperties['reload'])) {
  400. if(!isset($modx->registry)) {
  401. $modx->getService('registry', 'registry.modRegistry');
  402. }
  403. /** @var modRegistry $modx->registry */
  404. if(isset($modx->registry)) {
  405. $modx->registry->addRegister('resource_reload', 'registry.modDbRegister', array('directory' => 'resource_reload'));
  406. $this->reg = $modx->registry->resource_reload;
  407. if($this->reg->connect()) {
  408. $topic = '/resourcereload/' . $scriptProperties['reload'];
  409. $this->reg->subscribe($topic);
  410. $msgs = $this->reg->read(array('poll_limit'=> 1, 'remove_read'=> true));
  411. if(is_array($msgs)) {
  412. $reloadData = reset($msgs);
  413. }
  414. if(!is_array($reloadData)) {
  415. $reloadData = array();
  416. }
  417. $this->reg->unsubscribe($topic);
  418. }
  419. }
  420. }
  421. return $reloadData;
  422. }
  423. public function getResourceGroups() {
  424. $parentGroups = array();
  425. if ($this->resource->get('id') == 0) {
  426. $parent = $this->modx->getObject('modResource',$this->resource->get('parent'));
  427. /** @var modResource $parent */
  428. if ($parent) {
  429. $parentResourceGroups = $parent->getMany('ResourceGroupResources');
  430. /** @var modResourceGroupResource $parentResourceGroup */
  431. foreach ($parentResourceGroups as $parentResourceGroup) {
  432. $parentGroups[] = $parentResourceGroup->get('document_group');
  433. }
  434. $parentGroups = array_unique($parentGroups);
  435. }
  436. }
  437. $this->resourceArray['resourceGroups'] = array();
  438. $resourceGroups = $this->resource->getGroupsList(array('name' => 'ASC'),0,0);
  439. /** @var modResourceGroup $resourceGroup */
  440. foreach ($resourceGroups['collection'] as $resourceGroup) {
  441. $access = (boolean) $resourceGroup->get('access');
  442. if (!empty($parent) && $this->resource->get('id') == 0) {
  443. $access = in_array($resourceGroup->get('id'),$parentGroups) ? true : false;
  444. }
  445. $resourceGroupArray = array(
  446. $resourceGroup->get('id'),
  447. $resourceGroup->get('name'),
  448. $access,
  449. );
  450. $this->resourceArray['resourceGroups'][] = $resourceGroupArray;
  451. }
  452. return $this->resourceArray['resourceGroups'];
  453. }
  454. /**
  455. * Get the Help URL
  456. * @return string
  457. */
  458. public function getHelpUrl() {
  459. return 'Resources';
  460. }
  461. }