1: <?php
2: /**
3: * This file contains the cContentTypeAbstract class.
4: *
5: * @package Core
6: * @subpackage ContentType
7: * @version SVN Revision $Rev:$
8: *
9: * @author Simon Sprankel
10: * @copyright four for business AG <www.4fb.de>
11: * @license http://www.contenido.org/license/LIZENZ.txt
12: * @link http://www.4fb.de
13: * @link http://www.contenido.org
14: */
15: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
16:
17: /**
18: * Abstract content type from which every content type should inherit.
19: *
20: * @package Core
21: * @subpackage ContentType
22: */
23: abstract class cContentTypeAbstract {
24:
25: /**
26: * Constant defining that the settings should be interpreted as plaintext.
27: */
28: const SETTINGS_TYPE_PLAINTEXT = 'plaintext';
29:
30: /**
31: * Constant defining that the settings should be interpreted as XML.
32: */
33: const SETTINGS_TYPE_XML = 'xml';
34:
35: /**
36: * Name of the content type, e.g.
37: * 'CMS_TEASER'.
38: *
39: * @var string
40: */
41: protected $_type = '';
42:
43: /**
44: * Prefix of the content type, e.g.
45: * 'teaser'.
46: *
47: * @var string
48: */
49: protected $_prefix = 'abstract';
50:
51: /**
52: * Whether the settings should be interpreted as plaintext or XML.
53: *
54: * @var string
55: */
56: protected $_settingsType = self::SETTINGS_TYPE_PLAINTEXT;
57:
58: /**
59: * ID of the content type, e.g.
60: * 3 if CMS_TEASER[3] is used.
61: *
62: * @var integer
63: */
64: protected $_id;
65:
66: /**
67: * Array containing the values of all content types.
68: *
69: * @var array
70: */
71: protected $_contentTypes;
72:
73: /**
74: * CONTENIDO configuration array
75: *
76: * @var array
77: */
78: protected $_cfg;
79:
80: /**
81: * idartlang of corresponding article
82: *
83: * @var integer
84: */
85: protected $_idArtLang;
86:
87: /**
88: * idart of corresponding article
89: *
90: * @var integer
91: */
92: protected $_idArt;
93:
94: /**
95: * idcat of corresponding article
96: *
97: * @var integer
98: */
99: protected $_idCat;
100:
101: /**
102: * CONTENIDO client id
103: *
104: * @var integer
105: */
106: protected $_client;
107:
108: /**
109: * CONTENIDO language id
110: *
111: * @var integer
112: */
113: protected $_lang;
114:
115: /**
116: * CONTENIDO session object
117: *
118: * @var cSession
119: */
120: protected $_session;
121:
122: /**
123: * CONTENIDO configuration array for currently active client
124: *
125: * @var array
126: */
127: protected $_cfgClient;
128:
129: /**
130: * Whether to generate XHTML
131: *
132: * @var boolean
133: */
134: protected $_useXHTML;
135:
136: /**
137: * The path to the upload directory.
138: *
139: * @var string
140: */
141: protected $_uploadPath;
142:
143: /**
144: * The raw settings from the DB.
145: *
146: * @var string
147: */
148: protected $_rawSettings = array();
149:
150: /**
151: * The parsed settings.
152: *
153: * @var array string
154: */
155: protected $_settings = array();
156:
157: /**
158: * List of form field names which are used by this content type!
159: *
160: * @var array
161: */
162: protected $_formFields = array();
163:
164: /**
165: * Initialises class attributes with values from cRegistry.
166: *
167: * @param string $rawSettings the raw settings in an XML structure or as
168: * plaintext
169: * @param integer $id ID of the content type, e.g. 3 if CMS_TEASER[3] is
170: * used
171: * @param array $contentTypes array containing the values of all content
172: * types
173: * @return void
174: */
175: public function __construct($rawSettings, $id, array $contentTypes) {
176: $this->_rawSettings = $rawSettings;
177: $this->_id = $id;
178: $this->_contentTypes = $contentTypes;
179:
180: $this->_idArtLang = cRegistry::getArticleLanguageId();
181: $this->_idArt = cRegistry::getArticleId();
182: $this->_idCat = cRegistry::getCategoryId();
183: $this->_cfg = cRegistry::getConfig();
184: $this->_client = cRegistry::getClientId();
185: $this->_lang = cRegistry::getLanguageId();
186: $this->_cfgClient = cRegistry::getClientConfig();
187: $this->_session = cRegistry::getSession();
188: $this->_useXHTML = cSecurity::toBoolean(getEffectiveSetting('generator', 'xhtml', 'false'));
189: $this->_uploadPath = $this->_cfgClient[$this->_client]['upl']['path'];
190:
191: $this->_readSettings();
192: }
193:
194: /**
195: * Reads all settings from the $_rawSettings attribute (XML or plaintext)
196: * and stores them in the $_settings attribute (associative array or
197: * plaintext).
198: *
199: * @param string $rawSettings the raw settings which should be parsed
200: * @return void
201: */
202: protected function _readSettings() {
203: // if no settings have been given, do nothing
204: if (empty($this->_rawSettings)) {
205: return;
206: }
207: if ($this->_settingsType === self::SETTINGS_TYPE_XML) {
208: // if the settings should be interpreted as XML, process them
209: // accordingly
210: $this->_settings = cXmlBase::xmlStringToArray($this->_rawSettings);
211: // add the prefix to the settings array keys
212: foreach ($this->_settings as $key => $value) {
213: $this->_settings[$this->_prefix . '_' . $key] = $value;
214: unset($this->_settings[$key]);
215: }
216: } else {
217: // otherwise do not process the raw setting
218: $this->_settings = $this->_rawSettings;
219: }
220: }
221:
222: /**
223: * Function returns curren content type configuration as array
224: *
225: * @return array
226: */
227: public function getConfiguration() {
228: return $this->_settings;
229: }
230:
231: /**
232: * Stores all values from the $_POST array in the $_settings attribute
233: * (associative array) and saves them in the database (XML).
234: *
235: * @return void
236: */
237: protected function _storeSettings() {
238: $settingsToStore = '';
239: if ($this->_settingsType === self::SETTINGS_TYPE_XML) {
240: // if the settings should be stored as XML, process them accordingly
241: $settings = array();
242: // update the values in the settings array with the values from the
243: // $_POST array
244: foreach ($this->_formFields as $key) {
245: $keyWithoutPrefix = str_replace($this->_prefix . '_', '', $key);
246: if (isset($_POST[$key])) {
247: $this->_settings[$key] = $_POST[$key];
248: } else if (isset($_POST[$this->_prefix . '_array_' . $keyWithoutPrefix])) {
249: // key is of type prefix_array_field, so interpret value as
250: // an array
251: $this->_settings[$key] = explode(',', $_POST[$this->_prefix . '_array_' . $keyWithoutPrefix]);
252: }
253: $settings[$keyWithoutPrefix] = $this->_settings[$key];
254: }
255: $xml = cXmlBase::arrayToXml($settings, null, $this->_prefix);
256: $settingsToStore = $xml->asXML();
257: } else {
258: $settingsToStore = $this->_settings;
259: }
260: // store new settings in the database
261: conSaveContentEntry($this->_idArtLang, $this->_type, $this->_id, $settingsToStore);
262: }
263:
264: /**
265: * Since the content type code is evaled by php, the code has to be encoded.
266: *
267: * @param string $code code to encode
268: * @return string encoded code
269: */
270: protected function _encodeForOutput($code) {
271: $code = addslashes($code);
272: $code = str_replace("\\'", "'", $code);
273: $code = str_replace('\$', '\\$', $code);
274:
275: return $code;
276: }
277:
278: /**
279: * Builds an array with directory information from the given upload path.
280: *
281: * @param string $uploadPath path to upload directory (optional, default:
282: * root upload path
283: * of client)
284: * @return array with directory information (keys: name, path, sub)
285: */
286: public function buildDirectoryList($uploadPath = '') {
287: // make sure the upload path is set and ends with a slash
288: if ($uploadPath === '') {
289: $uploadPath = $this->_uploadPath;
290: }
291: if (substr($uploadPath, -1) !== '/') {
292: $uploadPath .= '/';
293: }
294:
295: $directories = array();
296:
297: if (is_dir($uploadPath)) {
298: if ($handle = opendir($uploadPath)) {
299: while (($entry = readdir($handle)) !== false) {
300: // ignore .svn directories as well as links to upper dirs
301: if ($entry != '.svn' && $entry != '.' && $entry != '..' && is_dir($uploadPath . $entry)) {
302: $directory = array();
303: $directory['name'] = $entry;
304: $directory['path'] = str_replace($this->_uploadPath, '', $uploadPath);
305: $directory['sub'] = $this->buildDirectoryList($uploadPath . $entry);
306: $directories[] = $directory;
307: }
308: }
309: }
310: closedir($handle);
311: }
312: return $directories;
313: }
314:
315: /**
316: * Generates a directory list from the given directory information (which is
317: * typically built by {@link cContentTypeAbstract::buildDirectoryList}).
318: *
319: * @param array $dirs directory information
320: * @return string HTML code showing a directory list
321: */
322: public function generateDirectoryList(array $dirs) {
323: $template = new cTemplate();
324: $i = 1;
325:
326: foreach ($dirs as $dirData) {
327: // set the active class if this is the chosen directory
328: $divClass = ($this->_isActiveDirectory($dirData))? 'active' : '';
329: $template->set('d', 'DIVCLASS', $divClass);
330:
331: $template->set('d', 'TITLE', $dirData['path'] . $dirData['name']);
332: $template->set('d', 'DIRNAME', $dirData['name']);
333:
334: $liClasses = array();
335: // check if the directory should be shown expanded or collapsed
336: if ($this->_shouldDirectoryBeExpanded($dirData)) {
337: $template->set('d', 'SUBDIRLIST', $this->generateDirectoryList($dirData['sub']));
338: } else if (isset($dirData['sub']) && count($dirData['sub']) > 0) {
339: $liClasses[] = 'collapsed';
340: $template->set('d', 'SUBDIRLIST', '');
341: } else {
342: $template->set('d', 'SUBDIRLIST', '');
343: }
344: if ($i === count($dirs)) {
345: $liClasses[] = 'last';
346: }
347: $template->set('d', 'LICLASS', implode(' ', $liClasses));
348:
349: $i++;
350: $template->next();
351: }
352:
353: return $template->generate($this->_cfg['path']['contenido'] . 'templates/standard/template.cms_filelist_dirlistitem.html', true);
354: }
355:
356: /**
357: * Checks whether the directory defined by the given directory
358: * information is the currently active directory.
359: * Overwrite in subclasses if you use generateDirectoryList!
360: *
361: * @param array $dirData directory information
362: * @return boolean whether the directory is the currently active directory
363: */
364: protected function _isActiveDirectory(array $dirData) {
365: return false;
366: }
367:
368: /**
369: * Checks whether the directory defined by the given directory information
370: * should be shown expanded.
371: * Overwrite in subclasses if you use getDirectoryList!
372: *
373: * @param array $dirData directory information
374: * @return boolean whether the directory should be shown expanded
375: */
376: protected function _shouldDirectoryBeExpanded(array $dirData) {
377: return false;
378: }
379:
380: /**
381: * Checks whether the given $subDir is a subdirectory of the given $dir.
382: *
383: * @param string $subDir the potential subdirectory
384: * @param string $dir the parent directory
385: * @return boolean whether the given $subDir is a subdirectory of $dir
386: */
387: protected function _isSubdirectory($subDir, $dir) {
388: $dirArray = explode('/', $dir);
389: $expand = false;
390: $checkDir = '';
391:
392: // construct the whole directory in single steps and check if the given
393: // directory can be found
394: foreach ($dirArray as $dirPart) {
395: $checkDir .= '/' . $dirPart;
396: if ($checkDir === '/' . $subDir) {
397: $expand = true;
398: }
399: }
400:
401: return $expand;
402: }
403:
404: /**
405: * Generates the code which should be shown if this content type is shown in
406: * the frontend.
407: *
408: * @return string escaped HTML code which sould be shown if content type is
409: * shown in frontend
410: */
411: public abstract function generateViewCode();
412:
413: /**
414: * Generates the code which should be shown if this content type is edited.
415: *
416: * @return string escaped HTML code which should be shown if content type is
417: * edited
418: */
419: public abstract function generateEditCode();
420:
421: }