PageRenderTime 333ms CodeModel.GetById 100ms app.highlight 126ms RepoModel.GetById 75ms app.codeStats 1ms

/lib/WV2/MetaProvider.php

https://bitbucket.org/webvariants/extended-meta-infos
PHP | 1484 lines | 799 code | 287 blank | 398 comment | 99 complexity | 76a937929557df3864e13fe451345767 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2
   3/**
   4 * @defgroup external Externe, öffentliche API
   5 */
   6
   7/**
   8 * Meta-Provider
   9 *
  10 * Diese Klasse stellt die API zum Zugriff auf die erweiterten Metainfos dar.
  11 * Sämtlicher Zugriff auf die Metadaten/-infos sollte von außerhalb dieses
  12 * AddOns *NUR* über diese Methoden erfolgen. Hier kann in keinem Fall Schaden
  13 * angerichtet werden.
  14 *
  15 * Von einigen Methoden gibt es 4fache Ausführungen: Eine für Artikel-Metadaten,
  16 * eine für Kategorien, eine für Medien und eine zusammengefasste für Objekte
  17 * aller Art. Der Methode für Objekte muss zusätzlich der Typ der Metadaten/-infos
  18 * mit übergeben werden. Es wird empfohlen, die spezifischen Methoden direkt
  19 * zu nutzen, da diese einfacher anzuwenden sind (bieten nur die wirklich
  20 * benötigten Parameter).Einzige Ausnahme ist getObjectMetaData, die Mutter aller
  21 * Hilfsmethoden: Da diese eine SQL-Abfrage erwartet ist sie nicht public. Dort
  22 * ist der Anwender demzufolge zum Nutzen der spezifischen Methoden gezwungen.
  23 *
  24 * Alle Methoden, die eine Angabe zum Artikeltyp erlauben, akzeptieren diese
  25 * als String (interner Name) oder als Zahl (ID). Die Umwandlung in das
  26 * benötigte Format erfolgt automatisch, um den Nutzer von der lästigen Arbeit,
  27 * selber getIdForName() aufrufen zu müssen, zu befreien.
  28 *
  29 * @ingroup external
  30 */
  31abstract class WV2_MetaProvider {
  32	/** @name Daten cachen */
  33
  34	/*@{*/
  35
  36	/**
  37	 * Daten für ein bestimmtes Objekt cachen
  38	 *
  39	 * Diese Method ruft für ein bestimmtes Objekt die Metadaten auf Vorrat ab,
  40	 * um nachfolgende Aufrufe zu beschleunigen. Der Cache ist flüchtig und nur
  41	 * für den aktuellen Request gültig.
  42	 *
  43	 * Alle Methoden, die Metadaten abrufen, holen ihre Daten aus dem Cache, wenn
  44	 * sie vorhanden ist. Wenn nicht, legen sie sie immerhin im Anschluss an ihre
  45	 * Arbeit dort ab.
  46	 *
  47	 * Im Regelfall ist es nicht nötig, Daten manuell über diese Methode in den
  48	 * Cache zu laden. Wenn jedoch im Frontend von einem Objekt beispielsweise 20
  49	 * Informationen abgerufen werden sollen, kann es Sinn machen, doch den Cache
  50	 * vorher manuell zu befüllen.
  51	 *
  52	 * Achtung: Der Cache ist für den gesamten Request persistent. Das heißt,
  53	 * dass Änderungen an den Metadaten in der Datenbank nicht dazu führen, dass
  54	 * die Daten hier im Cache ungültig werden. Der MetaProvider wird weiterhin
  55	 * für die Dauer des Requests die alten Daten zurückgeben.
  56	 *
  57	 * @param  mixed $object    das Objekt, für das die Daten geholt werden sollen
  58	 * @param  mixed $article   der Artikel, für den die Daten geholt werden sollen
  59	 * @param  mixed $category  die Kategorie, für die die Daten geholt werden sollen
  60	 * @param  mixed $medium    die Datei, für die die Daten geholt werden sollen
  61	 * @param  int   $clang     die Sprache, für die die Daten geholt werden sollen
  62	 * @param  int   $type      der Objekttyp
  63	 * @return int              die Anzahl der abgerufenen Metadaten (0 auch im Fehlerfalle)
  64	 */
  65	public static function prefetchMetaData($object, $clang = WV_Sally::CLANG_CURRENT, $type = WV2_Metainfoex::TYPE_ARTICLE) {
  66		$objectID  = WV2_Metainfoex::getIDForObject($object, false);
  67		$clang     = WV_Sally::clang($clang);
  68		$type      = (int) $type;
  69		$data      = sly_makeArray(self::getMetaDataForObject($objectID, null, null, $clang, $type));
  70		$ids       = array();
  71		$cache     = sly_Core::cache();
  72		$namespace = 'metainfoex.data';
  73
  74		if ($data === null) {
  75			return 0;
  76		}
  77
  78		foreach ($data as $date) {
  79			$ids[] = $date->getMetaInfoID();
  80			$key   = sly_Cache::generateKey('type', $type, $objectID, $clang, $date->getMetaInfoID());
  81
  82			$cache->set($namespace, $key, array(
  83				'object' => $date,
  84				'name'   => $date->getMetainfoName()
  85			));
  86		}
  87
  88		// Kennzeichnen, dass wir für dieses Objekt definitv alle im Moment verfügbaren Daten geholt haben.
  89		// Dann können andere Methoden davon ausgehen, dass es nicht mehr zu holen gibt, als hier vorliegen.
  90
  91		$key = sly_Cache::generateKey('type', $type, $objectID, $clang);
  92		$cache->set($namespace, $key, $ids);
  93
  94		return count($ids);
  95	}
  96
  97	public static function prefetchArticleMetaData($article, $clang = WV_Sally::CLANG_CURRENT) {
  98		return self::prefetchMetaData(WV2_Metainfoex::getIDForArticle($article), $clang, WV2_Metainfoex::TYPE_ARTICLE);
  99	}
 100
 101	public static function prefetchCategoryMetaData($categoryID, $clang = WV_Sally::CLANG_CURRENT) {
 102		return self::prefetchMetaData(WV2_Metainfoex::getIDForCategory($category), $clang, WV2_Metainfoex::TYPE_ARTICLE);
 103	}
 104
 105	public static function prefetchMediumMetaData($medium, $clang = WV_Sally::CLANG_CURRENT) {
 106		return self::prefetchMetaData(WV2_Metainfoex::getIDForMedium($medium), $clang, WV2_Metainfoex::TYPE_ARTICLE);
 107	}
 108
 109	/*@}*/
 110
 111
 112
 113
 114	/**
 115	 * Artikeltyp ermitteln
 116	 *
 117	 * Diese Methode gibt die ID des Typs eines Artikels zurück.
 118	 *
 119	 * @param  mixed $article  der Artikel
 120	 * @return mixed           der Name des Artikeltyps oder false, falls noch keiner zugewiesen wurde
 121	 */
 122	public static function getArticleTypeName($article = null) {
 123		$typeID = self::getArticleType($article);
 124		return $typeID == -1 ? false : _WV2_ArticleType::getInstance($typeID)->getName();
 125	}
 126
 127	/**
 128	 * Artikeltyp ermitteln
 129	 *
 130	 * Diese Methode gibt die ID des Typs eines Artikels zurück.
 131	 *
 132	 * @param  mixed $article  der Artikel
 133	 * @return int             die ID des Artikeltyps oder -1, falls der Artikel noch keinem Typ zugeordnet wurde
 134	 */
 135	public static function getArticleType($article = null) {
 136		$articleID = $article ? WV2_Metainfoex::getIDForArticle($article) : WV_Sally::getCurrentArticleID();
 137		$cache     = sly_Core::cache();
 138		$namespace = 'metainfoex.atypes';
 139		$cacheKey  = 'idfor_'.$articleID;
 140		$foundID   = $cache->get($namespace, $cacheKey, -1);
 141
 142		if ($foundID != -1) {
 143			return (int) $foundID;
 144		}
 145
 146		$sql  = WV_SQLEx::getInstance();
 147		$type = $sql->safeFetch('type_id', 'wv2_article_type', 'article_id = ?', $articleID);
 148		$type = $type === false ? -1 : (int) $type;
 149
 150		$cache->set($namespace, $cacheKey, $type);
 151		return $type;
 152	}
 153
 154	/**
 155	 * Artikeltyp als Objekt ermitteln
 156	 *
 157	 * Diese Methode gibt ein _WV2_ArticleType-Objekt zurück, anstatt nur der ID.
 158	 *
 159	 * @param  mixed $article    der Artikel
 160	 * @return _WV2_ArticleType  der Artikeltyp oder null, falls der Artikel noch keinem Typ zugeordnet wurde
 161	 */
 162	public static function getArticleTypeAsObject($article) {
 163		$type = self::getArticleType($article);
 164		return $type == -1 ? null : _WV2_ArticleType::getInstance($type);
 165	}
 166
 167	/**
 168	 * Prüft, ob ein Artikel von einem bestimmten Typ ist.
 169	 *
 170	 * @param  mixed $article      der Artikel
 171	 * @param  mixed $articleType  die ID / der Name des Artikeltyps oder null, falls alle
 172	 * @return bool                true oder false
 173	 */
 174	public static function isArticeOfType($articleType, $article = null) {
 175		$article = $article === null ? WV_Sally::getCurrentArticleID() : WV2_Metainfoex::getIDForArticle($article);
 176		return WV2_Metainfoex::getIDForArticleType($articleType, false) == self::getArticleType($article);
 177	}
 178
 179	/**
 180	 * Artikeltyp ermitteln
 181	 *
 182	 * Diese Methode gibt eine Liste aller Artikeltypen als _WV2_ArticleType-Objekte zurück.
 183	 *
 184	 * @param  string $sortby     das Sortierkriterium (kann jedes Attribut der Relation sein)
 185	 * @param  string $direction  die Sortierreihenfolge ("ASC" oder "DESC")
 186	 * @param  string $where      zusätzliches WHERE-Kriterium (Tabelle: sly_wv2_arttypes)
 187	 * @return array              eine Liste von _WV2_ArticleType-Objekten, die passen
 188	 */
 189	public static function getAllArticleTypes($sortby = 'title', $direction = 'ASC', $where = '1') {
 190		$types     = array();
 191		$data      = array();
 192		$namespace = 'metainfoex.types';
 193		$cache     = sly_Core::cache();
 194		$key       = sly_Cache::generateKey('all_by', $sortby, $direction, $where);
 195
 196		if (0 && $cache->exists($namespace, $key)) {
 197			$data = $cache->get($namespace, $key);
 198		}
 199		else {
 200			$sql  = WV_SQLEx::getInstance();
 201			$data = $sql->getArray('SELECT id FROM ~wv2_arttypes WHERE '.$where.' ORDER BY '.$sortby.' '.$direction, array(), '~');
 202			$cache->set($namespace, $key, $data);
 203		}
 204
 205		foreach ($data as $id) {
 206			$types[$id] = _WV2_ArticleType::getInstance($id);
 207		}
 208
 209		return $types;
 210	}
 211
 212	/**
 213	 * (Benötigte) Metainfos ermitteln
 214	 *
 215	 * Diese Methode ermittelt für einen Artikeltyp
 216	 * die dazugehörigen Metainfos. Wird für den
 217	 * Artikeltyp -1 übergeben, so wird ein leeres
 218	 * Array zurückgegeben, da der Typ "kein Typ"
 219	 * keine Metainfos besitzt.
 220	 *
 221	 * @param  mixed $articleType   die ID / der Name des Artikeltyps
 222	 * @return array                eine Liste von _WV2_MetaInfo-Objekten
 223	 */
 224	public static function getMetaInfosForArticleType($articleType) {
 225		$infos     = array();
 226		$data      = array();
 227		$namespace = 'metainfoex.infos';
 228		$cache     = sly_Core::cache();
 229		$key       = 'for_'.WV2_Metainfoex::TYPE_ARTICLE.'_'.WV2_Metainfoex::getIDForArticleType($articleType, false);
 230
 231		if ($cache->exists($namespace, $key)) {
 232			$data = $cache->get($namespace, $key);
 233		}
 234		else {
 235			$sql  = WV_SQLEx::getInstance();
 236			$data = $sql->getArray(
 237				'SELECT ~wv2_metainfo.* FROM ~wv2_metainfo_type, ~wv2_metainfo '.
 238				'WHERE id = metainfo_id AND type_id = ? AND meta_type = ? ORDER BY hidden ASC, position ASC',
 239				array(WV2_Metainfoex::getIDForArticleType($articleType, false), WV2_Metainfoex::TYPE_ARTICLE), '~'
 240			);
 241
 242			$cache->set($namespace, $key, $data);
 243		}
 244
 245		foreach ($data as $id => $row) {
 246			$infos[$id] = _WV2_MetaInfo::getInstance($id, WV2_Metainfoex::TYPE_ARTICLE, array_merge(array('id' => $id), $row));
 247		}
 248
 249		return $infos;
 250	}
 251
 252	/**
 253	 * Artikelanzahl ermitteln
 254	 *
 255	 * Diese Methode ermittelt, wie viele Artikel einem Artikeltyp angehören.
 256	 *
 257	 * @param  mixed $articleType  der Artikeltyp als ID oder Name
 258	 * @return int                 die Anzahl der zugehörigen Artikel
 259	 */
 260	public static function getArticleCountByType($articleType, $onlineOnly = true) {
 261		// Sorgen um clang sind egal, für jeden Artikel existiert hier nur ein Eintrag
 262
 263		$namespace = 'metainfoex.acount';
 264		$cache     = sly_Core::cache();
 265		$typeID    = WV2_Metainfoex::getIDForArticleType($articleType, false);
 266		$key       = 'by_type_'.$typeID;
 267
 268		if ($cache->exists($namespace, $key)) {
 269			$count = $cache->get($namespace, $key);
 270		}
 271		else {
 272			$count = 0;
 273			$sql   = WV_SQLEx::getInstance();
 274
 275			if (!$onlineOnly) {
 276				$count = $sql->count('wv2_article_type', 'type_id = ?', $typeID);
 277			}
 278			else {
 279				$query =
 280					'SELECT COUNT(*) as count FROM ~wv2_article_type at '.
 281					'JOIN ~article a ON (at.article_id = a.id) '.
 282					'WHERE at.type_id = ? AND a.status = 1';
 283
 284				$sql->queryEx($query, $typeID, '~');
 285
 286				$row   = $sql->row();
 287				$count = (int) $row['count'];
 288			}
 289
 290			$cache->set($namespace, $key, $count);
 291		}
 292
 293		return $count;
 294	}
 295
 296	/**
 297	 * Artikelliste ermitteln
 298	 *
 299	 * Diese Methode erzeugt eine Liste von OOArticle-Objekten basierend auf den
 300	 * gegebenen Filterkriterien zurück.
 301	 *
 302	 * Für das Sortierkriterium ($sortby) stehen die Tabellen-Aliase
 303	 *
 304	 *  - at (article_type)
 305	 *  - a (sly_article)
 306	 *
 307	 * bereit.
 308	 *
 309	 * @param  mixed  $articleType  der Artikeltyp als ID oder Name
 310	 * @param  bool   $onlineOnly   wenn true, werden nur online Artikel berücksichtigt
 311	 * @param  string $sortby       das Sortierkriterium (aus der Relation article oder wv2_article_type)
 312	 * @param  string $direction    die Sortierrichtung
 313	 * @param  string $limitClause  eine optionale "LIMIT a,b"-Angabe
 314	 * @param  int    $clang        die gewünschte Sprache
 315	 * @return array                Liste von passenden OOArticle-Objekten
 316	 */
 317	public static function getArticlesByType($articleType, $onlineOnly = true, $sortby = 'updatedate', $direction = 'ASC', $limitClause = '', $clang = WV_Sally::CLANG_CURRENT, $asObjects = true) {
 318		$cache       = sly_Core::cache();
 319		$articleType = WV2_Metainfoex::getIDForArticleType($articleType, false);
 320		$clang       = WV_Sally::clang($clang);
 321		$return      = array();
 322		$data        = array();
 323		$namespace   = 'metainfoex.alist';
 324		$key         = sly_Cache::generateKey('type', $articleType, $clang, $onlineOnly, $sortby, $direction, $limitClause);
 325
 326		if ($cache->exists($namespace, $key)) {
 327			$data = $cache->get($namespace, $key);
 328		}
 329		else {
 330			$sql    = WV_SQLEx::getInstance();
 331			$params = array($articleType);
 332			$query  = 'SELECT article_id, clang FROM ~wv2_article_type at, ~article a WHERE at.article_id = a.id AND type_id = ?';
 333
 334			if ($clang != WV_Sally::CLANG_ALL) {
 335				$params[] = $clang;
 336				$query .= ' AND clang = ?';
 337			}
 338
 339			if ($onlineOnly) {
 340				$query .= ' AND status = 1';
 341			}
 342
 343			$sql->queryEx($query.' ORDER BY '.$sortby.' '.$direction.' '.$limitClause, $params, '~');
 344
 345			foreach ($sql as $row) {
 346				$data[] = array_map('intval', $row);
 347			}
 348
 349			$cache->set($namespace, $key, $data);
 350		}
 351
 352		if (!$asObjects) {
 353			return $data;
 354		}
 355
 356		foreach ($data as $row) {
 357			$return[] = OOArticle::getArticleById($row['article_id'], $row['clang']);
 358		}
 359
 360		return $return;
 361	}
 362
 363	/**
 364	 * Artikelliste ermitteln
 365	 *
 366	 * Diese Methode erzeugt eine Liste von OOArticle-Objekten basierend auf den
 367	 * gegebenen Filterkriterien zurück. Das Sortierkriterium muss eine Spalte in
 368	 * der Tabelle sly_article sein.
 369	 *
 370	 * @param  mixed    $category     die Artikelkategorie
 371	 * @param  boolean  $onlineOnly   wenn true, werden nur online Artikel berücksichtigt (default: true)
 372	 * @param  string   $sortby       das Sortierkriterium (aus der Relation article oder wv2_article_type)
 373	 * @param  string   $direction    die Sortierrichtung
 374	 * @param  string   $limitClause  eine optionale "LIMIT a,b"-Angabe
 375	 * @param  int      $clang        die gewünschte Sprache
 376	 * @return array                  Liste von passenden OOArticle-Objekten
 377	 */
 378	public static function getArticlesByCategory($category, $onlineOnly = true, $sortby = 'updatedate', $direction = 'ASC', $limitClause = '', $clang = WV_Sally::CLANG_CURRENT) {
 379		$cache     = sly_Core::cache();
 380		$category  = WV2_Metainfoex::getIDForCategory($category);
 381		$clang     = WV_Sally::clang($clang);
 382		$return    = array();
 383		$data      = array();
 384		$namespace = 'metainfoex.alist';
 385		$key       = sly_Cache::generateKey('category', $category, $clang, $onlineOnly, $sortby, $direction, $limitClause);
 386
 387		if ($cache->exists($namespace, $key)) {
 388			$data = $cache->get($namespace, $key);
 389		}
 390		else {
 391			$sql   = WV_SQLEx::getInstance();
 392			$data  = array($category);
 393			$query = 'SELECT id,clang FROM ~article WHERE re_id = ?';
 394
 395			if ($clang != WV_Sally::CLANG_ALL) {
 396				$data[] = $clang;
 397				$query .= ' AND clang = ?';
 398			}
 399
 400			if ($onlineOnly) {
 401				$query .= ' AND status = 1';
 402			}
 403
 404			$sql->queryEx($query.'ORDER BY '.$sortby.' '.$direction.' '.$limitClause, $data, '~');
 405
 406			foreach ($sql as $row) {
 407				$data[] = $row;
 408			}
 409
 410			$cache->set($namespace, $key, $data);
 411		}
 412
 413		foreach ($data as $row) {
 414			$return[] = OOArticle::getArticleById($row['id'], $row['clang']);
 415		}
 416
 417		return $return;
 418	}
 419
 420	/** @name Alle verfügbaren Metainfos holen */
 421
 422	/*@{*/
 423
 424	/**
 425	 * Alle verfügbaren Metainfos holen
 426	 *
 427	 * Diese Methode gibt alle vorhandenen Metainfos (nicht die Metadaten!)
 428	 * zurück. Dabei kann ein WHERE-Statement für die wv2_metainfo-Relation
 429	 * sowie Sortierkriterium und -richtung angegeben werden.
 430	 *
 431	 * @param  string $where      das WHERE-Kriterium
 432	 * @param  string $sortby     das Sortierkriterium (kann jedes Attribut der Relation sein)
 433	 * @param  string $direction  die Sortierreihenfolge ("ASC" oder "DESC")
 434	 * @param  int    $type       der Typ (WV2_Metainfoex::TYPE-Konstanten)
 435	 * @return array              eine Liste von _WV2_MetaInfo-Objekten, die passen
 436	 */
 437	protected static function getAllObjectMetaInfos($where = '1', $sortby = 'position', $direction = 'ASC', $type = WV2_Metainfoex::TYPE_ARTICLE) {
 438		$infos     = array();
 439		$data      = array();
 440		$cache     = sly_Core::cache();
 441		$namespace = 'metainfoex.infos';
 442		$key       = sly_Cache::generateKey('for', $type, $where, $sortby, $direction);
 443
 444		if ($cache->exists($namespace, $key)) {
 445			$data = $cache->get($namespace, $key);
 446		}
 447		else {
 448			$sql    = WV_SQLEx::getInstance();
 449			$prefix = WV_SQLEx::getPrefix();
 450			$data   = $sql->getArray('SELECT id FROM '.$prefix.'wv2_metainfo WHERE '.$where.' AND meta_type = '.$type.' ORDER BY '.$sortby.' '.$direction);
 451
 452			$cache->set($namespace, $key, $data);
 453		}
 454
 455		foreach ($data as $id) {
 456			$infos[$id] = _WV2_MetaInfo::getInstance($id, $type);
 457		}
 458
 459		return $infos;
 460	}
 461
 462	public static function getAllArticleMetaInfos($where = '1', $sortby = 'position', $direction = 'ASC') {
 463		return self::getAllObjectMetaInfos($where, $sortby, $direction, WV2_Metainfoex::TYPE_ARTICLE);
 464	}
 465
 466	public static function getAllCategoryMetaInfos($where = '1', $sortby = 'position', $direction = 'ASC') {
 467		return self::getAllObjectMetaInfos($where, $sortby, $direction, WV2_Metainfoex::TYPE_CATEGORY);
 468	}
 469
 470	public static function getAllMediumMetaInfos($where = '1', $sortby = 'position', $direction = 'ASC') {
 471		return self::getAllObjectMetaInfos($where, $sortby, $direction, WV2_Metainfoex::TYPE_MEDIUM);
 472	}
 473
 474	/*@}*/
 475
 476	/** @name Metadaten für ein einzelnes Objekt ermitteln */
 477
 478	/*@{*/
 479
 480	/**
 481	 * Metadaten für ein einzelnes Objekt ermitteln
 482	 *
 483	 * Diese Methode ermittelt für ein bestimmtes Objekt die angelegten
 484	 * Metadaten. Zurückgegeben wird ein Array aus _WV2_MetaData-Objekten. Gibt
 485	 * es nur ein Metadatum, wird dieses direkt (ohne Array) zurückgegeben. Gibt
 486	 * es kein Metadatum, so wird ein MetaData-Objekt mit dem Standardwert
 487	 * zurückgegeben. Ist der Standardwert null, wird in diesem Fall direkt null
 488	 * zurückgegeben.
 489	 *
 490	 * Wenn ein Array zurückgegeben wird, so ist es assoziativ mit den
 491	 * Metainfo-Namen als Schlüsseln.
 492	 *
 493	 * Wenn als als Standardwert etwas anderes als null angegeben wird und der
 494	 * Anwender sicher ist, dass es nur ein Metadatum geben kann (weil er z.B.
 495	 * $metainfoToken angegeben hat), kann man immer direkt getValue() bzw.
 496	 * getKey() auf den Rückgabewert dieser Methode anwenden.
 497	 *
 498	 * @param  int    $object     die ID des Objekts oder ein Objekt eines bestimmten Typs (OOArticle, OOCategory, ...)
 499	 * @param  mixed  $article    der Artikel
 500	 * @param  mixed  $category   die Kategorie
 501	 * @param  mixed  $medium     das Medium
 502	 * @param  mixed  $metainfo   der Name der Metainformation oder null für alle
 503	 * @param  mixed  $default    der Standardwert, falls kein Metadatum gefunden wurde
 504	 * @param  int    $clang      die gewünschte Sprache
 505	 * @param  int    $type       der Typ (WV2_Metainfoex::TYPE-Konstanten)
 506	 * @return array              Liste der Metdaten wie oben beschrieben
 507	 */
 508	protected static function getMetaDataForObject($object, $metainfo = null, $default = null, $clang = WV_Sally::CLANG_CURRENT, $type = WV2_Metainfoex::TYPE_ARTICLE) {
 509		$clang     = WV_Sally::clang($clang);
 510		$type      = (int) $type;
 511		$objectID  = WV2_Metainfoex::getIDForObject($object, false);
 512		$metainfo  = WV2_Metainfoex::getIDForMetainfo($metainfo, $type, true);
 513		$return    = array();
 514		$cache     = sly_Core::cache();
 515		$namespace = 'metainfoex.data';
 516		$key       = sly_Cache::generateKey('type', $type, $objectID, $clang);
 517
 518		// Wurden alle Metadaten angefragt? Haben wir bereits alle Daten für dieses Objekt?
 519
 520		if ($metainfo === null && $cache->exists($namespace, $key)) {
 521			$metainfos = $cache->get($namespace, $key);
 522
 523			// Hat dieses Objekt keine Metadaten?
 524
 525			if (empty($metainfos)) {
 526				return is_null($default) ? null : new _WV2_MetaData($default, null, null, null, $type);
 527			}
 528
 529			// Bei genau einem Metadatum geben wir dieses direkt zurück.
 530
 531			if (count($metainfos) == 1) {
 532				$id   = reset($metainfos);
 533				$date = $cache->get($namespace, $key.'_'.$id);
 534				return $date['object'];
 535			}
 536
 537			// Das Objekt hat mehr als ein Metadatum.
 538
 539			$infos = array();
 540
 541			foreach ($metainfos as $id) {
 542				$date = $cache->get($namespace, $key.'_'.$id);
 543				$infos[$date['name']] = $date['object'];
 544			}
 545
 546			return $infos;
 547		}
 548
 549		// Wurde eine bestimmte Metainfo angefragt?
 550
 551		elseif ($metainfo !== null) {
 552			// Metadatum bereits geholt. Cool!
 553
 554			if ($cache->exists($namespace, $key.'_'.$metainfo)) {
 555				$date = $cache->get($namespace, $key.'_'.$metainfo);
 556				return $date['object'];
 557			}
 558
 559			// Metadatum existiert nicht. Aber vielleicht haben wir schon alle Daten geholt und die Anfrage
 560			// des Anwenders zielt auf eine eh nicht vorhandene? Dann können wir direkt den Standardwert
 561			// zurückgeben, da wir wissen, dass das Metdatum nicht existieren kann.
 562
 563			if ($cache->exists($namespace, $key)) {
 564				return is_null($default) ? null : new _WV2_MetaData($default, null, null, null, $type);
 565			}
 566		}
 567
 568		// Cache-Miss. Mist. Dann eben in die Datenbank...
 569
 570		$ids    = array();
 571		$filter = new WV_Filter_And(new WV2_Filter_MetaType($type), new WV2_Filter_ObjectID($objectID));
 572
 573		if ($metainfo) {
 574			$filter->add(new WV2_Filter_MetainfoID($metainfo));
 575		}
 576
 577		if ($clang != WV_Sally::CLANG_ALL) {
 578			$filter->add(new WV2_Filter_MetaCLang($clang));
 579		}
 580
 581		foreach (self::filterMetaData($filter) as $row) {
 582			$metainfoID = $row['metainfo_id'];
 583
 584			$return[$row['name']] = new _WV2_MetaData($row['value'], $metainfoID, $objectID, $row['clang'], $type);
 585
 586			// Daten cachen
 587
 588			$cache->set($namespace, $key.'_'.$metainfoID, array(
 589				'object' => $return[$row['name']],
 590				'name'   => $row['name']
 591			));
 592
 593			$ids[] = $metainfoID;
 594		}
 595
 596		// Wenn wir alle Metadaten geholt haben, merken wir uns eine Liste der IDs.
 597
 598		if ($metainfo === null) {
 599			$key = sly_Cache::generateKey('type', $type, $objectID, $clang);
 600			$cache->set($namespace, $key, $ids);
 601		}
 602
 603		// Nichts gefunden? Dann Standardwert oder null.
 604
 605		if (empty($return)) {
 606			return is_null($default) ? null : new _WV2_MetaData($default, null, null, null, $type);
 607		}
 608
 609		// dearrayfizieren
 610
 611		return count($return) == 1 ? reset($return) : $return;
 612	}
 613
 614	public static function articleData($metainfo = null, $default = null, $clang = WV_Sally::CLANG_CURRENT, $article = null) {
 615		$article = $article ? WV2_Metainfoex::getIDForArticle($article) : WV_Sally::getCurrentArticle();
 616		return self::getMetaDataForObject($article, $metainfo, $default, $clang, WV2_Metainfoex::TYPE_ARTICLE);
 617	}
 618
 619	public static function categoryData($metainfo = null, $default = null, $clang = WV_Sally::CLANG_CURRENT, $category = null) {
 620		$category = $category ? WV2_Metainfoex::getIDForCategory($category) : WV_Sally::getCurrentCategory();
 621		return self::getMetaDataForObject(WV2_Metainfoex::getIDForCategory($category), $metainfo, $default, $clang, WV2_Metainfoex::TYPE_CATEGORY);
 622	}
 623
 624	public static function mediumData($medium, $metainfo = null, $default = null, $clang = WV_Sally::CLANG_CURRENT) {
 625		return self::getMetaDataForObject(WV2_Metainfoex::getIDForMedium($medium), $metainfo, $default, $clang, WV2_Metainfoex::TYPE_MEDIUM);
 626	}
 627
 628	public static function objectData($object, $type, $metainfo = null, $default = null, $clang = WV_Sally::CLANG_CURRENT) {
 629		return self::getMetaDataForObject(WV2_Metainfoex::getIDForObject($object), $metainfo, $default, $clang, $type);
 630	}
 631
 632	/*@}*/
 633
 634	/** @name Passende Objekte anhand ihrer Metadaten ermitteln */
 635
 636	/*@{*/
 637
 638	/**
 639	 * Passende Objekte anhand ihrer Metadaten ermitteln
 640	 *
 641	 * Gibt ein Array aus OOArticle/OOCategory/OOMedia-Objekten zurück, die
 642	 * einen bestimmten Typ und eine bestimmte MetaInfo haben. Zusätzlich kann
 643	 * angegeben werden, ob die Metainfo einen bestimmten Wert hat ($value) und
 644	 * wie dieser Wert zu verstehen ist (ob er nur enthalten sein muss oder ob
 645	 * der Wert exakt dem Suchbegriff entsprechen muss).
 646	 *
 647	 * Die nötigen Konstanten für den $operator-Parameter sind in der Klasse WV2
 648	 * definiert. Nicht jeder Datentyp unterstützt jeden Filterparameter.
 649	 *
 650	 * Es wird empfohlen, direkt die Methoden getXXXWithMetaData zu verwenden, da
 651	 * diese auch nur die benötigten / erlaubten Parameter enthalten.
 652	 *
 653	 * Als Sortierkriterium muss eine Angabe der Form "tabelle.spalte" angegeben
 654	 * werden. Mögliche Tabellen sind
 655	 *
 656	 *  - article (sly_article)
 657	 *  - metadata (wv2_meta)
 658	 *  - metainfo (wv2_metainfo)
 659	 *  - articletype (nur für Artikel relevant)
 660	 *  - file (nur für Medien relevant)
 661	 *  - medium (Alias für file)
 662	 *
 663	 * Wird eine nicht bekannte Tabelle angegeben, wird die Angabe einfach
 664	 * ignoriert.
 665	 *
 666	 * @param  mixed   $metainfo     der Name der Metainformation
 667	 * @param  boolean $onlineOnly   wenn true, werden nur online Artikel berücksichtigt (default: true)
 668	 * @param  string  $value        der gesuchte Metdaten-Wert oder null, falls egal
 669	 * @param  int     $operator     Anweisungen an den Datentyp, wie die Suche nach dem Wert ($value) zu erfolgen hat
 670	 * @param  string  $sort         ine optionale "ORDER BY"-Klausel (ohne "ORDER BY")
 671	 * @param  mixed   $articleType  die ID / der Name des Artikeltyps oder null, falls alle
 672	 * @param  int     $clang        die Sprache der Artikel / Kategorien / Medien (WV_Sally::CLANG-Konstanten)
 673	 * @param  int     $type         der Typ (WV2_Metainfoex::TYPE-Konstanten)
 674	 * @return array                 eine Liste von passenden Artikeln / Kategorien / Medien
 675	 */
 676	public static function getObjectsWithMetaData($metainfo, $onlineOnly = true, $value = null, $operator = null, $sort = null, $articleType = null, $clang = WV_Sally::CLANG_CURRENT, $type = WV2_Metainfoex::TYPE_ARTICLE) {
 677		$clang       = WV_Sally::clang($clang);
 678		$metainfo    = WV2_Metainfoex::getIDForMetainfo($metainfo, $type, false);
 679		$articleType = WV2_Metainfoex::getIDForArticleType($articleType, true);
 680
 681		// Prüfen, ob die Ergebnisse schon im Cache liegen
 682
 683		$return    = array();
 684		$cache     = sly_Core::cache();
 685		$namespace = 'metainfoex.objects';
 686		$cacheKey  = sly_Cache::generateKey('metainfo', $metainfo, $onlineOnly, $value, $operator, $sort, $articleType, $clang, $type);
 687		$data      = $cache->get($namespace, $cacheKey, false);
 688
 689		if ($data === false) {
 690			//////////////////////////////////////////////////////////////////////////
 691			// Objekte finden, die die gesuchte Metainformation besitzen
 692			// Ob der gesuchte Wert enthalten ist, prüfen später die Datentypen
 693			// selbstständig.
 694
 695			$sortTable  = strpos($sort, '.') === false ? ''    : substr($sort, 0, strpos($sort, '.'));
 696			$sortColumn = strpos($sort, '.') === false ? $sort : substr($sort, strpos($sort, '.') + 1);
 697
 698			$params = array($metainfo);
 699
 700			switch ($type) {
 701				case WV2_Metainfoex::TYPE_ARTICLE:
 702
 703					switch ($sortTable) {
 704						case 'metadata':    $sortTable = 'm';    break;
 705						case 'metainfo':    $sortTable = 'mi';   break;
 706						case 'articletype': $sortTable = 'art';  break;
 707						case 'article':     $sortTable = 'aart'; break;
 708						default:            $sortTable = '';
 709					}
 710
 711					$query =
 712						'SELECT m.metainfo_id, m.object_id, m.clang, m.value '.
 713						'FROM ~wv2_meta m '.
 714						'LEFT JOIN ~wv2_metainfo mi ON m.metainfo_id = mi.id '.
 715						'LEFT JOIN ~wv2_article_type art ON art.article_id = m.object_id '.
 716						'LEFT JOIN ~article aart ON aart.id = m.object_id AND aart.clang = m.clang '.
 717						'WHERE mi.id = ?';
 718
 719					if ($articleType != null) {
 720						$query .= ' AND type_id = ?';
 721						$params[] = $articleType;
 722					}
 723
 724					if ($onlineOnly) {
 725						$query .= ' AND aart.status = 1';
 726					}
 727
 728					break;
 729
 730				case WV2_Metainfoex::TYPE_CATEGORY:
 731
 732					switch ($sortTable) {
 733						case 'metadata': $sortTable = 'm';    break;
 734						case 'metainfo': $sortTable = 'mi';   break;
 735						case 'article':  $sortTable = 'aart'; break;
 736						default:         $sortTable = '';
 737					}
 738
 739					$query =
 740						'SELECT m.metainfo_id, m.object_id, m.clang, m.value '.
 741						'FROM ~wv2_meta m '.
 742						'LEFT JOIN ~wv2_metainfo mi ON m.metainfo_id = mi.id '.
 743						'LEFT JOIN ~article aart ON aart.id = m.object_id AND aart.clang = m.clang '.
 744						'WHERE mi.id = ?';
 745
 746					if ($onlineOnly) {
 747						$query .= ' AND aart.status = 1';
 748					}
 749
 750					break;
 751
 752				case WV2_Metainfoex::TYPE_MEDIUM:
 753
 754					switch ($sortTable) {
 755						case 'metadata': $sortTable = 'm';  break;
 756						case 'metainfo': $sortTable = 'mi'; break;
 757						case 'medium':
 758						case 'file':     $sortTable = 'f';  break;
 759						default:         $sortTable = '';
 760					}
 761
 762					$column = class_exists('sly_I18N') ? 'id' : 'file_id'; // 'id' as of Sally 0.3
 763					$query  =
 764						'SELECT m.metainfo_id, m.object_id, m.clang, m.value '.
 765						'FROM ~wv2_meta m '.
 766						'LEFT JOIN ~wv2_metainfo mi ON m.metainfo_id = m.id '.
 767						'LEFT JOIN ~file f ON f.'.$column.' = m.object_id '.
 768						'WHERE mi.id = ?';
 769
 770					break;
 771
 772				default:
 773
 774					trigger_error('Unrecognized type ID '.$type.' given for getObjectsWithMetaData()', E_USER_ERROR);
 775			}
 776
 777			// Allgemeine Parameter hinzufügen
 778
 779			if ($clang != WV_Sally::CLANG_ALL) {
 780				$query   .= ' AND m.clang = ?';
 781				$params[] = $clang;
 782			}
 783
 784			if ($sortTable) {
 785				$query .= ' ORDER BY '.$sortTable.'.'.$sortColumn;
 786			}
 787
 788			$sql = WV_SQLEx::getClone();
 789			$sql->queryEx($query, $params, '~');
 790
 791			// Nichts gefunden? Und tschüss!
 792
 793			if ($sql->rows() == 0) {
 794				$sql = null;
 795				$cache->set($namespace, $cacheKey, array());
 796				return array();
 797			}
 798
 799			// Datentyp ermitteln
 800
 801			$datatype = _WV2_MetaInfo::getDatatypeWithParams($metainfo, $type);
 802			$params   = $datatype['params'];
 803			$data     = array();
 804
 805			// Gefundene Daten durchgehen
 806
 807			foreach ($sql as $row) {
 808				if ($value === null) {
 809					$obj = WV2_Metainfoex::getObject($row['object_id'], $row['clang'], $type);
 810
 811					if ($obj) {
 812						$data[] = array('object_id' => $row['object_id'], 'clang' => $row['clang']);
 813					}
 814				}
 815				else {
 816					$contained = WV_Datatype::call(
 817						$datatype['datatype'], 'isValueContained',
 818						array($value, $row['value'], $params, $operator)
 819					);
 820
 821					if ($contained) {
 822						$obj = WV2_Metainfoex::getObject($row['object_id'], $row['clang'], $type);
 823
 824						if ($obj) {
 825							$data[] = array('object_id' => $row['object_id'], 'clang' => $row['clang']);
 826						}
 827					}
 828				}
 829			}
 830
 831			$sql = null;
 832			$cache->set($namespace, $cacheKey, $data);
 833		}
 834
 835		foreach ($data as $date) {
 836			$obj = WV2_Metainfoex::getObject($date['object_id'], $date['clang'], $type);
 837			if ($obj) $return[] = $obj;
 838		}
 839
 840		return $return;
 841	}
 842
 843	public static function getArticlesWithMetaData($metainfo, $onlineOnly = true, $value = null, $operator = null, $sort = null, $articleType = null, $clang = WV_Sally::CLANG_CURRENT) {
 844		return self::getObjectsWithMetaData($metainfo, $onlineOnly, $value, $operator, $sort, $articleType, $clang, WV2_Metainfoex::TYPE_ARTICLE);
 845	}
 846
 847	public static function getCategoriesWithMetaData($metainfo, $onlineOnly = true, $value = null, $operator = null, $sort = null, $clang = WV_Sally::CLANG_CURRENT) {
 848		return self::getObjectsWithMetaData($metainfo, $onlineOnly, $value, $operator, $sort, null, $clang, WV2_Metainfoex::TYPE_CATEGORY);
 849	}
 850
 851	public static function getMediaWithMetaData($metainfo, $value = null, $operator = null, $sort = null) {
 852		return self::getObjectsWithMetaData($metainfo, true, $value, $operator, $sort, null, WV_Sally::CLANG_CURRENT, WV2_Metainfoex::TYPE_MEDIUM);
 853	}
 854
 855	/*@}*/
 856
 857	/** @name Werte einer Metainfo erfahren */
 858
 859	/*@{*/
 860
 861	/**
 862	 * Werte einer Metainfo erfahren
 863	 *
 864	 * Diese Methode ermittelt alle möglichen Werte, die eine Metainfo annehmen
 865	 * kann bzw. angenommen hat. Bei Strings macht nur die Suche nach
 866	 * angenommenen Werten Sinn, bei SELECTs auch die Suche nach den möglichen
 867	 * Werten.
 868	 *
 869	 * @param  mixed  $metainfo         die Metainfo
 870	 * @param  bool   $getOnlyExisting  wenn true, werden nur die Werte zurückgegeben, die eine Metainfo auch wirklich angenommen hat
 871	 * @param  int    $type             der Typ (WV2_Metainfoex::TYPE-Konstanten)
 872	 * @return array                    eine Liste von Alternativen
 873	 */
 874	protected static function getObjectMetaInfoValueSet($metainfo, $getOnlyExisting = false, $clang = WV_Sally::CLANG_CURRENT, $type = WV2_Metainfoex::TYPE_ARTICLE) {
 875		$clang    = WV_Sally::clang($clang);
 876		$metainfo = WV2_Metainfoex::getIDForMetainfo($metainfo, $type, false);
 877		$data     = _WV2_MetaInfo::getDatatypeWithParams($metainfo, $type);
 878
 879		if (!$data) {
 880			return array();
 881		}
 882
 883		// Da PHP keine Arrays zulässt, bei denen die Keys zwar
 884		// Strings, aber Zahlen sind ("8" wird immer zu 8 konvertiert),
 885		// muss der Datentyp explizit angeben, ob seine Liste assoziativ
 886		// oder normal zu behandeln ist.
 887
 888		$sql        = WV_SQLEx::getInstance();
 889		$datalist   = array();
 890		$isAssoc    = WV_Datatype::call($data['datatype'], 'usesAssociativeResults', array());
 891		$cache      = sly_Core::cache();
 892		$namespace  = 'metainfoex.valuesets';
 893		$cacheKey   = sly_Cache::generateKey('metainfo', $metainfo, $getOnlyExisting, $clang, $type);
 894		$cachedData = $cache->get($namespace, $cacheKey);
 895
 896		if (!empty($cachedData)) {
 897			return $cachedData;
 898		}
 899
 900		if ($getOnlyExisting) {
 901			$records = $sql->getArray('SELECT DISTINCT value FROM ~wv2_meta WHERE metainfo_id = ? AND clang = ?', array($metainfo, $clang), '~');
 902
 903			foreach ($records as $value) {
 904				$value = WV_Datatype::call($data['datatype'], 'deserializeValue', array($value, $data['params']));
 905
 906				$datalist = $isAssoc ? wv_merge($datalist, $value) : array_merge($datalist, wv_makeArray($value));
 907			}
 908
 909			$records  = null;
 910			$datalist = array_unique($datalist);
 911		}
 912		else {
 913			$datalist = WV_Datatype::call($data['datatype'], 'extractValuesFromParams', $data['params']);
 914		}
 915
 916		$cache->set($namespace, $cacheKey, $datalist);
 917		return $datalist;
 918	}
 919
 920	public static function getArticleMetaInfoValueSet($metainfo, $getOnlyExisting = false, $clang = WV_Sally::CLANG_CURRENT) {
 921		return self::getObjectMetaInfoValueSet($metainfo, $getOnlyExisting, $clang, WV2_Metainfoex::TYPE_ARTICLE);
 922	}
 923
 924	public static function getCategoryMetaInfoValueSet($metainfo, $getOnlyExisting = false, $clang = WV_Sally::CLANG_CURRENT) {
 925		return self::getObjectMetaInfoValueSet($metainfo, $getOnlyExisting, $clang, WV2_Metainfoex::TYPE_CATEGORY);
 926	}
 927
 928	public static function getMediumMetaInfoValueSet($metainfo, $getOnlyExisting = false, $clang = WV_Sally::CLANG_CURRENT) {
 929		return self::getObjectMetaInfoValueSet($metainfo, $getOnlyExisting, $clang, WV2_Metainfoex::TYPE_MEDIUM);
 930	}
 931
 932	/*@}*/
 933
 934	/** @name Prüfen, ob Wert vorhanden ist */
 935
 936	/*@{*/
 937
 938	/**
 939	 * Prüfen, ob Wert vorhanden ist
 940	 *
 941	 * Diese Methode prüft, ob ein bstimmtes Objekt ein bestimmtes Metadatum
 942	 * besitzt.
 943	 *
 944	 * @param  mixed  $object    das Objekt
 945	 * @param  mixed  $article   der Artikel
 946	 * @param  mixed  $category  die Kategorie
 947	 * @param  mixed  $medium    das Medium
 948	 * @param  mixed  $metainfo  die Metainfo
 949	 * @param  mixed  $value     der gesuchte Wert
 950	 * @param  int    $clang     die Sprache des Objekts
 951	 * @param  int    $type      der Typ des Objekts
 952	 * @return boolean           true, wenn der Artikel die gesuchte Information bestitzt, sonst false
 953	 */
 954	protected static function hasObjectValue($object, $metainfo, $value, $clang = WV_Sally::CLANG_CURRENT, $type = WV2_Metainfoex::TYPE_ARTICLE) {
 955		$metadata = self::getMetaDataForObject($object, $metainfo, null, $clang, $type);
 956		if (!$metadata) return false;
 957
 958		$v = $metadata->getValue();
 959
 960		if (!is_array($v)) return $value == $v;
 961		return in_array($value, array_keys($v)) || in_array($value, array_values($v));
 962	}
 963
 964	public static function hasArticleValue($metainfo, $value, $clang = WV_Sally::CLANG_CURRENT, $article) {
 965		return self::hasObjectValue(WV2_Metainfoex::getIDForArticle($article), $metainfo, $value, $clang, WV2_Metainfoex::TYPE_ARTICLE);
 966	}
 967
 968	public static function hasCategoryValue($metainfo, $value, $clang = WV_Sally::CLANG_CURRENT, $category) {
 969		return self::hasObjectValue(WV2_Metainfoex::getIDForCategory($category), $metainfo, $value, $clang, WV2_Metainfoex::TYPE_CATEGORY);
 970	}
 971
 972	public static function hasMediumValue($medium, $metainfo, $value, $clang = WV_Sally::CLANG_CURRENT) {
 973		return self::hasObjectValue(WV2_Metainfoex::getIDForMedium($medium), $metainfo, $value, $clang, WV2_Metainfoex::TYPE_MEDIUM);
 974	}
 975
 976	/*@}*/
 977
 978	/** @name Metadaten für alle Objekte ermitteln */
 979
 980	/*@{*/
 981
 982	/**
 983	 * Metadaten für alle Objekte ermitteln
 984	 *
 985	 * Diese Methode liefert NICHT die Metadaten eines einzelnes Objekt zurück,
 986	 * sondern die Metadaten aller Objekte, die die gewählte Metainformation
 987	 * besitzen. Daher kann man ihr auch nicht die ID eines Objekts übergeben.
 988	 * Sie dient primär als Hilfsmethode für getXXXValueSet().
 989	 *
 990	 * @param  mixed      $metainfo       die Metainfo
 991	 * @param  int|string $articleType    die ID / der Name des gesuchten Artikeltyps oder null für keine Angabe
 992	 * @param  int        $clang          die gewünschte Sprache
 993	 * @param  int        $type           der Typ des Objekts
 994	 * @return array                      Liste von _WV2_MetaData-Objekten
 995	 */
 996	public static function getObjectMetaDataForToken($metainfo = null, $clang = WV_Sally::CLANG_CURRENT, $type = WV2_Metainfoex::TYPE_ARTICLE) {
 997		switch ($type) {
 998			case WV2_Metainfoex::TYPE_ARTICLE:  return self::getArticleMetaDataForToken($metainfo, null, $clang);
 999			case WV2_Metainfoex::TYPE_CATEGORY: return self::getCategoryMetaDataForToken($metainfo, $clang);
1000			case WV2_Metainfoex::TYPE_MEDIUM:   return self::getMediumMetaDataForToken($metainfo, $clang);
1001		}
1002	}
1003
1004	public static function getArticleMetaDataForToken($metainfo = null, $articleType = null, $clang = WV_Sally::CLANG_CURRENT) {
1005		$metainfo        = WV2_Metainfoex::getIDForMetainfo($metainfo, WV2_Metainfoex::TYPE_ARTICLE, true);
1006		$articleType     = WV2_Metainfoex::getIDForArticleType($articleType, true);
1007		$params['clang'] = (int) $clang;
1008
1009		if ($metainfo)    $params['id']     = $metainfo;
1010		if ($articleType) $params['typeID'] = $articleType;
1011
1012		return self::getArticleMetaData($params);
1013	}
1014
1015	public static function getCategoryMetaDataForToken($metainfo = null, $clang = WV_Sally::CLANG_CURRENT) {
1016		$metainfo        = WV2_Metainfoex::getIDForMetainfo($metainfo, WV2_Metainfoex::TYPE_CATEGORY, true);
1017		$params['clang'] = (int) $clang;
1018
1019		if ($metainfo) {
1020			$params['id'] = $metainfo;
1021		}
1022
1023		return self::getCategoryMetaData($params);
1024	}
1025
1026	public static function getMediumMetaDataForToken($metainfo = null, $clang = WV_Sally::CLANG_CURRENT) {
1027		$metainfo        = WV2_Metainfoex::getIDForMetainfo($metainfo, WV2_Metainfoex::TYPE_MEDIUM, true);
1028		$params['clang'] = (int) $clang;
1029
1030		if ($metainfo) {
1031			$params['id'] = $metainfo;
1032		}
1033
1034		return self::getMediumMetaData($params);
1035	}
1036
1037	/*@}*/
1038
1039	/** @name Metadaten ermitteln */
1040
1041	/*@{*/
1042
1043	/**
1044	 * Metadaten ermitteln
1045	 *
1046	 * Gibt eine Liste von Metadaten zurück. Sie dient als Basismethode zur
1047	 * Abfrage von Metdaten von Artikeln und bietet verschiedene Parameter zur
1048	 * Selektion, Gruppierung oder Sortierung. Die anderen MetaData-Methoden
1049	 * sind quasi Shortcuts für häufig benutzte "Queries".
1050	 *
1051	 * Im $params-Array werden folgende Elemente in der folgenden Reihenfolge
1052	 * abgearbeitet:
1053	 *
1054	 * - 'articleID' => int | array
1055	 *   (wenn gesetzt, werden nur die Metadaten für einen Artikel / eine Menge
1056	 *   von Artikeln ermittelt)
1057	 * - 'name' => string | array
1058	 *   (wenn gesetzt, werden nur die Metadaten für eine bestimmte Metainfo
1059	 *   geholt (kann als Alternative zu 'id' dienen))
1060	 * - 'id'  => int | array
1061	 *   (wenn gesetzt, werden nur die Metadaten für eine bestimmte Metainfo
1062	 *   geholt (kann als Alternative zu 'name' dienen))
1063	 * - 'categoryID' => int | array
1064	 *   (wenn gesetzt, werden nur Artikel einer bestimmten Kategorie / von
1065	 *   bestimmten Kategorien ermittelt)
1066	 * - 'typeID' => int | string | array
1067	 *   (wenn gesetzt, werden die ermittelten Artikel nochmals nach ihrem Typ /
1068	 *   ihren Typen gefiltert)
1069	 * - 'orderby' => string
1070	 *   (kann jedes Attribut aus den Relationen article, wv2_article_meta und
1071	 *   wv2_metainfo sein; Standard ist "id")
1072	 * - 'direction' => ASC | DESC
1073	 *   (die Sortierreihenfolge als String; Standard ist ASC)
1074	 *
1075	 * Die Parameter in $params können auch als ein JSON-kodierter String
1076	 * angegeben werden ("{articleID:5}").
1077	 *
1078	 * Als Rückgabe generiert die Methode ein Array aus _WV2_MetaData-Objekten.
1079	 *
1080	 * @param  array $params  die Suchparameter
1081	 * @return array          die Liste der passenden Metadaten
1082	 */
1083	protected static function getObjectMetaData($params, $type) {
1084		$query     = '';
1085		$cache     = sly_Core::cache();
1086		$namespace = 'metainfoex.data';
1087		$cacheKey  = sly_Cache::generateKey('params', $params, $type);
1088		$data      = $cache->get($namespace, $cacheKey);
1089
1090		if (!empty($data)) {
1091			$result = array();
1092
1093			foreach ($data as $record) {
1094				$result[] = new _WV2_MetaData($record['value'], $record['metainfo_id'], $record['object_id'], $record['clang'], $type);
1095			}
1096
1097			return $result;
1098		}
1099
1100		if (!is_array($params)) {
1101			$params = json_decode($params, true);
1102		}
1103
1104		switch ($type) {
1105			case WV2_Metainfoex::TYPE_ARTICLE:
1106				$query =
1107					'SELECT m.* '.
1108					'FROM      ~wv2_meta         m '.
1109					'LEFT JOIN ~wv2_metainfo     infos ON m.metainfo_id = infos.id '.
1110					'LEFT JOIN ~wv2_article_type art   ON m.object_id   = art.article_id '.
1111					'LEFT JOIN ~article          a     ON m.object_id   = a.id AND m.clang = a.clang '.
1112					'WHERE %where% 1';
1113				break;
1114
1115			case WV2_Metainfoex::TYPE_CATEGORY:
1116			case WV2_Metainfoex::TYPE_MEDIUM:
1117				$query =
1118					'SELECT m.* '.
1119					'FROM      ~wv2_meta     m '.
1120					'LEFT JOIN ~wv2_metainfo infos ON m.metainfo_id = infos.id '.
1121					'LEFT JOIN ~article      a     ON m.object_id   = a.id AND m.clang = a.clang '.
1122					'WHERE %where% 1';
1123				break;
1124		}
1125
1126		// Parameter auspacken. extract() wäre uns zu unsicher, daher lieber
1127		// Stück für Stück von Hand.
1128
1129		$articleID  = sly_makeArray(isset($params['articleID'])  ? $params['articleID']  : null);
1130		$categoryID = sly_makeArray(isset($params['categoryID']) ? $params['categoryID'] : null);
1131		$mediumID   = sly_makeArray(isset($params['mediumID'])   ? $params['mediumID']   : null);
1132		$clang      = sly_makeArray(isset($params['clang'])      ? $params['clang']      : null);
1133		$typeID     = sly_makeArray(isset($params['typeID'])     ? $params['typeID']     : null);
1134		$name       = sly_makeArray(isset($params['name'])       ? $params['name']       : null);
1135		$id         = sly_makeArray(isset($params['id'])         ? $params['id']         : null);
1136
1137		// Parameter vorbereiten und entschärfen
1138
1139		$articleID  = array_map('intval', $articleID);
1140		$categoryID = array_map('intval', $categoryID);
1141		$mediumID   = array_map('intval', $mediumID);
1142		$typeID     = array_map('intval', $typeID);
1143		$clang      = array_map('intval', $clang);
1144		$id         = array_map('intval', $id);
1145
1146		foreach ($name as $metainfoName) {
1147			$id[] = WV2_Metainfoex::getIDForMetainfo($metainfoName, $type);
1148		}
1149
1150		// Minimieren
1151
1152		$articleID  = array_unique($articleID);
1153		$categoryID = array_unique($categoryID);
1154		$mediumID   = array_unique($mediumID);
1155		$typeID     = array_unique($typeID);
1156		$clang      = array_unique($clang);
1157		$id         = array_unique($id);
1158
1159		// Sprach-Konstanten ersetzen
1160
1161		$clang = wv_arrayReplace($clang, WV_Sally::CLANG_CURRENT, WV_Sally::clang());
1162
1163		if (in_array(WV_Sally::CLANG_ALL, $clang)) {
1164			$clang = array();
1165		}
1166
1167		// In Query einsetzen
1168
1169		if (!empty($articleID)) $query = str_replace('%where%', 'object_id IN ('.implode(',', $articleID).') AND %where%', $query);
1170		if (!empty($mediumID))  $query = str_replace('%where%', 'object_id IN ('.implode(',', $mediumID).') AND %where%',  $query);
1171		if (!empty($typeID))    $query = str_replace('%where%', 'type_id IN ('.implode(',', $typeID).') AND %where%',      $query);
1172		if (!empty($clang))     $query = str_replace('%where%', 'm.clang IN ('.implode(',', $clang).') AND %where%',       $query);
1173		if (!empty($id))        $query = str_replace('%where%', 'infos.id IN ('.implode(',', $id).') AND %where%',         $query);
1174
1175		// Die Angabe der Kategorie ist mehrdeutig. Ist sie die einzige Angabe,
1176		// ist die ID der Metadaten (object_id) für Kategorie-Metadaten gemeint.
1177		// Ist jedoch auch $articleID gesetzt, so ist sie eine zusätzliche
1178		// Einschränkung für Artikel-Metadaten. Die beiden public-Methoden kümmern
1179		// sich bereits darum, nur die gewünschten Parameter durchzulassen.
1180
1181		$column = 'object_id';
1182
1183		if (isset($params['articleID'])) {
1184			$column = 're_id';
1185		}
1186
1187		if (!empty($categoryID)) {
1188			$query = str_replace('%where%', $column.' IN ('.implode(',', $categoryID).') AND %where%', $query);
1189		}
1190
1191		// Query ist (fast) fertig.
1192
1193		$orderby   = isset($params['orderby'])   ? $params['orderby']   : 'a.id';
1194		$direction = isset($params['direction']) ? $params['direction'] : 'ASC';
1195		$query     = str_replace(array('~', '%where%'), array(WV_SQLEx::getPrefix(), ''), $query);
1196		$query    .= ' ORDER BY '.$orderby.' '.$direction;
1197		$result    = array();
1198		$sql       = WV_SQLEx::getClone();
1199		$cacheData = array();
1200
1201		$sql->queryEx($query, array(), '');
1202
1203		foreach ($sql as $row) {
1204			$result[] = new _WV2_MetaData($row['value'], (int) $row['metainfo_id'], (int) $row['object_id'], (int) $row['clang'], $type);
1205
1206			$cacheData[] = array(
1207				'value'       => $row['value'],
1208				'metainfo_id' => (int) $row['metainfo_id'],
1209				'object_id'   => (int) $row['object_id'],
1210				'clang'       => (int) $row['clang']
1211			);
1212		}
1213
1214		$cache->set($namespace, $cacheKey, $cacheData);
1215		return $result;
1216	}
1217
1218	public static function getArticleMetaData($params = null) {
1219		return self::getObjectMetaData($params, WV2_Metainfoex::TYPE_ARTICLE);
1220	}
1221
1222	public static function getCategoryMetaData($params = null) {
1223		if (is_array($params) && isset($params['articleID'])) unset($params['articleID']);
1224		return self::getObjectMetaData($params, WV2_Metainfoex::TYPE_CATEGORY);
1225	}
1226
1227	public static function getMediumMetaData($params = null) {
1228		return self::getObjectMetaData($params, WV2_Metainfoex::TYPE_MEDIUM);
1229	}
1230
1231	/*@}*/
1232
1233	public static function filterArticles(WV_IFilter $filter, $sortby = 'article.prior', $direction = 'ASC') {
1234		$cache     = sly_Core::cache();
1235		$namespace = 'metainfoex.filter.articles';
1236		$cacheKey  = sly_Cache::generateKey('filter', $filter, $sortby, $direction);
1237		$data      = $cache->get($namespace, $cacheKey);
1238
1239		if (!empty($data)) {
1240			$articles = array();
1241
1242			foreach ($data as $record) {
1243				$articles[] = OOArticle::getArticleById($record['id'], $record['clang']);
1244			}
1245
1246			return $articles;
1247		}
1248
1249		$filter = new WV_Filter_And($filter, new WV_Filter_IsArticle());
1250		$tables = array('article');
1251		$tables = array_unique(array_merge($tables, $filter->getRequiredTables()));
1252
1253		// JOIN-Bedingungen
1254
1255		$connectors = array(
1256			'wv2_arttypes'     => '1',
1257			'wv2_article_type' => '~wv2_article_type.article_id = ~article.id AND ~wv2_arttypes.id = ~wv2_article_type.type_id',
1258			'wv2_meta'         => '~wv2_meta.object_id = ~article.id AND ~wv2_meta.clang = ~article.clang AND ~wv2_meta.meta_type = '.WV2_Metainfoex::TYPE_ARTICLE,
1259			'wv2_metainfo'     => '~wv2_meta.metainfo_id = ~wv2_metainfo.id'
1260		);
1261
1262		// Query zusammensetzen
1263
1264		$prefix          = WV_SQLEx::getPrefix();
1265		$columnsToSelect = array($prefix.'article.id', $prefix.'article.clang');
1266
1267		if (in_array('getExtraColumns', get_class_methods($filter))) {
1268			$columnsToSelect = array_merge($columnsToSelect, $filter->getExtraColumns($tables));
1269		}
1270
1271		$cacheData = array();
1272		$sql       = WV_SQLEx::getInstance();
1273		$articles  = array();
1274
1275		if (strpos($sortby, '.') !== false) {
1276			$sortby = $prefix.$sortby;
1277		}
1278
1279		$sql->queryEx(
1280			'SELECT '.implode(', ', $columnsToSelect).' '.
1281			'FROM '.self::constructFilterQuery($tables, $connectors, $filter, 'article').' '.
1282			'ORDER BY '.$sortby.' '.$direction
1283		);
1284
1285		foreach ($sql as $row) {
1286			$articles[]  = OOArticle::getArticleById($row['id'], $row['clang']);
1287			$cacheData[] = $row;
1288		}
1289
1290		$cache->set($namespace, $cacheKey, $cacheData);
1291		return $articles;
1292	}
1293
1294	public static function filterCategories(WV_IFilter $filter, $sortby = 'article.prior', $direction = 'ASC') {
1295		$cache     = sly_Core::cache();
1296		$namespace = 'metainfoex.filter.categories';
1297		$cacheKey  = sly_Cache::generateKey('filter', $filter, $sortby, $direction);
1298		$data      = $cache->get($namespace, $cacheKey);
1299
1300		if (!empty($data)) {
1301			$categories = array();
1302
1303			foreach ($data as $record) {
1304				$categories[] = OOCategory::getCategoryById($record['id'], $record['clang']);
1305			}
1306
1307			return $categories;
1308		}
1309
1310		$filter = new WV_Filter_And($filter, new WV_Filter_IsCategory());
1311		$tables = array('article');
1312		$tables = array_unique(array_merge($tables, $filter->getRequiredTables()));
1313
1314		// JOIN-Bedingungen
1315
1316		$connectors = array(
1317			'wv2_meta'     => '~wv2_meta.object_id = ~article.id AND ~wv2_meta.meta_type = '.WV2_Metainfoex::TYPE_CATEGORY,
1318			'wv2_metainfo' => '~wv2_meta.metainfo_id = ~wv2_metainfo.id'
1319		);
1320
1321		// Query zusammensetzen
1322
1323		$prefix          = WV_SQLEx::getPrefix();
1324		$columnsToSelect = array($prefix.'article.id', $prefix.'article.clang');
1325
1326		if (in_array('getExtraColumns', get_class_methods($filter))) {
1327			$columnsToSelect = array_merge($columnsToSelect, $filter->getExtraColumns($tables));
1328		}
1329
1330		$sql        = WV_SQLEx::getInstance();
1331		$categories = array();
1332		$cacheData  = array();
1333
1334		if (strpos($sortby, '.') !== false) {
1335			$sortby = $prefix.$sortby;
1336		}
1337
1338		$sql->queryEx(
1339			'SELECT '.implode(', ', $columnsToSelect).' '.
1340			'FROM '.self::constructFilterQuery($tables, $connectors, $filter, 'article').' '.
1341			'ORDER BY '.$sortby.' '.$direction
1342		);
1343
1344		foreach ($sql as $row) {
1345			$categories[] = OOCategory::getCategoryById($row['id'], $row['clang']);
1346			$cacheData[]  = $row;
1347		}
1348
1349		$cache->set($namespace, $cacheKey, $cacheData);
1350		return $categories;
1351	}
1352
1353	public static function filterMedia(WV_IFilter $filter, $sortby = 'file.id', $direction = 'ASC') {
1354		$cache     = sly_Core::cache();
1355		$namespace = 'metainfoex.filter.media';
1356		$cacheKey  = sly_Cache::generateKey('filter', $filter, $sortby, $direction);
1357		$data      = $cache->get($namespace, $cacheKey);
1358
1359		if (!empty($data)) {
1360			$media = array();
1361
1362			foreach ($data as $record) {
1363				$media[] = OOMedia::getMediaById($record);
1364			}
1365
1366			return $media;
1367		}
1368
1369		$tables = array('f…

Large files files are truncated, but you can click here to view the full file