PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/symphony/lib/toolkit/class.resourcespage.php

https://github.com/nils-werner/symphony-2
PHP | 410 lines | 243 code | 55 blank | 112 comment | 50 complexity | f9579c343aa64884f09564f0217e18e9 MD5 | raw file
  1. <?php
  2. /**
  3. * @package toolkit
  4. */
  5. /**
  6. * The `ResourcesPage` abstract class controls the way "Datasource"
  7. * and "Events" index pages are displayed in the backend. It extends the
  8. * `AdministrationPage` class.
  9. *
  10. * @since Symphony 2.3
  11. * @see toolkit.AdministrationPage
  12. */
  13. require_once(TOOLKIT . '/class.administrationpage.php');
  14. require_once(TOOLKIT . '/class.resourcemanager.php');
  15. require_once(CONTENT . '/class.sortable.php');
  16. Abstract Class ResourcesPage extends AdministrationPage{
  17. /**
  18. * This method is invoked from the `Sortable` class and it contains the
  19. * logic for sorting (or unsorting) the resource index. It provides a basic
  20. * wrapper to the `ResourceManager`'s `fetch()` method.
  21. *
  22. * @see toolkit.ResourceManager#getSortingField
  23. * @see toolkit.ResourceManager#getSortingOrder
  24. * @see toolkit.ResourceManager#fetch
  25. * @param string $sort
  26. * The field to sort on which should match one of the table's column names.
  27. * If this is not provided the default will be determined by
  28. * `ResourceManager::getSortingField`
  29. * @param string $order
  30. * The direction to sort in, either 'asc' or 'desc'. If this is not provided
  31. * the value will be determined by `ResourceManager::getSortingOrder`.
  32. * @param array $params
  33. * An associative array of params (usually populated from the URL) that this
  34. * function uses. The current implementation will use `type` and `unsort` keys
  35. * @return array
  36. * An associative of the resource as determined by `ResourceManager::fetch`
  37. */
  38. public function sort(&$sort, &$order, array $params){
  39. $type = $params['type'];
  40. // If `?unsort` is appended to the URL, then sorting information are reverted
  41. // to their defaults
  42. if(isset($params['unsort'])) {
  43. ResourceManager::setSortingField($type, 'name', false);
  44. ResourceManager::setSortingOrder($type, 'asc');
  45. redirect(Administration::instance()->getCurrentPageURL());
  46. }
  47. // By default, sorting information are retrieved from
  48. // the filesystem and stored inside the `Configuration` object
  49. if(is_null($sort) && is_null($order)){
  50. $sort = ResourceManager::getSortingField($type);
  51. $order = ResourceManager::getSortingOrder($type);
  52. }
  53. // If the sorting field or order differs from what is saved,
  54. // update the config file and reload the page
  55. else if($sort != ResourceManager::getSortingField($type) || $order != ResourceManager::getSortingOrder($type)){
  56. ResourceManager::setSortingField($type, $sort, false);
  57. ResourceManager::setSortingOrder($type, $order);
  58. redirect(Administration::instance()->getCurrentPageURL());
  59. }
  60. return ResourceManager::fetch($params['type'], array(), array(), $sort . ' ' . $order);
  61. }
  62. /**
  63. * This function creates an array of all page titles in the system.
  64. *
  65. * @return array
  66. * An array of page titles
  67. */
  68. public function pagesFlatView(){
  69. $pages = PageManager::fetch(false, array('id'));
  70. foreach($pages as &$p) {
  71. $p['title'] = PageManager::resolvePageTitle($p['id']);
  72. }
  73. return $pages;
  74. }
  75. /**
  76. * This function contains the minimal amount of logic for generating the
  77. * index table of a given `$resource_type`. The table has name, source, pages
  78. * release date and author columns. The values for these columns are determined
  79. * by the resource's `about()` method.
  80. *
  81. * As Datasources types can be installed using Providers, the Source column
  82. * can be overridden with a Datasource's `getSourceColumn` method (if it exists).
  83. *
  84. * @param integer $resource_type
  85. * Either `RESOURCE_TYPE_EVENT` or `RESOURCE_TYPE_DATASOURCE`
  86. */
  87. public function __viewIndex($resource_type){
  88. $manager = ResourceManager::getManagerFromType($resource_type);
  89. $this->setPageType('table');
  90. Sortable::initialize($this, $resources, $sort, $order, array(
  91. 'type' => $resource_type,
  92. ));
  93. $columns = array(
  94. array(
  95. 'label' => __('Name'),
  96. 'sortable' => true,
  97. 'handle' => 'name'
  98. ),
  99. array(
  100. 'label' => __('Source'),
  101. 'sortable' => true,
  102. 'handle' => 'source'
  103. ),
  104. array(
  105. 'label' => __('Pages'),
  106. 'sortable' => false,
  107. ),
  108. array(
  109. 'label' => __('Release Date'),
  110. 'sortable' => true,
  111. 'handle' => 'release-date'
  112. ),
  113. array(
  114. 'label' => __('Author'),
  115. 'sortable' => true,
  116. 'handle' => 'author'
  117. )
  118. );
  119. $aTableHead = Sortable::buildTableHeaders(
  120. $columns, $sort, $order, (isset($_REQUEST['filter']) ? '&amp;filter=' . $_REQUEST['filter'] : '')
  121. );
  122. $aTableBody = array();
  123. if(!is_array($resources) || empty($resources)) {
  124. $aTableBody = array(
  125. Widget::TableRow(array(Widget::TableData(__('None found.'), 'inactive', NULL, count($aTableHead))), 'odd')
  126. );
  127. }
  128. else {
  129. foreach($resources as $r) {
  130. // Resource name
  131. $action = isset($r['can_parse']) && $r['can_parse'] === true ? 'edit' : 'info';
  132. $name = Widget::TableData(
  133. Widget::Anchor(
  134. $r['name'],
  135. SYMPHONY_URL . $_REQUEST['symphony-page'] . $action . '/' . $r['handle'] . '/',
  136. $r['handle']
  137. )
  138. );
  139. // Resource type/source
  140. if(isset($r['source'], $r['source']['id'])) {
  141. $section = Widget::TableData(
  142. Widget::Anchor(
  143. $r['source']['name'],
  144. SYMPHONY_URL . '/blueprints/sections/edit/' . $r['source']['id'] . '/',
  145. $r['source']['handle']
  146. )
  147. );
  148. }
  149. else if(isset($r['source']) && class_exists($r['source']['name']) && method_exists($r['source']['name'], 'getSourceColumn')) {
  150. $class = call_user_func(array($manager, '__getClassName'), $r['handle']);
  151. $section = Widget::TableData(call_user_func(array($class, 'getSourceColumn'), $r['handle']));
  152. }
  153. else if(isset($r['source'], $r['source']['name'])) {
  154. $section = Widget::TableData($r['source']['name']);
  155. }
  156. else {
  157. $section = Widget::TableData(__('Unknown'), 'inactive');
  158. }
  159. // Attached pages
  160. $pages = ResourceManager::getAttachedPages($resource_type, $r['handle']);
  161. $pagelinks = array();
  162. $i = 0;
  163. foreach($pages as $p) {
  164. ++$i;
  165. $pagelinks[] = Widget::Anchor(
  166. $p['title'],
  167. SYMPHONY_URL . '/blueprints/pages/edit/' . $p['id'] . '/'
  168. )->generate() . (count($pages) > $i ? (($i % 10) == 0 ? '<br />' : ', ') : '');
  169. }
  170. $pages = implode('', $pagelinks);
  171. if($pages == ''){
  172. $pagelinks = Widget::TableData(__('None'), 'inactive');
  173. }
  174. else {
  175. $pagelinks = Widget::TableData($pages, 'pages');
  176. }
  177. // Release date
  178. $releasedate = Widget::TableData(Lang::localizeDate(
  179. DateTimeObj::format($r['release-date'], __SYM_DATETIME_FORMAT__)
  180. ));
  181. // Authors
  182. $author = $r['author']['name'];
  183. if($author) {
  184. if(isset($r['author']['website'])) {
  185. $author = Widget::Anchor($r['author']['name'], General::validateURL($r['author']['website']));
  186. }
  187. else if(isset($r['author']['email'])) {
  188. $author = Widget::Anchor($r['author']['name'], 'mailto:' . $r['author']['email']);
  189. }
  190. }
  191. $author = Widget::TableData($author);
  192. $author->appendChild(Widget::Input('items[' . $r['handle'] . ']', null, 'checkbox'));
  193. $aTableBody[] = Widget::TableRow(array($name, $section, $pagelinks, $releasedate, $author));
  194. }
  195. }
  196. $table = Widget::Table(
  197. Widget::TableHead($aTableHead),
  198. NULL,
  199. Widget::TableBody($aTableBody),
  200. 'selectable'
  201. );
  202. $this->Form->appendChild($table);
  203. $tableActions = new XMLElement('div');
  204. $tableActions->setAttribute('class', 'actions');
  205. $options = array(
  206. array(NULL, false, __('With Selected...')),
  207. array('delete', false, __('Delete'), 'confirm'),
  208. );
  209. $pages = $this->pagesFlatView();
  210. $group_attach = array('label' => __('Attach to Page'), 'options' => array());
  211. $group_detach = array('label' => __('Detach from Page'), 'options' => array());
  212. $group_attach['options'][] = array('attach-all-pages', false, __('All'));
  213. $group_detach['options'][] = array('detach-all-pages', false, __('All'));
  214. foreach($pages as $p) {
  215. $group_attach['options'][] = array('attach-to-page-' . $p['id'], false, $p['title']);
  216. $group_detach['options'][] = array('detach-from-page-' . $p['id'], false, $p['title']);
  217. }
  218. $options[] = $group_attach;
  219. $options[] = $group_detach;
  220. /**
  221. * Allows an extension to modify the existing options for this page's
  222. * With Selected menu. If the `$options` parameter is an empty array,
  223. * the 'With Selected' menu will not be rendered.
  224. *
  225. * @delegate AddCustomActions
  226. * @since Symphony 2.3.2
  227. * @param string $context
  228. * '/blueprints/datasources/' or '/blueprints/events/'
  229. * @param array $options
  230. * An array of arrays, where each child array represents an option
  231. * in the With Selected menu. Options should follow the same format
  232. * expected by `Widget::__SelectBuildOption`. Passed by reference.
  233. */
  234. Symphony::ExtensionManager()->notifyMembers('AddCustomActions', $_REQUEST['symphony-page'], array(
  235. 'options' => &$options
  236. ));
  237. if(!empty($options)) {
  238. $tableActions->appendChild(Widget::Apply($options));
  239. $this->Form->appendChild($tableActions);
  240. }
  241. }
  242. /**
  243. * This function is called from the resources index when a user uses the
  244. * With Selected, or Apply, menu. The type of resource is given by
  245. * `$resource_type`. At this time the only two valid values,
  246. * `RESOURCE_TYPE_EVENT` or `RESOURCE_TYPE_DATASOURCE`.
  247. *
  248. * The function handles 'delete', 'attach', 'detach', 'attach all',
  249. * 'detach all' actions.
  250. *
  251. * @param integer $resource_type
  252. * Either `RESOURCE_TYPE_EVENT` or `RESOURCE_TYPE_DATASOURCE`
  253. */
  254. public function __actionIndex($resource_type){
  255. $manager = ResourceManager::getManagerFromType($resource_type);
  256. $checked = (is_array($_POST['items'])) ? array_keys($_POST['items']) : NULL;
  257. if (isset($_POST['action']) && is_array($_POST['action'])) {
  258. /**
  259. * Extensions can listen for any custom actions that were added
  260. * through `AddCustomPreferenceFieldsets` or `AddCustomActions`
  261. * delegates.
  262. *
  263. * @delegate CustomActions
  264. * @since Symphony 2.3.2
  265. * @param string $context
  266. * '/blueprints/datasources/' or '/blueprints/events/'
  267. * @param array $checked
  268. * An array of the selected rows. The value is usually the ID of the
  269. * the associated object.
  270. */
  271. Symphony::ExtensionManager()->notifyMembers('CustomActions', $_REQUEST['symphony-page'], array(
  272. 'checked' => $checked
  273. ));
  274. if (is_array($checked) && !empty($checked)) {
  275. if ($_POST['with-selected'] == 'delete') {
  276. $canProceed = true;
  277. foreach($checked as $handle) {
  278. $path = call_user_func(array($manager, '__getDriverPath'), $handle);
  279. if (!General::deleteFile($path)) {
  280. $folder = str_replace(DOCROOT, '', $path);
  281. $folder = str_replace('/' . basename($path), '', $folder);
  282. $this->pageAlert(
  283. __('Failed to delete %s.', array('<code>' . basename($path) . '</code>'))
  284. . ' ' . __('Please check permissions on %s', array('<code>' . $folder . '</code>'))
  285. , Alert::ERROR
  286. );
  287. $canProceed = false;
  288. }
  289. else {
  290. $pages = ResourceManager::getAttachedPages($resource_type, $handle);
  291. foreach($pages as $page) {
  292. ResourceManager::detach($resource_type, $handle, $page['id']);
  293. }
  294. }
  295. }
  296. if ($canProceed) redirect(Administration::instance()->getCurrentPageURL());
  297. }
  298. else if(preg_match('/^(at|de)?tach-(to|from)-page-/', $_POST['with-selected'])) {
  299. if (substr($_POST['with-selected'], 0, 6) == 'detach') {
  300. $page = str_replace('detach-from-page-', '', $_POST['with-selected']);
  301. foreach($checked as $handle) {
  302. ResourceManager::detach($resource_type, $handle, $page);
  303. }
  304. }
  305. else {
  306. $page = str_replace('attach-to-page-', '', $_POST['with-selected']);
  307. foreach($checked as $handle) {
  308. ResourceManager::attach($resource_type, $handle, $page);
  309. }
  310. }
  311. if($canProceed) redirect(Administration::instance()->getCurrentPageURL());
  312. }
  313. else if(preg_match('/^(at|de)?tach-all-pages$/', $_POST['with-selected'])) {
  314. $pages = PageManager::fetch(false, array('id'));
  315. if (substr($_POST['with-selected'], 0, 6) == 'detach') {
  316. foreach($checked as $handle) {
  317. foreach($pages as $page) {
  318. ResourceManager::detach($resource_type, $handle, $page['id']);
  319. }
  320. }
  321. }
  322. else {
  323. foreach($checked as $handle) {
  324. foreach($pages as $page) {
  325. ResourceManager::attach($resource_type, $handle, $page['id']);
  326. }
  327. }
  328. }
  329. redirect(Administration::instance()->getCurrentPageURL());
  330. }
  331. }
  332. }
  333. }
  334. /**
  335. * Returns the path to the component-template by looking at the
  336. * `WORKSPACE/template/` directory, then at the `TEMPLATES`
  337. * directory for the convention `*.tpl`. If the template
  338. * is not found, false is returned
  339. *
  340. * @param string $name
  341. * Name of the template
  342. * @return mixed
  343. * String, which is the path to the template if the template is found,
  344. * false otherwise
  345. */
  346. protected function getTemplate($name) {
  347. $format = '%s/%s.tpl';
  348. if(file_exists($template = sprintf($format, WORKSPACE . '/template', $name)))
  349. return $template;
  350. elseif(file_exists($template = sprintf($format, TEMPLATE, $name)))
  351. return $template;
  352. else
  353. return false;
  354. }
  355. }