PageRenderTime 88ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/web/concrete/core/Block/Block.php

https://github.com/Shotster/concrete5-5.7.0
PHP | 1139 lines | 839 code | 189 blank | 111 comment | 138 complexity | 9f640997a2a5d58fa9897dc554ceb1ed MD5 | raw file
Possible License(s): MIT, LGPL-2.1
  1. <?
  2. namespace Concrete\Core\Block;
  3. use \Concrete\Core\Foundation\Object;
  4. use Loader;
  5. use Environment;
  6. use CacheLocal;
  7. use BlockType;
  8. use Page;
  9. use Area;
  10. use Events;
  11. use Core;
  12. use Cache;
  13. use \Concrete\Core\Package\PackageList;
  14. use \Concrete\Core\Block\View\BlockView;
  15. use \Concrete\Core\Feature\Assignment\Assignment as FeatureAssignment;
  16. use \Concrete\Core\Feature\Assignment\CollectionVersionAssignment as CollectionVersionFeatureAssignment;
  17. class Block extends Object implements \Concrete\Core\Permission\ObjectInterface {
  18. protected $cID;
  19. protected $arHandle;
  20. protected $c;
  21. protected $csrID;
  22. protected $proxyBlock = false;
  23. protected $bActionCID;
  24. public static function populateManually($blockInfo, $c, $a) {
  25. $b = new Block;
  26. $b->setPropertiesFromArray($blockInfo);
  27. if (is_object($a)) {
  28. $b->a = $a;
  29. $b->arHandle = $a->getAreaHandle();
  30. } else if ($a != null) {
  31. $b->arHandle = $a; // passing the area name. We only pass the object when we're adding from the front-end
  32. }
  33. $b->cID = $c->getCollectionID();
  34. $b->c = $c;
  35. return $b;
  36. }
  37. public function getPermissionObjectIdentifier() {
  38. return $this->cID . ':' . $this->getAreaHandle() . ':' . $this->bID;
  39. }
  40. public function getPermissionResponseClassName() {
  41. return '\\Concrete\\Core\\Permission\\Response\\BlockResponse';
  42. }
  43. public function getPermissionAssignmentClassName() {
  44. return '\\Concrete\\Core\\Permission\\Assignment\\BlockAssignment';
  45. }
  46. public function getPermissionObjectKeyCategoryHandle() {
  47. return 'block';
  48. }
  49. public static function getByID($bID, $c = null, $a = null) {
  50. if ($c == null && $a == null) {
  51. $cID = 0;
  52. $arHandle = "";
  53. $cvID = 0;
  54. $b = CacheLocal::getEntry('block', $bID);
  55. } else {
  56. if (is_object($a)) {
  57. $arHandle = $a->getAreaHandle();
  58. } else if ($a != null) {
  59. $arHandle = $a;
  60. $a = Area::getOrCreate($c, $a);
  61. }
  62. $cID = $c->getCollectionID();
  63. $cvID = $c->getVersionID();
  64. $b = CacheLocal::getEntry('block', $bID . ':' . $cID . ':' . $cvID . ':' . $arHandle);
  65. }
  66. if ($b instanceof Block) {
  67. return $b;
  68. }
  69. $db = Loader::db();
  70. $b = new Block;
  71. if ($c == null && $a == null) {
  72. // just grab really specific block stuff
  73. $q = "select bID, bIsActive, BlockTypes.btID, Blocks.btCachedBlockRecord, BlockTypes.btHandle, BlockTypes.pkgID, BlockTypes.btName, bName, bDateAdded, bDateModified, bFilename, Blocks.uID from Blocks inner join BlockTypes on (Blocks.btID = BlockTypes.btID) where bID = ?";
  74. $b->isOriginal = 1;
  75. $v = array($bID);
  76. } else {
  77. $b->arHandle = $arHandle;
  78. $b->a = $a;
  79. $b->cID = $cID;
  80. $b->c = ($c) ? $c : '';
  81. $vo = $c->getVersionObject();
  82. $cvID = $vo->getVersionID();
  83. $v = array($b->arHandle, $cID, $cvID, $bID);
  84. $q = "select CollectionVersionBlocks.isOriginal, CollectionVersionBlocks.cbIncludeAll, Blocks.btCachedBlockRecord, BlockTypes.pkgID, CollectionVersionBlocks.cbOverrideAreaPermissions, CollectionVersionBlocks.cbDisplayOrder, Blocks.bIsActive, Blocks.bID, Blocks.btID, bName, bDateAdded, bDateModified, bFilename, btHandle, Blocks.uID from CollectionVersionBlocks inner join Blocks on (CollectionVersionBlocks.bID = Blocks.bID) inner join BlockTypes on (Blocks.btID = BlockTypes.btID) where CollectionVersionBlocks.arHandle = ? and CollectionVersionBlocks.cID = ? and (CollectionVersionBlocks.cvID = ? or CollectionVersionBlocks.cbIncludeAll=1) and CollectionVersionBlocks.bID = ?";
  85. }
  86. $r = $db->query($q, $v);
  87. $row = $r->fetchRow();
  88. if (is_array($row)) {
  89. $b->setPropertiesFromArray($row);
  90. $r->free();
  91. $bt = BlockType::getByID($b->getBlockTypeID());
  92. $class = $bt->getBlockTypeClass();
  93. if ($class == false) {
  94. // we can't find the class file, so we return
  95. return false;
  96. }
  97. $b->instance = new $class($b);
  98. if ($c != null || $a != null) {
  99. CacheLocal::set('block', $bID . ':' . $cID . ':' . $cvID . ':' . $arHandle, $b);
  100. } else {
  101. $ca = new Cache();
  102. CacheLocal::set('block', $bID, $b);
  103. }
  104. return $b;
  105. }
  106. }
  107. /**
  108. * Returns a global block
  109. */
  110. public static function getByName($globalBlockName) {
  111. if(!$globalBlockName) return;
  112. $db = Loader::db();
  113. $scrapbookHelper=Loader::helper('concrete/scrapbook');
  114. $globalScrapbookPage=$scrapbookHelper->getGlobalScrapbookPage();
  115. if ($globalScrapbookPage->getCollectionID()) {
  116. $row = $db->getRow( 'SELECT b.bID, cvb.arHandle FROM Blocks AS b, CollectionVersionBlocks AS cvb '.
  117. 'WHERE b.bName=? AND b.bID=cvb.bID AND cvb.cID=? ORDER BY cvb.cvID DESC',
  118. array($globalBlockName, intval($globalScrapbookPage->getCollectionId()) ) );
  119. if ($row != false && isset($row['bID']) && $row['bID'] > 0) {
  120. return Block::getByID( $row['bID'], $globalScrapbookPage, $row['arHandle'] );
  121. }
  122. }
  123. //If we made it this far, either there's no scrapbook (clean installation of Concrete5.5+),
  124. // or the block wasn't in the legacy scrapbook -- so look in stacks...
  125. $sql = 'SELECT b.bID, cvb.arHandle, cvb.cID'
  126. . ' FROM Blocks AS b'
  127. . ' INNER JOIN CollectionVersionBlocks AS cvb ON b.bID = cvb.bID'
  128. . ' INNER JOIN CollectionVersions AS cv ON cvb.cID = cv.cID AND cvb.cvID = cv.cvID'
  129. . ' WHERE b.bName = ? AND cv.cvIsApproved = 1'
  130. . ' AND cvb.cID IN (SELECT cID FROM Stacks)'
  131. . ' ORDER BY cvb.cvID DESC'
  132. . ' LIMIT 1';
  133. $vals = array($globalBlockName);
  134. $row = $db->getRow($sql, $vals);
  135. if ($row != false && isset($row['bID']) && $row['bID'] > 0) {
  136. return Block::getByID($row['bID'], Page::getByID($row['cID']), $row['arHandle']);
  137. } else {
  138. return new Block();
  139. }
  140. }
  141. public function setProxyBlock($block) {
  142. $this->proxyBlock = $block;
  143. }
  144. public function getProxyBlock() {
  145. return $this->proxyBlock;
  146. }
  147. public function display( $view = 'view') {
  148. if ($this->getBlockTypeID() < 1) {
  149. return ;
  150. }
  151. $bv = new BlockView($this);
  152. $bv->render($view);
  153. }
  154. // if $c is provided, then we check to see if this particular block is aliased
  155. // to this particular collection
  156. public function isAlias($c = null) {
  157. if ($c) {
  158. $db = Loader::db();
  159. $cID = $c->getCollectionID();
  160. $vo = $c->getVersionObject();
  161. $cvID = $vo->getVersionID();
  162. $q = "select bID from CollectionVersionBlocks where bID = ? and cID=? and isOriginal = 0 and cvID = ?";
  163. $r = $db->query($q, array($this->bID, $cID, $cvID));
  164. if ($r) {
  165. return ($r->numRows() > 0);
  166. }
  167. } else {
  168. return (!$this->isOriginal);
  169. }
  170. }
  171. public function isAliasOfMasterCollection() {
  172. return $this->getBlockCollectionObject()->isBlockAliasedFromMasterCollection($this);
  173. }
  174. public function isGlobal() {
  175. return false; // legacy. no more scrapbooks in the dashboard.
  176. }
  177. public function isBlockInStack() {
  178. $co = $this->getBlockCollectionObject();
  179. if (is_object($co)) {
  180. if ($co->getPageTypeHandle() == STACKS_PAGE_TYPE) {
  181. return true;
  182. }
  183. }
  184. return false;
  185. }
  186. public function getBlockCachedRecord() {
  187. return $this->btCachedBlockRecord;
  188. }
  189. public function getBlockCachedOutput($area) {
  190. $db = Loader::db();
  191. $arHandle = $this->getAreaHandle();
  192. if ($this->isBlockInStack() && is_object($area)) {
  193. $arHandle = $area->getAreaHandle();
  194. $cx = Page::getCurrentPage();
  195. $cID = $cx->getCollectioniD();
  196. $cvID = $cx->getVersionID();
  197. } else {
  198. $c = $this->getBlockCollectionObject();
  199. $cID = $c->getCollectionID();
  200. $cvID = $c->getVersionID();
  201. }
  202. $r = $db->GetRow('select btCachedBlockOutput, btCachedBlockOutputExpires from CollectionVersionBlocksOutputCache where cID = ? and cvID = ? and bID = ? and arHandle = ? ', array(
  203. $cID, $cvID, $this->getBlockID(), $arHandle));
  204. if ($r['btCachedBlockOutputExpires'] < time()) {
  205. return false;
  206. }
  207. return $r['btCachedBlockOutput'];
  208. }
  209. public function setBlockCachedOutput($content, $lifetime, $area) {
  210. $db = Loader::db();
  211. $c = $this->getBlockCollectionObject();
  212. $btCachedBlockOutputExpires = strtotime('+5 years');
  213. if ($lifetime > 0) {
  214. $btCachedBlockOutputExpires = time() + $lifetime;
  215. }
  216. $arHandle = $this->getAreaHandle();
  217. $cID = $c->getCollectionID();
  218. $cvID = $c->getVersionID();
  219. if ($this->isBlockInStack() && is_object($area)) {
  220. $arHandle = $area->getAreaHandle();
  221. $cx = Page::getCurrentPage();
  222. $cID = $cx->getCollectioniD();
  223. $cvID = $cx->getVersionID();
  224. }
  225. if ($arHandle && $cID && $cvID) {
  226. $db->Replace('CollectionVersionBlocksOutputCache', array('cID' => $cID, 'cvID' => $cvID, 'bID' => $this->getBlockID(), 'arHandle' => $arHandle, 'btCachedBlockOutput' => $content, 'btCachedBlockOutputExpires' => $btCachedBlockOutputExpires),
  227. array('cID', 'cvID', 'arHandle', 'bID'), true);
  228. }
  229. }
  230. public function inc($file) {
  231. $b = $this;
  232. if (file_exists($this->getBlockPath() . '/' . $file)) {
  233. include($this->getBlockPath() . '/' . $file);
  234. }
  235. }
  236. /*
  237. * Returns a path to where the block type's files are located.
  238. * @access public
  239. * @return string $path
  240. */
  241. function revertToAreaPermissions() {
  242. $c = $this->getBlockCollectionObject();
  243. $db = Loader::db();
  244. $v = array($c->getCollectionID(), $c->getVersionID(), $this->bID);
  245. $db->query("delete from BlockPermissionAssignments where cID = ? and cvID = ? and bID = ?", $v);
  246. $v[] = $this->arHandle;
  247. $db->query("update CollectionVersionBlocks set cbOverrideAreaPermissions = 0 where cID = ? and (cvID = ? or cbIncludeAll=1) and bID = ? and arHandle = ?", $v);
  248. }
  249. public function getBlockPath() {
  250. if ($this->getPackageID() > 0) {
  251. $pkgHandle = $this->getPackageHandle();
  252. $dirp = (is_dir(DIR_PACKAGES . '/' . $pkgHandle)) ? DIR_PACKAGES : DIR_PACKAGES_CORE;
  253. $dir = $dirp . '/' . $pkgHandle . '/' . DIRNAME_BLOCKS . '/' . $this->getBlockTypeHandle();
  254. } else {
  255. if (is_dir(DIR_FILES_BLOCK_TYPES . '/' . $this->getBlockTypeHandle())) {
  256. $dir = DIR_FILES_BLOCK_TYPES . '/' . $this->getBlockTypeHandle();
  257. } else {
  258. $dir = DIR_FILES_BLOCK_TYPES_CORE . '/' . $this->getBlockTypeHandle();
  259. }
  260. }
  261. return $dir;
  262. }
  263. function loadNewCollection(&$c) {
  264. $this->c = $c;
  265. }
  266. function setBlockAreaObject(&$a) {
  267. $this->a = $a;
  268. $this->arHandle = $a->getAreaHandle();
  269. }
  270. function getBlockAreaObject() {
  271. if (is_object($this->a)) {
  272. return $this->a;
  273. }
  274. }
  275. public function disableBlockVersioning() {
  276. return $this->cbIncludeAll;
  277. }
  278. function getOriginalCollection() {
  279. // given a block ID, we find the original collection ID (where this bID is marked as isOriginal)
  280. $db = Loader::db();
  281. $q = "select Pages.cID, cIsTemplate from Pages inner join CollectionVersionBlocks on (CollectionVersionBlocks.cID = Pages.cID) where CollectionVersionBlocks.bID = ? and CollectionVersionBlocks.isOriginal = 1";
  282. $r = $db->query($q, array($this->bID));
  283. if ($r) {
  284. $row = $r->fetchRow();
  285. $cID = $row['cID'];
  286. $nc = Page::getByID($cID, "ACTIVE");
  287. return $nc;
  288. }
  289. }
  290. function getNumChildren() {
  291. $db = Loader::db();
  292. $q = "select count(*) as total from CollectionVersionBlocks where bID = ? and isOriginal = 0";
  293. $total = $db->getOne($q, array($this->bID));
  294. return $total;
  295. }
  296. public function getInstance() {
  297. if (ENABLE_BLOCK_CACHE && $this->instance->cacheBlockRecord() && is_object($this->instance->getBlockControllerData())) {
  298. $this->instance->__construct();
  299. } else {
  300. $bt = $this->getBlockTypeObject();
  301. $class = $bt->getBlockTypeClass();
  302. $this->instance = new $class($this);
  303. }
  304. $this->instance->setBlockObject($this);
  305. return $this->instance;
  306. }
  307. public function getController() {
  308. return $this->getInstance();
  309. }
  310. function getCollectionList() {
  311. // gets a list of collections that include this block, along with area name, etc...
  312. // used in the block_details.php page in the admin control panel
  313. $db = Loader::db();
  314. $q = "select DISTINCT Pages.cID from CollectionVersionBlocks inner join Pages on (CollectionVersionBlocks.cID = Pages.cID) inner join CollectionVersions on (CollectionVersions.cID = Pages.cID) where CollectionVersionBlocks.bID = ?";
  315. $r = $db->query($q, array($this->bID));
  316. $cArray = array();
  317. if ($r) {
  318. while ($row = $r->fetchRow()) {
  319. $cArray[] = Page::getByID($row['cID'], 'RECENT');
  320. }
  321. $r->free();
  322. return $cArray;
  323. }
  324. }
  325. function update($data) {
  326. // this function updates fields common to every block
  327. $db = Loader::db();
  328. $dh = Loader::helper('date');
  329. $bDateModified = $dh->getSystemDateTime();
  330. $bID = $this->bID;
  331. $v = array($bDateModified, $bID);
  332. $q = "update Blocks set bDateModified = ? where bID = ?";
  333. $r = $db->prepare($q);
  334. $res = $db->execute($r, $v);
  335. $this->refreshBlockOutputCache();
  336. $btID = $this->getBlockTypeID();
  337. $bt = BlockType::getByID($btID);
  338. $class = $bt->getBlockTypeClass();
  339. $bc = new $class($this);
  340. $bc->save($data);
  341. }
  342. function isActive() {
  343. return $this->bIsActive;
  344. }
  345. function deactivate() {
  346. $db = Loader::db();
  347. $q = "update Blocks set bIsActive = 0 where bID = ?";
  348. $db->query($q, array($this->bID));
  349. }
  350. function activate() {
  351. $db = Loader::db();
  352. $q = "update Blocks set bIsActive = 1 where bID = ?";
  353. $db->query($q, array($this->bID));
  354. }
  355. public function getPackageID() {return $this->pkgID;}
  356. public function getPackageHandle() {
  357. return PackageList::getHandle($this->pkgID);
  358. }
  359. function updateBlockName( $name, $force=0) {
  360. // this function allows children blocks to change the name of the block. This is useful
  361. // for the block search functionality - a content local block can make the block name
  362. // the fix 30 characters of the content field, for example. This only works if no name has
  363. // been assigned to the block already. If one has, then we disregard.
  364. $db = Loader::db();
  365. if (!$this->bName || $force==1) {
  366. if( strlen($name)>60 ) $name = substr($name, 0, 60) . '...';
  367. $v = array(htmlspecialchars($name), $this->bID);
  368. $q = "UPDATE Blocks SET bName = ? WHERE bID = ?";
  369. $r = $db->query($q,$v);
  370. //$res = $db->execute($r, $v);
  371. $this->bName=$name;
  372. }
  373. }
  374. function alias($c) {
  375. // creates an alias of the block, attached to this collection, within the CollectionVersionBlocks table
  376. // additionally, this command grabs the permissions from the original record in the
  377. // CollectionVersionBlocks table, and attaches them to the new one
  378. $db = Loader::db();
  379. $bID = $this->bID;
  380. $newBlockDisplayOrder = $c->getCollectionAreaDisplayOrder($this->getAreaHandle());
  381. $cvID = $c->getVersionID();
  382. $cID = $c->getCollectionID();
  383. $v = array($cID, $cvID, $this->bID, $this->getAreaHandle());
  384. $q = "select count(bID) from CollectionVersionBlocks where cID = ? and cvID = ? and bID = ? and arHandle = ?";
  385. $total = $db->getOne($q, $v);
  386. if ($total == 0) {
  387. array_push($v, $newBlockDisplayOrder, 0, $this->overrideAreaPermissions());
  388. $q = "insert into CollectionVersionBlocks (cID, cvID, bID, arHandle, cbDisplayOrder, isOriginal, cbOverrideAreaPermissions) values (?, ?, ?, ?, ?, ?, ?)";
  389. $r = $db->prepare($q);
  390. $res = $db->execute($r, $v);
  391. // styles
  392. $csrID = $this->getBlockCustomStyleRuleID();
  393. if ($csrID > 0) {
  394. $db->Execute('insert into CollectionVersionBlockStyles (cID, cvID, bID, arHandle, csrID) values (?, ?, ?, ?, ?)', array(
  395. $cID,
  396. $cvID,
  397. $this->bID,
  398. $this->getAreaHandle(),
  399. $csrID
  400. ));
  401. }
  402. if ($res) {
  403. // now we grab the permissions from the block we're aliasing from
  404. $oc = $this->getBlockCollectionObject();
  405. $ocID = $oc->getCollectionID();
  406. $ocvID = $oc->getVersionID();
  407. $qf = "select faID from BlockFeatureAssignments where bID = ? and cID = ? and cvID = ?";
  408. $rf = $db->query($qf, array($this->bID, $ocID, $ocvID));
  409. if ($rf) {
  410. while ($rowf = $rf->fetchRow()) {
  411. $db->Replace('BlockFeatureAssignments',
  412. array('cID' => $cID, 'cvID' => $cvID, 'bID' => $this->bID, 'faID' => $rowf['faID']),
  413. array('cID', 'cvID', 'bID', 'faID'), true);
  414. }
  415. $rf->free();
  416. }
  417. $qa = "select paID, pkID from BlockPermissionAssignments where bID = ? and cID = ? and cvID = ?";
  418. $ra = $db->query($qa, array($this->bID, $ocID, $ocvID));
  419. if ($ra) {
  420. while ($row_a = $ra->fetchRow()) {
  421. $db->Replace('BlockPermissionAssignments',
  422. array('cID' => $cID, 'cvID' => $cvID, 'bID' => $this->bID, 'paID' => $row_a['paID'], 'pkID' => $row_a['pkID']),
  423. array('cID', 'cvID', 'bID', 'paID', 'pkID'), true);
  424. }
  425. $ra->free();
  426. }
  427. }
  428. }
  429. }
  430. /**
  431. * Moves a block onto a new page and into a new area. Does not change any data about the block otherwise
  432. */
  433. function move($nc, $area) {
  434. $db = Loader::db();
  435. $bID = $this->getBlockID();
  436. $cID = $this->getBlockCollectionID();
  437. $newBlockDisplayOrder = $nc->getCollectionAreaDisplayOrder($area->getAreaHandle());
  438. $v = array($nc->getCollectionID(), $nc->getVersionID(), $area->getAreaHandle(), $newBlockDisplayOrder, $cID, $bID, $this->arHandle);
  439. $db->Execute('update CollectionVersionBlocks set cID = ?, cvID = ?, arHandle = ?, cbDisplayOrder = ? where cID = ? and bID = ? and arHandle = ? and isOriginal = 1', $v);
  440. }
  441. function duplicate($nc, $isCopyFromMasterCollectionPropagation = false) {
  442. // duplicate takes a new collection as its argument, and duplicates the existing block
  443. // to that collection
  444. $db = Loader::db();
  445. $dh = Loader::helper('date');
  446. $bt = BlockType::getByID($this->getBlockTypeID());
  447. $blockTypeClass = $bt->getBlockTypeClass();
  448. $bc = new $blockTypeClass($this);
  449. if(!$bc) return false;
  450. $bDate = $dh->getSystemDateTime();
  451. $v = array($this->bName, $bDate, $bDate, $this->bFilename, $this->btID, $this->uID);
  452. $q = "insert into Blocks (bName, bDateAdded, bDateModified, bFilename, btID, uID) values (?, ?, ?, ?, ?, ?)";
  453. $r = $db->prepare($q);
  454. $res = $db->execute($r, $v);
  455. $newBID = $db->Insert_ID(); // this is the latest inserted block ID
  456. // now, we duplicate the block-specific permissions
  457. $oc = $this->getBlockCollectionObject();
  458. $ocID = $oc->getCollectionID();
  459. $ovID = $oc->getVersionID();
  460. $ncID = $nc->getCollectionID();
  461. $nvID = $nc->getVersionID();
  462. $q = "select paID, pkID from BlockPermissionAssignments where cID = '$ocID' and bID = ? and cvID = ?";
  463. $r = $db->query($q, array($this->bID, $ovID));
  464. if ($r) {
  465. while ($row = $r->fetchRow()) {
  466. $db->Replace('BlockPermissionAssignments',
  467. array('cID' => $ncID, 'cvID' => $nvID, 'bID' => $newBID, 'paID' => $row['paID'], 'pkID' => $row['pkID']),
  468. array('cID', 'cvID', 'bID', 'paID', 'pkID'), true);
  469. }
  470. $r->free();
  471. }
  472. // we duplicate block-specific sub-content
  473. if ($isCopyFromMasterCollectionPropagation && method_exists($bc, 'duplicate_master')) {
  474. $bc->duplicate_master($newBID, $nc);
  475. } else {
  476. $bc->duplicate($newBID);
  477. }
  478. $features = $bc->getBlockTypeFeatureObjects();
  479. if (count($features) > 0) {
  480. foreach($features as $fe) {
  481. $fd = $fe->getFeatureDetailObject($bc);
  482. $fa = CollectionVersionFeatureAssignment::add($fe, $fd, $nc);
  483. $db->Execute('insert into BlockFeatureAssignments (cID, cvID, bID, faID) values (?, ?, ?, ?)', array(
  484. $ncID, $nvID, $newBID, $fa->getFeatureAssignmentID()
  485. ));
  486. }
  487. }
  488. // finally, we insert into the CollectionVersionBlocks table
  489. if (!is_numeric($this->cbDisplayOrder)) {
  490. $newBlockDisplayOrder = $nc->getCollectionAreaDisplayOrder($this->arHandle);
  491. } else {
  492. $newBlockDisplayOrder = $this->cbDisplayOrder;
  493. }
  494. //$v = array($ncID, $nvID, $newBID, $this->areaName, $newBlockDisplayOrder, 1);
  495. $v = array($ncID, $nvID, $newBID, $this->arHandle, $newBlockDisplayOrder, 1, $this->overrideAreaPermissions());
  496. $q = "insert into CollectionVersionBlocks (cID, cvID, bID, arHandle, cbDisplayOrder, isOriginal, cbOverrideAreaPermissions) values (?, ?, ?, ?, ?, ?, ?)";
  497. $r = $db->prepare($q);
  498. $res = $db->execute($r, $v);
  499. // now we make a DUPLICATE entry in the BlockRelations table, so that we know that the blocks are chained together
  500. $v2 = array($this->bID, $newBID, "DUPLICATE");
  501. $q2 = "insert into BlockRelations (originalBID, bID, relationType) values (?, ?, ?)";
  502. $r2 = $db->prepare($q2);
  503. $res2 = $db->execute($r2, $v2);
  504. $nb = Block::getByID($newBID, $nc, $this->arHandle);
  505. $csrID = $this->getBlockCustomStyleRuleID();
  506. if ($csrID > 0) {
  507. $v = array($ncID, $nvID, $newBID, $this->arHandle, $csrID);
  508. $db->Execute('insert into CollectionVersionBlockStyles (cID, cvID, bID, arHandle, csrID) values (?, ?, ?, ?, ?)', $v);
  509. }
  510. return $nb;
  511. }
  512. public function getBlockCustomStyleRule() {
  513. if ($this->getBlockCustomStyleRuleID() > 0) {
  514. $txt = Loader::helper('text');
  515. $csr = CustomStyleRule::getByID($this->getBlockCustomStyleRuleID());
  516. $arHandle = $txt->filterNonAlphaNum($this->getAreaHandle());
  517. if (is_object($csr)) {
  518. $csr->setCustomStyleNameSpace('blockStyle' . $this->getBlockID() . $arHandle );
  519. return $csr;
  520. }
  521. }
  522. }
  523. public function getBlockCustomStyleRuleID() {
  524. $db = Loader::db();
  525. if (!isset($this->csrID)) {
  526. $co = $this->getBlockCollectionObject();
  527. $csrCheck = CacheLocal::getEntry('csrCheck', $co->getCollectionID() . ':' . $co->getVersionID());
  528. $csrObject = CacheLocal::getEntry('csrObject', $co->getCollectionID() . ':' . $co->getVersionID() . ':' . $this->getAreaHandle() . ':' . $this->getBlockID());
  529. if (is_object($csrObject)) {
  530. $this->csrID = $csrObject->getCustomStyleRuleID();
  531. return $csrObject->getCustomStyleRuleID();
  532. } else if ($csrCheck) {
  533. return false;
  534. }
  535. $arHandle = $this->getAreaHandle();
  536. if ($arHandle) {
  537. $a = $this->getBlockAreaObject();
  538. if ($a->isGlobalArea()) {
  539. // then we need to check against the global area name. We currently have the wrong area handle passed in
  540. $arHandle = STACKS_AREA_NAME;
  541. }
  542. $v = array(
  543. $co->getCollectionID(),
  544. $co->getVersionID(),
  545. $arHandle,
  546. $this->bID
  547. );
  548. $this->csrID = $db->GetOne('select csrID from CollectionVersionBlockStyles where cID = ? and cvID = ? and arHandle = ? and bID = ?', $v);
  549. } else {
  550. $this->csrID = 0;
  551. }
  552. }
  553. return $this->csrID;
  554. }
  555. public function resetBlockCustomStyle($updateAll = false) {
  556. $db = Loader::db();
  557. $c = $this->getBlockCollectionObject();
  558. $cvID = $c->getVersionID();
  559. if ($updateAll) {
  560. $r = $db->Execute('select cID, cvID, bID, arHandle from CollectionVersionBlockStyles where bID = ? and csrID = ?', array($this->bID, $this->getBlockCustomStyleRuleID()));
  561. while ($row = $r->FetchRow()) {
  562. $c1 = Page::getByID($row['cID'], $row['cvID']);
  563. $b1 = Block::getByID($row['bID'], $c1, $row['arHandle']);
  564. }
  565. $db->Execute('delete from CollectionVersionBlockStyles where bID = ? and csrID = ?', array(
  566. $this->bID,
  567. $this->getBlockCustomStyleRuleID()
  568. ));
  569. } else {
  570. $db->Execute('delete from CollectionVersionBlockStyles where cID = ? and cvID = ? and arHandle = ? and bID = ?', array(
  571. $this->getBlockCollectionID(),
  572. $cvID,
  573. $this->getAreaHandle(),
  574. $this->bID
  575. ));
  576. }
  577. }
  578. public function __destruct() {
  579. unset($this->c);
  580. unset($this->a);
  581. unset($this->instance);
  582. }
  583. public function setBlockCustomStyle($csr, $updateAll = false) {
  584. $db = Loader::db();
  585. $c = $this->getBlockCollectionObject();
  586. $cvID = $c->getVersionID();
  587. if ($updateAll) {
  588. $r = $db->Execute('select cID, cvID, bID, arHandle from CollectionVersionBlocks where bID = ?', array($this->bID));
  589. while ($row = $r->FetchRow()) {
  590. $c1 = Page::getByID($row['cID'], $row['cvID']);
  591. $b1 = Block::getByID($row['bID'], $c1, $row['arHandle']);
  592. $b1->setBlockCustomStyle($csr, false);
  593. }
  594. } else {
  595. if ($csr->getCustomStyleRuleID() > 0) {
  596. $db->Replace('CollectionVersionBlockStyles',
  597. array('cID' => $this->getBlockCollectionID(), 'cvID' => $cvID, 'arHandle' => $this->getAreaHandle(), 'bID' => $this->bID, 'csrID' => $csr->getCustomStyleRuleID()),
  598. array('cID', 'cvID', 'bID', 'arHandle'), true
  599. );
  600. $this->refreshCache();
  601. }
  602. }
  603. }
  604. function getBlockCollectionObject() {
  605. if (is_object($this->c)) {
  606. return $this->c;
  607. } else {
  608. return $this->getOriginalCollection();
  609. }
  610. }
  611. public function setBlockCollectionObject($c) {
  612. $this->c = $c;
  613. }
  614. function getBlockCollectionID() {
  615. return $this->cID;
  616. }
  617. function getBlockTypeName() {
  618. return $this->btName;
  619. }
  620. function getBlockTypeHandle() {
  621. return $this->btHandle;
  622. }
  623. function getBlockFilename() {
  624. return $this->bFilename;
  625. }
  626. public function getBlockDisplayOrder() {
  627. return $this->cbDisplayOrder;
  628. }
  629. function getBlockID() {
  630. return $this->bID;
  631. }
  632. function getBlockTypeID() {
  633. return $this->btID;
  634. }
  635. public function getBlockTypeObject() {
  636. return BlockType::getByID($this->btID);
  637. }
  638. function getAreaHandle() {
  639. return $this->arHandle;
  640. }
  641. function getBlockUserID() {
  642. return $this->uID;
  643. }
  644. function getBlockName() {
  645. return $this->bName;
  646. }
  647. /**
  648. * Gets the date the block was added
  649. * if user is specified, returns in the current user's timezone
  650. * @param string $type (system || user)
  651. * @return string date formated like: 2009-01-01 00:00:00
  652. */
  653. function getBlockDateAdded($type = 'system') {
  654. if(ENABLE_USER_TIMEZONES && $type == 'user') {
  655. $dh = Loader::helper('date');
  656. return $dh->getLocalDateTime($this->bDateAdded);
  657. } else {
  658. return $this->bDateAdded;
  659. }
  660. }
  661. function getBlockDateLastModified() {
  662. return $this->bDateModified;
  663. }
  664. function _getBlockAction() {
  665. $cID = $this->getBlockActionCollectionID();
  666. $bID = $this->getBlockID();
  667. $arHandle = urlencode($this->getAreaHandle());
  668. $step = ($_REQUEST['step']) ? '&amp;step=' . $_REQUEST['step'] : '';
  669. $valt = Loader::helper('validation/token');
  670. $token = $valt->generate();
  671. $str = DIR_REL . "/" . DISPATCHER_FILENAME . "?cID={$cID}&amp;bID={$bID}&amp;arHandle={$arHandle}" . $step . "&amp;ccm_token=" . $token;
  672. return $str;
  673. }
  674. public function setBlockActionCollectionID($bActionCID) {
  675. $this->bActionCID = $bActionCID;
  676. }
  677. /**
  678. * @return integer|false The block action collection id or false if not found
  679. */
  680. public function getBlockActionCollectionID() {
  681. if ($this->bActionCID > 0) {
  682. return $this->bActionCID;
  683. }
  684. $c = Page::getCurrentPage();
  685. if (is_object($c)) {
  686. return $c->getCollectionID();
  687. }
  688. $c = $this->getBlockCollectionObject();
  689. if (is_object($c)) {
  690. return $c->getCollectionID();
  691. }
  692. return false;
  693. }
  694. function getBlockEditAction() {
  695. return $this->_getBlockAction();
  696. }
  697. function getBlockUpdateInformationAction() {
  698. $str = $this->_getBlockAction();
  699. return $str . '&amp;btask=update_information';
  700. }
  701. function getBlockMasterCollectionAliasAction() {
  702. $str = $this->_getBlockAction();
  703. return $str . '&amp;btask=mc_alias';
  704. }
  705. function getBlockUpdateCssAction() {
  706. $str = $this->_getBlockAction();
  707. return $str . '&amp;btask=update_block_css';
  708. }
  709. function isEditable() {
  710. $bv = new BlockView($this);
  711. $path = $bv->getBlockPath(FILENAME_BLOCK_EDIT);
  712. if (file_exists($path . '/' . FILENAME_BLOCK_EDIT)) {
  713. return true;
  714. }
  715. return false;
  716. }
  717. function overrideAreaPermissions() {
  718. if (!$this->cbOverrideAreaPermissions) {
  719. $this->cbOverrideAreaPermissions = 0;
  720. }
  721. return $this->cbOverrideAreaPermissions;
  722. }
  723. public function delete($forceDelete = false) {
  724. $this->deleteBlock($forceDelete);
  725. }
  726. function deleteBlock($forceDelete = false) {
  727. $db = Loader::db();
  728. if ($this->bID < 1) {
  729. return false;
  730. }
  731. $cID = $this->cID;
  732. $c = $this->getBlockCollectionObject();
  733. $cvID = $c->getVersionID();
  734. $bID = $this->bID;
  735. $arHandle = $this->arHandle;
  736. // if this block is located in a master collection, we're going to delete all the instances of the block,
  737. // regardless
  738. if (($c instanceof Page && $c->isMasterCollection() && !$this->isAlias()) || $forceDelete) {
  739. // forceDelete is used by the administration console
  740. // this is an original. We're deleting it, and everything else having to do with it
  741. $q = "delete from CollectionVersionBlocks where bID = ?";
  742. $r = $db->query($q, array($bID));
  743. $q = "delete from ComposerContentLayout where bID = ?";
  744. $r = $db->query($q, array($bID));
  745. $q = "delete from BlockPermissionAssignments where bID = ?";
  746. $r = $db->query($q, array($bID));
  747. $q = "delete from CollectionVersionBlockStyles where bID = ?";
  748. $r = $db->query($q, array($bID));
  749. } else {
  750. $q = "delete from CollectionVersionBlocks where cID = ? and (cvID = ? or cbIncludeAll=1) and bID = ? and arHandle = ?";
  751. $r = $db->query($q, array($cID, $cvID, $bID, $arHandle));
  752. // next, we delete the groups instance of this block
  753. $q = "delete from BlockPermissionAssignments where bID = ? and cvID = ? and cID = ?";
  754. $r = $db->query($q, array($bID, $cvID, $cID));
  755. $q = "delete from CollectionVersionBlockStyles where cID = ? and cvID = ? and bID = ? and arHandle = ?";
  756. $r = $db->query($q, array($cID, $cvID, $bID, $arHandle));
  757. }
  758. // delete any feature assignments that have been attached to this block to the collection version
  759. $faIDs = $db->GetCol('select faID from BlockFeatureAssignments where cID = ? and cvID = ? and bID = ?', array(
  760. $cID, $cvID, $bID
  761. ));
  762. foreach($faIDs as $faID) {
  763. $fa = FeatureAssignment::getByID($faID, $c);
  764. $fa->delete();
  765. }
  766. //then, we see whether or not this block is aliased to anything else
  767. $totalBlocks = $db->GetOne('select count(*) from CollectionVersionBlocks where bID = ?', array($bID));
  768. $totalBlocks += $db->GetOne('select count(*) from btCoreScrapbookDisplay where bOriginalID = ?', array($bID));
  769. if ($totalBlocks < 1) {
  770. $q = "delete from BlockRelations where originalBID = ? or bID = ?";
  771. $r = $db->query($q, array($this->bID, $this->bID));
  772. // this block is not referenced in the system any longer, so we delete the entry in the blocks table, as well as the entries in the corresponding
  773. // sub-blocks table
  774. $v = array($this->bID);
  775. // so, first we delete the block's sub content
  776. $bt = BlockType::getByID($this->getBlockTypeID());
  777. if( $bt && method_exists($bt,'getBlockTypeClass') ){
  778. $class = $bt->getBlockTypeClass();
  779. $bc = new $class($this);
  780. $bc->delete();
  781. }
  782. // now that the block's subcontent delete() method has been run, we delete the block from the Blocks table
  783. $q = "delete from Blocks where bID = ?";
  784. $r = $db->query($q, $v);
  785. // Aaaand then we delete all scrapbooked blocks to this entry
  786. $r = $db->Execute('select cID, cvID, CollectionVersionBlocks.bID, arHandle from CollectionVersionBlocks inner join btCoreScrapbookDisplay on CollectionVersionBlocks.bID = btCoreScrapbookDisplay.bID where bOriginalID = ?', array($bID));
  787. while ($row = $r->FetchRow()) {
  788. $c = Page::getByID($row['cID'], $row['cvID']);
  789. $b = Block::getByID($row['bID'], $c, $row['arHandle']);
  790. $b->delete();
  791. }
  792. }
  793. }
  794. function setOriginalBlockID($originalBID) {
  795. $this->originalBID = $originalBID;
  796. }
  797. public function moveBlockToDisplayOrderPosition($afterBlock) {
  798. // first, we increase the display order of all blocks found after this one.
  799. $db = Loader::db();
  800. $c = $this->getBlockCollectionObject();
  801. if ($afterBlock instanceof Block) {
  802. $q = "update CollectionVersionBlocks set cbDisplayOrder = cbDisplayOrder + 1 where cID = ? and (cvID = ? or cbIncludeAll=1) and arHandle = ? and cbDisplayOrder > ?";
  803. $v = array($c->getCollectionID(), $c->getVersionID(), $this->arHandle, $afterBlock->getBlockDisplayOrder());
  804. $db->Execute($q, $v);
  805. // now we set this block's display order to 1 + the current block
  806. $q = "update CollectionVersionBlocks set cbDisplayOrder = ? where bID = ? and cID = ? and (cvID = ? or cbIncludeAll=1) and arHandle = ?";
  807. $v = array($afterBlock->getBlockDisplayOrder() + 1, $this->getBlockID(), $c->getCollectionID(), $c->getVersionID(), $this->arHandle);
  808. $db->Execute($q, $v);
  809. } else {
  810. $q = "update CollectionVersionBlocks set cbDisplayOrder = cbDisplayOrder + 1 where cID = ? and (cvID = ? or cbIncludeAll=1) and arHandle = ?";
  811. $v = array($c->getCollectionID(), $c->getVersionID(), $this->arHandle);
  812. $db->Execute($q, $v);
  813. $q = "update CollectionVersionBlocks set cbDisplayOrder = ? where bID = ? and cID = ? and (cvID = ? or cbIncludeAll=1) and arHandle = ?";
  814. $v = array(0, $this->getBlockID(), $c->getCollectionID(), $c->getVersionID(), $this->arHandle);
  815. $db->Execute($q, $v);
  816. }
  817. }
  818. public function setAbsoluteBlockDisplayOrder($do) {
  819. $db = Loader::db();
  820. $cID = $this->cID;
  821. $bID = $this->bID;
  822. $arHandle = $this->arHandle;
  823. $c = $this->getBlockCollectionObject();
  824. $cvID = $c->getVersionID();
  825. $q = "update CollectionVersionBlocks set cbDisplayOrder = ? where bID = ? and cID = ? and (cvID = ? or cbIncludeAll=1) and arHandle = ?";
  826. $r = $db->query($q, array($do, $bID, $cID, $cvID, $arHandle));
  827. }
  828. public function doOverrideAreaPermissions() {
  829. $db = Loader::db();
  830. $c = $this->getBlockCollectionObject();
  831. $v = array($c->getCollectionID(), $c->getVersionID(), $this->bID, $this->arHandle);
  832. $db->query("update CollectionVersionBlocks set cbOverrideAreaPermissions = 1 where cID = ? and (cvID = ? or cbIncludeAll = 1) and bID = ? and arHandle = ?", $v);
  833. $v = array($c->getCollectionID(), $c->getVersionID(), $this->bID);
  834. $db->query("delete from BlockPermissionAssignments where cID = ? and cvID = ? and bID = ?", $v);
  835. // copy permissions from the page to the area
  836. $permissions = PermissionKey::getList('block');
  837. foreach($permissions as $pk) {
  838. $pk->setPermissionObject($this);
  839. $pk->copyFromPageOrAreaToBlock();
  840. }
  841. }
  842. public function setCustomTemplate($template) {
  843. $data['bFilename'] = $template;
  844. $this->updateBlockInformation($data);
  845. }
  846. public function setName($name) {
  847. $data['bName'] = $name;
  848. $this->updateBlockInformation($data);
  849. }
  850. public function refreshBlockOutputCache() {
  851. $db = Loader::db();
  852. $cID = $this->getBlockCollectionID();
  853. $bID = $this->getBlockID();
  854. $c = $this->getBlockCollectionObject();
  855. $v = array($c->getCollectionID(), $c->getVersionID(), $this->getAreaHandle(), $bID);
  856. $db->Execute('update CollectionVersionBlocksOutputCache set btCachedBlockOutputExpires = 0 where cID = ? and cvID = ? and arHandle = ? and bID = ?', $v);
  857. }
  858. /**
  859. * Removes a cached version of the block
  860. */
  861. public function refreshCache() {
  862. /*
  863. // if the block is a global block, we need to delete all cached versions that reference it.
  864. if ($this->bIsGlobal) {
  865. $this->refreshCacheAll();
  866. } else {
  867. $c = $this->getBlockCollectionObject();
  868. $a = $this->getBlockAreaObject();
  869. if (is_object($c) && is_object($a)) {
  870. Cache::delete('block', $this->getBlockID() . ':' . $c->getCollectionID() . ':' . $c->getVersionID() . ':' . $a->getAreaHandle());
  871. Cache::delete('block_view_output', $c->getCollectionID() . ':' . $this->getBlockID() . ':' . $a->getAreaHandle());
  872. Cache::delete('collection_blocks', $c->getCollectionID() . ':' . $c->getVersionID());
  873. }
  874. Cache::delete('block', $this->getBlockID());
  875. // now we check the scrapbook display
  876. $db = Loader::db();
  877. $rows=$db->getAll('select cID, cvID, arHandle FROM CollectionVersionBlocks cvb inner join btCoreScrapbookDisplay bts on bts.bID = cvb.bID where bts.bOriginalID = ?', array($this->getBlockID()));
  878. foreach($rows as $row){
  879. Cache::delete('block', $this->getBlockID() . ':' . intval($row['cID']) . ':' . intval($row['cvID']) . ':' . $row['arHandle'] );
  880. Cache::delete('block_view_output', $row['cID'] . ':' . $this->getBlockID() . ':' . $row['arHandle']);
  881. Cache::delete('block', $this->getBlockID());
  882. }
  883. if ($this->getBlockTypeHandle() == BLOCK_HANDLE_SCRAPBOOK_PROXY && is_object($a)) {
  884. $rows=$db->getAll('select cID, cvID, arHandle FROM CollectionVersionBlocks cvb inner join btCoreScrapbookDisplay bts on bts.bOriginalID = cvb.bID where bts.bID = ?', array($this->getBlockID()));
  885. foreach($rows as $row){
  886. Cache::delete('block', $row['bID'] . ':' . $c->getCollectionID() . ':' . $c->getVersionID() . ':' . $a->getAreaHandle());
  887. Cache::delete('block_view_output', $c->getCollectionID() . ':' . $row['bID'] . ':' . $a->getAreaHandle());
  888. }
  889. }
  890. }
  891. */
  892. }
  893. public function refreshCacheAll() {
  894. /*
  895. $db = Loader::db();
  896. $rows=$db->getAll( 'SELECT cID, cvID, arHandle FROM CollectionVersionBlocks WHERE bID='.intval($this->getBlockID()) );
  897. foreach($rows as $row){
  898. Cache::delete('block', $this->getBlockID() . ':' . intval($row['cID']) . ':' . intval($row['cvID']) . ':' . $row['arHandle'] );
  899. Cache::delete('block_view_output', $row['cID'] . ':' . $this->getBlockID(). ':' . $row['arHandle']);
  900. Cache::delete('collection_blocks', $row['cID'] . ':' . $row['cvID']);
  901. Cache::delete('block', $this->getBlockID());
  902. }
  903. */
  904. }
  905. public function export($node, $exportType = 'full') {
  906. if (!$this->isAliasOfMasterCollection()) {
  907. $blockNode = $node->addChild('block');
  908. $blockNode->addAttribute('type', $this->getBlockTypeHandle());
  909. $blockNode->addAttribute('name', $this->getBlockName());
  910. if ($this->getBlockFilename() != '') {
  911. $blockNode->addAttribute('custom-template', $this->getBlockFilename());
  912. }
  913. if (is_object($this->c) && $this->c->isMasterCollection()) {
  914. $mcBlockID = Loader::helper('validation/identifier')->getString(8);
  915. ContentExporter::addMasterCollectionBlockID($this, $mcBlockID);
  916. $blockNode->addAttribute('mc-block-id', $mcBlockID);
  917. }
  918. if ($exportType == 'full') {
  919. $bc = $this->getInstance();
  920. $bc->export($blockNode);
  921. }
  922. } else {
  923. $blockNode = $node->addChild('block');
  924. $blockNode->addAttribute('mc-block-id', ContentExporter::getMasterCollectionTemporaryBlockID($this));
  925. }
  926. }
  927. function updateBlockInformation($data) {
  928. // this is the function that updates a block's information, like its block filename, and block name
  929. $db = Loader::db();
  930. $dh = Loader::helper('date');
  931. $dt = $dh->getSystemDateTime();
  932. $bName = $this->bName;
  933. $bFilename = $this->bFilename;
  934. if (isset($data['bName'])) {
  935. $bName = $data['bName'];
  936. }
  937. if (isset($data['bFilename'])) {
  938. $bFilename = $data['bFilename'];
  939. }
  940. $v = array($bName, $bFilename, $dt, $this->bID);
  941. $q = "update Blocks set bName = ?, bFilename = ?, bDateModified = ? where bID = ?";
  942. $r = $db->prepare($q);
  943. $res = $db->execute($r, $v);
  944. $this->refreshBlockOutputCache();
  945. }
  946. }