resource.class.php 21 KB

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