1: <?php
2:
3: /**
4: *
5: * A facade class for the Markdown library
6: *
7: * @package alpha::util
8: * @since 1.0
9: * @author John Collins <dev@alphaframework.org>
10: * @version $Id: MarkdownFacade.inc 1550 2012-07-29 21:15:40Z alphadevx $
11: * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
12: * @copyright Copyright (c) 2012, John Collins (founder of Alpha Framework).
13: * All rights reserved.
14: *
15: * <pre>
16: * Redistribution and use in source and binary forms, with or
17: * without modification, are permitted provided that the
18: * following conditions are met:
19: *
20: * * Redistributions of source code must retain the above
21: * copyright notice, this list of conditions and the
22: * following disclaimer.
23: * * Redistributions in binary form must reproduce the above
24: * copyright notice, this list of conditions and the
25: * following disclaimer in the documentation and/or other
26: * materials provided with the distribution.
27: * * Neither the name of the Alpha Framework nor the names
28: * of its contributors may be used to endorse or promote
29: * products derived from this software without specific
30: * prior written permission.
31: *
32: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
33: * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
34: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
35: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
37: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
39: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
40: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
43: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45: * </pre>
46: *
47: */
48: class MarkdownFacade {
49: /**
50: * The markdown-format content that we will render
51: *
52: * @var string
53: * @since 1.0
54: */
55: private $content;
56:
57: /**
58: * The business object that stores the content will be rendered to Markdown
59: *
60: * @var AlphaDAO
61: * @since 1.0
62: */
63: private $BO = null;
64:
65: /**
66: * The auto-generated name of the Markdown HTML cache file for the BO
67: *
68: * @var string
69: * @since 1.0
70: */
71: private $filename;
72:
73: /**
74: * The constructor
75: *
76: * @param AlphaDAO $BO
77: * @param boolean $useCache
78: * @since 1.0
79: */
80: public function __construct($BO, $useCache = true) {
81: global $config;
82:
83: $this->BO = $BO;
84: if($this->BO instanceof ArticleObject && $this->BO->isLoadedFromFile()) {
85: $underscoreTimeStamp = str_replace(array('-',' ',':'), '_', $this->BO->getContentFileDate());
86: $this->filename = $config->get('app.file.store.dir').'cache/html/'.get_class($this->BO).'_'.$this->BO->get('title').'_'.$underscoreTimeStamp.'.html';
87: }else{
88: $this->filename = $config->get('app.file.store.dir').'cache/html/'.get_class($this->BO).'_'.$this->BO->getID().'_'.$this->BO->getVersion().'.html';
89: }
90:
91: if(!$useCache) {
92: $this->content = $this->markdown($this->BO->get('content', true));
93: }else{
94: if ($this->checkCache()) {
95: $this->loadCache();
96: }else{
97: if($this->BO->get('content', true) == '') {
98: // the content may not be loaded from the DB at this stage due to a previous soft-load
99: $this->BO->reload();
100: }
101:
102: $this->content = $this->markdown($this->BO->get('content', true));
103:
104: $this->cache();
105: }
106: }
107:
108: // Replace all instances of $attachURL in link tags to links to the ViewAttachment controller
109: $attachments = array();
110: preg_match_all('/href\=\"\$attachURL\/.*\"/', $this->content, $attachments);
111:
112: foreach($attachments[0] as $attachmentURL) {
113: $start = strpos($attachmentURL, '/');
114: $end = strrpos($attachmentURL, '"');
115: $fileName = substr($attachmentURL, $start+1, $end-($start+1));
116:
117: if(method_exists($this->BO, 'getAttachmentSecureURL')) {
118: $this->content = str_replace($attachmentURL, 'href="'.$this->BO->getAttachmentSecureURL($fileName).'" rel="nofollow"', $this->content);
119: }
120: }
121:
122: // Handle image attachments
123: $attachments = array();
124: preg_match_all('/\<img\ src\=\"\$attachURL\/.*\".*\>/', $this->content, $attachments);
125:
126: foreach($attachments[0] as $attachmentURL) {
127: $start = strpos($attachmentURL, '/');
128: $end = strrpos($attachmentURL, '" alt');
129: $fileName = substr($attachmentURL, $start+1, $end-($start+1));
130:
131: if($config->get('cms.images.widget')) {
132: // get the details of the source image
133: $path = $this->BO->getAttachmentsLocation().'/'.$fileName;
134: $image_details = getimagesize($path);
135: $imgType = $image_details[2];
136: if($imgType == 1)
137: $type = 'gif';
138: elseif($imgType == 2)
139: $type = 'jpg';
140: elseif($imgType == 3)
141: $type = 'png';
142:
143: $img = new Image($path, $image_details[0], $image_details[1], $type, 0.95, false, (boolean)$config->get('cms.images.widget.secure'));
144:
145: $this->content = str_replace($attachmentURL, $img->renderHTMLLink(), $this->content);
146: }else{
147: // render a normal image link to the ViewAttachment controller
148: if(method_exists($this->BO, 'getAttachmentSecureURL')) {
149: $this->content = str_replace($attachmentURL, '<img src="'.$this->BO->getAttachmentSecureURL($fileName).'">', $this->content);
150: }
151: }
152: }
153: }
154:
155: /**
156: * Facade method which will invoke our custom markdown class rather than the standard one
157: *
158: * @return string
159: * @since 1.0
160: */
161: public function markdown($text) {
162: global $config;
163:
164: // Initialize the parser and return the result of its transform method.
165: static $parser;
166:
167: if (!isset($parser)) {
168: $parser_class = 'AlphaMarkdown';
169: $parser = new $parser_class;
170: }
171:
172: /*
173: * Replace all instances of $sysURL in the text with the app.url setting from config
174: */
175: $text = str_replace('$sysURL', $config->get('app.url'), $text);
176:
177: // transform text using parser.
178: return $parser->transform($text);
179: }
180:
181: /**
182: * Getter for the content
183: *
184: * @return string
185: * @since 1.0
186: */
187: public function getContent() {
188: return $this->content;
189: }
190:
191: /**
192: * Saves the HTML generated by Markdown to the cache directory
193: *
194: * @since 1.0
195: */
196: private function cache() {
197: // check to ensure that the article is not transient before caching it
198: if ($this->BO->getID() != '00000000000' || $this->BO->isLoadedFromFile()) {
199: $fp=fopen($this->filename,"w");
200: if (!$fp) {
201: throw new AlphaException('Failed to open the cache file for writing, directory permissions my not be set correctly!');
202: }else{
203: flock($fp,2); // locks the file for writting
204: fwrite($fp,$this->content);
205: flock($fp,3); // unlocks the file
206: fclose($fp); //closes the file
207: }
208: }
209: }
210:
211: /**
212: * Used to check the HTML cache for the BO cache file
213: *
214: * @return boolean
215: * @since 1.0
216: */
217: public function checkCache() {
218: return file_exists($this->filename);
219: }
220:
221: /**
222: * Method to load the content of the cache file to the $content attribute of this object
223: *
224: * @since 1.0
225: */
226: public function loadCache() {
227: $fp = fopen($this->filename,"r");
228:
229: if (!$fp) {
230: throw new AlphaException('Failed to open the cache file for reading, directory permissions my not be set correctly!');
231: }else{
232: $this->content = fread($fp, filesize($this->filename));
233: fclose($fp); //closes the file
234: }
235: }
236: }
237: ?>