PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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