Overview

Packages

  • CONTENIDO
  • Core
    • Authentication
    • Backend
    • Cache
    • CEC
    • Chain
    • ContentType
    • Database
    • Debug
    • Exception
    • Frontend
      • Search
      • URI
      • Util
    • GenericDB
      • Model
    • GUI
      • HTML
    • I18N
    • LayoutHandler
    • Log
    • Security
    • Session
    • Util
    • Validation
    • Versioning
    • XML
  • Module
    • ContentSitemapHtml
    • ContentSitemapXml
    • ContentUserForum
    • NavigationTop
    • ScriptCookieDirective
  • mpAutoloaderClassMap
  • None
  • PHP
  • Plugin
    • ContentAllocation
    • CronjobOverview
    • FormAssistant
    • FrontendLogic
    • FrontendUsers
    • Linkchecker
    • ModRewrite
    • Newsletter
    • Repository
      • FrontendNavigation
      • KeywordDensity
    • SIWECOS
    • SmartyWrapper
    • UrlShortener
    • UserForum
    • Workflow
  • PluginManager
  • Setup
    • Form
    • GUI
    • Helper
      • Environment
      • Filesystem
      • MySQL
      • PHP
    • UpgradeJob

Classes

  • cApiPathresolveCacheHelper
  • cArray
  • cArticleCollector
  • cDirHandler
  • cFileHandler
  • cHTMLInputSelectElement
  • cIterator
  • cString
  • cStringMultiByteWrapper
  • cZipArchive
  • UI_Config_Table
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: /**
  3:  * This file contains the array utility class.
  4:  *
  5:  * @package    Core
  6:  * @subpackage Util
  7:  * @author     Dominik Ziegler
  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:  * The
 18:  * article collector returns you a list of articles, which destination you can
 19:  * choose.
 20:  * You have the ability to limit, sort and filter the article list.
 21:  *
 22:  * You can configure the article collector with an options array, which can include the
 23:  * following configuration.
 24:  *
 25:  * - idcat - category ID
 26:  * - categories - array with multiple category IDs
 27:  * - lang - language ID, active language if ommited
 28:  * - client - client ID, active client if ommited
 29:  * - artspecs - array of article specifications, which should be considered
 30:  * - offline - include offline article in the collection, defaults to false
 31:  * - offlineonly - only list offline articles, defaults to false
 32:  * - start - include start article in the collection, defaults to false
 33:  * - startonly - only list start articles, defaults to false
 34:  * - order - articles will be ordered by this property, defaults to created
 35:  * - direction - order direction, ASC or DESC for ascending/descending, defaults to DESC
 36:  * - limit - limit numbers of articles in collection, default to 0 (unlimited)
 37:  *
 38:  * TODO: Use generic DB instead of SQL queries
 39:  *
 40:  * @package Core
 41:  * @subpackage Util
 42:  */
 43: class cArticleCollector implements SeekableIterator, Countable {
 44: 
 45:     /**
 46:      * Options for the collector.
 47:      *
 48:      * @var array
 49:      */
 50:     protected $_options = array();
 51: 
 52:     /**
 53:      * Loaded articles.
 54:      *
 55:      * @var array
 56:      */
 57:     protected $_articles = array();
 58: 
 59:     /**
 60:      * Total paging data.
 61:      *
 62:      * @var array
 63:      */
 64:     protected $_pages = array();
 65: 
 66:     /**
 67:      * Start articles of the requested categories.
 68:      *
 69:      * @var array
 70:      */
 71:     protected $_startArticles = array();
 72: 
 73:     /**
 74:      * Current position for the iterator.
 75:      *
 76:      * @var int
 77:      */
 78:     protected $_currentPosition = 0;
 79: 
 80:     /**
 81:      * Constructor to create an instance of this class.
 82:      *
 83:      * If options are defined, the loading process is automatically
 84:      * initiated.
 85:      *
 86:      * @param array $options [optional, default: empty array]
 87:      *                       array with options for the collector
 88:      *
 89:      * @throws cDbException
 90:      */
 91:     public function __construct($options = array()) {
 92:         $this->setOptions($options);
 93:         $this->loadArticles();
 94:     }
 95: 
 96:     /**
 97:      * Setter for the collector options. Validates incoming options and sets the
 98:      * default of the missing options.
 99:      *
100:      * @param array $options
101:      *         array with option
102:      */
103:     public function setOptions($options) {
104:         if (isset($options['idcat']) && !isset($options['categories'])) {
105:             $options['categories'] = array(
106:                     $options['idcat']
107:             );
108:         }
109: 
110:         if (isset($options['categories']) === false) {
111:             $options['categories'] = array();
112:         }
113: 
114:         if (isset($options['lang']) === false) {
115:             $options['lang'] = cRegistry::getLanguageId();
116:         }
117: 
118:         if (isset($options['client']) === false) {
119:             $options['client'] = cRegistry::getClientId();
120:         }
121: 
122:         if (isset($options['start']) === false) {
123:             $options['start'] = false;
124:         }
125: 
126:         if (isset($options['startonly']) === false) {
127:             $options['startonly'] = false;
128:         }
129: 
130:         if (isset($options['offline']) === false) {
131:             $options['offline'] = false;
132:         }
133: 
134:         if (isset($options['offlineonly']) === false) {
135:             $options['offlineonly'] = false;
136:         }
137: 
138:         switch ($options['order']) {
139:             case 'sortsequence':
140:                 $options['order'] = 'artsort';
141:                 break;
142: 
143:             case 'title':
144:                 $options['order'] = 'title';
145:                 break;
146: 
147:             case 'modificationdate':
148:                 $options['order'] = 'lastmodified';
149:                 break;
150: 
151:             case 'publisheddate':
152:                 $options['order'] = 'published';
153:                 break;
154: 
155:             case 'creationdate':
156:             default:
157:                 $options['order'] = 'created';
158:                 break;
159:         }
160: 
161:         if (isset($options['artspecs']) === false) {
162:             $options['artspecs'] = array();
163:         }
164: 
165:         if (isset($options['direction']) === false) {
166:             $options['direction'] = 'DESC';
167:         }
168: 
169:         if (isset($options['limit']) === false) {
170:             $options['limit'] = 0;
171:         }
172: 
173:         if (isset($options['offset']) === false) {
174:             $options['offset'] = 0;
175:         }
176: 
177:         $this->_options = $options;
178:     }
179: 
180:     /**
181:      * Executes the article search with the given options.
182:      *
183:      * @throws cDbException
184:      */
185:     public function loadArticles() {
186:         $this->_articles = array();
187: 
188:         $cfg = cRegistry::getConfig();
189:         $db  = cRegistry::getDb();
190: 
191:         $sql = "SELECT startidartlang, idcat
192:                 FROM " . $cfg['tab']['cat_lang'] . "
193:                 WHERE idlang=" . $this->_options['lang'];
194:         if (count($this->_options['categories']) > 0) {
195:             $sql .= " AND idcat IN ('" . implode("','", $this->_options['categories']) . "')";
196:         }
197:         $db->query($sql);
198: 
199:         while ($db->nextRecord()) {
200:             $startId = $db->f('startidartlang');
201:             if ($startId > 0) {
202:                 $this->_startArticles[$db->f('idcat')] = $startId;
203:             }
204:         }
205: 
206:         // This sql-line uses cat_art table with alias c. If no categories found, it writes only "WHERE" into sql-query
207:         $sqlCat = (count($this->_options['categories']) > 0) ? ", " . $cfg['tab']['cat_art'] . " AS c WHERE c.idcat IN ('" . implode("','", $this->_options['categories']) . "') AND b.idart = c.idart AND " : ' WHERE ';
208: 
209:         $sqlArtSpecs = (count($this->_options['artspecs']) > 0) ? " a.artspec IN ('" . implode("','", $this->_options['artspecs']) . "') AND " : '';
210:         $sqlStartArticles = '';
211: 
212:         if (count($this->_startArticles) > 0) {
213:             if ($this->_options['start'] == false) {
214:                 $sqlStartArticles = "a.idartlang NOT IN ('" . implode("','", $this->_startArticles) . "') AND ";
215:             }
216: 
217:             if ($this->_options['startonly'] == true) {
218:                 $sqlStartArticles = "a.idartlang IN ('" . implode("','", $this->_startArticles) . "') AND ";
219:             }
220:         }
221: 
222:         if ($this->_options['startonly'] == true && count($this->_startArticles) == 0) {
223:             return;
224:         }
225: 
226:         $sql = "SELECT DISTINCT a.idartlang FROM " . $cfg['tab']['art_lang'] . " AS a, ";
227:         $sql .= $cfg['tab']['art'] . " AS b";
228:         $sql .= $sqlCat . $sqlStartArticles . $sqlArtSpecs . "b.idclient = '" . $this->_options['client'] . "' AND ";
229:         $sql .= "a.idlang = '" . $this->_options['lang'] . "' AND " . "a.idart = b.idart";
230: 
231:         if ($this->_options['offlineonly'] == true) {
232:             $sql .= " AND a.online = 0";
233:         } elseif ($this->_options['offline'] == false) {
234:             $sql .= " AND a.online = 1";
235:         }
236: 
237:         $sql .= " ORDER BY a." . $this->_options['order'] . " " . $this->_options['direction'];
238: 
239:         if ((int) $this->_options['limit'] > 0) {
240:             $sql .= " LIMIT " . cSecurity::toInteger($this->_options['limit']);
241:         }
242: 
243:         if ((int) $this->_options['offset'] > 0) {
244:             $sql .= " OFFSET " . cSecurity::toInteger($this->_options['offset']);
245:         }
246: 
247:         $db->query($sql);
248: 
249:         while ($db->nextRecord()) {
250:             $artLangId = $db->f('idartlang');
251:             $this->_articles[] = new cApiArticleLanguage($artLangId);
252:         }
253: 
254:         // Execute cec hook
255:         cApiCecHook::execute('Contenido.ArticleCollector.Articles', array(
256:             'idart' => cRegistry::getArticleId(),
257:             'articles' => $this->_articles
258:         ));
259:     }
260: 
261:     /**
262:      * Compatibility method for old ArticleCollection class. Returns the start
263:      * article of a category. Does work only if one category was requested.
264:      *
265:      * @return cApiArticleLanguage
266:      * 
267:      * @throws cBadMethodCallException
268:      */
269:     public function startArticle() {
270:         if (count($this->_startArticles) != 1) {
271:             throw new cBadMethodCallException("Can not load start article due to multiple loaded start articles.");
272:         }
273: 
274:         return new cApiArticleLanguage(current($this->_startArticles));
275:     }
276: 
277:     /**
278:      * Compatibility method for old ArticleCollection class. Returns the next
279:      * article.
280:      *
281:      * @return bool|cApiArticleLanguage
282:      */
283:     public function nextArticle() {
284:         $next = $this->current();
285:         $this->next();
286: 
287:         if ($next instanceof cApiArticleLanguage) {
288:             return $next;
289:         }
290: 
291:         return false;
292:     }
293: 
294:     /**
295:      * Compatibility method for old ArticleCollection. Split the article results
296:      * into pages of a given size.
297:      * Example: Article Collection with 5 articles
298:      * [0] => 250 [1] => 251 [2] => 253 [3] => 254 [4] => 255
299:      * $collection->setResultPerPage(2)
300:      * Would split the results into 3 pages
301:      * [0] => [0] => 250 [1] => 251 [1] => [0] => 253 [1] => 254 [2] => [0] =>
302:      * 255
303:      * A page can be selected with $collection->setPage(int page)
304:      *
305:      * @param int $resPerPage
306:      */
307:     public function setResultPerPage($resPerPage) {
308:         if ($resPerPage > 0) {
309:             if (is_array($this->_articles)) {
310:                 $this->_pages = array_chunk($this->_articles, $resPerPage);
311:             } else {
312:                 $this->_pages = array();
313:             }
314:         }
315:     }
316: 
317:     /**
318:      * Compatibility method for old ArticleCollection. Select a page if the
319:      * results was divided before.
320:      * $collection->setResultPerPage(2); $collection->setPage(1);
321:      * // Iterate through all articles of page two while ($art =
322:      * $collection->nextArticle()) { ... }
323:      *
324:      * @param int $page
325:      *         The page of the article collection
326:      */
327:     public function setPage($page) {
328:         if (array_key_exists($page, $this->_pages)) {
329:             $this->_articles = $this->_pages[$page];
330:         }
331:     }
332:     /**
333:      * Seeks a specific position in the loaded articles.
334:      *
335:      * @param int $position
336:      *         position to load
337:      * 
338:      * @throws cOutOfBoundsException
339:      */
340:     public function seek($position) {
341:         $this->_currentPosition = $position;
342: 
343:         if ($this->valid() === false) {
344:             throw new cOutOfBoundsException("Invalid seek position: " . $position);
345:         }
346:     }
347: 
348:     /**
349:      * Method "rewind" of the implemented iterator.
350:      */
351:     public function rewind() {
352:         $this->_currentPosition = 0;
353:     }
354: 
355:     /**
356:      * Method "current" of the implemented iterator.
357:      *
358:      * @return mixed
359:      */
360:     public function current() {
361:         return $this->_articles[$this->_currentPosition];
362:     }
363: 
364:     /**
365:      * Method "key" of the implemented iterator.
366:      *
367:      * @return int
368:      */
369:     public function key() {
370:         return $this->_currentPosition;
371:     }
372: 
373:     /**
374:      * Method "next" of the implemented iterator.
375:      */
376:     public function next() {
377:         ++$this->_currentPosition;
378:     }
379: 
380:     /**
381:      * Method "valid" of the implemented iterator.
382:      *
383:      * @return bool
384:      */
385:     public function valid() {
386:         return isset($this->_articles[$this->_currentPosition]);
387:     }
388: 
389:     /**
390:      * Method "count" of the implemented Countable interface. Returns the amount
391:      * of all loaded articles.
392:      *
393:      * @return int
394:      */
395:     public function count() {
396:         return count($this->_articles);
397:     }
398: 
399:     /**
400:      * @return array
401:      */
402:     public function getStartArticles()
403:     {
404:         return $this->_startArticles;
405:     }
406: 
407: }
408: 
CMS CONTENIDO 4.10.1 API documentation generated by ApiGen 2.8.0