PageRenderTime 61ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/bedita-app/controllers/frontend_controller.php

http://bedita.googlecode.com/
PHP | 2522 lines | 1710 code | 223 blank | 589 comment | 348 complexity | 1370bca25b21f13322c9b2e00f70b1a1 MD5 | raw file
Possible License(s): AGPL-1.0, AGPL-3.0, LGPL-3.0, LGPL-2.1, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*-----8<--------------------------------------------------------------------
  3. *
  4. * BEdita - a semantic content management framework
  5. *
  6. * Copyright 2008 ChannelWeb Srl, Chialab Srl
  7. *
  8. * This file is part of BEdita: you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as published
  10. * by the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. * BEdita is distributed WITHOUT ANY WARRANTY; without even the implied
  13. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. * See the GNU Lesser General Public License for more details.
  15. * You should have received a copy of the GNU Lesser General Public License
  16. * version 3 along with BEdita (see LICENSE.LGPL).
  17. * If not, see <http://gnu.org/licenses/lgpl-3.0.html>.
  18. *
  19. *------------------------------------------------------------------->8-----
  20. */
  21. /**
  22. * Frontend base class (Frontend API)
  23. *
  24. *
  25. * @version $Revision: 3921 $
  26. * @modifiedby $LastChangedBy: bato $
  27. * @lastmodified $LastChangedDate: 2012-09-03 16:14:14 +0200 (Mon, 03 Sep 2012) $
  28. *
  29. * $Id: frontend_controller.php 3921 2012-09-03 14:14:14Z bato $
  30. */
  31. if(defined('BEDITA_CORE_PATH')) {
  32. require_once (BEDITA_CORE_PATH . DS . 'bedita_exception.php');
  33. }
  34. abstract class FrontendController extends AppController {
  35. /**
  36. * object status used to filter
  37. *
  38. * @var array
  39. */
  40. private $status = array('on');
  41. /**
  42. * define which publication date has to be checked
  43. * "start" = true to check Content.start_date <= now
  44. * "end" = true to check Content.end_date >= now
  45. *
  46. * @var array
  47. */
  48. protected $checkPubDate = array("start" => true, "end" => true);
  49. /**
  50. * true to load objects in base level mode (BEObject without relations and LangText model are loaded)
  51. *
  52. * @var boolean
  53. */
  54. protected $baseLevel = false;
  55. /**
  56. * default options used to find sections' children
  57. * "showAllContents" => true to get all sections' children when a content is selected
  58. * false to get only content selected
  59. * "itemsByType" => true to divide children by type (i.e. Document, Event,....)
  60. * false to put all content type children in 'childContents' array and section type children in 'sectionChilds'
  61. * "childrenParams" => array to define special filters ('filter' array) and pagination options ("order", "dir", "dim", "page")
  62. * detail level ("detailed" => true, default false used only if "showAllContents" => true)
  63. *
  64. * @var array
  65. */
  66. protected $sectionOptions = array("showAllContents" => true, "itemsByType" => false, "childrenParams" => array());
  67. /**
  68. * set the XML format to display, possible values "tags", "attributes"
  69. *
  70. * @var string
  71. */
  72. protected $xmlFormat = "attributes";
  73. /**
  74. * current publication
  75. *
  76. * @var string
  77. */
  78. protected $publication = "";
  79. /**
  80. * default defined in captcha component
  81. *
  82. * @var array
  83. */
  84. protected $captchaOptions = array();
  85. /**
  86. * annotation options
  87. * object type => find options (filter and pagination)
  88. *
  89. * @var array
  90. */
  91. protected $annotationOptions = array("comment" => array());
  92. /**
  93. * BE obj internal cache
  94. * id => array(...)
  95. *
  96. * @var array
  97. */
  98. protected $objectCache = array();
  99. /**
  100. * tag and category options
  101. *
  102. * @var array
  103. */
  104. protected $tagOptions = array();
  105. /**
  106. * search options, attribute used on search
  107. *
  108. * @var array
  109. */
  110. protected $searchOptions = array("order" => false, "dir" => 1, "dim" => 50, "page" => 1, "filter" => false);
  111. /**
  112. * user logged in or not
  113. *
  114. * @var bool
  115. */
  116. protected $logged = false;
  117. /**
  118. * path to redirect after login action
  119. *
  120. * @var string
  121. */
  122. protected $loginRedirect = "/";
  123. /**
  124. * path to redirect after logout action
  125. *
  126. * @var string
  127. */
  128. protected $logoutRedirect = "/";
  129. /**
  130. * if it's true show unauthorized objects for user in list setting "authorized" => false in object array
  131. * else the unauthorized objects aren't in list (default)
  132. *
  133. * main objects requested are always blocked if user is not authorized to see them
  134. *
  135. * @var bool
  136. */
  137. protected $showUnauthorized = false;
  138. const UNLOGGED = "unlogged";
  139. const UNAUTHORIZED = "unauthorized";
  140. /**
  141. * set FrontendController::logged private attribute
  142. *
  143. * check if there's an active session and try to login if user not logged
  144. * - if "authorizedGroups" array defined in frontend.ini.php, user has to be in one of those groups
  145. * - if "staging" is defined only backend authorized groups are permitted
  146. * - otherwise any group is accepted
  147. *
  148. * @return mixed
  149. */
  150. protected function checkLogin() {
  151. if ($this->skipCheck) {
  152. return;
  153. }
  154. if(!$this->BeAuth->isLogged()) {
  155. if(Configure::read("staging") === true) {
  156. $frontendGroupsCanLogin = array(); // only backend authorized groups
  157. } else {
  158. // frontend only authorized groups (default empty)
  159. $confGroups = Configure::read("authorizedGroups");
  160. // which groups? authorized groups if defined, or any group
  161. $frontendGroupsCanLogin = (!empty($confGroups))? $confGroups :
  162. ClassRegistry::init("Group")->getList(array("backend_auth" => 0));
  163. }
  164. // try to login user if POST data are corrected
  165. if (!empty($this->params["form"]["login"])) {
  166. $userid = (isset($this->params["form"]["login"]["userid"])) ? $this->params["form"]["login"]["userid"] : "" ;
  167. $password = (isset($this->params["form"]["login"]["passwd"])) ? $this->params["form"]["login"]["passwd"] : "" ;
  168. if(!$this->BeAuth->login($userid, $password, null, $frontendGroupsCanLogin)) {
  169. //$this->loginEvent('warn', $userid, "login not authorized");
  170. $this->userErrorMessage(__("Wrong username/password or session expired", true));
  171. $this->logged = false;
  172. } else {
  173. $this->eventInfo("FRONTEND logged in publication");
  174. }
  175. $redirect = (!empty($this->params["form"]["backURL"]))? $this->params["form"]["backURL"] : $this->loginRedirect;
  176. $this->redirect($redirect);
  177. return true;
  178. }
  179. $this->logged = false;
  180. } else {
  181. $this->logged = true;
  182. }
  183. /*
  184. * if user is unlogged and it's a staging site OR
  185. * if user hasn't permissions to access at the publication
  186. * throws exception
  187. */
  188. if ( (!$this->logged && Configure::read("staging") === true) || ((empty($this->params["pass"][0]) || $this->params["pass"][0] != "logout") && !$this->publication["authorized"])) {
  189. $errorType = (!$this->logged)? self::UNLOGGED : self::UNAUTHORIZED;
  190. $this->accessDenied($errorType);
  191. }
  192. }
  193. /**
  194. * convienience method to do operations before login check
  195. * for example you could set FrontendController::skipCheck to true avoiding user session check
  196. */
  197. protected function beforeCheckLogin() {}
  198. /**
  199. * show login form or redirect if user is already logged
  200. *
  201. * @param string $backName nickname or id of section to go after login
  202. */
  203. protected function login($backName=null) {
  204. $urlToGo = (!empty($backName))? Router::url('/'. $backName, true) : $this->loginRedirect;
  205. if ($this->isLogged()) {
  206. $this->redirect($urlToGo);
  207. }
  208. $this->accessDenied(self::UNLOGGED);
  209. }
  210. /**
  211. * perform logout operation
  212. *
  213. * @param boolean $autoRedirect
  214. */
  215. protected function logout($autoRedirect=true) {
  216. $this->BeAuth->logout();
  217. $this->eventInfo("FRONTEND logged out: publication " . $this->publication["title"]);
  218. if ($autoRedirect) {
  219. $this->redirect($this->logoutRedirect);
  220. }
  221. }
  222. /**
  223. * manage access denied. If you want another behavior override it in pages_controller
  224. *
  225. * user unlogged: render login view (if user doesn't arrive from login page set info message)
  226. * user unauthorized to access that item: render unauthorized view (set error message)
  227. *
  228. * for other custom type will try to render a view with $type name
  229. * (i.e. $type="access_denied" render views/pages/access_denied.[tpl|ctp] template)
  230. *
  231. * @param string $type, which type of access denied
  232. * @throws BeditaFrontAccessException
  233. */
  234. protected function accessDenied($type) {
  235. if ($type == self::UNLOGGED && !strstr($this->here,"/login")) {
  236. $message = __("You have to be logged to access that item",true);
  237. $this->userInfoMessage($message);
  238. } elseif ($type == self::UNAUTHORIZED) {
  239. $message = __("You aren't authorized to access that item",true);
  240. $this->userErrorMessage($message);
  241. }
  242. throw new BeditaFrontAccessException(null, array("errorType" => $type));
  243. }
  244. /**
  245. * get private logged var
  246. *
  247. * @return boolean
  248. */
  249. protected function isLogged() {
  250. return $this->logged;
  251. }
  252. /**
  253. * called before action to initialize
  254. * $uses & $components array don't work... (abstract class ??)
  255. *
  256. * @throws BeditaPublicationException
  257. * @see bedita-app/AppController#initAttributes()
  258. */
  259. final protected function initAttributes() {
  260. if(!isset($this->BEObject)) {
  261. $this->BEObject = $this->loadModelByType('BEObject');
  262. }
  263. if(!isset($this->Section)) {
  264. $this->Section = $this->loadModelByType('Section');
  265. }
  266. if(!isset($this->Stream)) {
  267. $this->Stream = $this->loadModelByType('Stream');
  268. }
  269. if(!isset($this->BeLangText)) {
  270. App::import('Component', 'BeLangText');
  271. $this->BeLangText = new BeLangTextComponent();
  272. }
  273. if(!isset($this->Tree)) {
  274. $this->Tree = $this->loadModelByType('Tree');
  275. }
  276. $conf = Configure::getInstance() ;
  277. if (!empty($conf->draft))
  278. $this->status[] = "draft";
  279. // check publication status
  280. $pubStatus = $this->BEObject->field("status", array("id" => Configure::read("frontendAreaId")));
  281. if ($pubStatus != "on") {
  282. $statusSaved = $this->status;
  283. $this->status = array('on', 'off', 'draft');
  284. $this->publication = $this->loadObj(Configure::read("frontendAreaId"), false);
  285. $this->status = $statusSaved;
  286. $this->set('publication', $this->publication);
  287. if (Configure::read("draft") == false or ($pubStatus == "off")) {
  288. throw new BeditaPublicationException("Publication not ON", array("layout" => $pubStatus));
  289. }
  290. }
  291. $this->publication = $this->loadObj(Configure::read("frontendAreaId"),false);
  292. // set publication data for template
  293. $this->set('publication', $this->publication);
  294. // set filterPublicationDate
  295. $filterPubDate = Configure::read("filterPublicationDate");
  296. if (isset($filterPubDate)) {
  297. if (is_array($filterPubDate)) {
  298. $this->checkPubDate = $filterPubDate;
  299. } elseif ($filterPubDate === true) {
  300. $this->checkPubDate = array("start" => true, "end" => true);
  301. } elseif ($filterPubDate === false) {
  302. $this->checkPubDate = array("start" => false, "end" => false);
  303. }
  304. }
  305. $this->historyItem["area_id"] = $this->publication["id"];
  306. $this->beforeCheckLogin();
  307. }
  308. /**
  309. * override AppController::setupLocale. Used setup specific locale
  310. *
  311. * @see bedita-app/AppController#setupLocale()
  312. */
  313. protected function setupLocale() {
  314. $this->currLang = $this->Session->read('Config.language');
  315. $conf = Configure::getInstance();
  316. if($this->currLang === null || empty($this->currLang)) {
  317. if (isset($conf->cookieName["langSelect"])) {
  318. $lang = $this->Cookie->read($conf->cookieName["langSelect"]);
  319. }
  320. if(!empty($lang) && array_key_exists($lang, $conf->frontendLangs)) {
  321. $this->currLang = $lang;
  322. } else {
  323. // HTTP autodetect
  324. $l10n = new L10n();
  325. $l10n->get();
  326. $lang = $l10n->lang;
  327. if(!empty($lang)) {
  328. if(array_key_exists($lang, $conf->frontendLangs)) {
  329. $this->currLang = $lang;
  330. } else if (!empty($conf->frontendLangsMap[$lang])) {
  331. $lang = $conf->frontendLangsMap[$lang];
  332. if(array_key_exists($lang, $conf->frontendLangs)) {
  333. $this->currLang = $lang;
  334. }
  335. }
  336. }
  337. if(empty($this->currLang)) {
  338. $this->currLang = $conf->frontendLang;
  339. }
  340. }
  341. $this->Session->write('Config.language', $this->currLang);
  342. Configure::write('Config.language', $this->currLang);
  343. }
  344. $this->set('currLang', $this->currLang);
  345. if(isset( $conf->locales[$this->currLang])) {
  346. $this->currLocale = setlocale(LC_ALL, $conf->locales[$this->currLang]);
  347. } else {
  348. $this->currLocale = setlocale(LC_ALL, '');
  349. }
  350. $this->set('currLocale', $this->currLocale);
  351. if(isset( $conf->datePatternLocale[$this->currLang])) {
  352. Configure::write('datePattern', $conf->datePatternLocale[$this->currLang]);
  353. }
  354. if(isset( $conf->dateTimePatternLocale[$this->currLang])) {
  355. Configure::write('dateTimePattern', $conf->dateTimePatternLocale[$this->currLang]);
  356. }
  357. $dateFormatValidation = $conf->datePattern;
  358. $dateFormatValidation = preg_replace(array("/%d/", "/%m/", "/%Y/"), array("dd","mm","yyyy"), $dateFormatValidation);
  359. Configure::write('dateFormatValidation', $dateFormatValidation);
  360. }
  361. /**
  362. * change language
  363. *
  364. * @param string $lang
  365. * @param string $forward redirect action after changing language. If it's null redirect to refere
  366. * @return string
  367. * @throws BeditaException
  368. */
  369. public function lang($lang, $forward = null) {
  370. if (empty($lang)) {
  371. throw new BeditaException("No lang selected");
  372. }
  373. $conf = Configure::getInstance();
  374. if (!array_key_exists($lang, $conf->frontendLangs)) {
  375. throw new BeditaException("wrong lang selected: ".$lang);
  376. }
  377. $this->Session->write('Config.language', $lang);
  378. $this->Cookie->write($conf->cookieName["langSelect"], $lang, false, '+350 day');
  379. $this->currLang = $lang;
  380. if(!empty($forward)) {
  381. if (substr($forward, 0, 5) != "http:") {
  382. if (strpos("/", $forward) != 1)
  383. $forward = "/" . $forward;
  384. if (!empty($this->params["pass"][2])) {
  385. $forward .= "/" . implode("/", array_slice($this->params["pass"],2));
  386. }
  387. }
  388. $this->redirect($forward);
  389. } else {
  390. $this->redirect($this->referer());
  391. }
  392. }
  393. /**
  394. * check if current date is compatible with required pubblication dates (start/end date)
  395. *
  396. * @param array $obj
  397. * @return boolean, true if content may be published, false otherwise
  398. */
  399. protected function checkPubblicationDate(array $obj) {
  400. $currDate = strftime("%Y-%m-%d");
  401. if(isset($obj["start_date"]) && $this->checkPubDate["start"]) {
  402. if(strncmp($currDate, $obj["start_date"], 10) < 0)
  403. return false;
  404. }
  405. if(isset($obj["end_date"]) && $this->checkPubDate["end"]) {
  406. if(strncmp($currDate, $obj["end_date"], 10) > 0)
  407. return false;
  408. }
  409. return true;
  410. }
  411. /**
  412. * handle Exceptions
  413. *
  414. * @param Exception $ex
  415. * @return AppError
  416. */
  417. public static function handleExceptions(Exception $ex) {
  418. if ($ex instanceof BeditaPublicationException) {
  419. $currentController = AppController::currentController();
  420. echo $currentController->render(false, $ex->getLayout());
  421. } elseif ($ex instanceof BeditaFrontAccessException) {
  422. $errorType = $ex->getErrorType();
  423. $params = array(
  424. 'details' => $ex->getDetails(),
  425. 'msg' => $ex->getMessage(),
  426. 'result' => $ex->result,
  427. 'errorType' => $ex->getErrorType()
  428. );
  429. include_once (APP . 'app_error.php');
  430. return new AppError('handleExceptionFrontAccess', $params, $ex->errorTrace());
  431. } elseif ($ex instanceof BeditaRuntimeException) {
  432. include_once (APP . 'app_error.php');
  433. return new AppError('handleExceptionRuntime',
  434. array('details' => $ex->getDetails(), 'msg' => $ex->getMessage(),
  435. 'result' => $ex->result), $ex->errorTrace());
  436. } elseif ($ex instanceof SmartyException) {
  437. include_once (APP . 'app_error.php');
  438. $trace = $ex->getFile()." - line: ". $ex->getLine()." \nTrace:\n". $ex->getTraceAsString();
  439. return new AppError('handleExceptionRuntime', array('msg' => $ex->getMessage(), 'details' => ''), $trace);
  440. } else {
  441. if($ex instanceof BeditaException) {
  442. $errTrace = $ex->errorTrace();
  443. $details = $ex->getDetails();
  444. $result = $ex->result;
  445. } else {
  446. $errTrace = get_class($ex)." - ". $ex->getMessage().
  447. "\nFile: ".$ex->getFile()." - line: ".$ex->getLine()."\nTrace:\n".$ex->getTraceAsString();
  448. $details = "";
  449. $result = "";
  450. }
  451. include_once (APP . 'app_error.php');
  452. return new AppError('handleExceptionFrontend',
  453. array('details' => $details, 'msg' => $ex->getMessage(),
  454. 'result' => $result), $errTrace);
  455. }
  456. }
  457. /**
  458. * handle error, logging if log level is 'debug'
  459. *
  460. * @see bedita-app/AppController#handleError()
  461. */
  462. public function handleError($eventMsg, $userMsg, $errTrace) {
  463. if(Configure::read('debug') > 0) {
  464. $this->log($errTrace);
  465. }
  466. }
  467. /**
  468. * Get tree starting from specified section or area
  469. *
  470. * @param string|int $parentName parent nickname or id
  471. * @param boolean $loadContents if it's true load all contents too. Default false
  472. * @param array $exclude_nicknames list exclude sections
  473. * @param int $depth tree's depth level (default=null => all levels)
  474. * @return array
  475. * */
  476. protected function loadSectionsTree($parentName, $loadContents = false, array $exclude_nicknames = array(), $depth = null, $flatMode = false) {
  477. $conf = Configure::getInstance();
  478. $parent_id = is_numeric($parentName) ? $parentName: $this->BEObject->getIdFromNickname($parentName);
  479. $result = array();
  480. $filter["object_type_id"] = $conf->objectTypes['section']["id"];
  481. if (empty($parent_id)) {
  482. throw new BeditaException(__("Error loading sections tree. Missing parent" . ": " . $parentName, true));
  483. }
  484. $sections = $this->BeTree->getChildren($parent_id, $this->status, $filter, "priority");
  485. foreach ($sections['items'] as $s) {
  486. if(!empty($exclude_nicknames) && in_array($s['nickname'], $exclude_nicknames)) {
  487. continue;
  488. }
  489. $sectionObject = $this->loadObj($s['id']);
  490. if ($sectionObject !== self::UNLOGGED && $sectionObject !== self::UNAUTHORIZED) {
  491. $resultSections = array();
  492. $resultObjects = array();
  493. $this->setCanonicalPath($sectionObject);
  494. if($loadContents) {
  495. $option = array("filter" => array("object_type_id" => Configure::read("objectTypes.leafs.id")));
  496. $objs = $this->loadSectionObjects($s['id'], $option);
  497. $resultObjects = (!$this->sectionOptions["itemsByType"] && !empty($objs["childContents"]))? $objs["childContents"] : $objs;
  498. }
  499. if ($depth === null || $depth > 1) {
  500. $innerDepth = ($depth === null) ? null : $depth-1;
  501. $resultSections = $this->loadSectionsTree($s['id'], $loadContents, $exclude_nicknames, $innerDepth, $flatMode);
  502. }
  503. if(!$flatMode) {
  504. if(!empty($resultObjects)) {
  505. $sectionObject['objects'] = $resultObjects;
  506. }
  507. if(!empty($resultSections)) {
  508. $sectionObject['sections'] = $resultSections;
  509. }
  510. $result[] = $sectionObject;
  511. } else {
  512. $result[] = $sectionObject;
  513. if(!empty($resultSections)) {
  514. $result = array_merge($result, $resultSections);
  515. }
  516. if(!empty($resultObjects)) {
  517. $result = array_merge($result, $resultObjects);
  518. }
  519. }
  520. }
  521. }
  522. return $result;
  523. }
  524. /**
  525. * Set canonical path in object data array, check parent authorization
  526. * - $obj["canonicalPath"] will contain new caclulated canonical path
  527. * - update $this->objectCache
  528. * - setup $obj["parentAuthorized"]
  529. * - setup $obj["pathSection"] for sections
  530. *
  531. * @param array $obj, containing at least "id" and "nickname"
  532. */
  533. protected function setCanonicalPath(array &$obj) {
  534. $objectId = $obj["id"];
  535. if(isset($this->objectCache[$objectId]["canonicalPath"]) &&
  536. isset($this->objectCache[$objectId]["parentAuthorized"])) {
  537. $obj["canonicalPath"] = $this->objectCache[$objectId]["canonicalPath"];
  538. $obj["parentAuthorized"] = $this->objectCache[$objectId]["parentAuthorized"];
  539. return;
  540. }
  541. if($obj["object_type_id"] == Configure::read("objectTypes.area.id")) {
  542. $obj["canonicalPath"] = "/";
  543. $obj["parentAuthorized"] = $obj["authorized"];
  544. return;
  545. }
  546. $pathSection = $this->getPath($objectId);
  547. if($obj["object_type_id"] == Configure::read("objectTypes.section.id")) {
  548. $obj["pathSection"] = $pathSection;
  549. }
  550. $parentAuthorized = true;
  551. foreach ($pathSection as $ps) {
  552. if ($parentAuthorized && !empty($ps["authorized"]) && !$ps["authorized"]) {
  553. $parentAuthorized = false;
  554. }
  555. }
  556. $obj["parentAuthorized"] = $parentAuthorized;
  557. $canPath = "";
  558. if(!empty($pathSection)) {
  559. $parentSec = end($pathSection);
  560. $canPath = $parentSec["canonicalPath"];
  561. }
  562. $canPath .= (($canPath === "/") ? "" : "/");
  563. $menu = true;
  564. if($obj["object_type_id"] == Configure::read("objectTypes.section.id")) {
  565. $menu = !isset($obj["menu"]) ? true : (($obj["menu"] === '0') ? false : true);
  566. }
  567. if($menu) {
  568. $canPath .= $obj["nickname"];
  569. }
  570. $obj["canonicalPath"] = $canPath;
  571. if(isset($this->objectCache[$objectId])) {
  572. $this->objectCache[$objectId]["canonicalPath"] = $canPath;
  573. $this->objectCache[$objectId]["parentAuthorized"] = $parentAuthorized;
  574. }
  575. return;
  576. }
  577. /**
  578. * Get sections levels
  579. *
  580. * Find all ancestors from secName and build an array of levels
  581. * Each key in array returned is a level:
  582. * 0 is the first level
  583. * 1 is the second level
  584. * etc...
  585. *
  586. * set selected = true in a section if it's an ancestor (parent) of $secName
  587. *
  588. * @param string $secName nickname or section id
  589. * @param boolean $loadContents true meaning it loads all contents of each section
  590. * @param array $exclude_nicknames list exclude sections
  591. *
  592. * @return array of level selected
  593. */
  594. protected function loadSectionsLevels($secName, $loadContents=false, array $exclude_nicknames=null) {
  595. $conf = Configure::getInstance();
  596. $result = array();
  597. $section_id = is_numeric($secName) ? $secName : $this->BEObject->getIdFromNickname($secName);
  598. $path = $this->Tree->field("object_path", array("id" => $section_id));
  599. $parents = explode("/", trim($path,"/"));
  600. $level = 0;
  601. $filter["object_type_id"] = $conf->objectTypes['section']["id"];
  602. foreach ($parents as $p_id) {
  603. $sections = $this->BeTree->getChildren($p_id, $this->status, $filter, "priority");
  604. foreach ($sections["items"] as $s) {
  605. if(!empty($exclude_nicknames) && in_array($s['nickname'], $exclude_nicknames))
  606. continue ;
  607. $sectionObject = $this->loadObj($s['id']);
  608. if ($sectionObject !== self::UNLOGGED && $sectionObject !== self::UNAUTHORIZED) {
  609. if (in_array($s["id"], $parents)) {
  610. $sectionObject["selected"] = true;
  611. }
  612. if($loadContents) {
  613. $option = array("filter" => array("object_type_id" => Configure::read("objectTypes.leafs.id")));
  614. $objs = $this->loadSectionObjects($s['id'], $option);
  615. $sectionObject['objects'] = (!$this->sectionOptions["itemsByType"] && !empty($objs["childContents"]))? $objs["childContents"] : $objs;
  616. }
  617. $result[$level][] = $sectionObject;
  618. }
  619. }
  620. $level++;
  621. }
  622. return $result;
  623. }
  624. /**
  625. * load all publications
  626. *
  627. * @param string $tplVar, var name for template.
  628. * If not defined result will be set to "publicationsList" var
  629. *
  630. */
  631. protected function loadPublications($tplVar=null) {
  632. $publications = array();
  633. $filter = array("object_type_id" => Configure::read("objectTypes.area.id"));
  634. $res = $this->BEObject->findObjects(null, null, $this->status, $filter);
  635. if (!empty($res["items"])) {
  636. foreach ($res["items"] as $pub) {
  637. $obj = $this->loadObj($pub["id"]);
  638. if ($obj !== self::UNLOGGED && $obj !== self::UNAUTHORIZED)
  639. $publications[] = $obj;
  640. }
  641. }
  642. $tplVar = (!empty($tplVar))? $tplVar : "publicationsList";
  643. $this->set($tplVar, $publications);
  644. }
  645. /**
  646. * find first active section and load it as home page section
  647. * if any section was found load publication as home page section
  648. */
  649. public function homePage() {
  650. $filter = array("object_type_id" => Configure::read("objectTypes.section.id"));
  651. $child = $this->BeTree->getChildren($this->publication["id"], $this->getStatus(), $filter, null, true, 1, 1);
  652. $homePageSectionId = (empty($child["items"]))? $this->publication["id"] : $child["items"][0]["id"];
  653. $this->action = 'section';
  654. $this->section($homePageSectionId);
  655. }
  656. /**
  657. * prepare an XML containing sitemap specification
  658. * view in bedita-app/views/pages/sitemap_xml.tpl
  659. */
  660. public function sitemapXml() {
  661. $this->sitemap(true);
  662. $this->layout = null;
  663. $this->view = "Smarty";
  664. header("Content-type: text/xml; charset=utf-8");
  665. }
  666. /**
  667. * build array for sitemap
  668. *
  669. * @param boolean $xml_out
  670. * @return array
  671. */
  672. public function sitemap($xml_out = false) {
  673. $conf = Configure::getInstance() ;
  674. $extract_all = (!empty($conf->sitemapAllContent)) ? $conf->sitemapAllContent : false;
  675. $itemsByType = $this->sectionOptions["itemsByType"];
  676. $this->sectionOptions["itemsByType"] = false;
  677. $flatMode = $xml_out? true : false;
  678. $sectionsTree = $this->loadSectionsTree($conf->frontendAreaId,$extract_all, null, 10000, $flatMode) ;
  679. $this->sectionOptions["itemsByType"] = $itemsByType;
  680. if($xml_out) {
  681. $pubMap = array();
  682. $pubMap['loc'] = $this->publication["public_url"];
  683. $pubMap['lastmod'] = !empty($this->publication['last_modified']) ?
  684. substr($this->publication["last_modified"], 0, 10) : substr($this->publication["modified"], 0, 10);
  685. $pubMap['priority'] = !empty($this->publication['map_priority']) ?
  686. $this->publication['map_priority'] : null;
  687. $pubMap['changefreq'] = !empty($this->publication['map_changefreq']) ?
  688. $this->publication['map_changefreq'] : null;
  689. $urlset[] = $pubMap;
  690. if($extract_all) {
  691. $option = array("filter" => array("object_type_id" => Configure::read("objectTypes.leafs.id")),
  692. "sectionPath" => "");
  693. $objs = $this->loadSectionObjects($conf->frontendAreaId, $option);
  694. $resultObjects = (!$this->sectionOptions["itemsByType"] && !empty($objs["childContents"]))? $objs["childContents"] : $objs;
  695. if(!empty($resultObjects)) {
  696. $sectionsTree = array_merge($resultObjects, $sectionsTree);
  697. }
  698. }
  699. $i = count($urlset);
  700. $sectionModel = ClassRegistry::init("Section");
  701. foreach($sectionsTree as $v) {
  702. $urlset[$i] = array();
  703. $urlset[$i]['loc'] = $this->publication["public_url"]. $v['canonicalPath'];
  704. if($v['object_type_id'] == $conf->objectTypes["section"]["id"]) {
  705. $secFields = $sectionModel->find("first",
  706. array("conditions" => array("id"=>$v["id"]), "contain" => array()));
  707. if(!empty($secFields['last_modified'])) {
  708. $urlset[$i]['lastmod'] = substr($secFields['last_modified'], 0, 10);
  709. } else {
  710. $urlset[$i]['lastmod'] = substr($v["modified"], 0, 10);
  711. }
  712. if(!empty($secFields['map_priority'])) {
  713. $urlset[$i]['priority'] = $secFields['map_priority'];
  714. }
  715. if(!empty($secFields['map_changefreq'])) {
  716. $urlset[$i]['changefreq'] = $secFields['map_changefreq'];
  717. }
  718. } else {
  719. $urlset[$i]['lastmod'] = substr($v["modified"], 0, 10);
  720. }
  721. $urlset[$i]['menu'] = $v["menu"];
  722. $i++;
  723. }
  724. $this->set('urlset',$urlset);
  725. } else {
  726. if(!in_array('BeTree', $this->helpers)) {
  727. $this->helpers[] = 'BeTree';
  728. }
  729. }
  730. $this->set('sections_tree',$sectionsTree);
  731. }
  732. /**
  733. * Publish RSS feed with contents inside section $sectionName
  734. * Use callback controller methods (if defined):
  735. * - $sectionName."RssChannel" to fetch channel data
  736. * - $sectionName."RssItems" to fetch rss items
  737. *
  738. * If callbacks methods are not defined (default) load section and object data
  739. * and build rss data with defaults
  740. *
  741. * @param string $sectionName, section's nickname/unique name
  742. */
  743. public function rss($sectionName) {
  744. $channel = array();
  745. $s = array();
  746. // fetch channel data, use $sectionName."RssChannel" method if exists
  747. $methodName = $sectionName . "RssChannel";
  748. if (method_exists($this, $methodName)) {
  749. $channel = $this->{$methodName}();
  750. } else {
  751. // build channel data from section
  752. $s = $this->loadObjByNick($sectionName);
  753. if ($s === self::UNLOGGED || $s === self::UNAUTHORIZED) {
  754. $this->accessDenied($s);
  755. }
  756. if($s['syndicate'] === "off") {
  757. throw new BeditaException(__("Content not found", true));
  758. }
  759. $this->setCanonicalPath($s);
  760. App::import("Sanitize");
  761. $title = Sanitize::html($this->publication["public_name"] . " - " . $s['title']);
  762. $channel = array( 'title' => $title,
  763. 'link' => $s["canonicalPath"],
  764. 'description' => Sanitize::html($s['description']),
  765. 'language' => $s['lang'],
  766. );
  767. }
  768. $this->set('channelData', $channel);
  769. // fetch rss items, use
  770. $rssItems = array();
  771. $methodName = $sectionName . "RssItems";
  772. // check before filter method
  773. if (method_exists($this, $methodName)) {
  774. $rssItems = $this->{$methodName}();
  775. } else {
  776. if(empty($s)) { // if channel data has been redefined
  777. $s = $this->loadObjByNick($sectionName);
  778. $this->setCanonicalPath($s);
  779. }
  780. $items = $this->BeTree->getChildren($s['id'], $this->status, false, "priority", ($s['priority_order']=="asc"), 1, 40);
  781. if(!empty($items) && !empty($items['items'])) {
  782. foreach($items['items'] as $index => $item) {
  783. $obj = $this->loadObj($item['id']);
  784. if ($obj !== self::UNLOGGED && $obj !== self::UNAUTHORIZED) {
  785. $rssItems[] = $this->buildRssItem($obj, $s['canonicalPath']);
  786. }
  787. }
  788. }
  789. }
  790. $this->set('items', $rssItems);
  791. $this->view = 'View';
  792. // add RSS helper if not present
  793. if(!in_array('Rss', $this->helpers)) {
  794. $this->helpers[] = 'Rss';
  795. }
  796. $this->layout = NULL;
  797. header("Content-type: text/xml; charset=utf-8");
  798. }
  799. /**
  800. * Build a single RSS item from a BE object array
  801. * If section "canonicalPath" is set, links are created with it
  802. * If not: use object canonicalPath if present, otherwise object unique name (nickname)
  803. *
  804. * @param array $obj
  805. * @param string $canonicalPath
  806. * @return array
  807. */
  808. protected function buildRssItem(array &$obj, $canonicalPath = null) {
  809. $description = $obj['description'];
  810. if (!empty($obj['abstract'])) {
  811. $description .= "<hr/>" . $obj['abstract'];
  812. }
  813. if (!empty($obj['body'])) {
  814. $description .= "<hr/>" . $obj['body'];
  815. }
  816. $link = !empty($canonicalPath) ? ($canonicalPath ."/". $obj['nickname']) :
  817. (!empty($obj['canonicalPath']) ? $obj['canonicalPath'] : $obj['nickname']);
  818. return array( 'title' => $obj['title'], 'description' => $description,
  819. 'pubDate' => $obj['created'], 'link' => $link);
  820. }
  821. /**
  822. * output a kml defined by a section
  823. * @param string $sectionName
  824. */
  825. public function kml($sectionName) {
  826. $this->section($sectionName);
  827. $this->layout = 'ajax';
  828. header("Content-type: application/vnd.google-earth.kml+xml");
  829. header("Content-Disposition: attachment; filename=" . $sectionName . ".kml");
  830. }
  831. /**
  832. * output a georss atom representation of section
  833. * @param string $sectionName
  834. */
  835. public function georssatom($sectionName) {
  836. $this->section($sectionName);
  837. $this->layout = 'ajax';
  838. header("Content-type: application/atom+xml; charset=utf-8");
  839. }
  840. /**
  841. * output a georss representation of section
  842. * @param string $sectionName
  843. */
  844. public function georss($sectionName) {
  845. $gml = (!empty($this->params['named']['gml']));
  846. $this->section($sectionName);
  847. $s = $this->viewVars["section"];
  848. $channel = array( 'title' => $this->publication["public_name"] . " - " . $s['title'] ,
  849. 'link' => "/section/".$sectionName,
  850. 'description' => $s['description'],
  851. 'language' => $s['lang'],
  852. );
  853. $this->set('channelData', $channel);
  854. $rssItems = array();
  855. $items = $s['childContents'];
  856. if(!empty($items)) {
  857. foreach($items as $index => $obj) {
  858. $description = $obj['description'];
  859. $description .= (!empty($obj['abstract']) && !empty($description))? "<hr/>" . $obj['abstract'] : $obj['abstract'];
  860. $description .= (!empty($obj['body']) && !empty($description))? "<hr/>" . $obj['body'] : $obj['body'];
  861. if(!empty($obj['GeoTag'][0]['latitude']) && !empty($obj['GeoTag'][0]['longitude'])) {
  862. $position = $obj['GeoTag'][0]['latitude'] . ' ' . $obj['GeoTag'][0]['longitude'];
  863. $item = array('item' => array(
  864. 'title' => $obj['title'],
  865. 'description' => $description,
  866. 'pubDate' => $obj['created'],
  867. 'link' => $s['canonicalPath']."/".$obj['nickname']
  868. ));
  869. if($gml) { // geoRss GML
  870. $item['georss:where'] = array(
  871. 0 => array(
  872. 'gml:Point' => array(
  873. 0 => array(
  874. 'gml:pos' => $position
  875. )
  876. )
  877. )
  878. );
  879. } else { // geoRss simple
  880. $item['georss:point'] = $position;
  881. }
  882. $rssItems[] = $item;
  883. }
  884. }
  885. }
  886. $this->set('items', array($rssItems));
  887. $attrib = array(
  888. "version" => "2.0",
  889. "xmlns:georss" => "http://www.georss.org/georss",
  890. "xmlns:gml" => "http://www.opengis.net/gml"
  891. );
  892. $this->set('attrib',$attrib);
  893. $this->view = 'View';
  894. // add RSS helper if not present
  895. if(!in_array('Rss', $this->helpers)) {
  896. $this->helpers[] = 'Rss';
  897. }
  898. $this->layout = NULL;
  899. header("Content-type: application/text+xml; charset=utf-8");
  900. }
  901. /**
  902. * output a json object of returned array by section or content method
  903. * @param string $name
  904. * @return string|int $name, nickname or id
  905. */
  906. public function json($name) {
  907. $this->route($name);
  908. header("Content-Type: application/json");
  909. $this->view = 'View';
  910. $this->layout = null;
  911. $this->action = "json";
  912. $this->set("data", $this->viewVars["section"]);
  913. }
  914. /**
  915. * output an xml of returned array by section or content method
  916. *
  917. * passing a "format" named parameters in the url obtain an xml "attributes" format or an xml "tags" format
  918. * i.e. http://www.example.com/xml/nickname/format:tags output a tag style xml
  919. * default is defined by class attribute xmlFormat
  920. *
  921. * @param string|int $name, nickname or id
  922. */
  923. public function xml($name) {
  924. $this->route($name);
  925. $this->outputXML(array("section" => $this->viewVars["section"]));
  926. }
  927. /**
  928. * output an xml of returned array by loadObj/loadObjByNick method
  929. *
  930. * passing a "format" named parameters in the url obtain an xml "attributes" format or an xml "tags" format
  931. * i.e. http://www.example.com/xmlobject/nickname/format:tags output a tag style xml
  932. * default is defined by class attribute xmlFormat
  933. *
  934. * @param string|int $name, nickname or id
  935. */
  936. public function xmlobject($name) {
  937. $object = (is_numeric($name))? $this->loadObj($name) : $this->loadObjByNick($name);
  938. if ($object === self::UNLOGGED || $object === self::UNAUTHORIZED) {
  939. $this->accessDenied($object);
  940. }
  941. $this->outputXML(array("object" => $object));
  942. }
  943. /**
  944. * prepare to XML output
  945. *
  946. * @param array $data
  947. */
  948. private function outputXML($data) {
  949. $this->RequestHandler->setContent("xml", "text/xml");
  950. $this->RequestHandler->respondAs("xml", array("charset" => "utf-8"));
  951. $this->RequestHandler->renderAs($this, "xml");
  952. $availableFormat = array("attributes", "tags");
  953. if (!empty($this->passedArgs["format"]) && in_array($this->passedArgs["format"],$availableFormat)) {
  954. $options = array("format" => $this->passedArgs["format"]);
  955. } else {
  956. $options = array("format" => $this->xmlFormat);
  957. }
  958. $this->set("options", $options);
  959. $this->set("data", $data);
  960. $this->action = "xml";
  961. $this->view = 'View';
  962. }
  963. /**
  964. * Like loadObj using nickname
  965. *
  966. * @param string $obj_nick
  967. * @param boolean $blockAccess see FrontendController::loadObj()
  968. * @return array
  969. */
  970. protected function loadObjByNick($obj_nick, $blockAccess = true) {
  971. return $this->loadObj($this->BEObject->getIdFromNickname($obj_nick), $blockAccess);
  972. }
  973. /**
  974. * Like loadAndSetObj using nickname
  975. *
  976. * @param string $obj_nick
  977. * @param string $var_name view var name
  978. * @param boolean $blockAccess see FrontendController::loadObj()
  979. * @return array
  980. */
  981. protected function loadAndSetObjByNick($obj_nick, $var_name = null, $blockAccess = true) {
  982. return $this->loadAndSetObj($this->BEObject->getIdFromNickname($obj_nick) , $var_name, $blockAccess);
  983. }
  984. /**
  985. * Load bedita Object and set view var with $var_name or object type (e.g. "Document", "Event"..)
  986. * Returns object loaded
  987. * Throws Exception on errors
  988. *
  989. * @param int $obj_id
  990. * @param string $var_name view var name
  991. * @param boolean $blockAccess see FrontendController::loadObj()
  992. * @return array
  993. */
  994. protected function loadAndSetObj($obj_id, $var_name = null, $blockAccess = true) {
  995. $obj = $this->loadObj($obj_id, $blockAccess);
  996. if ($obj === self::UNLOGGED || $obj == self::UNAUTHORIZED) {
  997. return $obj;
  998. }
  999. $this->set((isset($var_name)? $var_name: $obj['object_type']),$obj);
  1000. return true;
  1001. }
  1002. /**
  1003. * set model bindings for BEdita object
  1004. *
  1005. * @param string $modelType model name of BE object
  1006. * @return array that contains:
  1007. * "bindings_used" => multidimensional array of bindings used,
  1008. * "bindings_list" => one dimensional array with the simple list of bindings ordered using a "natural order" algorithm
  1009. *
  1010. */
  1011. protected function setObjectBindings($modelType) {
  1012. if(!isset($this->{$modelType})) {
  1013. $this->{$modelType} = $this->loadModelByType($modelType);
  1014. }
  1015. if (!$this->baseLevel) {
  1016. $bindingsUsed = $this->modelBindings($this->{$modelType}, "frontend");
  1017. } else {
  1018. $bindingsUsed = array("BEObject" => array("LangText"));
  1019. if ($modelType == "Section") {
  1020. $bindingsUsed[] = "Tree";
  1021. }
  1022. $this->{$modelType}->contain($bindingsUsed);
  1023. }
  1024. $listOfBindings = BeLib::getInstance()->arrayValues($bindingsUsed, true);
  1025. natsort($listOfBindings);
  1026. return array("bindings_used" => $bindingsUsed, "bindings_list" => $listOfBindings);
  1027. }
  1028. /**
  1029. * Returns bedita Object
  1030. * Throws Exception on errors
  1031. *
  1032. * @param int $obj_id
  1033. * @param boolean $blockAccess
  1034. * if it's set a "frontend_access_without_block" permission on the object this param is ignored
  1035. * and the object returned (array) will have a key named "authorized" set to true or false
  1036. * depending on whether the user has permission to access at the object
  1037. * else if it's set a "frontend_access_with_block" permission on the object
  1038. * true => if user is unlogged return UNLOGGED constant
  1039. * if user is logged and he hasn't permission to access at the object return UNAUTHORIZED constant
  1040. * false => if user unlogged dosen't block the action and the object returned (array)
  1041. * will have a key named "authorized" set to false
  1042. * if user is logged but not authorized the object returned (array)
  1043. *
  1044. * note: if FrontendController::showUnauthorized is set to true and the user is logged
  1045. * then all unauthorized object will have set "authorized" to false regardless object permission
  1046. *
  1047. * @return array object detail
  1048. */
  1049. protected function loadObj($obj_id, $blockAccess=true) {
  1050. if($obj_id === null) {
  1051. throw new BeditaException(__("Content not found", true));
  1052. }
  1053. // use object cache
  1054. if(isset($this->objectCache[$obj_id])) {
  1055. $modelType = $this->objectCache[$obj_id]["object_type"];
  1056. $bindings = $this->setObjectBindings($modelType);
  1057. $bindingsDiff = array_diff($this->objectCache[$obj_id]["bindings"]["bindings_list"], $bindings["bindings_list"]);
  1058. // cached object is used only if its bindings contain more data or equal than those of the request
  1059. if (!empty($bindingsDiff) || ($this->objectCache[$obj_id]["bindings"]["bindings_list"] == $bindings["bindings_list"])) {
  1060. return $this->objectCache[$obj_id];
  1061. }
  1062. }
  1063. // check permissions and set $authorized true/false
  1064. if (!$this->skipCheck) {
  1065. // get permissions set on this object
  1066. $permissionModel = ClassRegistry::init("Permission");
  1067. $perms = $permissionModel->isPermissionSetted($obj_id, array(
  1068. Configure::read("objectPermissions.frontend_access_with_block"),
  1069. Configure::read("objectPermissions.frontend_access_without_block")
  1070. ));
  1071. // authorization defaults to false
  1072. $authorized = false;
  1073. if (!$perms) {
  1074. // even with check no perms found, set auth true
  1075. $authorized = true;
  1076. } else {
  1077. // divide perms by type (blocking or not)
  1078. $permsWithBlock = array();
  1079. $permsWithoutBlock = array();
  1080. foreach ($perms as $p) {
  1081. if ($p["Permission"]["flag"] == Configure::read("objectPermissions.frontend_access_without_block")) {
  1082. $permsWithoutBlock[] = $p;
  1083. } else {
  1084. $permsWithBlock[] = $p;
  1085. }
  1086. }
  1087. // if user is not logged
  1088. if (!$this->logged) {
  1089. if (!empty($permsWithBlock)) {
  1090. if (!$this->showUnauthorized) {
  1091. if($blockAccess) {
  1092. return self::UNLOGGED;
  1093. }
  1094. }
  1095. }
  1096. } else {
  1097. if ($permissionModel->checkPermissionByUser($perms, $this->BeAuth->user)) {
  1098. $authorized = true;
  1099. } else {
  1100. if (!empty($permsWithBlock)) {
  1101. if (!$this->showUnauthorized) {
  1102. if($blockAccess) {
  1103. return self::UNAUTHORIZED;
  1104. }
  1105. }
  1106. }
  1107. }
  1108. }
  1109. }
  1110. } else {
  1111. $authorized = true;
  1112. }
  1113. if (!isset($this->objectCache[$obj_id])) {
  1114. $modelType = $this->BEObject->getType($obj_id);
  1115. $bindings = $this->setObjectBindings($modelType);
  1116. }
  1117. $obj = $this->{$modelType}->find("first", array(
  1118. "conditions" => array(
  1119. "BEObject.id" => $obj_id,
  1120. "BEObject.status" => $this->status
  1121. )
  1122. )
  1123. );
  1124. if(empty($obj)) {
  1125. throw new BeditaException(__("Content not found", true));
  1126. }
  1127. // #304 status filter for Category and Tag
  1128. if(!empty($obj['Category'])) {
  1129. $cc = array();
  1130. foreach($obj['Category'] as $k => $v) {
  1131. if(in_array($v['status'],$this->status)) {
  1132. $cc[] = $v;
  1133. }
  1134. }
  1135. unset($obj['Category']);
  1136. $obj['Category'] = $cc;
  1137. }
  1138. if(!empty($obj['Tag'])) {
  1139. $tt = array();
  1140. foreach($obj['Tag'] as $k => $v) {
  1141. if(in_array($v['status'],$this->status)) {
  1142. $tt[] = $v;
  1143. }
  1144. }
  1145. unset($obj['Tag']);
  1146. $obj['Tag'] = $tt;
  1147. }
  1148. if(!$this->checkPubblicationDate($obj)) {
  1149. throw new BeditaException(__("Content not found", true));
  1150. }
  1151. $obj["publication_date"] = (!empty($obj["start_date"]))? $obj["start_date"] : $obj["created"];
  1152. $this->BeLangText->setObjectLang($obj, $this->currLang, $this->status);
  1153. if(!empty($obj["RelatedObject"])) {
  1154. $obj['relations'] = $this->objectRelationArray($obj['RelatedObject'], $this->status, array("mainLanguage" => $this->currLang));
  1155. unset($obj["RelatedObject"]);
  1156. $obj['relations_count'] = array();
  1157. foreach ($obj["relations"] as $k=>$v) {
  1158. $obj['relations_count'][$k] = count($v);
  1159. }
  1160. }
  1161. if (!empty($obj['Annotation'])) {
  1162. $this->setupAnnotations($obj, $this->status);
  1163. }
  1164. unset($obj['Annotation']);
  1165. if (!empty($obj['ObjectProperty'])) {
  1166. foreach ($obj['ObjectProperty'] as $prop) {
  1167. $properties[$prop["name"]] = $prop;
  1168. }
  1169. $obj['ObjectProperty'] = $properties;
  1170. }
  1171. $obj['object_type'] = $modelType;
  1172. $obj['authorized'] = $authorized;
  1173. // add bindings used
  1174. $obj['bindings'] = $bindings;
  1175. $this->objectCache[$obj_id] = $obj;
  1176. return $obj;
  1177. }
  1178. /**
  1179. * Load objects in section $parent_id and set in view vars an array for each object type
  1180. * (e.g. in view you will have
  1181. * $Document => array(0 => ..., 1 => ...)
  1182. * $Event" => array(0 => ..., 1 => ...)
  1183. * )
  1184. *
  1185. * @param int $parent_id
  1186. * @param array $options, filter and pagination options
  1187. */
  1188. protected function loadAndSetSectionObjects($parent_id, $options=array()) {
  1189. $sectionItems = $this->loadSectionObjects($parent_id);
  1190. foreach($sectionItems as $key => $objs) {
  1191. $this->set($key, $objs);
  1192. }
  1193. }
  1194. /**
  1195. * Load objects in section $parentNick and set in view vars an array for each object type
  1196. *
  1197. * @param string $parentNick
  1198. * @param array $options, filter and pagination options
  1199. */
  1200. protected function loadAndSetSectionObjectsByNick($parentNick, $options=array()) {
  1201. $sectionItems = $this->loadSectionObjectsByNick($parentNick, $options);
  1202. foreach($sectionItems as $key => $objs) {
  1203. $this->set($key, $objs);
  1204. }
  1205. }
  1206. /**
  1207. * Load objects in section $parentNick
  1208. *
  1209. * @param string $parentNick
  1210. * @param array $options, filter and pagination options
  1211. *
  1212. * @return array
  1213. */
  1214. protected function loadSectionObjectsByNick($parentNick, $options=array()) {
  1215. return $this->loadSectionObjects($this->BEObject->getIdFromNickname($parentNick), $options);
  1216. }
  1217. /**
  1218. * Load objects in section $parent_id
  1219. *
  1220. * @param int $parent_id
  1221. * @param array $options, filter, pagination and other options
  1222. *
  1223. * @return array
  1224. */
  1225. protected function loadSectionObjects($parent_id, $options=array()) {
  1226. if(empty($parent_id)) {
  1227. throw new BeditaException("Bad data");
  1228. }
  1229. $this->checkParentStatus($parent_id);
  1230. if(isset($this->objectCache[$parent_id]["menu"])){
  1231. $menu = $this->objectCache[$parent_id]["menu"];
  1232. $priorityOrder = $this->objectCache[$parent_id]["priority_order"];
  1233. } else {
  1234. $menu = $this->Tree->field("menu", array("id" => $parent_id));
  1235. $priorityOrder = $this->Section->field("priority_order", array("id" => $parent_id));
  1236. if(isset($this->objectCache[$parent_id])) {
  1237. $this->objectCache[$parent_id]["menu"] = $menu;
  1238. $this->objectCache[$parent_id]["priority_order"] = $priorityOrder;
  1239. }
  1240. }
  1241. $findAltPath = ($menu === '0');
  1242. if(empty($priorityOrder)) {
  1243. $priorityOrder = "asc";
  1244. }
  1245. $sectionItems = array();
  1246. $filter = (!empty($options["filter"]))? $options["filter"] : false;
  1247. $order = (!empty($options["order"]))? $options["order"] : "priority";
  1248. $dir = (isset($options["dir"]))? $options["dir"] : ($priorityOrder == "asc");
  1249. $page = (!empty($options["page"]))? $options["page"] : 1;
  1250. $dim = (!empty($options["dim"]))? $options["dim"] : 100000;
  1251. $s = $this->BEObject->getStartQuote();
  1252. $e = $this->BEObject->getEndQuote();
  1253. // add rules for start and end pubblication date
  1254. if ($this->checkPubDate["start"] == true && empty($filter["Content.start_date"])) {
  1255. $filter["Content.start_date"] = "<= '" . date("Y-m-d") . "' OR {$s}Content{$e}.{$s}start_date{$e} IS NULL";
  1256. }
  1257. if ($this->checkPubDate["end"] == true && empty($filter["Content.end_date"])) {
  1258. $filter["Content.end_date"] = ">= '" . date("Y-m-d") . "' OR {$s}Content{$e}.{$s}end_date{$e} IS NULL";
  1259. }
  1260. $items = $this->BeTree->getChildren($parent_id, $this->status, $filter, $order, $dir, $page, $dim);
  1261. if(!empty($items) && !empty($items['items'])) {
  1262. foreach($items['items'] as $index => $item) {
  1263. $obj = $this->loadObj($item['id']);
  1264. if ($obj !== self::UNAUTHORIZED && $obj !== self::UNLOGGED) {
  1265. if(empty($obj["canonicalPath"])) {
  1266. if(empty($options["sectionPath"])) {
  1267. if($findAltPath) {
  1268. $this->setCanonicalPath($obj);
  1269. } else {
  1270. $s = $this->loadObj($parent_id);
  1271. if ($s === self::UNAUTHORIZED || $s === self::UNLOGGED) {
  1272. return array();
  1273. }
  1274. $this->setCanonicalPath($s);
  1275. $obj["canonicalPath"] = (($s["canonicalPath"] != "/") ? $s["canonicalPath"] : "")
  1276. . "/" . $obj["nickname"];
  1277. }
  1278. } else {
  1279. $obj["canonicalPath"] = (($options["sectionPath"] != "/") ? $options["sectionPath"] : "")
  1280. . "/" . $obj["nickname"];
  1281. }
  1282. }
  1283. if (isset($options["setAuthorizedTo"])) {
  1284. $obj["authorized"] = $options["setAuthorizedTo"];
  1285. }
  1286. if ($this->sectionOptions["itemsByType"]) {
  1287. $sectionItems[$obj['object_type']][] = $obj;
  1288. } else {
  1289. if ($obj["object_type"] == Configure::read("objectTypes.section.model"))
  1290. $sectionItems["childSections"][] = $obj;
  1291. else
  1292. $sectionItems["childContents"][] = $obj;
  1293. }
  1294. }
  1295. }
  1296. $sectionItems["toolbar"] = $items['toolbar'];
  1297. }
  1298. return $sectionItems;
  1299. }
  1300. /**
  1301. * find first section that contain content ($name) then call section method
  1302. *
  1303. * @param string|id $name, id or content nickname
  1304. */
  1305. public function content($name) {
  1306. if(empty($name))
  1307. throw new BeditaException(__("Content not found", true));
  1308. $content_id = is_numeric($name) ? $name : $this->BEObject->getIdFromNickname($name);
  1309. // if it's defined frontend publication id then search content inside that publication else in all BEdita
  1310. $conditions = (!empty($this->publication["id"]))? "id = $content_id AND object_path LIKE '/" . $this->publication["id"] . "/%'" : "id = $content_id" ;
  1311. $section_id = $this->Tree->field('parent_id',$conditions, "priority");
  1312. if($section_id === false) {
  1313. throw new BeditaException(__("Content not found", true));
  1314. }
  1315. $this->action = 'section';
  1316. $this->section($section_id, $content_id);
  1317. }
  1318. /**
  1319. * find section and contents from section nick or section id and set template vars
  1320. *
  1321. * Set section and:
  1322. * if $contentName=null set all contents in section
  1323. * if $contentName is defined set single content
  1324. * if $contentName is defined and $this->showAllContents=true set content and other contents too (default)
  1325. *
  1326. * Execute 'sectionNickname'BeforeFilter and/or 'sectionNickName'BeforeRender
  1327. * if they're set in the controller (i.e. pages_controller.php)
  1328. *
  1329. * @param string/int $secName: section nick or section id
  1330. * @param string/int $contentName: content nick or content id
  1331. */
  1332. public function section($secName, $contentName = null) {
  1333. if (is_numeric($secName)) {
  1334. $sectionId = $secName;
  1335. $secName = $this->BEObject->getNicknameFromId($sectionId);
  1336. } else {
  1337. $sectionId = $this->BEObject->getIdFromNickname($secName);
  1338. }
  1339. $content_id = null;
  1340. if(!empty($contentName)) {
  1341. if (is_numeric($contentName)) {
  1342. $content_id = $contentName;
  1343. $contentName = $this->BEObject->getNicknameFromId($content_id);
  1344. } else {
  1345. $content_id = $this->BEObject->getIdFromNickname($contentName);
  1346. }
  1347. $contentType = $this->BEObject->getType($content_id);
  1348. if($contentType === "Section") {
  1349. $args = func_get_args();
  1350. array_shift($args);
  1351. return call_user_func_array(array($this, "section"), $args);
  1352. // check that contentName is a child of secName
  1353. } elseif ( $this->Tree->find('count',array("conditions" => array("id" => $content_id, "parent_id" => $sectionId))) == 0 ) {
  1354. throw new BeditaException(__("Content " . $contentName . " doesn't belong to " . $secName, true));
  1355. }
  1356. $contentNameFilter = BeLib::getInstance()->variableFromNickname($contentName);
  1357. }
  1358. $secNameFilter = BeLib::getInstance()->variableFromNickname($secName);
  1359. // section before filter
  1360. if (method_exists($this, $secNameFilter . "BeforeFilter")) {
  1361. $this->{$secNameFilter . "BeforeFilter"}($contentName);
  1362. }
  1363. // content before filter
  1364. if ($contentName && method_exists($this, $contentNameFilter . "BeforeFilter")) {
  1365. $this->{$contentNameFilter . "BeforeFilter"}($secName);
  1366. }
  1367. $section = $this->loadObj($sectionId);
  1368. if ($sect

Large files files are truncated, but you can click here to view the full file