0byt3m1n1
Path:
/
data
/
applications
/
aps.bak
/
concrete5
/
5.6.0.2-2
/
standard
/
htdocs
/
concrete
/
core
/
models
/
[
Home
]
File: area.php
<?php defined('C5_EXECUTE') or die("Access Denied."); /** * @package Pages * @category Concrete * @author Andrew Embler <andrew@concrete5.org> * @copyright Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org) * @license http://www.concrete5.org/license/ MIT License * */ /** * An area object is used within templates to mark certain portions of pages as editable and containers of dynamic content * * @package Pages * @author Andrew Embler <andrew@concrete5.org> * @category Concrete * @copyright Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org) * @license http://www.concrete5.org/license/ MIT License * */ class Concrete5_Model_Area extends Object { public $cID, $arID, $arHandle; public $c; /* area-specific attributes */ /** * limits the number of blocks in the area * @var int */ public $maximumBlocks = -1; // /** * sets a custom template for all blocks in the area * @see Area::getCustomTemplates() * @var array */ public $customTemplateArray = array(); /** * block type handle for the block to automatically activate on first_run * @var string */ public $firstRunBlockTypeHandle; /** * if set higher, any blocks that aren't rated high enough aren't seen (unless you have sufficient privs) * @var int */ public $ratingThreshold = 0; // /** * @var boolean */ public $showControls = true; /** * @var array */ public $attributes = array(); /** * @var string */ public $enclosingStart = ''; /** * Denotes if we should run sprintf() on blockWrapperStart * @var boolean */ public $enclosingStartHasReplacements = false; /** * @var string */ public $enclosingEnd = ''; /** * Denotes if we should run sprintf() on blockWrapperStartEnd * @var boolean */ public $enclosingEndHasReplacements = false; /* run-time variables */ /** * the number of blocks currently rendered in the area * @see Area::getTotalBlocksInArea() * @var int */ public $totalBlocks = 0; /** * Array of Blocks within the current area * not an array actually until it's set * @see Area::getAreaBlocksArray() * @var Block[] */ public $areaBlocksArray; /** * The constructor is used primarily on page templates to create areas of content that are editable within the cms. * ex: $a = new Area('Main'); $a->display($c) * We actually use Collection::getArea() when we want to interact with a fully * qualified Area object when dealing with a Page/Collection object * * @param string * @return void */ public function __construct($arHandle) { $this->arHandle = $arHandle; $v = View::getInstance(); if (!$v->editingEnabled()) { $this->showControls = false; } } public function getPermissionObjectIdentifier() { return $this->getCollectionID() . ':' . $this->getAreaHandle(); } /** * returns the Collection's cID * @return int */ public function getCollectionID() {return $this->cID;} /** * returns the Collection object for the current Area * @return Collection */ public function getAreaCollectionObject() {return $this->c;} /** * whether or not it's a global area * @return bool */ public function isGlobalArea() {return $this->arIsGlobal;} /** * returns the arID of the current area * @return int */ public function getAreaID() {return $this->arID;} /** * returns the handle for the current area * @return string */ public function getAreaHandle() {return $this->arHandle;} /** * returns an array of custom templates * @return array */ public function getCustomTemplates() {return $this->customTemplateArray;} /** * sets a custom block template for blocks of a type specified by the btHandle * @param string $btHandle handle for the block type * @param string $temp string identifying the block template ex: breadcrumb */ public function setCustomTemplate($btHandle, $temp) {$this->customTemplateArray[$btHandle] = $temp;} /** * Returns the total number of blocks in an area. * @param Page $c must be passed if the display() method has not been run on the area object yet. */ public function getTotalBlocksInArea($c = false) { if (!is_array($this->areaBlocksArray) && is_object($c)) { $this->getAreaBlocksArray($c); } return $this->totalBlocks; } /** * check if the area has permissions that override the page's permissions * @return boolean */ public function overrideCollectionPermissions() {return $this->arOverrideCollectionPermissions; } /** * @return int */ public function getAreaCollectionInheritID() {return $this->arInheritPermissionsFromAreaOnCID;} /** * Sets the total number of blocks an area allows. Does not limit by type. * @param int $num * @return void */ public function setBlockLimit($num) { $this->maximumBlocks = $num; } /** * * @param $attr * @param $val * @return void */ public function setAttribute($attr, $val) { $this->attributes[$attr] = $val; } /** * * @param $attr * @return */ public function getAttribute($attr) { return $this->attributes[$attr]; } /** * disables controls for the current area * @return void */ public function disableControls() { $this->showControls = false; } /** * determines if the current Area can accept additonal Blocks * @return boolean */ public function areaAcceptsBlocks() { return (($this->maximumBlocks > $this->totalBlocks) || ($this->maximumBlocks == -1)); } /** * gets the maximum allowed number of blocks, -1 if unlimited * @return int */ public function getMaximumBlocks() {return $this->maximumBlocks;} /** * * @return string */ function getAreaUpdateAction($task = 'update', $alternateHandler = null) { $valt = Loader::helper('validation/token'); $token = '&' . $valt->getParameter(); $step = ($_REQUEST['step']) ? '&step=' . $_REQUEST['step'] : ''; $c = $this->getAreaCollectionObject(); if ($alternateHandler) { $str = $alternateHandler . "?atask={$task}&cID=" . $c->getCollectionID() . "&arHandle=" . $this->getAreaHandle() . $step . $token; } else { $str = DIR_REL . "/" . DISPATCHER_FILENAME . "?atask=" . $task . "&cID=" . $c->getCollectionID() . "&arHandle=" . $this->getAreaHandle() . $step . $token; } return $str; } /** * Gets the Area object for the given page and area handle * @param Page|Collection $c * @param string $arHandle * @return Area */ public static function get(&$c, $arHandle) { if (!is_object($c)) { return false; } $ca = new Cache(); $a = Cache::get('area', $c->getCollectionID() . ':' . $arHandle); if ($a instanceof Area) { return $a; } $db = Loader::db(); // First, we verify that this is a legitimate area $v = array($c->getCollectionID(), $arHandle); $q = "select arID, arOverrideCollectionPermissions, arInheritPermissionsFromAreaOnCID, arIsGlobal from Areas where cID = ? and arHandle = ?"; $arRow = $db->getRow($q, $v); if ($arRow['arID'] > 0) { $area = new Area($arHandle); $area->arID = $arRow['arID']; $area->arOverrideCollectionPermissions = $arRow['arOverrideCollectionPermissions']; $area->arIsGlobal = $arRow['arIsGlobal']; $area->arInheritPermissionsFromAreaOnCID = $arRow['arInheritPermissionsFromAreaOnCID']; $area->cID = $c->getCollectionID(); $area->c = &$c; Cache::set('area', $c->getCollectionID() . ':' . $arHandle, $area); return $area; } } /** * Gets or creates if necessary an Area for the given Page, Handle * @param Page|Collection $c * @param string $arHandle * @param boolean $arIsGlobal * @return Area */ public static function getOrCreate(&$c, $arHandle, $arIsGlobal = 0) { /* different than get(), getOrCreate() is called by the templates. If no area record exists for the permissions cID / handle combination, we create one. This is to make our lives easier */ $area = self::get($c, $arHandle); if (is_object($area)) { if ($area->isGlobalArea() == $arIsGlobal) { return $area; } else if (!$area->isGlobalArea() && !$arIsGlobal) { return $area; } } $cID = $c->getCollectionID(); $db = Loader::db(); if (!$arIsGlobal) { $arIsGlobal = 0; } $db->Replace('Areas', array('cID' => $cID, 'arHandle' => $arHandle, 'arIsGlobal' => $arIsGlobal), array('arHandle', 'cID'), true); if ($arIsGlobal) { // we create a stack for it Stack::getOrCreateGlobalArea($arHandle); } $area = self::get($c, $arHandle); // we're assuming the insert succeeded $area->rescanAreaPermissionsChain(); return $area; } /** * Get all of the blocks within the current area for a given page * @param Page|Collection $c * @return Block[] */ public function getAreaBlocksArray($c) { if (is_array($this->areaBlocksArray)) { return $this->areaBlocksArray; } $this->cID = $c->getCollectionID(); $this->c = $c; $this->areaBlocksArray = array(); if ($this->arIsGlobal) { $blocks = array(); $cp = new Permissions($c); if ($cp->canViewPageVersions()) { $c = Stack::getByName($this->arHandle); } else { $c = Stack::getByName($this->arHandle, 'ACTIVE'); } if (is_object($c)) { $blocks = $c->getBlocks(STACKS_AREA_NAME); $globalArea = self::get($c, STACKS_AREA_NAME); } } else { $blocks = $c->getBlocks($this->arHandle); } foreach($blocks as $ab) { if ($this->arIsGlobal && is_object($globalArea)) { $ab->setBlockAreaObject($globalArea); } else { $ab->setBlockAreaObject($this); } $this->areaBlocksArray[] = $ab; $this->totalBlocks++; } return $this->areaBlocksArray; } /** * determins based on permissions what types of blocks, if any can be added to this area * @param Page|Collection $c * @param AreaPermissions * @return boolean|BlockTypeList */ public function getAddBlockTypes(&$c, &$ap) { if ($ap->canAddBlocks()) { $bt = new BlockTypeList($ap->addBlockTypes); } else { $bt = false; } return $bt; } /** * gets a list of all areas - no relation to the current page or area object * possibly could be set as a static method?? * @return array */ public function getHandleList() { $db = Loader::db(); $r = $db->Execute('select distinct arHandle from Areas order by arHandle asc'); $handles = array(); while ($row = $r->FetchRow()) { $handles[] = $row['arHandle']; } $r->Free(); unset($r); unset($db); return $handles; } /** * This function removes all permissions records for the current Area * and sets it to inherit from the Page permissions * @return void */ function revertToPagePermissions() { // this function removes all permissions records for a particular area on this page // and sets it to inherit from the page above // this function will also need to ensure that pages below it do the same $db = Loader::db(); $v = array($this->getAreaHandle(), $this->getCollectionID()); $db->query("delete from AreaPermissionAssignments where arHandle = ? and cID = ?", $v); $db->query("update Areas set arOverrideCollectionPermissions = 0 where arID = ?", array($this->getAreaID())); // now we set rescan this area to determine where it -should- be inheriting from $this->arOverrideCollectionPermissions = false; $this->rescanAreaPermissionsChain(); $areac = $this->getAreaCollectionObject(); if ($areac->isMasterCollection()) { $this->rescanSubAreaPermissionsMasterCollection($areac); } else if ($areac->overrideTemplatePermissions()) { // now we scan sub areas $this->rescanSubAreaPermissions(); } $ca = new Cache(); $a = Cache::delete('area', $this->getCollectionID() . ':' . $this->getAreaHandle()); } public function __destruct() { unset($this->c); } /** * Rescans the current Area's permissions ensuring that it's enheriting permissions properly up the chain * @return void */ public function rescanAreaPermissionsChain() { $db = Loader::db(); if ($this->overrideCollectionPermissions()) { return false; } // first, we obtain the inheritance of permissions for this particular collection $areac = $this->getAreaCollectionObject(); if (is_a($areac, 'Page')) { if ($areac->getCollectionInheritance() == 'PARENT') { $cIDToCheck = $areac->getCollectionParentID(); // first, we temporarily set the arInheritPermissionsFromAreaOnCID to whatever the arInheritPermissionsFromAreaOnCID is set to // in the immediate parent collection $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())); $db->query("update Areas set arInheritPermissionsFromAreaOnCID = ? where arID = ?", array($arInheritPermissionsFromAreaOnCID, $this->getAreaID())); // now we do the recursive rescan to see if any areas themselves override collection permissions while ($cIDToCheck > 0) { $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())); if ($row['arOverrideCollectionPermissions'] == 1) { break; } else { $cIDToCheck = $row['cParentID']; } } if (is_array($row)) { if ($row['arOverrideCollectionPermissions']) { // then that means we have successfully found a parent area record that we can inherit from. So we set // out current area to inherit from that COLLECTION ID (not area ID - from the collection ID) $db->query("update Areas set arInheritPermissionsFromAreaOnCID = ? where arID = ?", array($row['cID'], $this->getAreaID())); $this->arInheritPermissionsFromAreaOnCID = $row['cID']; } } } else if ($areac->getCollectionInheritance() == 'TEMPLATE') { // we grab an area on the master collection (if it exists) $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())); if ($doOverride) { $db->query("update Areas set arInheritPermissionsFromAreaOnCID = ? where arID = ?", array($areac->getPermissionsCollectionID(), $this->getAreaID())); $this->arInheritPermissionsFromAreaOnCID = $areac->getPermissionsCollectionID(); } } } Cache::delete('area', $this->getCollectionID() . ':' . $this->getAreaHandle()); } /** * works a lot like rescanAreaPermissionsChain() but it works down. This is typically only * called when we update an area to have specific permissions, and all areas that are on pagesbelow it with the same * handle, etc... should now inherit from it. * @return void */ function rescanSubAreaPermissions($cIDToCheck = null) { // works a lot like rescanAreaPermissionsChain() but it works down. This is typically only // called when we update an area to have specific permissions, and all areas that are on pagesbelow it with the same // handle, etc... should now inherit from it. $db = Loader::db(); if (!$cIDToCheck) { $cIDToCheck = $this->getCollectionID(); } $v = array($this->getAreaHandle(), 'PARENT', $cIDToCheck); $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); while ($row = $r->fetchRow()) { // these are all the areas we need to update. $db->query("update Areas set arInheritPermissionsFromAreaOnCID = " . $this->getAreaCollectionInheritID() . " where arID = " . $row['arID']); $this->rescanSubAreaPermissions($row['cID']); } } /** * similar to rescanSubAreaPermissions, but for those who have setup their pages to inherit master collection permissions * @see Area::rescanSubAreaPermissions() * @return void */ function rescanSubAreaPermissionsMasterCollection($masterCollection) { // like above, but for those who have setup their pages to inherit master collection permissions // this might make more sense in the collection class, but I'm putting it here if (!$masterCollection->isMasterCollection()) { return false; } // 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 $toSetCID = ($this->overrideCollectionPermissions()) ? $masterCollection->getCollectionID() : 0; $db = Loader::db(); $v = array($this->getAreaHandle(), 'TEMPLATE', $masterCollection->getCollectionID()); $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); } /** * displays the Area in the page * ex: $a = new Area('Main'); $a->display($c); * @param Page|Collection $c * @param Block[] $alternateBlockArray optional array of blocks to render instead of default behavior * @return void */ function display(&$c, $alternateBlockArray = null) { if(!intval($c->cID)){ //Invalid Collection return false; } if ($this->arIsGlobal) { $stack = Stack::getByName($this->arHandle); } $currentPage = Page::getCurrentPage(); $ourArea = self::getOrCreate($c, $this->arHandle, $this->arIsGlobal); if (count($this->customTemplateArray) > 0) { $ourArea->customTemplateArray = $this->customTemplateArray; } if (count($this->attributes) > 0) { $ourArea->attributes = $this->attributes; } if ($this->maximumBlocks > -1) { $ourArea->maximumBlocks = $this->maximumBlocks; } $ap = new Permissions($ourArea); if (!$ap->canViewArea()) { return false; } $blocksToDisplay = ($alternateBlockArray) ? $alternateBlockArray : $ourArea->getAreaBlocksArray($c, $ap); $this->totalBlocks = $ourArea->getTotalBlocksInArea(); $u = new User(); $bv = new BlockView(); // now, we iterate through these block groups (which are actually arrays of block objects), and display them on the page if ($this->showControls && $c->isEditMode() && $ap->canViewAreaControls()) { $bv->renderElement('block_area_header', array('a' => $ourArea)); } $bv->renderElement('block_area_header_view', array('a' => $ourArea)); //display layouts tied to this area //Might need to move this to a better position $areaLayouts = $this->getAreaLayouts($c); if(is_array($areaLayouts) && count($areaLayouts)){ foreach($areaLayouts as $layout){ $layout->display($c,$this); } if($this->showControls && ($c->isArrangeMode() || $c->isEditMode())) { echo '<div class="ccm-layouts-block-arrange-placeholder ccm-block-arrange"></div>'; } } $blockPositionInArea = 1; //for blockWrapper output foreach ($blocksToDisplay as $b) { $includeEditStrip = false; $bv = new BlockView(); $bv->setAreaObject($ourArea); // this is useful for rendering areas from one page // onto the next and including interactive elements if ($currentPage->getCollectionID() != $c->getCollectionID()) { $b->setBlockActionCollectionID($c->getCollectionID()); } if ($this->arIsGlobal && is_object($stack)) { $b->setBlockActionCollectionID($stack->getCollectionID()); } $p = new Permissions($b); if ($c->isEditMode() && $this->showControls && $p->canViewEditInterface()) { $includeEditStrip = true; } if ($p->canViewBlock()) { if (!$c->isEditMode()) { $this->outputBlockWrapper(true, $b, $blockPositionInArea); } if ($includeEditStrip) { $bv->renderElement('block_controls', array( 'a' => $ourArea, 'b' => $b, 'p' => $p )); $bv->renderElement('block_header', array( 'a' => $ourArea, 'b' => $b, 'p' => $p )); } $bv->render($b); if ($includeEditStrip) { $bv->renderElement('block_footer'); } if (!$c->isEditMode()) { $this->outputBlockWrapper(false, $b, $blockPositionInArea); } } $blockPositionInArea++; } $bv->renderElement('block_area_footer_view', array('a' => $ourArea)); if ($this->showControls && $c->isEditMode() && $ap->canViewAreaControls()) { $bv->renderElement('block_area_footer', array('a' => $ourArea)); } } /** * outputs the block wrapers for each block * Internal helper function for display() * @return void */ protected function outputBlockWrapper($isStart, &$block, $blockPositionInArea) { static $th = null; $enclosing = $isStart ? $this->enclosingStart : $this->enclosingEnd; $hasReplacements = $isStart ? $this->enclosingStartHasReplacements : $this->enclosingEndHasReplacements; if (!empty($enclosing) && $hasReplacements) { $bID = $block->getBlockID(); $btHandle = $block->getBlockTypeHandle(); $bName = ($btHandle == 'core_stack_display') ? Stack::getByID($block->getInstance()->stID)->getStackName() : $block->getBlockName(); $th = is_null($th) ? Loader::helper('text') : $th; $bSafeName = $th->entities($bName); $alternatingClass = ($blockPositionInArea % 2 == 0) ? 'even' : 'odd'; echo sprintf($enclosing, $bID, $btHandle, $bSafeName, $blockPositionInArea, $alternatingClass); } else { echo $enclosing; } } /** * Gets all layout grid objects for a collection * @param Page|Collection $c * @return Layout[] */ public function getAreaLayouts($c){ if( !intval($c->cID) ){ //Invalid Collection return false; } if (!$c->hasLayouts()) { return array(); } $db = Loader::db(); $vals = array( intval($c->cID), $c->getVersionID(), $this->getAreaHandle() ); $sql = 'SELECT * FROM CollectionVersionAreaLayouts WHERE cID=? AND cvID=? AND arHandle=? ORDER BY position ASC, cvalID ASC'; $rows = $db->getArray($sql,$vals); $layouts=array(); $i=0; if(is_array($rows)) foreach($rows as $row){ $layout = Layout::getById( intval($row['layoutID']) ); if( is_object($layout) ){ $i++; //check position is correct, update if not if( $i != $row['position'] || $renumbering ){ $renumbering=1; $db->query( 'UPDATE CollectionVersionAreaLayouts SET position=? WHERE cvalID=?' , array($i, $row['cvalID']) ); } $layout->position=$i; $layout->cvalID = intval($row['cvalID']); $layout->setAreaObj( $this ); $layout->setAreaNameNumber( intval($row['areaNameNumber']) ); $layouts[]=$layout; } } return $layouts; } /** * Exports the area to content format * @todo need more documentation export? */ public function export($p, $page) { $area = $p->addChild('area'); $area->addAttribute('name', $this->getAreaHandle()); $blocks = $page->getBlocks($this->getAreaHandle()); foreach($blocks as $bl) { $bl->export($area); } } /** * Specify HTML to automatically print before blocks contained within the area * Pass true for $hasReplacements if the $html contains sprintf replacements tokens. * Available tokens: * %1$s -> Block ID * %2$s -> Block Type Handle * %3$s -> Block/Stack Name * %4$s -> Block position in area (first block is 1, second block is 2, etc.) * %5$s -> 'odd' or 'even' (useful for "zebra stripes" CSS classes) * @param string $html * @param boolean $hasReplacements * @return void */ function setBlockWrapperStart($html, $hasReplacements = false) { $this->enclosingStart = $html; $this->enclosingStartHasReplacements = $hasReplacements; } /** * Set HTML that automatically prints after any blocks contained within the area * Pass true for $hasReplacements if the $html contains sprintf replacements tokens. * See setBlockWrapperStart() comments for available tokens. * @param string $html * @param boolean $hasReplacements * @return void */ function setBlockWrapperEnd($html, $hasReplacements = false) { $this->enclosingEnd = $html; $this->enclosingEndHasReplacements = $hasReplacements; } public function overridePagePermissions() { $db = Loader::db(); $cID = $this->getCollectionID(); $v = array($cID, $this->getAreaHandle()); // update the Area record itself. Hopefully it's been created. $db->query("update Areas set arOverrideCollectionPermissions = 1, arInheritPermissionsFromAreaOnCID = 0 where arID = ?", array($this->getAreaID())); // copy permissions from the page to the area $permissions = PermissionKey::getList('area'); foreach($permissions as $pk) { $pk->setPermissionObject($this); $pk->copyFromPageToArea(); } // finally, we rescan subareas so that, if they are inheriting up the tree, they inherit from this place $this->arInheritPermissionsFromAreaOnCID = $this->getCollectionID(); // we don't need to actually save this on the area, but we need it for the rescan function $this->arOverrideCollectionPermissions = 1; // to match what we did above - useful for the rescan functions below $acobj = $this->getAreaCollectionObject(); if ($acobj->isMasterCollection()) { // 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 $this->rescanSubAreaPermissionsMasterCollection($acobj); } else { $this->rescanSubAreaPermissions(); } $a = Cache::delete('area', $this->getCollectionID() . ':' . $this->getAreaHandle()); } }