com.lokorin.lokorin.lib
[ class tree: com.lokorin.lokorin.lib ] [ index: com.lokorin.lokorin.lib ] [ all elements ]

Source for file lib_mplf_archive.php

Documentation is available at lib_mplf_archive.php

  1. <?php
  2. /*
  3. * Lokorin.com
  4. * Copyright 2004-2006
  5. * Licensed under the GNU LGPL. See COPYING for full terms.
  6. */
  7. /**
  8. * A library that contains everything that is connected to MPLF's online filter
  9. * archive.
  10. * @author Andreas Launila
  11. * @version $Revision: 1.9 $
  12. * @package com.lokorin.lokorin.lib
  13. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  14. */
  15.  
  16. /**
  17. * For access to common constants and functions.
  18. */
  19. require_once('common.php');
  20.  
  21. global $archive;
  22. $archive = new FilterArchive();
  23.  
  24. /**
  25. * Describes a filter archive. It contains categories structured into a
  26. * navigatable tree. Each category can then contain filters.
  27. * @author Andreas Launila
  28. * @package com.lokorin.lokorin.lib
  29. */
  30. class FilterArchive {
  31. /**
  32. * Stores categories that have been loaded. Key is the id, value is the
  33. * Category instance.
  34. * @var array
  35. */
  36. private $categories;
  37. /**
  38. * Stores the top level categories in the category tree, key is irrelevant,
  39. * vaue is a Category instance.
  40. * @var array
  41. */
  42. private $topCategories;
  43. /**
  44. * Stores filters that have been loaded. Key is the id, value is the Filter
  45. * instance.
  46. * @var array
  47. */
  48. private $filters;
  49. /**
  50. * Stores edits that have been loaded. Key is the id, value is the Edit
  51. * instance.
  52. * @var array
  53. */
  54. private $edits;
  55. /**
  56. * Stores moderators that have been loaded. Key is the id, value is the
  57. * Moderator instance.
  58. * @var array
  59. */
  60. private $moderators;
  61. /**
  62. * Constructor for FilterArchive.
  63. */
  64. public function __construct() {
  65. global $db;
  66. //Initialize local variables.
  67. $this->categories = array();
  68. $this->filters = array();
  69. $this->edits = array();
  70. $this->moderators = array();
  71. //Get all categories.
  72. $fields = array(
  73. "id",
  74. "name",
  75. "description"
  76. );
  77. $rows = $db->querySelect(TABLE_MPLF_CATEGORIES, $fields);
  78. $categories = array();
  79. foreach($rows as $row) {
  80. $categories[$row['id']] = new Category($row['id'], $row['name'],
  81. $row['description']);
  82. }
  83. //Structure the categories into the tree.
  84. $topCategoryIds = array();
  85. $rows = $db->querySelect(TABLE_MPLF_CATEGORIES,
  86. array("id", "parent_id"), "ORDER by parent_id DESC");
  87. foreach($rows as $row) {
  88. if($row['parent_id'] == 0) {
  89. $topCategoryIds[] = $row['id'];
  90. } else {
  91. $categories[$row['parent_id']]->addChild($categories[$row['id']]);
  92. }
  93. }
  94. $topCategories = array();
  95. foreach($topCategoryIds as $id) {
  96. $topCategories[] = $categories[$id];
  97. }
  98. $this->categories = $categories;
  99. $this->topCategories = $topCategories;
  100. }
  101. /**
  102. * Constructs the Category tree and returns the top level categories.
  103. * @return array All top level categories.
  104. */
  105. public function getCategoryTree() {
  106. return $this->topCategories;
  107. }
  108. /**
  109. * Gets a list of all category names.
  110. * @return array Key is the id, value is the corresponding category name.
  111. */
  112. public function getAllCategoryNames() {
  113. $categories = $this->getCategoryTree();
  114. $names = array();
  115. foreach($categories as $cat) {
  116. $names += $this->getCategoryNames($cat);
  117. }
  118. return $names;
  119. }
  120. /**
  121. * Gets the category names for the specified category and all sub
  122. * categories.
  123. * @param Category $category The category that should be traversed.
  124. * @param string $base The prefix that should be used for all category
  125. * names.
  126. * @return array An array of string where each value represent a category
  127. * name.
  128. */
  129. private function getCategoryNames(Category $category, $base = '') {
  130. $result = array();
  131. $result[$category->getId()] = $base.$category->getName();
  132. $children = $category->getChildren();
  133. if(sizeof($children) == 0) {
  134. return $result;
  135. }
  136. foreach($children as $cat) {
  137. $result += $this->getCategoryNames($cat, $base.$category->getName().'->');
  138. }
  139. return $result;
  140. }
  141. /**
  142. * Gets the path to that a specified category through the tree.
  143. * @param integer $categoryId The id of the category for which the path
  144. * should be found.
  145. * @return array The category ids sorted so that the id with key 0 is
  146. * the top level, 1 the next step, 2 the step after that etc. An
  147. * empty array means that the category could not be found.
  148. */
  149. public function getPathTo($categoryId) {
  150. //We are forced to do a DFS because of how the tree is arranged.
  151. $topLevel = $this->getCategoryTree();
  152. foreach($topLevel as $category) {
  153. $path = $this->recursiveFind($category, $categoryId);
  154. if(count($path) > 0) {
  155. return $path;
  156. }
  157. }
  158. return array();
  159. }
  160. /**
  161. * A recursive function for finding the correct path via DFS.
  162. * @param Category $startCategory The Category instance where the
  163. * search should start.
  164. * @param integer $stopId The id of the category where the search
  165. * should stop, i.e. the category to find.
  166. * @return array All steps that were taken to find the stopId,
  167. * including the stopId itself. An empty array means that the
  168. * stopId could not be found.
  169. */
  170. private function recursiveFind($startCategory, $stopId) {
  171. if($startCategory->getId() == $stopId) {
  172. return array($startCategory->getId());
  173. }
  174. $children = $startCategory->getChildren();
  175. foreach($children as $child) {
  176. $find = $this->recursiveFind($child, $stopId);
  177. if(sizeof($find) > 0) {
  178. return array_merge(array($startCategory->getId()), $find);
  179. }
  180. }
  181. return array();
  182. }
  183. /**
  184. * Adds a filter to the archive.
  185. * @param string $contents The XML contents of the filter file.
  186. * @param string $description A short description of the filter.
  187. * @param integer $categoryId The unique identifier of the category that
  188. * the filter should be placed in.
  189. * @param string $author The name of the author of the filter.
  190. * @return boolean True on success, false otherwise.
  191. */
  192. public function addFilter($contents, $description, $categoryId, $author) {
  193. function xml2array($text) {
  194. $reg_exp = '/<(.*?)>(.*?)<\/\\1>/s';
  195. $match = array();
  196. preg_match_all($reg_exp, $text, $match);
  197. foreach($match[1] as $key=>$val) {
  198. if(preg_match($reg_exp, $match[2][$key])) {
  199. $array[$val] = xml2array($match[2][$key]);
  200. } else {
  201. $value = $match[2][$key];
  202. if(strstr($value, '<![CDATA[') !== false) {
  203. $value = str_replace('<![CDATA[', '', $value);
  204. $value = str_replace(']]>', '', $value);
  205. }
  206. $array[$val] = $value;
  207. }
  208. }
  209. return $array;
  210. }
  211. //Parse the contents.
  212. $parsedData = array();
  213. $curItem = '';
  214. $parsedData = xml2array($contents);
  215. if(!(isset($parsedData['filter']['name']) &&
  216. isset($parsedData['filter']['version']))) {
  217. return false;
  218. }
  219. $vars = array(
  220. 'id' => '',
  221. 'category_id' => $categoryId,
  222. 'name' => $parsedData['filter']['name'],
  223. 'description' => $description,
  224. 'time_added' => time(),
  225. 'version' => $parsedData['filter']['version'],
  226. 'contents' => $contents,
  227. 'author' => $author,
  228. 'moderator_id' => 0
  229. );
  230. global $db;
  231. $db->queryInsert(TABLE_MPLF_FILTERS, $vars);
  232. return true;
  233. }
  234. /**
  235. * Adds a suggestion of a filter for the moderators to concider.
  236. * @param integer $filterId The unique identifier of the filter that the
  237. * change should affect.
  238. * @param string $description A description of what the change is.
  239. * @param string $contents The new suggested contents for the filter file.
  240. */
  241. public function suggestFilterChange($filterId, $description, $contents) {
  242. global $db;
  243. $vars = array(
  244. 'id' => '',
  245. 'filter_id' => $filterId,
  246. 'timestamp' => time(),
  247. 'description' => $description,
  248. 'contents_after' => $contents,
  249. 'ip' => $_SERVER['REMOTE_ADDR']
  250. );
  251. $db->queryInsert(TABLE_MPLF_CHANGES, $vars);
  252. }
  253. /**
  254. * Get the category with the specified id.
  255. * @param integer $id The unique identifier for the category.
  256. * @return Category The requested Category instance, null if none could be
  257. * loaded.
  258. */
  259. public function getCategory($id) {
  260. if(!isset($this->categories[$id])) {
  261. //Attempt to load it.
  262. try {
  263. $this->categories[$id] = new Category($id);
  264. } catch(Exception $e) {}
  265. }
  266. if(isset($this->categories[$id])) {
  267. //Now loaded, return it.
  268. return $this->categories[$id];
  269. }
  270. return null;
  271. }
  272. /**
  273. * Get the edit with the specified id.
  274. * @param integer $id The unique identifier for the edit.
  275. * @return Edit The requested Edit instance, null if none could be
  276. * loaded.
  277. */
  278. public function getEdit($id) {
  279. if(!isset($this->edits[$id])) {
  280. //Attempt to load it.
  281. try {
  282. $this->edits[$id] = new Edit($id);
  283. } catch(Exception $e) {}
  284. }
  285. if(isset($this->edits[$id])) {
  286. //Now loaded, return it.
  287. return $this->edits[$id];
  288. }
  289. return null;
  290. }
  291. /**
  292. * Get the filter with the specified id.
  293. * @param integer $id The unique identifier for the filter.
  294. * @return Filter The requested Filter instance, null if none could be
  295. * loaded.
  296. */
  297. public function getFilter($id) {
  298. if(!isset($this->filters[$id])) {
  299. //Attempt to load it.
  300. try {
  301. $this->filters[$id] = new Filter($id);
  302. } catch(Exception $e) {}
  303. }
  304. if(isset($this->filters[$id])) {
  305. //Now loaded, return it.
  306. return $this->filters[$id];
  307. }
  308. return null;
  309. }
  310. /**
  311. * Get the moderator with the specified id.
  312. * @param integer $id The unique identifier for the moderator.
  313. * @return Moderator The requested Moderator instance, null if none could
  314. * be loaded.
  315. */
  316. public function getModerator($id) {
  317. if(!isset($this->moderators[$id])) {
  318. //Attempt to load it.
  319. $moderator = new Moderator($id);
  320. if($moderator->isValid()) {
  321. $this->moderators[$id] = $moderator;
  322. }
  323. }
  324. if(isset($this->filters[$id])) {
  325. //Now loaded, return it.
  326. return $this->moderators[$id];
  327. }
  328. return null;
  329. }
  330. }
  331.  
  332. /**
  333. * Describes a link category.
  334. * @author Andreas Launila
  335. * @package com.lokorin.lokorin.lib
  336. */
  337. class Category extends TableEntry {
  338. /**
  339. * The name of the category.
  340. * @var string
  341. */
  342. private $name;
  343. /**
  344. * The description of the category.
  345. * @var string
  346. */
  347. private $description;
  348. /**
  349. * The Category instances that are direct children to this instance.
  350. * @var array
  351. */
  352. private$children;
  353. /**
  354. * Constructor for Category.
  355. * @param integer $id The unique identifier to be used.
  356. */
  357. public function __construct($id) {
  358. $this->children = array();
  359. $fields = array(
  360. "name",
  361. "description"
  362. );
  363. parent::__construct(TABLE_MPLF_CATEGORIES, $id, $fields);
  364. }
  365. /**
  366. * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
  367. */
  368. protected function readRow($row) {
  369. $this->name = $row['name'];
  370. $this->description = $row['description'];
  371. }
  372. /**
  373. * Gets the name for the specific instance (not including parents).
  374. * @return string A single category name.
  375. */
  376. public function getName() {
  377. return $this->name;
  378. }
  379. /**
  380. * Gets the description of the category.
  381. * @return sring A category description.
  382. */
  383. public function getDescription() {
  384. return $this->description;
  385. }
  386. /**
  387. * Adds a child (Category instance).
  388. * @param string $childToAdd The Category instance that should be added
  389. * as child element.
  390. */
  391. public function addChild(Category $childToAdd) {
  392. $this->children[] = $childToAdd;
  393. }
  394. /**
  395. * Gets all the direct children instances.
  396. * @return array Key is irrelevant, value is a Category instance.
  397. */
  398. public function getChildren() {
  399. return $this->children;
  400. }
  401. /**
  402. * Gets all filters associated with the category, e.g. all filters that
  403. * have the category as their category.
  404. * @return array Key is irrelevant, Value is Filter instance.
  405. */
  406. public function getAssociatedFilters() {
  407. global $db, $archive;
  408. $rows = $db->querySelect(TABLE_MPLF_FILTERS, array('id'),
  409. "WHERE (category_id=".$this->getId().") AND (moderator_id != 0)");
  410. $filters = array();
  411. foreach($rows as $row) {
  412. try {
  413. $filters[] = $archive->getFilter($row['id']);
  414. } catch(Exception $e) {}
  415. }
  416. return $filters;
  417. }
  418. }
  419.  
  420. /**
  421. * Describes a filter.
  422. * @author Andreas Launila
  423. * @package com.lokorin.lokorin.lib
  424. */
  425. class Filter extends TableEntry {
  426. /**
  427. * The name of the filter.
  428. * @var string
  429. */
  430. private $name;
  431. /**
  432. * A description of the filter.
  433. * @var string
  434. */
  435. private $description;
  436. /**
  437. * The timestamp representing the time when the filter was first added.
  438. * @var integer
  439. */
  440. private $timeAdded;
  441. /**
  442. * The MPLF version that the filter was designed for.
  443. * @var string
  444. */
  445. private $version;
  446. /**
  447. * The author of the filter.
  448. * @var string
  449. */
  450. private $author;
  451. /**
  452. * The unique identifiers of Edits that belong to the filter.
  453. * @var array
  454. */
  455. private $edits;
  456. /**
  457. * The unique identifier of the category that the filter belongs to.
  458. * @var integer
  459. */
  460. private $categoryId;
  461. /**
  462. * The contents of the associated XML file.
  463. * @var string
  464. */
  465. private $contents;
  466. /**
  467. * Constructor for Filter.
  468. * @param integer $id The id of the filter.
  469. */
  470. public function __construct($id) {
  471. $fields = array(
  472. 'category_id',
  473. 'name',
  474. 'description',
  475. 'time_added',
  476. 'version',
  477. 'author',
  478. 'contents'
  479. );
  480. parent::__construct(TABLE_MPLF_FILTERS, $id, $fields);
  481. }
  482. /**
  483. * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
  484. */
  485. protected function readRow($row) {
  486. $this->categoryId = $row['category_id'];
  487. $this->name = htmlspecialchars($row['name']);
  488. $this->description = htmlspecialchars($row['description']);
  489. $this->timeAdded = $row['time_added'];
  490. $this->version = $row['version'];
  491. $this->author = htmlspecialchars($row['author']);
  492. $this->contents = $row['contents'];
  493. }
  494. /**
  495. * Gets the name of the filter.
  496. * @return string A filter name.
  497. */
  498. public function getName() {
  499. return $this->name;
  500. }
  501. /**
  502. * Gets the description of the filter.
  503. * @return string A filter description.
  504. */
  505. public function getDescription() {
  506. return $this->description;
  507. }
  508. /**
  509. * Gets the timestamp for when the filter was added.
  510. * @return integer An Unix timestamp.
  511. */
  512. public function getAddedTimestamp() {
  513. return $this->timeAdded;
  514. }
  515. /**
  516. * Gets the MPLF version that the filter was designed for.
  517. * @return string A version string, e.g. "1.3".
  518. */
  519. public function getVersion() {
  520. return $this->version;
  521. }
  522. /**
  523. * Gets the author of the filter.
  524. * @return string An author name.
  525. */
  526. public function getAuthor() {
  527. return $this->author;
  528. }
  529. /**
  530. * Gets the category that the filter belongs to.
  531. * @return Category An instance of Category..
  532. */
  533. public function getCategory() {
  534. return new Category($this->categoryId);
  535. }
  536. /**
  537. * Gets all Edit instances that are associated with the filter.
  538. * @return array Key is the chronological order with 0 being the most
  539. * recent and so on. Value is an Edit instance.
  540. */
  541. public function getAssociatedEdits() {
  542. global $db;
  543. $edits = array();
  544. $rows = $db->querySelect(TABLE_MPLF_EDITS, array('id'),
  545. "WHERE filter_id=".$db->escape(parent::$this->getId())." ORDER BY timestamp");
  546. foreach($rows as $row) {
  547. $edits[] = new Edit($row['id']);
  548. }
  549. return $edits;
  550. }
  551. /**
  552. * Gets the contents of the associated XML file.
  553. * @return string An XML file.
  554. * @access public
  555. */
  556. public function getContents() {
  557. return $this->contents;
  558. }
  559. }
  560.  
  561. /**
  562. * Describes an edit to an filter.
  563. * @author Andreas Launila
  564. * @package com.lokorin.lokorin.lib
  565. */
  566. class Edit extends TableEntry {
  567. /**
  568. * The timestamp when the edit was performed.
  569. * @var integer
  570. */
  571. private $timeEdited;
  572. /**
  573. * The description of what was done during the edit.
  574. * @var string
  575. */
  576. private $description;
  577. /**
  578. * The id of the moderator that approved the edit.
  579. * @var integer
  580. */
  581. private $moderatorId;
  582. /**
  583. * The id of the filter that was edited.
  584. * @var integer
  585. */
  586. private $filterId;
  587. /**
  588. * Constructor for Edit.
  589. * @param integer $id The id of the edit to be constructed.
  590. */
  591. public function __construct($id) {
  592. $fields = array(
  593. 'timestamp',
  594. 'description',
  595. 'moderator_id',
  596. 'filter_id'
  597. );
  598. parent::__construct(TABLE_MPLF_EDITS, $id, $fields);
  599. }
  600. /**
  601. * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
  602. */
  603. protected function readRow($row) {
  604. $this->timeEdited = $row['timestamp'];
  605. $this->description = htmlspecialchars($row['description']);
  606. $this->moderatorId = $row['moderator_id'];
  607. $this->filterId = $row['filter_id'];
  608. }
  609. /**
  610. * Gets the time when the edit was performed.
  611. * @return integer A unix timestamp.
  612. */
  613. public function getEditedTimestamp() {
  614. return $this->timeEdited;
  615. }
  616. /**
  617. * Gets the description connected to the edit.
  618. * @return string A description of what has changed.
  619. */
  620. public function getDescription() {
  621. return $this->description;
  622. }
  623. /**
  624. * Get the id of the moderator that approved the edit.
  625. * @return integer An unique moderator identificator.
  626. */
  627. public function getModeratorId() {
  628. return $this->moderatorId;
  629. }
  630. /**
  631. * Get the id of the filter that was edited.
  632. * @return integer An unique filter identificator.
  633. */
  634. public function getFilterId() {
  635. return $this->filterId;
  636. }
  637. }
  638.  
  639. /**
  640. * Describes a moderator.
  641. * @author Andreas Launila
  642. * @package com.lokorin.lokorin.lib
  643. */
  644. class Moderator extends TableEntry {
  645. /**
  646. * The username of the moderator.
  647. * @var string
  648. */
  649. private $name;
  650. /**
  651. * Constructor for Moderator.
  652. * @param integer $id The unique identifier for the Moderator.
  653. */
  654. public function __construct($id) {
  655. parent::__construct(TABLE_MPLF_MODERATORS, $id, array('name'));
  656. }
  657. /**
  658. * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
  659. */
  660. protected function readRow($row) {
  661. $this->name = $row['name'];
  662. }
  663. /**
  664. * Gets the name of the moderator.
  665. * @return string A moderator name.
  666. */
  667. public function getName() {
  668. return $this->name;
  669. }
  670. }
  671. ?>

Documentation generated on Sun, 16 Apr 2006 21:03:40 +0200 by phpDocumentor 1.3.0RC4