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