PageRenderTime 48ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/baser/models/page.php

https://github.com/hashing/basercms
PHP | 1170 lines | 713 code | 129 blank | 328 comment | 162 complexity | 47f14fc91f8d71b91526b62a08bbac29 MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /**
  4. * ページモデル
  5. *
  6. * PHP versions 5
  7. *
  8. * baserCMS : Based Website Development Project <http://basercms.net>
  9. * Copyright 2008 - 2012, baserCMS Users Community <http://sites.google.com/site/baserusers/>
  10. *
  11. * @copyright Copyright 2008 - 2012, baserCMS Users Community
  12. * @link http://basercms.net baserCMS Project
  13. * @package baser.models
  14. * @since baserCMS v 0.1.0
  15. * @version $Revision$
  16. * @modifiedby $LastChangedBy$
  17. * @lastmodified $Date$
  18. * @license http://basercms.net/license/index.html
  19. */
  20. /**
  21. * ページモデル
  22. *
  23. * @package baser.models
  24. */
  25. class Page extends AppModel {
  26. /**
  27. * クラス名
  28. * @var string
  29. * @access public
  30. */
  31. var $name = 'Page';
  32. /**
  33. * データベース接続
  34. *
  35. * @var string
  36. * @access public
  37. */
  38. var $useDbConfig = 'baser';
  39. /**
  40. * belongsTo
  41. *
  42. * @var array
  43. * @access public
  44. */
  45. var $belongsTo = array(
  46. 'PageCategory' => array( 'className'=>'PageCategory',
  47. 'foreignKey'=>'page_category_id'),
  48. 'User' => array('className'=> 'User',
  49. 'foreignKey'=>'author_id'));
  50. /**
  51. * ビヘイビア
  52. *
  53. * @var array
  54. * @access public
  55. */
  56. var $actsAs = array('BcContentsManager', 'BcCache');
  57. /**
  58. * 更新前のページファイルのパス
  59. *
  60. * @var string
  61. * @access public
  62. */
  63. var $oldPath = '';
  64. /**
  65. * ファイル保存可否
  66. * true の場合、ページデータ保存の際、ページテンプレートファイルにも内容を保存する
  67. * テンプレート読み込み時などはfalseにして保存しないようにする
  68. *
  69. * @var boolean
  70. * @access public
  71. */
  72. var $fileSave = true;
  73. /**
  74. * 検索テーブルへの保存可否
  75. *
  76. * @var boolean
  77. * @access public
  78. */
  79. var $contentSaving = true;
  80. /**
  81. * 非公開WebページURLリスト
  82. * キャッシュ用
  83. *
  84. * @var mixed
  85. * @deprecated
  86. * @access protected
  87. */
  88. var $_unpublishes = -1;
  89. /**
  90. * 公開WebページURLリスト
  91. * キャッシュ用
  92. *
  93. * @var mixed
  94. * @access protected
  95. */
  96. var $_publishes = -1;
  97. /**
  98. * WebページURLリスト
  99. * キャッシュ用
  100. *
  101. * @var mixed
  102. * @access protected
  103. */
  104. var $_pages = -1;
  105. /**
  106. * 最終登録ID
  107. * モバイルページへのコピー処理でスーパークラスの最終登録IDが上書きされ、
  108. * コントローラーからは正常なIDが取得できないのでモバイルページへのコピー以外の場合だけ保存する
  109. *
  110. * @var int
  111. * @access private
  112. */
  113. var $__pageInsertID = null;
  114. /**
  115. * バリデーション
  116. *
  117. * @var array
  118. * @access public
  119. */
  120. var $validate = array(
  121. 'name' => array(
  122. array( 'rule' => array('notEmpty'),
  123. 'message' => 'ページ名を入力してください。',
  124. 'required' => true),
  125. array( 'rule' => array('maxLength', 50),
  126. 'message' => 'ページ名は50文字以内で入力してください。'),
  127. array( 'rule' => array('pageExists'),
  128. 'message' => '指定したページは既に存在します。ファイル名、またはカテゴリを変更してください。')
  129. ),
  130. 'page_category_id' => array(
  131. array( 'rule' => array('pageExists'),
  132. 'message' => '指定したページは既に存在します。ファイル名、またはカテゴリを変更してください。')
  133. ),
  134. 'title' => array(
  135. array( 'rule' => array('maxLength', 255),
  136. 'message' => 'ページタイトルは255文字以内で入力してください。')
  137. ),
  138. 'description' => array(
  139. array( 'rule' => array('maxLength', 255),
  140. 'message' => '説明文は255文字以内で入力してください。')
  141. )
  142. );
  143. /**
  144. * フォームの初期値を設定する
  145. *
  146. * @return array 初期値データ
  147. * @access public
  148. */
  149. function getDefaultValue() {
  150. if(!empty($_SESSION['Auth']['User'])) {
  151. $data[$this->name]['author_id'] = $_SESSION['Auth']['User']['id'];
  152. }
  153. $data[$this->name]['sort'] = $this->getMax('sort')+1;
  154. $data[$this->name]['status'] = false;
  155. return $data;
  156. }
  157. /**
  158. * beforeSave
  159. *
  160. * @return boolean
  161. * @access public
  162. */
  163. function beforeSave() {
  164. if(!$this->fileSave) {
  165. return true;
  166. }
  167. // 保存前のページファイルのパスを取得
  168. if($this->exists()) {
  169. $this->oldPath = $this->_getPageFilePath(
  170. $this->find('first', array(
  171. 'conditions' => array('Page.id' => $this->data['Page']['id']),
  172. 'recursive' => -1)
  173. )
  174. );
  175. }else {
  176. $this->oldPath = '';
  177. }
  178. // 新しいページファイルのパスが開けるかチェックする
  179. $result = true;
  180. if(!$this->checkOpenPageFile($this->data)){
  181. $result = false;
  182. }
  183. if(isset($this->data['Page'])){
  184. $data = $this->data['Page'];
  185. } else {
  186. $data = $this->data;
  187. }
  188. if(!empty($data['reflect_mobile'])){
  189. $data['url'] = '/'.Configure::read('BcAgent.mobile.prefix').$this->removeAgentPrefixFromUrl($data['url']);
  190. if(!$this->checkOpenPageFile($data)){
  191. $result = false;
  192. }
  193. }
  194. if(!empty($data['reflect_smartphone'])){
  195. $data['url'] = '/'.Configure::read('BcAgent.smartphone.prefix').$this->removeAgentPrefixFromUrl($data['url']);
  196. if(!$this->checkOpenPageFile($data)){
  197. $result = false;
  198. }
  199. }
  200. return $result;
  201. }
  202. /**
  203. * プレフィックスを取り除く
  204. *
  205. * @param type $url
  206. * @return type
  207. */
  208. function removeAgentPrefixFromUrl($url) {
  209. if(preg_match('/^\/'.Configure::read('BcAgent.mobile.prefix').'\//', $url)) {
  210. $url = preg_replace('/^\/'.Configure::read('BcAgent.mobile.prefix').'\//', '/', $url);
  211. } elseif(preg_match('/^\/'.Configure::read('BcAgent.smartphone.prefix').'\//', $url)) {
  212. $url = preg_replace('/^\/'.Configure::read('BcAgent.smartphone.prefix').'\//', '/', $url);
  213. }
  214. return $url;
  215. }
  216. /**
  217. * 最終登録IDを取得する
  218. *
  219. * @return int
  220. * @access public
  221. */
  222. function getInsertID(){
  223. if(!$this->__pageInsertID){
  224. $this->__pageInsertID = parent::getInsertID();
  225. }
  226. return $this->__pageInsertID;
  227. }
  228. /**
  229. * ページテンプレートファイルが開けるかチェックする
  230. *
  231. * @param array $data ページデータ
  232. * @return boolean
  233. * @access public
  234. */
  235. function checkOpenPageFile($data){
  236. $path = $this->_getPageFilePath($data);
  237. $File = new File($path);
  238. if($File->open('w')) {
  239. $File->close();
  240. $File = null;
  241. return true;
  242. }else {
  243. return false;
  244. }
  245. }
  246. /**
  247. * afterSave
  248. *
  249. * @param array $created
  250. * @return boolean
  251. * @access public
  252. */
  253. function afterSave($created) {
  254. if(isset($this->data['Page'])){
  255. $data = $this->data['Page'];
  256. } else {
  257. $data = $this->data;
  258. }
  259. // タイトルタグと説明文を追加
  260. if(empty($data['id'])) {
  261. $data['id'] = $this->id;
  262. }
  263. if($this->fileSave) {
  264. $this->createPageTemplate($data);
  265. }
  266. // 検索用テーブルに登録
  267. if($this->contentSaving) {
  268. if(empty($data['exclude_search'])) {
  269. $this->saveContent($this->createContent($data));
  270. } else {
  271. $this->deleteContent($data['id']);
  272. }
  273. }
  274. // モバイルデータの生成
  275. if(!empty($data['reflect_mobile'])) {
  276. $this->refrect('mobile', $data);
  277. }
  278. if(!empty($data['reflect_smartphone'])){
  279. $this->refrect('smartphone', $data);
  280. }
  281. }
  282. /**
  283. * 関連ページに反映する
  284. *
  285. * @param string $type
  286. * @param array $data
  287. * @return boolean
  288. */
  289. function refrect($type, $data) {
  290. if(isset($this->data['Page'])){
  291. $data = $this->data['Page'];
  292. }
  293. // モバイルページへのコピーでスーパークラスのIDを上書きしてしまうので退避させておく
  294. $this->__pageInsertID = parent::getInsertID();
  295. $agentId = $this->PageCategory->getAgentId($type);
  296. if(!$agentId){
  297. // カテゴリがない場合は trueを返して終了
  298. return true;
  299. }
  300. $data['url'] = '/'.Configure::read('BcAgent.'.$type.'.prefix').$this->removeAgentPrefixFromUrl($data['url']);
  301. $agentPage = $this->find('first',array('conditions'=>array('Page.url'=>$data['url']),'recursive'=>-1));
  302. unset($data['id']);
  303. unset($data['sort']);
  304. unset($data['status']);
  305. if($agentPage){
  306. $agentPage['Page']['name'] = $data['name'];
  307. $agentPage['Page']['title'] = $data['title'];
  308. $agentPage['Page']['description'] = $data['description'];
  309. $agentPage['Page']['draft'] = $data['draft'];
  310. $agentPage['Page']['modified'] = $data['modified'];
  311. $agentPage['Page']['contents'] = $data['contents'];
  312. $agentPage['Page']['reflect_mobile'] = false;
  313. $agentPage['Page']['reflect_smartphone'] = false;
  314. $this->set($agentPage);
  315. }else{
  316. if($data['page_category_id']){
  317. $fields = array('parent_id','name','title');
  318. $pageCategoryTree = $this->PageCategory->getTreeList($fields,$data['page_category_id']);
  319. $path = getViewPath().'pages'.DS.Configure::read('BcAgent.'.$type.'.prefix');
  320. $parentId = $agentId;
  321. foreach($pageCategoryTree as $pageCategory) {
  322. $path .= '/'.$pageCategory['PageCategory']['name'];
  323. $categoryId = $this->PageCategory->getIdByPath($path);
  324. if(!$categoryId){
  325. $pageCategory['PageCategory']['parent_id'] = $parentId;
  326. $this->PageCategory->create($pageCategory);
  327. $ret = $this->PageCategory->save();
  328. $parentId = $categoryId = $this->PageCategory->getInsertID();
  329. }else{
  330. $parentId = $categoryId;
  331. }
  332. }
  333. $data['page_category_id'] = $categoryId;
  334. }else{
  335. $data['page_category_id'] = $agentId;
  336. }
  337. $data['author_id'] = $_SESSION['Auth']['User']['id'];
  338. $data['sort'] = $this->getMax('sort')+1;
  339. $data['status'] = false; // 新規ページの場合は非公開とする
  340. unset($data['publish_begin']);
  341. unset($data['publish_end']);
  342. unset($data['created']);
  343. unset($data['modified']);
  344. $data['reflect_mobile'] = false;
  345. $data['reflect_smartphone'] = false;
  346. $this->create($data);
  347. }
  348. return $this->save();
  349. }
  350. /**
  351. * 検索用データを生成する
  352. *
  353. * @param array $data
  354. * @return array
  355. * @access public
  356. */
  357. function createContent($data) {
  358. if(isset($data['Page'])) {
  359. $data = $data['Page'];
  360. }
  361. if(!isset($data['publish_begin'])) {
  362. $data['publish_begin'] = '';
  363. }
  364. if(!isset($data['publish_end'])) {
  365. $data['publish_end'] = '';
  366. }
  367. if(!$data['title']) {
  368. $data['title'] = Inflector::camelize($data['name']);
  369. }
  370. // モバイル未対応
  371. $PageCategory = ClassRegistry::init('PageCategory');
  372. $excludeIds = am($PageCategory->getAgentCategoryIds('mobile'), $PageCategory->getAgentCategoryIds('smartphone'));
  373. if(in_array($data['page_category_id'], $excludeIds)) {
  374. return array();
  375. }
  376. $_data = array();
  377. $_data['Content']['type'] = 'ページ';
  378. // $this->idに値が入ってない場合もあるので
  379. if(!empty($data['id'])) {
  380. $_data['Content']['model_id'] = $data['id'];
  381. } else {
  382. $_data['Content']['model_id'] = $this->id;
  383. }
  384. $_data['Content']['category'] = '';
  385. if(!empty($data['page_category_id'])) {
  386. $categoryPath = $PageCategory->getPath($data['page_category_id'], array('title'));
  387. if($categoryPath) {
  388. $_data['Content']['category'] = $categoryPath[0]['PageCategory']['title'];
  389. }
  390. }
  391. $_data['Content']['title'] = $data['title'];
  392. $parameters = split('/', preg_replace("/^\//", '', $data['url']));
  393. $detail = $this->requestAction(array('controller' => 'pages', 'action' => 'display'), array('pass' => $parameters, 'return') );
  394. $detail = preg_replace('/<!-- BaserPageTagBegin -->.*?<!-- BaserPageTagEnd -->/is', '', $detail);
  395. $_data['Content']['detail'] = $data['description'].' '.$detail;
  396. $_data['Content']['url'] = $data['url'];
  397. $_data['Content']['status'] = $this->allowedPublish($data['status'], $data['publish_begin'], $data['publish_end']);
  398. return $_data;
  399. }
  400. /**
  401. * beforeDelete
  402. *
  403. * @return boolean
  404. * @access public
  405. */
  406. function beforeDelete() {
  407. return $this->deleteContent($this->id);
  408. }
  409. /**
  410. * データが公開済みかどうかチェックする
  411. * 同様のメソッド checkPublish があり DB接続前提でURLでチェックする仕組みだが
  412. * こちらは、実データで直接チェックする
  413. * TODO メソッド名のリファクタリング要
  414. *
  415. * @param boolean $status
  416. * @param boolean $publishBegin
  417. * @param boolean $publishEnd
  418. * @return array
  419. * @access public
  420. */
  421. function allowedPublish($status, $publishBegin, $publishEnd) {
  422. if(!$status) {
  423. return false;
  424. }
  425. if($publishBegin && $publishBegin != '0000-00-00 00:00:00') {
  426. if($publishBegin < date('Y-m-d H:i:s')) {
  427. return false;
  428. }
  429. }
  430. if($publishEnd && $publishEnd != '0000-00-00 00:00:00') {
  431. if($publishEnd > date('Y-m-d H:i:s')) {
  432. return false;
  433. }
  434. }
  435. return true;
  436. }
  437. /**
  438. * DBデータを元にページテンプレートを全て生成する
  439. *
  440. * @return boolean
  441. * @access public
  442. */
  443. function createAllPageTemplate(){
  444. $pages = $this->find('all', array('recursive' => -1));
  445. $result = true;
  446. foreach($pages as $page){
  447. if(!$this->createPageTemplate($page)){
  448. $result = false;
  449. }
  450. }
  451. return $result;
  452. }
  453. /**
  454. * ページテンプレートを生成する
  455. *
  456. * @param array $data ページデータ
  457. * @return boolean
  458. * @access public
  459. */
  460. function createPageTemplate($data){
  461. if(isset($data['Page'])){
  462. $data = $data['Page'];
  463. }
  464. $contents = $this->addBaserPageTag($data['id'], $data['contents'], $data['title'],$data['description']);
  465. // 新しいページファイルのパスを取得する
  466. $newPath = $this->_getPageFilePath($data);
  467. // ファイルに保存
  468. $newFile = new File($newPath, true);
  469. if($newFile->open('w')) {
  470. if($newFile->append($contents)) {
  471. // テーマやファイル名が変更された場合は元ファイルを削除する
  472. if($this->oldPath && ($newPath != $this->oldPath)) {
  473. $oldFile = new File($this->oldPath);
  474. $oldFile->delete();
  475. unset($oldFile);
  476. }
  477. }
  478. $newFile->close();
  479. unset($newFile);
  480. @chmod($newPath, 0666);
  481. return true;
  482. }else {
  483. return false;
  484. }
  485. }
  486. /**
  487. * ページファイルのディレクトリを取得する
  488. *
  489. * @param array $data
  490. * @return string
  491. * @access protected
  492. */
  493. function _getPageFilePath($data) {
  494. if(isset($data['Page'])){
  495. $data = $data['Page'];
  496. }
  497. $file = $data['name'];
  498. $categoryId = $data['page_category_id'];
  499. $SiteConfig = ClassRegistry::getObject('SiteConfig');
  500. if(!$SiteConfig){
  501. $SiteConfig = ClassRegistry::init('SiteConfig');
  502. }
  503. $SiteConfig->cacheQueries = false;
  504. $siteConfig = $SiteConfig->findExpanded();
  505. $theme = $siteConfig['theme'];
  506. // pagesディレクトリのパスを取得
  507. if($theme) {
  508. $path = WWW_ROOT.'themed'.DS.$theme.DS.'pages'.DS;
  509. }else {
  510. $path = VIEWS.'pages'.DS;
  511. }
  512. if(!is_dir($path)) {
  513. mkdir($path);
  514. chmod($path,0777);
  515. }
  516. if($categoryId) {
  517. $this->PageCategory->cacheQueries = false;
  518. $categoryPath = $this->PageCategory->getPath($categoryId, null, null, -1);
  519. if($categoryPath) {
  520. foreach($categoryPath as $category) {
  521. $path .= $category['PageCategory']['name'].DS;
  522. if(!is_dir($path)) {
  523. mkdir($path,0777);
  524. chmod($path,0777);
  525. }
  526. }
  527. }
  528. }
  529. return $path.$file.Configure::read('BcApp.templateExt');
  530. }
  531. /**
  532. * ページファイルを削除する
  533. *
  534. * @param array $data
  535. */
  536. function delFile($data) {
  537. $path = $this->_getPageFilePath($data);
  538. if($path) {
  539. return unlink($path);
  540. }
  541. return true;
  542. }
  543. /**
  544. * ページのURLを取得する
  545. *
  546. * @param array $data
  547. * @return string
  548. * @access public
  549. */
  550. function getPageUrl($data) {
  551. if(isset($data['Page'])) {
  552. $data = $data['Page'];
  553. }
  554. $categoryId = $data['page_category_id'];
  555. $url = '/';
  556. if($categoryId) {
  557. $this->PageCategory->cacheQueries = false;
  558. $categoryPath = $this->PageCategory->getPath($categoryId);
  559. if($categoryPath) {
  560. foreach($categoryPath as $key => $category) {
  561. if($key == 0 && $category['PageCategory']['name'] == Configure::read('BcAgent.mobile.prefix')) {
  562. $url .= Configure::read('BcAgent.mobile.prefix').'/';
  563. } else {
  564. $url .= $category['PageCategory']['name'].'/';
  565. }
  566. }
  567. }
  568. }
  569. return $url.$data['name'];
  570. }
  571. /**
  572. * Baserが管理するタグを追加する
  573. *
  574. * @param string $id
  575. * @param string $contents
  576. * @param string $title
  577. * @param string $description
  578. * @return string
  579. * @access public
  580. */
  581. function addBaserPageTag($id,$contents,$title,$description) {
  582. $tag = '<!-- BaserPageTagBegin -->'."\n";
  583. $tag .= '<?php $bcBaser->setTitle(\''.$title.'\') ?>'."\n";
  584. $tag .= '<?php $bcBaser->setDescription(\''.$description.'\') ?>'."\n";
  585. if($id) {
  586. $tag .= '<?php $bcBaser->setPageEditLink('.$id.') ?>'."\n";
  587. }
  588. $tag .= '<!-- BaserPageTagEnd -->'."\n";
  589. return $tag . $contents;
  590. }
  591. /**
  592. * ページ存在チェック
  593. *
  594. * @param string チェック対象文字列
  595. * @return boolean
  596. * @access public
  597. */
  598. function pageExists($check) {
  599. if($this->exists()) {
  600. return true;
  601. }else {
  602. $conditions['Page.name'] = $this->data['Page']['name'];
  603. if(empty($this->data['Page']['page_category_id'])) {
  604. if(isset($this->data['Page']['page_type']) && $this->data['Page']['page_type'] == 2) {
  605. $conditions['Page.page_category_id'] = $this->PageCategory->getAgentId('mobile');
  606. } elseif(isset($this->data['Page']['page_type']) && $this->data['Page']['page_type'] == 3) {
  607. $conditions['Page.page_category_id'] = $this->PageCategory->getAgentId('smartphone');
  608. } else {
  609. $conditions['Page.page_category_id'] = NULL;
  610. }
  611. }else {
  612. $conditions['Page.page_category_id'] = $this->data['Page']['page_category_id'];
  613. }
  614. if(!$this->find('first', array('conditions' => $conditions, 'recursive' => -1))) {
  615. return true;
  616. }else {
  617. return !file_exists($this->_getPageFilePath($this->data));
  618. }
  619. }
  620. }
  621. /**
  622. * コントロールソースを取得する
  623. *
  624. * @param string $field フィールド名
  625. * @param array $options
  626. * @return mixed $controlSource コントロールソース
  627. * @access public
  628. */
  629. function getControlSource($field, $options = array()) {
  630. switch ($field) {
  631. case 'page_category_id':
  632. $catOption = array();
  633. $isSuperAdmin = false;
  634. $agentRoot = true;
  635. extract($options);
  636. if(!empty($userGroupId)) {
  637. if(!isset($pageCategoryId)) {
  638. $pageCategoryId = '';
  639. }
  640. if($userGroupId == 1) {
  641. $isSuperAdmin = true;
  642. }
  643. // 現在のページが編集不可の場合、現在表示しているカテゴリも取得する
  644. if(!$pageEditable && $pageCategoryId) {
  645. $catOption = array('conditions' => array('OR' => array('PageCategory.id' => $pageCategoryId)));
  646. }
  647. // super admin でない場合は、管理許可のあるカテゴリのみ取得
  648. if(!$isSuperAdmin) {
  649. $catOption['ownerId'] = $userGroupId;
  650. }
  651. if($pageEditable && !$rootEditable && !$isSuperAdmin) {
  652. unset($empty);
  653. $agentRoot = false;
  654. }
  655. }
  656. $options = am($options, $catOption);
  657. $categories = $this->PageCategory->getControlSource('parent_id', $options);
  658. // 「指定しない」追加
  659. if(isset($empty)) {
  660. if($categories) {
  661. $categories = array('' => $empty) + $categories;
  662. } else {
  663. $categories = array('' => $empty);
  664. }
  665. }
  666. if(!$agentRoot) {
  667. // TODO 整理
  668. $agentId = $this->PageCategory->getAgentId('mobile');
  669. if(isset($categories[$agentId])) {
  670. unset($categories[$agentId]);
  671. }
  672. $agentId = $this->PageCategory->getAgentId('smartphone');
  673. if(isset($categories[$agentId])) {
  674. unset($categories[$agentId]);
  675. }
  676. }
  677. $controlSources['page_category_id'] = $categories;
  678. break;
  679. case 'user_id':
  680. $controlSources['user_id'] = $this->User->getUserList($options);
  681. break;
  682. }
  683. if(isset($controlSources[$field])) {
  684. return $controlSources[$field];
  685. }else {
  686. return false;
  687. }
  688. }
  689. /**
  690. * 非公開チェックを行う
  691. *
  692. * @param string $url
  693. * @return boolean
  694. * @access public
  695. * @deprecated isPageUrl と組み合わせて checkPublish を利用してください。
  696. */
  697. function checkUnPublish($url) {
  698. if($this->_unpublishes == -1) {
  699. $conditions['or']['Page.status'] = false;
  700. $conditions['or'][] = array(array('Page.publish_begin >' => date('Y-m-d H:i:s')),
  701. array('Page.publish_begin <>' => '0000-00-00 00:00:00'),
  702. array('Page.publish_begin <>' => NULL));
  703. $conditions['or'][] = array(array('Page.publish_end <' => date('Y-m-d H:i:s')),
  704. array('Page.publish_end <>' => '0000-00-00 00:00:00'),
  705. array('Page.publish_end <>' => NULL));
  706. $pages = $this->find('all',array('fields'=>'url','conditions'=>$conditions,'recursive'=>-1));
  707. if(!$pages) {
  708. $this->_unpublishes = array();
  709. return false;
  710. }
  711. $this->_unpublishes = Set::extract('/Page/url', $pages);
  712. }
  713. if(preg_match('/\/$/', $url)) {
  714. $url .= 'index';
  715. }
  716. $url = preg_replace('/^\/'.Configure::read('BcRequest.agentAlias').'\//', '/'.Configure::read('BcRequest.agentPrefix').'/', $url);
  717. return in_array($url,$this->_unpublishes);
  718. }
  719. /**
  720. * キャッシュ時間を取得する
  721. *
  722. * @param string $url
  723. * @return mixed int or false
  724. */
  725. function getCacheTime($url) {
  726. $url = preg_replace('/^\/'.Configure::read('BcRequest.agentAlias').'\//', '/'.Configure::read('BcRequest.agentPrefix').'/', $url);
  727. $page = $this->find('first', array('conditions' => array('Page.url' => $url), 'recursive' => -1));
  728. if(!$page) {
  729. return false;
  730. }
  731. if($page['Page']['status'] && $page['Page']['publish_end'] && $page['Page']['publish_end'] != '0000-00-00 00:00:00') {
  732. return strtotime($page['Page']['publish_end']) - time();
  733. } else {
  734. return Configure::read('BcCache.defaultCachetime');
  735. }
  736. }
  737. /**
  738. * 公開チェックを行う
  739. *
  740. * @param string $url
  741. * @return boolean
  742. * @access public
  743. */
  744. function checkPublish($url) {
  745. if(preg_match('/\/$/', $url)) {
  746. $url .= 'index';
  747. }
  748. $url = preg_replace('/^\/'.Configure::read('BcRequest.agentAlias').'\//', '/'.Configure::read('BcRequest.agentPrefix').'/', $url);
  749. if($this->_publishes == -1) {
  750. $conditions = $this->getConditionAllowPublish();
  751. // 毎秒抽出条件が違うのでキャッシュしない
  752. $pages = $this->find('all', array(
  753. 'fields' => 'url',
  754. 'conditions'=> $conditions,
  755. 'recursive' => -1,
  756. 'cache' => false
  757. ));
  758. if(!$pages) {
  759. $this->_publishes = array();
  760. return false;
  761. }
  762. $this->_publishes = Set::extract('/Page/url', $pages);
  763. }
  764. return in_array($url,$this->_publishes);
  765. }
  766. /**
  767. * 公開済の conditions を取得
  768. *
  769. * @return array
  770. * @access public
  771. */
  772. function getConditionAllowPublish() {
  773. $conditions[$this->alias.'.status'] = true;
  774. $conditions[] = array('or'=> array(array($this->alias.'.publish_begin <=' => date('Y-m-d H:i:s')),
  775. array($this->alias.'.publish_begin' => NULL),
  776. array($this->alias.'.publish_begin' => '0000-00-00 00:00:00')));
  777. $conditions[] = array('or'=> array(array($this->alias.'.publish_end >=' => date('Y-m-d H:i:s')),
  778. array($this->alias.'.publish_end' => NULL),
  779. array($this->alias.'.publish_end' => '0000-00-00 00:00:00')));
  780. return $conditions;
  781. }
  782. /**
  783. * ページファイルを登録する
  784. * ※ 再帰処理
  785. *
  786. * @param string $pagePath
  787. * @param string $parentCategoryId
  788. * @return array 処理結果 all / success
  789. * @access protected
  790. */
  791. function entryPageFiles($targetPath,$parentCategoryId = '') {
  792. if(function_exists('ini_set')) {
  793. ini_set('max_execution_time', 0);
  794. ini_set('max_input_time', 0);
  795. ini_set('memory_limit ', '256M');
  796. }
  797. $this->fileSave = false;
  798. $folder = new Folder($targetPath);
  799. $files = $folder->read(true,true,true);
  800. $insert = 0;
  801. $update = 0;
  802. $all = 0;
  803. // カテゴリの取得・登録
  804. $categoryName = basename($targetPath);
  805. $pageCategoryId = '';
  806. $this->PageCategory->updateRelatedPage = false;
  807. if($categoryName != 'pages') {
  808. // カテゴリ名の取得
  809. // 標準では設定されてないので、利用する場合は、あらかじめ bootstrap 等で宣言しておく
  810. $categoryTitles = Configure::read('Baser.pageCategoryTitles');
  811. $categoryTitle = -1;
  812. if($categoryTitles) {
  813. $categoryNames = explode('/', str_replace(getViewPath().'pages'.DS, '', $targetPath));
  814. foreach($categoryNames as $key => $value) {
  815. if(isset($categoryTitles[$value])) {
  816. if(count($categoryNames) == ($key + 1)) {
  817. $categoryTitle = $categoryTitles[$value]['title'];
  818. }elseif(isset($categoryTitles[$value]['children'])) {
  819. $categoryTitles = $categoryTitles[$value]['children'];
  820. }
  821. }
  822. }
  823. }
  824. $categoryId = $this->PageCategory->getIdByPath($targetPath);
  825. if($categoryId) {
  826. $pageCategoryId = $categoryId;
  827. if($categoryTitle != -1) {
  828. $pageCategory = $this->PageCategory->find('first', array('conditions' => array('PageCategory.id' => $pageCategoryId), 'recursive' => -1));
  829. $pageCategory['PageCategory']['title'] = $categoryTitle;
  830. $this->PageCategory->set($pageCategory);
  831. $this->PageCategory->save();
  832. }
  833. }else {
  834. $pageCategory['PageCategory']['parent_id'] = $parentCategoryId;
  835. $pageCategory['PageCategory']['name'] = $categoryName;
  836. if($categoryTitle == -1) {
  837. $pageCategory['PageCategory']['title'] = $categoryName;
  838. } else {
  839. $pageCategory['PageCategory']['title'] = $categoryTitle;
  840. }
  841. $pageCategory['PageCategory']['sort'] = $this->PageCategory->getMax('sort')+1;
  842. $this->PageCategory->cacheQueries = false;
  843. $this->PageCategory->create($pageCategory);
  844. if($this->PageCategory->save()) {
  845. $pageCategoryId = $this->PageCategory->getInsertID();
  846. }
  847. }
  848. }else {
  849. $categoryName = '';
  850. }
  851. // ファイル読み込み・ページ登録
  852. if(!$files[1]) $files[1] = array();
  853. foreach($files[1] as $path) {
  854. if(preg_match('/'.preg_quote(Configure::read('BcApp.templateExt')).'$/is',$path) == false) {
  855. continue;
  856. }
  857. $pageName = basename($path, Configure::read('BcApp.templateExt'));
  858. $file = new File($path);
  859. $contents = $file->read();
  860. $file->close();
  861. $file = null;
  862. // タイトル取得・置換
  863. $titleReg = '/<\?php\s+?\$bcBaser->setTitle\(\'(.*?)\'\)\s+?\?>/is';
  864. if(preg_match($titleReg,$contents,$matches)) {
  865. $title = trim($matches[1]);
  866. $contents = preg_replace($titleReg,'',$contents);
  867. }else {
  868. $title = Inflector::camelize($pageName);
  869. }
  870. // 説明文取得・置換
  871. $descriptionReg = '/<\?php\s+?\$bcBaser->setDescription\(\'(.*?)\'\)\s+?\?>/is';
  872. if(preg_match($descriptionReg,$contents,$matches)) {
  873. $description = trim($matches[1]);
  874. $contents = preg_replace($descriptionReg,'',$contents);
  875. }else {
  876. $description = '';
  877. }
  878. // PageTagコメントの削除
  879. $pageTagReg = '/<\!\-\- BaserPageTagBegin \-\->.*?<\!\-\- BaserPageTagEnd \-\->/is';
  880. $contents = preg_replace($pageTagReg,'',$contents);
  881. $conditions['Page.name'] = $pageName;
  882. if($pageCategoryId) {
  883. $conditions['Page.page_category_id'] = $pageCategoryId;
  884. }else{
  885. $conditions['Page.page_category_id'] = null;
  886. }
  887. $page = $this->find('first', array('conditions' => $conditions, 'recursive' => -1));
  888. if($page) {
  889. $chage = false;
  890. if($title != $page['Page']['title']) {
  891. $chage = true;
  892. }
  893. if($description != $page['Page']['description']) {
  894. $chage = true;
  895. }
  896. if(trim($contents) != trim($page['Page']['contents'])) {
  897. $chage = true;
  898. }
  899. if($chage) {
  900. $page['Page']['title'] = $title;
  901. $page['Page']['description'] = $description;
  902. $page['Page']['contents'] = $contents;
  903. $this->set($page);
  904. if($this->save()) {
  905. $update++;
  906. }
  907. }
  908. }else {
  909. $page = $this->getDefaultValue();
  910. $page['Page']['name'] = $pageName;
  911. $page['Page']['title'] = $title;
  912. $page['Page']['description'] = $description;
  913. $page['Page']['contents'] = $contents;
  914. $page['Page']['page_category_id'] = $pageCategoryId;
  915. $page['Page']['url'] = $this->getPageUrl($page);
  916. $this->create($page);
  917. if($this->save()) {
  918. $insert++;
  919. }
  920. }
  921. $all++;
  922. }
  923. // フォルダー内の登録
  924. if(!$files[0]) $files[0] = array();
  925. foreach($files[0] as $file) {
  926. $folderName = basename($file);
  927. if($folderName != '_notes' && $folderName != 'admin') {
  928. $result = $this->entryPageFiles($file,$pageCategoryId);
  929. $insert += $result['insert'];
  930. $update += $result['update'];
  931. $all += $result['all'];
  932. }
  933. }
  934. return array('all'=>$all,'insert'=>$insert,'update'=>$update);
  935. }
  936. /**
  937. * 関連ページの存在チェック
  938. * 存在する場合は、ページIDを返す
  939. *
  940. * @param array $data ページデータ
  941. * @return mixed ページID / false
  942. * @access public
  943. */
  944. function agentExists ($type, $data) {
  945. if(isset($data['Page'])){
  946. $data = $data['Page'];
  947. }
  948. $url = $this->removeAgentPrefixFromUrl($data['url']);
  949. if(preg_match('/^\/'.Configure::read('BcAgent.'.$type.'.prefix').'\//is', $url)){
  950. // 対象ページがモバイルページの場合はfalseを返す
  951. return false;
  952. }
  953. return $this->field('id',array('Page.url'=>'/'.Configure::read('BcAgent.'.$type.'.prefix').$url));
  954. }
  955. /**
  956. * ページで管理されているURLかチェックする
  957. *
  958. * @param string $url
  959. * @return boolean
  960. * @access public
  961. */
  962. function isPageUrl($url) {
  963. if(preg_match('/\/$/', $url)) {
  964. $url .= 'index';
  965. }
  966. $url = preg_replace('/^\/'.Configure::read('BcRequest.agentAlias').'\//', '/'.Configure::read('BcRequest.agentPrefix').'/', $url);
  967. if($this->_pages == -1) {
  968. $pages = $this->find('all', array(
  969. 'fields' => 'url',
  970. 'recursive' => -1
  971. ));
  972. if(!$pages) {
  973. $this->_pages = array();
  974. return false;
  975. }
  976. $this->_pages = Set::extract('/Page/url', $pages);
  977. }
  978. return in_array($url,$this->_pages);
  979. }
  980. /**
  981. * Removes record for given ID. If no ID is given, the current ID is used. Returns true on success.
  982. *
  983. * @param mixed $id ID of record to delete
  984. * @param boolean $cascade Set to true to delete records that depend on this record
  985. * @return boolean True on success
  986. * @access public
  987. * @link http://book.cakephp.org/view/690/del
  988. */
  989. function del($id = null, $cascade = true) {
  990. // メッセージ用にデータを取得
  991. $page = $this->read(null, $id);
  992. /* 削除処理 */
  993. if(parent::del($id, $cascade)) {
  994. // ページテンプレートを削除
  995. $this->delFile($page);
  996. // 公開状態だった場合、サイトマップのキャッシュを削除
  997. // 公開期間のチェックは行わず確実に削除
  998. if($page['Page']['status']) {
  999. clearViewCache();
  1000. }
  1001. return true;
  1002. } else {
  1003. return false;
  1004. }
  1005. }
  1006. /**
  1007. * ページデータをコピーする
  1008. *
  1009. * @param int $id
  1010. * @param array $data
  1011. * @return mixed page Or false
  1012. */
  1013. function copy($id = null, $data = array()) {
  1014. if($id) {
  1015. $data = $this->find('first', array('conditions' => array('Page.id' => $id), 'recursive' => -1));
  1016. }
  1017. $data['Page']['name'] .= '_copy';
  1018. $data['Page']['title'] .= '_copy';
  1019. if(!empty($_SESSION['Auth']['User'])) {
  1020. $data['Page']['author_id'] = $_SESSION['Auth']['User']['id'];
  1021. }
  1022. $data['Page']['sort'] = $this->getMax('sort')+1;
  1023. $data['Page']['status'] = false;
  1024. $data['Page']['url'] = $this->getPageUrl($data);
  1025. unset($data['Page']['id']);
  1026. unset($data['Page']['created']);
  1027. unset($data['Page']['modified']);
  1028. $this->create($data);
  1029. $result = $this->save();
  1030. if($result) {
  1031. return $result;
  1032. } else {
  1033. if(isset($this->validationErrors['name']) && $this->validationErrors['name'] != 'ページ名は50文字以内で入力してください。') {
  1034. return $this->copy(null, $data);
  1035. } else {
  1036. return false;
  1037. }
  1038. }
  1039. }
  1040. }
  1041. ?>