PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/concrete/core/models/area.php

https://bitbucket.org/selfeky/xclusivescardwebsite
PHP | 823 lines | 419 code | 123 blank | 281 comment | 97 complexity | f80489d8dee4d61d99239817d49a0e6e MD5 | raw file
  1. <?php
  2. defined('C5_EXECUTE') or die("Access Denied.");
  3. /**
  4. * @package Pages
  5. * @category Concrete
  6. * @author Andrew Embler <andrew@concrete5.org>
  7. * @copyright Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org)
  8. * @license http://www.concrete5.org/license/ MIT License
  9. *
  10. */
  11. /**
  12. * An area object is used within templates to mark certain portions of pages as editable and containers of dynamic content
  13. *
  14. * @package Pages
  15. * @author Andrew Embler <andrew@concrete5.org>
  16. * @category Concrete
  17. * @copyright Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org)
  18. * @license http://www.concrete5.org/license/ MIT License
  19. *
  20. */
  21. class Concrete5_Model_Area extends Object {
  22. public $cID, $arID, $arHandle;
  23. public $c;
  24. /* area-specific attributes */
  25. /**
  26. * limits the number of blocks in the area
  27. * @var int
  28. */
  29. public $maximumBlocks = -1; //
  30. /**
  31. * sets a custom template for all blocks in the area
  32. * @see Area::getCustomTemplates()
  33. * @var array
  34. */
  35. public $customTemplateArray = array();
  36. /**
  37. * block type handle for the block to automatically activate on first_run
  38. * @var string
  39. */
  40. public $firstRunBlockTypeHandle;
  41. /**
  42. * if set higher, any blocks that aren't rated high enough aren't seen (unless you have sufficient privs)
  43. * @var int
  44. */
  45. public $ratingThreshold = 0; //
  46. /**
  47. * @var boolean
  48. */
  49. public $showControls = true;
  50. /**
  51. * @var array
  52. */
  53. public $attributes = array();
  54. /**
  55. * @var string
  56. */
  57. public $enclosingStart = '';
  58. /**
  59. * Denotes if we should run sprintf() on blockWrapperStart
  60. * @var boolean
  61. */
  62. public $enclosingStartHasReplacements = false;
  63. /**
  64. * @var string
  65. */
  66. public $enclosingEnd = '';
  67. /**
  68. * Denotes if we should run sprintf() on blockWrapperStartEnd
  69. * @var boolean
  70. */
  71. public $enclosingEndHasReplacements = false;
  72. /* run-time variables */
  73. /**
  74. * the number of blocks currently rendered in the area
  75. * @see Area::getTotalBlocksInArea()
  76. * @var int
  77. */
  78. public $totalBlocks = 0;
  79. /**
  80. * Array of Blocks within the current area
  81. * not an array actually until it's set
  82. * @see Area::getAreaBlocksArray()
  83. * @var Block[]
  84. */
  85. public $areaBlocksArray;
  86. /**
  87. * The constructor is used primarily on page templates to create areas of content that are editable within the cms.
  88. * ex: $a = new Area('Main'); $a->display($c)
  89. * We actually use Collection::getArea() when we want to interact with a fully
  90. * qualified Area object when dealing with a Page/Collection object
  91. *
  92. * @param string
  93. * @return void
  94. */
  95. public function __construct($arHandle) {
  96. $this->arHandle = $arHandle;
  97. $v = View::getInstance();
  98. if (!$v->editingEnabled()) {
  99. $this->showControls = false;
  100. }
  101. }
  102. public function getPermissionObjectIdentifier() {
  103. return $this->getCollectionID() . ':' . $this->getAreaHandle();
  104. }
  105. /**
  106. * returns the Collection's cID
  107. * @return int
  108. */
  109. public function getCollectionID() {return $this->cID;}
  110. /**
  111. * returns the Collection object for the current Area
  112. * @return Collection
  113. */
  114. public function getAreaCollectionObject() {return $this->c;}
  115. /**
  116. * whether or not it's a global area
  117. * @return bool
  118. */
  119. public function isGlobalArea() {return $this->arIsGlobal;}
  120. /**
  121. * returns the arID of the current area
  122. * @return int
  123. */
  124. public function getAreaID() {return $this->arID;}
  125. /**
  126. * returns the handle for the current area
  127. * @return string
  128. */
  129. public function getAreaHandle() {return $this->arHandle;}
  130. /**
  131. * returns an array of custom templates
  132. * @return array
  133. */
  134. public function getCustomTemplates() {return $this->customTemplateArray;}
  135. /**
  136. * sets a custom block template for blocks of a type specified by the btHandle
  137. * @param string $btHandle handle for the block type
  138. * @param string $view string identifying the block template ex: 'templates/breadcrumb.php'
  139. */
  140. public function setCustomTemplate($btHandle, $view) {$this->customTemplateArray[$btHandle] = $view;}
  141. /**
  142. * Returns the total number of blocks in an area.
  143. * @param Page $c must be passed if the display() method has not been run on the area object yet.
  144. */
  145. public function getTotalBlocksInArea($c = false) {
  146. if (!is_array($this->areaBlocksArray) && is_object($c)) {
  147. $this->getAreaBlocksArray($c);
  148. }
  149. return $this->totalBlocks;
  150. }
  151. /**
  152. * check if the area has permissions that override the page's permissions
  153. * @return boolean
  154. */
  155. public function overrideCollectionPermissions() {return $this->arOverrideCollectionPermissions; }
  156. /**
  157. * @return int
  158. */
  159. public function getAreaCollectionInheritID() {return $this->arInheritPermissionsFromAreaOnCID;}
  160. /**
  161. * Sets the total number of blocks an area allows. Does not limit by type.
  162. * @param int $num
  163. * @return void
  164. */
  165. public function setBlockLimit($num) {
  166. $this->maximumBlocks = $num;
  167. }
  168. /**
  169. *
  170. * @param $attr
  171. * @param $val
  172. * @return void
  173. */
  174. public function setAttribute($attr, $val) {
  175. $this->attributes[$attr] = $val;
  176. }
  177. /**
  178. *
  179. * @param $attr
  180. * @return
  181. */
  182. public function getAttribute($attr) {
  183. return $this->attributes[$attr];
  184. }
  185. /**
  186. * disables controls for the current area
  187. * @return void
  188. */
  189. public function disableControls() {
  190. $this->showControls = false;
  191. }
  192. /**
  193. * determines if the current Area can accept additonal Blocks
  194. * @return boolean
  195. */
  196. public function areaAcceptsBlocks() {
  197. return (($this->maximumBlocks > $this->totalBlocks) || ($this->maximumBlocks == -1));
  198. }
  199. /**
  200. * gets the maximum allowed number of blocks, -1 if unlimited
  201. * @return int
  202. */
  203. public function getMaximumBlocks() {return $this->maximumBlocks;}
  204. /**
  205. *
  206. * @return string
  207. */
  208. function getAreaUpdateAction($task = 'update', $alternateHandler = null) {
  209. $valt = Loader::helper('validation/token');
  210. $token = '&' . $valt->getParameter();
  211. $step = ($_REQUEST['step']) ? '&step=' . $_REQUEST['step'] : '';
  212. $c = $this->getAreaCollectionObject();
  213. if ($alternateHandler) {
  214. $str = $alternateHandler . "?atask={$task}&cID=" . $c->getCollectionID() . "&arHandle=" . $this->getAreaHandle() . $step . $token;
  215. } else {
  216. $str = DIR_REL . "/" . DISPATCHER_FILENAME . "?atask=" . $task . "&cID=" . $c->getCollectionID() . "&arHandle=" . $this->getAreaHandle() . $step . $token;
  217. }
  218. return $str;
  219. }
  220. /**
  221. * Gets the Area object for the given page and area handle
  222. * @param Page|Collection $c
  223. * @param string $arHandle
  224. * @param int|null $arIsGlobal
  225. * @return Area
  226. */
  227. public static function get(&$c, $arHandle, $arIsGlobal = null) {
  228. if (!is_object($c)) {
  229. return false;
  230. }
  231. // Right now we are splitting the cache to deal with times when Areas
  232. // get converted to GlobalAreas and back the other way
  233. $globalCache = $arIsGlobal ? ':1' : '';
  234. $a = CacheLocal::getEntry('area', $c->getCollectionID() . ':' . $arHandle . $globalCache);
  235. if ($a instanceof Area) {
  236. return $a;
  237. }
  238. $db = Loader::db();
  239. // First, we verify that this is a legitimate area
  240. $v = array($c->getCollectionID(), $arHandle);
  241. $q = "select arID, arOverrideCollectionPermissions, arInheritPermissionsFromAreaOnCID, arIsGlobal from Areas where cID = ? and arHandle = ?";
  242. $arRow = $db->getRow($q, $v);
  243. if ($arRow['arID'] > 0) {
  244. $area = new Area($arHandle);
  245. $area->arID = $arRow['arID'];
  246. $area->arOverrideCollectionPermissions = $arRow['arOverrideCollectionPermissions'];
  247. $area->arIsGlobal = $arRow['arIsGlobal'];
  248. $area->arInheritPermissionsFromAreaOnCID = $arRow['arInheritPermissionsFromAreaOnCID'];
  249. $area->cID = $c->getCollectionID();
  250. $area->c = &$c;
  251. CacheLocal::set('area', $c->getCollectionID() . ':' . $arHandle . $globalCache, $area);
  252. return $area;
  253. }
  254. }
  255. /**
  256. * Gets or creates if necessary an Area for the given Page, Handle
  257. * @param Page|Collection $c
  258. * @param string $arHandle
  259. * @param boolean $arIsGlobal
  260. * @return Area
  261. */
  262. public static function getOrCreate(&$c, $arHandle, $arIsGlobal = 0) {
  263. /*
  264. different than get(), getOrCreate() is called by the templates. If no area record exists for the
  265. permissions cID / handle combination, we create one. This is to make our lives easier
  266. */
  267. $area = self::get($c, $arHandle, $arIsGlobal);
  268. if (is_object($area)) {
  269. if ($area->isGlobalArea() == $arIsGlobal) {
  270. return $area;
  271. } else if (!$area->isGlobalArea() && !$arIsGlobal) {
  272. return $area;
  273. }
  274. }
  275. $cID = $c->getCollectionID();
  276. $db = Loader::db();
  277. if (!$arIsGlobal) {
  278. $arIsGlobal = 0;
  279. }
  280. $db->Replace('Areas', array('cID' => $cID, 'arHandle' => $arHandle, 'arIsGlobal' => $arIsGlobal), array('arHandle', 'cID'), true);
  281. if ($arIsGlobal) {
  282. // we create a stack for it
  283. Stack::getOrCreateGlobalArea($arHandle);
  284. }
  285. $area = self::get($c, $arHandle); // we're assuming the insert succeeded
  286. $area->rescanAreaPermissionsChain();
  287. // we need to update the local cache
  288. $globalCache = $arIsGlobal ? ':1' : '';
  289. CacheLocal::set('area', $c->getCollectionID() . ':' . $arHandle . $globalCache, $area);
  290. return $area;
  291. }
  292. public static function getAreaHandleFromID($arID) {
  293. $db = Loader::db();
  294. return $db->GetOne('select arHandle from Areas where arID = ?', array($arID));
  295. }
  296. /**
  297. * Get all of the blocks within the current area for a given page
  298. * @param Page|Collection $c
  299. * @return Block[]
  300. */
  301. public function getAreaBlocksArray($c) {
  302. if (is_array($this->areaBlocksArray)) {
  303. return $this->areaBlocksArray;
  304. }
  305. $this->cID = $c->getCollectionID();
  306. $this->c = $c;
  307. $this->areaBlocksArray = array();
  308. if ($this->arIsGlobal) {
  309. $blocks = array();
  310. $cp = new Permissions($c);
  311. if ($cp->canViewPageVersions()) {
  312. $c = Stack::getByName($this->arHandle);
  313. } else {
  314. $c = Stack::getByName($this->arHandle, 'ACTIVE');
  315. }
  316. if (is_object($c)) {
  317. $blocks = $c->getBlocks(STACKS_AREA_NAME);
  318. $globalArea = self::get($c, STACKS_AREA_NAME);
  319. }
  320. } else {
  321. $blocks = $c->getBlocks($this->arHandle);
  322. }
  323. foreach($blocks as $ab) {
  324. if ($this->arIsGlobal && is_object($globalArea)) {
  325. $ab->setBlockAreaObject($globalArea);
  326. } else {
  327. $ab->setBlockAreaObject($this);
  328. }
  329. $this->areaBlocksArray[] = $ab;
  330. $this->totalBlocks++;
  331. }
  332. return $this->areaBlocksArray;
  333. }
  334. /**
  335. * determins based on permissions what types of blocks, if any can be added to this area
  336. * @param Page|Collection $c
  337. * @param AreaPermissions
  338. * @return boolean|BlockTypeList
  339. */
  340. public function getAddBlockTypes(&$c, &$ap) {
  341. if ($ap->canAddBlocks()) {
  342. $bt = new BlockTypeList($ap->addBlockTypes);
  343. } else {
  344. $bt = false;
  345. }
  346. return $bt;
  347. }
  348. /**
  349. * gets a list of all areas - no relation to the current page or area object
  350. * possibly could be set as a static method??
  351. * @return array
  352. */
  353. public function getHandleList() {
  354. $db = Loader::db();
  355. $r = $db->Execute('select distinct arHandle from Areas order by arHandle asc');
  356. $handles = array();
  357. while ($row = $r->FetchRow()) {
  358. $handles[] = $row['arHandle'];
  359. }
  360. $r->Free();
  361. unset($r);
  362. unset($db);
  363. return $handles;
  364. }
  365. /**
  366. * This function removes all permissions records for the current Area
  367. * and sets it to inherit from the Page permissions
  368. * @return void
  369. */
  370. function revertToPagePermissions() {
  371. // this function removes all permissions records for a particular area on this page
  372. // and sets it to inherit from the page above
  373. // this function will also need to ensure that pages below it do the same
  374. $db = Loader::db();
  375. $v = array($this->getAreaHandle(), $this->getCollectionID());
  376. $db->query("delete from AreaPermissionAssignments where arHandle = ? and cID = ?", $v);
  377. $db->query("update Areas set arOverrideCollectionPermissions = 0 where arID = ?", array($this->getAreaID()));
  378. // now we set rescan this area to determine where it -should- be inheriting from
  379. $this->arOverrideCollectionPermissions = false;
  380. $this->rescanAreaPermissionsChain();
  381. $areac = $this->getAreaCollectionObject();
  382. if ($areac->isMasterCollection()) {
  383. $this->rescanSubAreaPermissionsMasterCollection($areac);
  384. } else if ($areac->overrideTemplatePermissions()) {
  385. // now we scan sub areas
  386. $this->rescanSubAreaPermissions();
  387. }
  388. }
  389. public function __destruct() {
  390. unset($this->c);
  391. }
  392. /**
  393. * Rescans the current Area's permissions ensuring that it's enheriting permissions properly up the chain
  394. * @return void
  395. */
  396. public function rescanAreaPermissionsChain() {
  397. $db = Loader::db();
  398. if ($this->overrideCollectionPermissions()) {
  399. return false;
  400. }
  401. // first, we obtain the inheritance of permissions for this particular collection
  402. $areac = $this->getAreaCollectionObject();
  403. if (is_a($areac, 'Page')) {
  404. if ($areac->getCollectionInheritance() == 'PARENT') {
  405. $cIDToCheck = $areac->getCollectionParentID();
  406. // first, we temporarily set the arInheritPermissionsFromAreaOnCID to whatever the arInheritPermissionsFromAreaOnCID is set to
  407. // in the immediate parent collection
  408. $arInheritPermissionsFromAreaOnCID = $db->getOne("select a.arInheritPermissionsFromAreaOnCID from Pages c inner join Areas a on (c.cID = a.cID) where c.cID = ? and a.arHandle = ?", array($cIDToCheck, $this->getAreaHandle()));
  409. if ($arInheritPermissionsFromAreaOnCID > 0) {
  410. $db->query("update Areas set arInheritPermissionsFromAreaOnCID = ? where arID = ?", array($arInheritPermissionsFromAreaOnCID, $this->getAreaID()));
  411. }
  412. // now we do the recursive rescan to see if any areas themselves override collection permissions
  413. while ($cIDToCheck > 0) {
  414. $row = $db->getRow("select c.cParentID, c.cID, a.arHandle, a.arOverrideCollectionPermissions, a.arID from Pages c inner join Areas a on (c.cID = a.cID) where c.cID = ? and a.arHandle = ?", array($cIDToCheck, $this->getAreaHandle()));
  415. if ($row['arOverrideCollectionPermissions'] == 1) {
  416. break;
  417. } else {
  418. $cIDToCheck = $row['cParentID'];
  419. }
  420. }
  421. if (is_array($row)) {
  422. if ($row['arOverrideCollectionPermissions'] && $row['cID'] > 0) {
  423. // then that means we have successfully found a parent area record that we can inherit from. So we set
  424. // out current area to inherit from that COLLECTION ID (not area ID - from the collection ID)
  425. $db->query("update Areas set arInheritPermissionsFromAreaOnCID = ? where arID = ?", array($row['cID'], $this->getAreaID()));
  426. $this->arInheritPermissionsFromAreaOnCID = $row['cID'];
  427. }
  428. }
  429. } else if ($areac->getCollectionInheritance() == 'TEMPLATE') {
  430. // we grab an area on the master collection (if it exists)
  431. $doOverride = $db->getOne("select arOverrideCollectionPermissions from Pages c inner join Areas a on (c.cID = a.cID) where c.cID = ? and a.arHandle = ?", array($areac->getPermissionsCollectionID(), $this->getAreaHandle()));
  432. if ($doOverride && $areac->getPermissionsCollectionID() > 0) {
  433. $db->query("update Areas set arInheritPermissionsFromAreaOnCID = ? where arID = ?", array($areac->getPermissionsCollectionID(), $this->getAreaID()));
  434. $this->arInheritPermissionsFromAreaOnCID = $areac->getPermissionsCollectionID();
  435. }
  436. }
  437. }
  438. }
  439. /**
  440. * works a lot like rescanAreaPermissionsChain() but it works down. This is typically only
  441. * called when we update an area to have specific permissions, and all areas that are on pagesbelow it with the same
  442. * handle, etc... should now inherit from it.
  443. * @return void
  444. */
  445. function rescanSubAreaPermissions($cIDToCheck = null) {
  446. // works a lot like rescanAreaPermissionsChain() but it works down. This is typically only
  447. // called when we update an area to have specific permissions, and all areas that are on pagesbelow it with the same
  448. // handle, etc... should now inherit from it.
  449. $db = Loader::db();
  450. if (!$cIDToCheck) {
  451. $cIDToCheck = $this->getCollectionID();
  452. }
  453. $v = array($this->getAreaHandle(), 'PARENT', $cIDToCheck);
  454. $r = $db->query("select Areas.arID, Areas.cID from Areas inner join Pages on (Areas.cID = Pages.cID) where Areas.arHandle = ? and cInheritPermissionsFrom = ? and arOverrideCollectionPermissions = 0 and cParentID = ?", $v);
  455. while ($row = $r->fetchRow()) {
  456. // these are all the areas we need to update.
  457. if ($this->getAreaCollectionInheritID() > 0) {
  458. $db->query("update Areas set arInheritPermissionsFromAreaOnCID = ? where arID = ?", array($this->getAreaCollectionInheritID(), $row['arID']));
  459. $this->rescanSubAreaPermissions($row['cID']);
  460. }
  461. }
  462. }
  463. /**
  464. * similar to rescanSubAreaPermissions, but for those who have setup their pages to inherit master collection permissions
  465. * @see Area::rescanSubAreaPermissions()
  466. * @return void
  467. */
  468. function rescanSubAreaPermissionsMasterCollection($masterCollection) {
  469. // like above, but for those who have setup their pages to inherit master collection permissions
  470. // this might make more sense in the collection class, but I'm putting it here
  471. if (!$masterCollection->isMasterCollection()) {
  472. return false;
  473. }
  474. // if we're not overriding permissions on the master collection then we set the ID to zero. If we are, then we set it to our own ID
  475. $toSetCID = ($this->overrideCollectionPermissions()) ? $masterCollection->getCollectionID() : 0;
  476. $db = Loader::db();
  477. $v = array($this->getAreaHandle(), 'TEMPLATE', $masterCollection->getCollectionID());
  478. $db->query("update Areas, Pages set Areas.arInheritPermissionsFromAreaOnCID = " . $toSetCID . " where Areas.cID = Pages.cID and Areas.arHandle = ? and cInheritPermissionsFrom = ? and arOverrideCollectionPermissions = 0 and cInheritPermissionsFromCID = ?", $v);
  479. }
  480. /**
  481. * displays the Area in the page
  482. * ex: $a = new Area('Main'); $a->display($c);
  483. * @param Page|Collection $c
  484. * @param Block[] $alternateBlockArray optional array of blocks to render instead of default behavior
  485. * @return void
  486. */
  487. function display(&$c, $alternateBlockArray = null) {
  488. if(!intval($c->cID)){
  489. //Invalid Collection
  490. return false;
  491. }
  492. if ($this->arIsGlobal) {
  493. $stack = Stack::getByName($this->arHandle);
  494. }
  495. $currentPage = Page::getCurrentPage();
  496. $ourArea = self::getOrCreate($c, $this->arHandle, $this->arIsGlobal);
  497. if (count($this->customTemplateArray) > 0) {
  498. $ourArea->customTemplateArray = $this->customTemplateArray;
  499. }
  500. if (count($this->attributes) > 0) {
  501. $ourArea->attributes = $this->attributes;
  502. }
  503. if ($this->maximumBlocks > -1) {
  504. $ourArea->maximumBlocks = $this->maximumBlocks;
  505. }
  506. $ap = new Permissions($ourArea);
  507. if (!$ap->canViewArea()) {
  508. return false;
  509. }
  510. $blocksToDisplay = ($alternateBlockArray) ? $alternateBlockArray : $ourArea->getAreaBlocksArray($c, $ap);
  511. $this->totalBlocks = $ourArea->getTotalBlocksInArea();
  512. $u = new User();
  513. $bv = new BlockView();
  514. // now, we iterate through these block groups (which are actually arrays of block objects), and display them on the page
  515. if ($this->showControls && $c->isEditMode() && $ap->canViewAreaControls()) {
  516. $bv->renderElement('block_area_header', array('a' => $ourArea));
  517. }
  518. $bv->renderElement('block_area_header_view', array('a' => $ourArea));
  519. //display layouts tied to this area
  520. //Might need to move this to a better position
  521. $areaLayouts = $this->getAreaLayouts($c);
  522. if(is_array($areaLayouts) && count($areaLayouts)){
  523. foreach($areaLayouts as $layout){
  524. $layout->display($c,$this);
  525. }
  526. if($this->showControls && ($c->isArrangeMode() || $c->isEditMode())) {
  527. echo '<div class="ccm-layouts-block-arrange-placeholder ccm-block-arrange"></div>';
  528. }
  529. }
  530. $blockPositionInArea = 1; //for blockWrapper output
  531. foreach ($blocksToDisplay as $b) {
  532. $includeEditStrip = false;
  533. $bv = new BlockView();
  534. $bv->setAreaObject($ourArea);
  535. // this is useful for rendering areas from one page
  536. // onto the next and including interactive elements
  537. if ($currentPage->getCollectionID() != $c->getCollectionID()) {
  538. $b->setBlockActionCollectionID($c->getCollectionID());
  539. }
  540. if ($this->arIsGlobal && is_object($stack)) {
  541. $b->setBlockActionCollectionID($stack->getCollectionID());
  542. }
  543. $p = new Permissions($b);
  544. if ($c->isEditMode() && $this->showControls && $p->canViewEditInterface()) {
  545. $includeEditStrip = true;
  546. }
  547. if ($p->canViewBlock()) {
  548. if (!$c->isEditMode()) {
  549. $this->outputBlockWrapper(true, $b, $blockPositionInArea);
  550. }
  551. if ($includeEditStrip) {
  552. $bv->renderElement('block_controls', array(
  553. 'a' => $ourArea,
  554. 'b' => $b,
  555. 'p' => $p
  556. ));
  557. $bv->renderElement('block_header', array(
  558. 'a' => $ourArea,
  559. 'b' => $b,
  560. 'p' => $p
  561. ));
  562. }
  563. $bv->render($b);
  564. if ($includeEditStrip) {
  565. $bv->renderElement('block_footer');
  566. }
  567. if (!$c->isEditMode()) {
  568. $this->outputBlockWrapper(false, $b, $blockPositionInArea);
  569. }
  570. }
  571. $blockPositionInArea++;
  572. }
  573. $bv->renderElement('block_area_footer_view', array('a' => $ourArea));
  574. if ($this->showControls && $c->isEditMode() && $ap->canViewAreaControls()) {
  575. $bv->renderElement('block_area_footer', array('a' => $ourArea));
  576. }
  577. }
  578. /**
  579. * outputs the block wrapers for each block
  580. * Internal helper function for display()
  581. * @return void
  582. */
  583. protected function outputBlockWrapper($isStart, &$block, $blockPositionInArea) {
  584. static $th = null;
  585. $enclosing = $isStart ? $this->enclosingStart : $this->enclosingEnd;
  586. $hasReplacements = $isStart ? $this->enclosingStartHasReplacements : $this->enclosingEndHasReplacements;
  587. if (!empty($enclosing) && $hasReplacements) {
  588. $bID = $block->getBlockID();
  589. $btHandle = $block->getBlockTypeHandle();
  590. $bName = ($btHandle == 'core_stack_display') ? Stack::getByID($block->getInstance()->stID)->getStackName() : $block->getBlockName();
  591. $th = is_null($th) ? Loader::helper('text') : $th;
  592. $bSafeName = $th->entities($bName);
  593. $alternatingClass = ($blockPositionInArea % 2 == 0) ? 'even' : 'odd';
  594. echo sprintf($enclosing, $bID, $btHandle, $bSafeName, $blockPositionInArea, $alternatingClass);
  595. } else {
  596. echo $enclosing;
  597. }
  598. }
  599. /**
  600. * Gets all layout grid objects for a collection
  601. * @param Page|Collection $c
  602. * @return Layout[]
  603. */
  604. public function getAreaLayouts($c){
  605. if( !intval($c->cID) ){
  606. //Invalid Collection
  607. return false;
  608. }
  609. if (!$c->hasLayouts()) {
  610. return array();
  611. }
  612. $db = Loader::db();
  613. $vals = array( intval($c->cID), $c->getVersionID(), $this->getAreaHandle() );
  614. $sql = 'SELECT * FROM CollectionVersionAreaLayouts WHERE cID=? AND cvID=? AND arHandle=? ORDER BY position ASC, cvalID ASC';
  615. $rows = $db->getArray($sql,$vals);
  616. $layouts=array();
  617. $i=0;
  618. if(is_array($rows)) foreach($rows as $row){
  619. $layout = Layout::getById( intval($row['layoutID']) );
  620. if( is_object($layout) ){
  621. $i++;
  622. //check position is correct, update if not
  623. if( $i != $row['position'] || $renumbering ){
  624. $renumbering=1;
  625. $db->query( 'UPDATE CollectionVersionAreaLayouts SET position=? WHERE cvalID=?' , array($i, $row['cvalID']) );
  626. }
  627. $layout->position=$i;
  628. $layout->cvalID = intval($row['cvalID']);
  629. $layout->setAreaObj( $this );
  630. $layout->setAreaNameNumber( intval($row['areaNameNumber']) );
  631. $layouts[]=$layout;
  632. }
  633. }
  634. return $layouts;
  635. }
  636. /**
  637. * Exports the area to content format
  638. * @todo need more documentation export?
  639. */
  640. public function export($p, $page) {
  641. $area = $p->addChild('area');
  642. $area->addAttribute('name', $this->getAreaHandle());
  643. $blocks = $page->getBlocks($this->getAreaHandle());
  644. foreach($blocks as $bl) {
  645. $bl->export($area);
  646. }
  647. }
  648. /**
  649. * Specify HTML to automatically print before blocks contained within the area
  650. * Pass true for $hasReplacements if the $html contains sprintf replacements tokens.
  651. * Available tokens:
  652. * %1$s -> Block ID
  653. * %2$s -> Block Type Handle
  654. * %3$s -> Block/Stack Name
  655. * %4$s -> Block position in area (first block is 1, second block is 2, etc.)
  656. * %5$s -> 'odd' or 'even' (useful for "zebra stripes" CSS classes)
  657. * @param string $html
  658. * @param boolean $hasReplacements
  659. * @return void
  660. */
  661. function setBlockWrapperStart($html, $hasReplacements = false) {
  662. $this->enclosingStart = $html;
  663. $this->enclosingStartHasReplacements = $hasReplacements;
  664. }
  665. /**
  666. * Set HTML that automatically prints after any blocks contained within the area
  667. * Pass true for $hasReplacements if the $html contains sprintf replacements tokens.
  668. * See setBlockWrapperStart() comments for available tokens.
  669. * @param string $html
  670. * @param boolean $hasReplacements
  671. * @return void
  672. */
  673. function setBlockWrapperEnd($html, $hasReplacements = false) {
  674. $this->enclosingEnd = $html;
  675. $this->enclosingEndHasReplacements = $hasReplacements;
  676. }
  677. public function overridePagePermissions() {
  678. $db = Loader::db();
  679. $cID = $this->getCollectionID();
  680. $v = array($cID, $this->getAreaHandle());
  681. // update the Area record itself. Hopefully it's been created.
  682. $db->query("update Areas set arOverrideCollectionPermissions = 1, arInheritPermissionsFromAreaOnCID = 0 where arID = ?", array($this->getAreaID()));
  683. // copy permissions from the page to the area
  684. $permissions = PermissionKey::getList('area');
  685. foreach($permissions as $pk) {
  686. $pk->setPermissionObject($this);
  687. $pk->copyFromPageToArea();
  688. }
  689. // finally, we rescan subareas so that, if they are inheriting up the tree, they inherit from this place
  690. $this->arInheritPermissionsFromAreaOnCID = $this->getCollectionID(); // we don't need to actually save this on the area, but we need it for the rescan function
  691. $this->arOverrideCollectionPermissions = 1; // to match what we did above - useful for the rescan functions below
  692. $acobj = $this->getAreaCollectionObject();
  693. if ($acobj->isMasterCollection()) {
  694. // if we're updating the area on a master collection we need to go through to all areas set on subpages that aren't set to override to change them to inherit from this area
  695. $this->rescanSubAreaPermissionsMasterCollection($acobj);
  696. } else {
  697. $this->rescanSubAreaPermissions();
  698. }
  699. }
  700. }