1: <?php
2: /**
3: * This file contains the article language collection and item class.
4: *
5: * @package Core
6: * @subpackage GenericDB_Model
7: * @author Bjoern Behrens
8: * @copyright four for business AG <www.4fb.de>
9: * @license http://www.contenido.org/license/LIZENZ.txt
10: * @link http://www.4fb.de
11: * @link http://www.contenido.org
12: */
13:
14: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
15:
16: /**
17: * Article language collection
18: *
19: * @package Core
20: * @subpackage GenericDB_Model
21: */
22: class cApiArticleLanguageCollection extends ItemCollection {
23:
24: /**
25: * Create a new collection of items.
26: *
27: * @param string $select [optional]
28: * where clause to use for selection (see ItemCollection::select())
29: */
30: public function __construct($select = false) {
31: global $cfg;
32: parent::__construct($cfg['tab']['art_lang'], 'idartlang');
33: $this->_setItemClass('cApiArticleLanguage');
34:
35: // set the join partners so that joins can be used via link() method
36: $this->_setJoinPartner('cApiArticleCollection');
37: $this->_setJoinPartner('cApiLanguageCollection');
38: $this->_setJoinPartner('cApiTemplateConfigurationCollection');
39:
40: if ($select !== false) {
41: $this->select($select);
42: }
43: }
44:
45: /**
46: * Creates an article language item entry.
47: *
48: * @global object $auth
49: * @param int $idart
50: * @param int $idlang
51: * @param string $title
52: * @param string $urlname
53: * @param string $pagetitle
54: * @param string $summary
55: * @param int $artspec [optional]
56: * @param string $created [optional]
57: * @param string $author [optional]
58: * @param string $lastmodified [optional]
59: * @param string $modifiedby [optional]
60: * @param string $published [optional]
61: * @param string $publishedby [optional]
62: * @param int $online [optional]
63: * @param int $redirect [optional]
64: * @param string $redirect_url [optional]
65: * @param int $external_redirect [optional]
66: * @param int $artsort [optional]
67: * @param int $timemgmt [optional]
68: * @param string $datestart [optional]
69: * @param string $dateend [optional]
70: * @param int $status [optional]
71: * @param int $time_move_cat [optional]
72: * @param int $time_target_cat [optional]
73: * @param int $time_online_move [optional]
74: * @param int $locked [optional]
75: * @param mixed $free_use_01 [optional]
76: * @param mixed $free_use_02 [optional]
77: * @param mixed $free_use_03 [optional]
78: * @param int $searchable [optional]
79: * @param float $sitemapprio [optional]
80: * @param string $changefreq [optional]
81: * @return cApiArticleLanguage
82: */
83: public function create($idart, $idlang, $title, $urlname, $pagetitle,
84: $summary, $artspec = 0, $created = '', $author = '',
85: $lastmodified = '', $modifiedby = '', $published = '',
86: $publishedby = '', $online = 0, $redirect = 0, $redirect_url = '',
87: $external_redirect = 0, $artsort = 0, $timemgmt = 0, $datestart = '',
88: $dateend = '', $status = 0, $time_move_cat = 0, $time_target_cat = 0,
89: $time_online_move = 0, $locked = 0, $free_use_01 = '', $free_use_02 = '',
90: $free_use_03 = '', $searchable = 1, $sitemapprio = 0.5, $changefreq = '') {
91: global $auth;
92:
93: if (empty($author)) {
94: $author = $auth->auth['uname'];
95: }
96: if (empty($created)) {
97: $created = date('Y-m-d H:i:s');
98: }
99: if (empty($lastmodified)) {
100: $lastmodified = date('Y-m-d H:i:s');
101: }
102:
103: $urlname = (trim($urlname) == '') ? trim($title) : trim($urlname);
104:
105: $item = $this->createNewItem();
106:
107: $item->set('idart', $idart);
108: $item->set('idlang', $idlang);
109: $item->set('title', $title);
110: $item->set('urlname', $urlname);
111: $item->set('pagetitle', $pagetitle);
112: $item->set('summary', $summary);
113: $item->set('artspec', $artspec);
114: $item->set('created', $created);
115: $item->set('author', $author);
116: $item->set('lastmodified', $lastmodified);
117: $item->set('modifiedby', $modifiedby);
118: $item->set('published', $published);
119: $item->set('publishedby', $publishedby);
120: $item->set('online', $online);
121: $item->set('redirect', $redirect);
122: $item->set('redirect_url', $redirect_url);
123: $item->set('external_redirect', $external_redirect);
124: $item->set('artsort', $artsort);
125: $item->set('timemgmt', $timemgmt);
126: $item->set('datestart', $datestart);
127: $item->set('dateend', $dateend);
128: $item->set('status', $status);
129: $item->set('time_move_cat', $time_move_cat);
130: $item->set('time_target_cat', $time_target_cat);
131: $item->set('time_online_move', $time_online_move);
132: $item->set('locked', $locked);
133: $item->set('free_use_01', $free_use_01);
134: $item->set('free_use_02', $free_use_02);
135: $item->set('free_use_03', $free_use_03);
136: $item->set('searchable', $searchable);
137: $item->set('sitemapprio', $sitemapprio);
138: $item->set('changefreq', $changefreq);
139:
140: $item->store();
141:
142: return $item;
143: }
144:
145: /**
146: * Returns id (idartlang) of articlelanguage by article id and language id
147: *
148: * @param int $idcat
149: * @param int $idlang
150: * @return int
151: */
152: public function getIdByArticleIdAndLanguageId($idart, $idlang) {
153: $sql = "SELECT idartlang FROM `%s` WHERE idart = %d AND idlang = %d";
154: $this->db->query($sql, $this->table, $idart, $idlang);
155: return ($this->db->nextRecord()) ? $this->db->f('idartlang') : 0;
156: }
157:
158: }
159:
160: /**
161: * CONTENIDO API - Article Object
162: *
163: * This object represents a CONTENIDO article
164: *
165: * Create object with
166: * $obj = new cApiArticleLanguage(idartlang);
167: * or with
168: * $obj = new cApiArticleLanguage();
169: * $obj->loadByArticleAndLanguageId(idart, lang);
170: *
171: * You can now read the article properties with
172: * $obj->getField(property);
173: *
174: * List of article properties:
175: *
176: * idartlang - Language dependant article id
177: * idart - Language indepenant article id
178: * idclient - Id of the client
179: * idtplcfg - Template configuration id
180: * title - Internal Title
181: * pagetitle - HTML Title
182: * summary - Article summary
183: * created - Date created
184: * lastmodified - Date lastmodiefied
185: * author - Article author (username)
186: * online - On-/offline
187: * redirect - Redirect
188: * redirect_url - Redirect URL
189: * artsort - Article sort key
190: * timemgmt - Time management
191: * datestart - Time management start date
192: * dateend - Time management end date
193: * status - Article status
194: * free_use_01 - Free to use
195: * free_use_02 - Free to use
196: * free_use_03 - Free to use
197: * time_move_cat - Move category after time management
198: * time_target_cat - Move category to this cat after time management
199: * time_online_move - Set article online after move
200: * external_redirect - Open article in new window
201: * locked - Article is locked for editing
202: * searchable - Whether article should be found via search
203: * sitemapprio - The priority for the sitemap
204: *
205: * You can extract article content with the
206: * $obj->getContent(contype [, number]) method.
207: *
208: * To extract the first headline you can use:
209: *
210: * $headline = $obj->getContent("htmlhead", 1);
211: *
212: * If the second parameter is ommitted the method returns an array with all
213: * available
214: * content of this type. The array has the following schema:
215: *
216: * array(number => content);
217: *
218: * $headlines = $obj->getContent("htmlhead");
219: *
220: * $headlines[1] First headline
221: * $headlines[2] Second headline
222: * $headlines[6] Sixth headline
223: *
224: * Legal content type string are defined in the CONTENIDO system table
225: * 'con_type'.
226: * Default content types are:
227: *
228: * NOTE: This parameter is case insesitive, you can use html or cms_HTML or
229: * CmS_HtMl.
230: * Your don't need start with cms, but it won't crash if you do so.
231: *
232: * htmlhead - HTML Headline
233: * html - HTML Text
234: * headline - Headline (no HTML)
235: * text - Text (no HTML)
236: * img - Upload id of the element
237: * imgdescr - Image description
238: * link - Link (URL)
239: * linktarget - Linktarget (_self, _blank, _top ...)
240: * linkdescr - Linkdescription
241: * swf - Upload id of the element
242: *
243: * @package Core
244: * @subpackage GenericDB_Model
245: */
246: class cApiArticleLanguage extends Item {
247:
248: /**
249: * Config array
250: *
251: * @var array
252: */
253: public $tab;
254:
255: /**
256: * Article content
257: *
258: * @deprecated [2015-05-27]
259: * @var array
260: */
261: public $content = NULL;
262:
263: /**
264: * Constructor Function
265: *
266: * @param mixed $mId [optional]
267: * Specifies the ID of item to load
268: */
269: public function __construct($mId = false) {
270: global $cfg;
271: parent::__construct($cfg['tab']['art_lang'], 'idartlang');
272: $this->setFilters(array(), array());
273: if ($mId !== false) {
274: $this->loadByPrimaryKey($mId);
275: }
276: }
277:
278: /**
279: * Create a version of this article language with its contents/metatags;
280: * the version is the new editable article language version
281: *
282: * @param string $type
283: * meta, content or complete
284: */
285: public function markAsEditable($type = '') {
286: global $cfg;
287:
288: // create new editable version
289: $sql = 'SELECT max(version) AS max FROM %s WHERE idartlang = %d';
290: $this->db->query($sql, $cfg['tab']['art_lang_version'], $this->get('idartlang'));
291: while ($this->db->nextRecord()) {
292: $maxVersion = $this->db->f('max');
293: }
294:
295: $parameters = $this->values;
296: $parameters['version'] = $maxVersion + 1;
297: $artLangVersionColl = new cApiArticleLanguageVersionCollection();
298: $artLangVersion = $artLangVersionColl->create($parameters);
299:
300: if ($type == 'content' || $type == 'complete') {
301: // load content of article language version into $artLangVersion->content
302: $artLangVersion->loadByArticleLanguageIdAndVersion($artLangVersion->get('idartlang'), $artLangVersion->get('version'), true);
303: $contentVersion = new cApiContent();
304: $oType = new cApiType();
305: $this->_loadArticleContent();
306:
307: // get all Contents/Versions
308: $mergedContent = array();
309: foreach ($this->content AS $type => $typeids) {
310: foreach ($typeids AS $typeid => $value) {
311: $mergedContent[$type][$typeid] = '';
312: }
313: }
314: foreach ($artLangVersion->content AS $type => $typeids) {
315: foreach ($typeids AS $typeid => $value) {
316: $mergedContent[$type][$typeid] = '';
317: }
318: }
319:
320: // set new Content Versions
321: foreach ($mergedContent AS $type => $typeids) {
322: foreach ($typeids AS $typeid => $value) {
323: $oType->loadByType($type);
324: if (isset($this->content[$type][$typeid])) {
325: $contentVersion->loadByArticleLanguageIdTypeAndTypeId($this->get('idartlang'), $oType->get('idtype'), $typeid);
326: if (isset($contentVersion)) {
327: $contentVersion->markAsEditable($artLangVersion->get('version'), 0);
328: }
329: } else {
330: $contentParameters = array(
331: 'idartlang' => $artLangVersion->get('idartlang'),
332: 'idtype' => $oType->get('idtype'),
333: 'typeid' => $typeid,
334: 'version' => $artLangVersion->get('version'),
335: 'author' => $this->get('author'),
336: 'deleted' => 1
337: );
338: $contentVersionColl = new cApiContentVersionCollection();
339: $contentVersionColl->create($contentParameters);
340: }
341: }
342: }
343: }
344:
345: if ($type == 'meta' || $type == 'complete') {
346: // set new meta tag versions
347: $metaTag = new cApiMetaTag();
348: $sql = 'SELECT idmetatag AS id
349: FROM `%s`
350: WHERE idartlang = %d';
351: $this->db->query(
352: $sql,
353: cRegistry::getDbTableName('meta_tag'),
354: $this->get('idartlang')
355: );
356: while ($this->db->nextRecord()) {
357: $metaTagIds[] = $this->db->f('id');
358: }
359: if(isset($metaTagIds)) {
360: foreach ($metaTagIds AS $id) {
361: $metaTag->loadBy('idmetatag', $id);
362: $metaTag->markAsEditable($artLangVersion->get('version'));
363: }
364: }
365: }
366: }
367:
368: /**
369: * Load data by article and language id
370: *
371: * @param int $idart
372: * Article id
373: * @param int $idlang
374: * Language id
375: * Flag to fetch content
376: * @return bool
377: * true on success, otherwise false
378: */
379: public function loadByArticleAndLanguageId($idart, $idlang) {
380: $result = true;
381: if (!$this->isLoaded()) {
382: $aProps = array(
383: 'idart' => $idart,
384: 'idlang' => $idlang
385: );
386: $aRecordSet = $this->_oCache->getItemByProperties($aProps);
387: if ($aRecordSet) {
388: // entry in cache found, load entry from cache
389: $this->loadByRecordSet($aRecordSet);
390: } else {
391: $idartlang = $this->_getIdArtLang($idart, $idlang);
392: $result = $this->loadByPrimaryKey($idartlang);
393: }
394: }
395:
396: return $result;
397: }
398:
399: /**
400: * Extract 'idartlang' for a specified 'idart' and 'idlang'
401: *
402: * @param int $idart
403: * Article id
404: * @param int $idlang
405: * Language id
406: * @return int
407: * Language dependant article id
408: */
409: protected function _getIdArtLang($idart, $idlang) {
410: global $cfg;
411:
412: $sql = 'SELECT idartlang FROM `%s` WHERE idart = %d AND idlang = %d';
413: $this->db->query($sql, $cfg['tab']['art_lang'], $idart, $idlang);
414: $this->db->nextRecord();
415:
416: return $this->db->f('idartlang');
417: }
418:
419: /**
420: * Load the articles content and stores it in the 'content' property of the
421: * article object.
422: *
423: * $article->content[type][number] = value;
424: *
425: * @deprecated [2015-05-15]
426: * use _loadArticleContent
427: */
428: public function loadArticleContent() {
429: cDeprecated('This method is deprecated and is not needed any longer');
430: $this->_loadArticleContent();
431: }
432:
433: /**
434: * Load the articles content and stores it in the 'content' property of the
435: * article object.
436: *
437: * $article->content[type][number] = value;
438: *
439: * @deprecated [2015-05-15]
440: * use _loadArticleContent
441: */
442: protected function _getArticleContent() {
443: cDeprecated('This method is deprecated and is not needed any longer');
444: $this->_loadArticleContent();
445: }
446:
447: /**
448: * Load the articles content and stores it in the 'content' property of the
449: * article object, whenever it is needed to get the content of the article.
450: *
451: * $article->content[type][number] = value;
452: */
453: protected function _loadArticleContent() {
454: global $cfg;
455:
456: if (NULL !== $this->content) {
457: return;
458: }
459:
460: $sql = 'SELECT b.type, a.typeid, a.value FROM `%s` AS a, `%s` AS b ' . 'WHERE a.idartlang = %d AND b.idtype = a.idtype ORDER BY a.idtype, a.typeid';
461:
462: $this->db->query($sql, $cfg['tab']['content'], $cfg['tab']['type'], $this->get('idartlang'));
463:
464: $this->content = array();
465: while ($this->db->nextRecord()) {
466: $this->content[strtolower($this->db->f('type'))][$this->db->f('typeid')] = $this->db->f('value');
467: }
468: }
469:
470: /**
471: * Get the value of an article property
472: *
473: * List of article properties:
474: *
475: * idartlang - Language dependant article id
476: * idart - Language indepenant article id
477: * idclient - Id of the client
478: * idtplcfg - Template configuration id
479: * title - Internal Title
480: * pagetitle - HTML Title
481: * summary - Article summary
482: * created - Date created
483: * lastmodified - Date lastmodiefied
484: * author - Article author (username)
485: * online - On-/offline
486: * redirect - Redirect
487: * redirect_url - Redirect URL
488: * artsort - Article sort key
489: * timemgmt - Time management
490: * datestart - Time management start date
491: * dateend - Time management end date
492: * status - Article status
493: * free_use_01 - Free to use
494: * free_use_02 - Free to use
495: * free_use_03 - Free to use
496: * time_move_cat - Move category after time management
497: * time_target_cat - Move category to this cat after time management
498: * time_online_move - Set article online after move
499: * external_redirect - Open article in new window
500: * locked - Article is locked for editing
501: * searchable - Whether article should be found via search
502: * sitemapprio - The priority for the sitemap
503: *
504: * @param string $name
505: * @param bool $bSafe [optional]
506: * Flag to run defined outFilter on passed value
507: * NOTE: It's not used ATM!
508: * @return string
509: * Value of property
510: */
511: public function getField($name, $bSafe = true) {
512: return $this->values[$name];
513: }
514:
515: /**
516: * Userdefined setter for article language fields.
517: *
518: * @todo should return return value of overloaded method
519: * @param string $name
520: * @param mixed $value
521: * @param bool $bSafe [optional]
522: * Flag to run defined inFilter on passed value
523: */
524: public function setField($name, $value, $bSafe = true) {
525: switch ($name) {
526: case 'urlname':
527: $value = conHtmlSpecialChars(cString::cleanURLCharacters($value), ENT_QUOTES);
528: break;
529: case 'timemgmt':
530: case 'time_move_cat':
531: case 'time_online_move':
532: case 'redirect':
533: case 'external_redirect':
534: case 'locked':
535: $value = ($value == 1) ? 1 : 0;
536: break;
537: case 'idart':
538: case 'idlang':
539: case 'artspec':
540: case 'online':
541: case 'searchable':
542: case 'artsort':
543: case 'status':
544: $value = (int) $value;
545: break;
546: case 'redirect_url':
547: $value = ($value == 'http://' || $value == '') ? '0' : $value;
548: break;
549: }
550:
551: parent::setField($name, $value, $bSafe);
552: }
553:
554: /**
555: * Get content(s) from an article.
556: *
557: * Returns the specified content element or an array("id"=>"value") if the
558: * second parameter is omitted.
559: *
560: * Legal content type string are defined in the CONTENIDO system table
561: * 'con_type'.
562: * Default content types are:
563: *
564: * NOTE: Parameter is case insensitive, you can use html or cms_HTML or
565: * CmS_HtMl.
566: * You don't need to start with cms, but it won't crash if you do so.
567: *
568: * htmlhead - HTML Headline
569: * html - HTML Text
570: * headline - Headline (no HTML)
571: * text - Text (no HTML)
572: * img - Upload id of the element
573: * imgdescr - Image description
574: * link - Link (URL)
575: * linktarget - Linktarget (_self, _blank, _top ...)
576: * linkdescr - Linkdescription
577: * swf - Upload id of the element
578: *
579: * @param string $type
580: * CMS_TYPE - Legal cms type string
581: * @param int|NULL $id [optional]
582: * Id of the content
583: * @return string|array
584: * data
585: */
586: public function getContent($type = '', $id = NULL) {
587: if (NULL === $this->content) {
588: $this->_loadArticleContent();
589: }
590:
591: if (empty($this->content)) {
592: return '';
593: }
594:
595: if ($type == '') {
596: return $this->content;
597: }
598:
599: $type = strtolower($type);
600:
601: if (false === stripos($type, 'cms_')) {
602: $type = 'cms_' . $type;
603: }
604:
605: if (is_null($id)) {
606: // return Array
607: return $this->content[$type];
608: }
609:
610: // return String
611: return (isset($this->content[$type][$id])) ? $this->content[$type][$id] : '';
612: }
613:
614: /**
615: * Similar to getContent this function returns the cContentType object
616: *
617: * @param string $type
618: * Name of the content type
619: * @param int $id
620: * Id of the content type in this article
621: * @return bool|cContentType
622: * Returns false if the name was invalid
623: */
624: public function getContentObject($type, $id) {
625: $typeClassName = 'cContentType' . ucfirst(strtolower(str_replace('CMS_', '', $type)));
626:
627: if (!class_exists($typeClassName)) {
628: return false;
629: }
630:
631: return new $typeClassName($this->getContent($type, $id), $id, $this->content);
632: }
633:
634: /**
635: * Similar to getContent this function returns the view code of the cContentType object
636: *
637: * @param string $type
638: * Name of the content type
639: * @param int $id
640: * Id of the content type in this article
641: * @return string
642: */
643: public function getContentViewCode($type, $id) {
644: $object = $this->getContentObject($type, $id);
645: if ($object === false) {
646: return "";
647: }
648:
649: return $object->generateViewCode();
650: }
651:
652: /**
653: * Returns all available content types
654: *
655: * @throws cException
656: * if no content has been loaded
657: * @return array
658: */
659: public function getContentTypes() {
660: if (empty($this->content)) {
661: $this->_loadArticleContent();
662: }
663:
664: return (is_array($this->content)) ? array_keys($this->content) : array();
665: }
666:
667: /**
668: * Returns the link to the current object.
669: *
670: * @param int $changeLangId [optional]
671: * change language id for URL (optional)
672: * @return string
673: * link
674: */
675: public function getLink($changeLangId = 0) {
676: if ($this->isLoaded() === false) {
677: return '';
678: }
679:
680: $options = array();
681: $options['idart'] = $this->get('idart');
682: $options['lang'] = ($changeLangId == 0) ? $this->get('idlang') : $changeLangId;
683: if ($changeLangId > 0) {
684: $options['changelang'] = $changeLangId;
685: }
686:
687: return cUri::getInstance()->build($options);
688: }
689:
690: }
691: