- <?php
- /*
- * Lokorin.com
- * Copyright 2004-2006
- * Licensed under the GNU LGPL. See COPYING for full terms.
- */
- /**
- * A library that contains everything that has to do with the site's project
- * system.
- * @author Andreas Launila
- * @version $Revision: 1.32 $
- * @package com.lokorin.lokorin.lib
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
-
- /**
- * For access to common constants and functions.
- */
- require_once('common.php');
-
- /**
- * The total width, in pixels, that the menu is allowed to occupy.
- * @var integer
- * @access private
- */
- define('TOTAL_WIDTH', 650);
- /**
- * The width, in pixels, that each menu link should be represented with.
- * @var integer
- * @access private
- */
- define('MENU_ITEM_WIDTH', 124);
-
- /**
- * Gets a project based on the current directory. If the current directory is
- * one of the projects' home directories then one of those projects are
- * returned.
- * @return Project A Project instance that is connected with the current
- * directory. If there are no such then null will be returned.
- * @throws NoSuchElementException If no project for the directory is found.
- * @access public
- */
- function getProjectBasedOnDir() {
- global $db;
-
- doInclude('lib_util');
- $dir = getCurrentDirectory();
-
- try {
- return new Project($db->querySelectFirst(TABLE_PROJECTS, 'id',
- "WHERE relative_path = ".$db->escape($dir)));
- } catch(Exception $e) {
- throw new NoSuchElementException("No project was found for the " .
- "directory (".$dir.")");
- }
- }
-
- /**
- * Gets the names of all available projects.
- * @return array The project names as values with the unique identifier for
- * the corresponding project as key.
- * @access public
- */
- function getAllProjectNames() {
- global $db;
-
- $rows = $db->querySelect(TABLE_PROJECTS, array('id', 'name'),
- "ORDER BY timestamp DESC");
- $names = array();
- foreach($rows as $row) {
- $names[$row['id']] = $row['name'];
- }
- return($names);
- }
-
- /**
- * Get the descriptions for all available project stages.
- * @return array The stage descriptions as value with the unique identifier
- * for the corresponding project as key.
- * @access public
- */
- function getAllStageDescriptions() {
- global $db;
-
- $rows = $db->querySelect(TABLE_PROJECT_STAGES, array('id', 'description'),
- "ORDER BY id DESC");
- $names = array();
- foreach($rows as $row) {
- $names[$row['id']] = $row['description'];
- }
- return($names);
- }
-
- /**
- * Gets all available projects.
- * @return array Each avaialable project represented as a Project instance.
- * @access public
- */
- function getAllProjects() {
- return getProjects("ORDER BY timestamp DESC");
- }
-
- /**
- * Gets all projects that match a specified sql selector statement.
- * @param string $sqlSelector The sql statement that specifies the project that
- * should be retrieved.
- * @return array An array containing Project instances representing the
- * retrieved projects.
- * @access public
- */
- function getProjects($sqlSelector) {
- global $db;
-
- $rows = $db->querySelect(TABLE_PROJECTS, array('id'), $sqlSelector);
- $projects = array();
- foreach($rows as $row) {
- $projects[] = new Project($row['id']);
- }
- return $projects;
- }
-
- /**
- * Gets the number of projects available.
- * @return integer A number of projects.
- * @access public
- */
- function getProjectCount() {
- global $db;
-
- return $db->queryCount(TABLE_PROJECTS);
- }
-
- /**
- * Describes a project.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class Project extends TableEntry {
- /**
- * The name of the project.
- * @var string
- */
- private $name;
- /**
- * The unique identifier of the programming language that represents the
- * project.
- * @var integer
- */
- private $langId;
- /**
- * The language version that the project usues.
- * @var string
- */
- private $langVersion;
- /**
- * The path from the root to the projects directory. Alternativly an
- * absolute url starting with 'http://' can be specified.
- * @var string
- */
- private $path;
- /**
- * Whether or not the project has any projects associated with it. True if
- * the project has downloads, false otherwise.
- * @var boolean
- */
- private $hasDownloads;
- /**
- * Whether or not the project's source is available for download. True if
- * the project has source available for download, false otherwise. If it is
- * false then it's assumed that the source can be gotten through contact.
- * @var boolean
- */
- private $hasSource;
- /**
- * The name of the icon image used to represent the project.
- * @var string
- */
- private $iconName;
- /**
- * Whether or not the project should be shown in the site's menu. True if
- * the project should be shown, false otherwise.
- * @var boolean
- */
- private $doDisplayInMenu;
- /**
- * The unique identifier for the stage that the project is currently at.
- * @var integer
- */
- private $stageId;
- /**
- * The unix timestamp that represents when the project was added.
- * @var integer
- */
- private $timestamp;
- /**
- * The license if any that the project is released under. The license
- * information should be in the form of XHTML code.
- * @var string
- */
- private $license;
- /**
- * A processed description in XHTML of what the project is about, it's
- * goals and so on.
- * @var string
- */
- private $description;
- /**
- * The timestamp describing the point in time when the description was
- * last processed.
- * @var integer
- */
- private $timeProcessed;
- /**
- * The description that the project pages should have.
- * @var string
- */
- private $pageDescription;
-
- /**
- * Constructor for Project.
- * @param integer $id The unique identifier for the project.
- */
- function __construct($id) {
- $fields = array(
- 'name',
- 'lang_id',
- 'lang_ver',
- 'relative_path',
- 'has_downloads',
- 'has_source',
- 'icon_name',
- 'display_menulink',
- 'stage_id',
- 'timestamp',
- 'processed_description',
- 'license',
- 'timestamp_description_processed',
- 'page_description'
- );
- parent::__construct(TABLE_PROJECTS, $id, $fields);
- }
-
- /**
- * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
- */
- protected function readRow($row) {
- $this->name = $row['name'];
- $this->langId = $row['lang_id'];
- $this->langVersion = $row['lang_ver'];
- $this->path = $row['relative_path'];
- $this->hasDownloads = $row['has_downloads'];
- $this->hasSource = $row['has_source'];
- $this->iconName = $row['icon_name'];
- $this->doDisplayInMenu = $row['display_menulink'];
- $this->stageId = $row['stage_id'];
- $this->timestamp = $row['timestamp'];
- $this->description = $row['processed_description'];
- $this->license = $row['license'];
- $this->timeProcessed = $row['timestamp_description_processed'];
- $this->pageDescription = $row['page_description'];
- if($this->pageDescription == '') {
- //Use the first sentence in the description instead.
- $description = preg_replace("/<.*?>/", "", $this->getDescriptionAsHtml());
- $description = preg_replace("/<.*?$/", "", $description);
- $this->pageDescription = substr($description, 0, strpos($description, '.') + 1);
- }
- }
-
- /**
- * Gets the link representation for the project. If the project has an
- * icon then it is used to represent the project, otherwise a text link is
- * used.
- * @return string An XHTML compliant link representation.
- */
- public function getLink() {
- global $db;
-
- $projPath = $this->path;
- if(strpos($projPath, 'http://') === false) {
- $projPath = PAGE_ROOT.$projPath;
- }
- $output = '<a href="'.$projPath.'">';
- if($this->iconName != '') {
- doInclude('lib_images');
- $iconPath = FOLDER_ICONS.$this->iconName;
- if(!file_exists(DOC_ROOT.$iconPath)) {
- doInclude('lib_errors');
- logException(new FileNotFoundException('Project Icon ('.$iconPath.
- ') is missing.'));
- return '';
- }
- $output .= getImageCode($iconPath, $this->name, $this->name, 'icon');
- } else {
- $output .= $this->name;
- }
- return $output.'</a>';
- }
-
- /**
- * Gets the programming language used in the project.
- * @return ProgrammingLanguage The ProgrammingLanguage instance that
- * represents the used language.
- */
- public function getProgrammingLanguage() {
- doInclude('lib_languages');
- return new ProgrammingLanguage($this->langId);
- }
-
- /**
- * Gets the stage that the project is currently at.
- * @return Stage The Stage instance that represents the current Stage.
- */
- public function getStage() {
- return new Stage($this->stageId);
- }
-
- /**
- * Gets a short synopsis of the project. The synopsis consists of the name
- * and link to the project along with a list with the following
- * information: language (and version), when it was started, current stage
- * and a short description.
- * @return string XHTML compliant code representing a short synopsis of
- * the project.
- */
- public function getSynopsis() {
- $stage = $this->getStage();
-
- //Get the first sentence of the description and use it as description.
-
-
- $output = '<a href="'.PAGE_ROOT.$this->path.'">'.$this->name.'</a>' .
- '<ul>';
- try {
- $lang = $this->getProgrammingLanguage();
- $output .= '<li><i>Language</i>: '.$lang->getLink().' '.
- $this->langVersion.'</li>';
- } catch(Exception $e) {}
- $output .= '<li><i>Started</i>: '.date(DATE_LONG, $this->timestamp).'</li>' .
- '<li><i>Status</i>: '.$stage->getDescription().'</li>' .
- '<li><i>Short description</i>: '.$this->pageDescription.'</li>' .
- '</ul>';
- return $output;
- }
-
- /**
- * Gets the name of the project.
- * @return string A name.
- */
- public function getName() {
- return $this->name;
- }
-
- /**
- * Gets a summary of all information available on the project.
- * @return string XHTML compliant code representing all information on the
- * project.
- */
- public function getInfo() {
- //Construct the icon info.
- $icon = '';
- if($this->iconName != '') {
- doInclude('lib_images');
- $iconPath = ROOT.FOLDER_ICONS.$this->iconName;
- $icon = '<li><i>Icon</i>: '.
- getImageCode($iconPath, 'Project icon', '', 'icon').'</li>';
- }
-
- //Construct additional info.
- $additional = '';
- if($this->hasDownloads == 1) {
- $additional .= 'This project has downloadable items.<br />';
- }
- if($this->hasSource == 1) {
- $additional .= 'This project\'s source code is available for ' .
- 'download.<br />';
- } else {
- $additional .= 'This project\'s source code is available through ' .
- '<a href="'.PAGE_ROOT.'contact">contact</a>.<br />';
- }
-
- //Get the language and stage.
- $lang = $this->getProgrammingLanguage();
- $stage = $this->getStage();
-
- //Get the license information.
- $license = "";
- if(strlen($this->license) != 0) {
- $license = "<li><i>License</i>: ".$this->license."</li>";
- }
-
- //Construct the output.
- return $this->getDescriptionAsHtml().
- '<h2>Project information</h2>' .
- '<ul>' .
- '<li><i>Name</i>: '.$this->name.'</li>'.
- $icon.
- '<li><i>Started</i>: '.date(DATE_LONG, $this->timestamp).'</li>' .
- '<li><i>Language</i>: '.$lang->getLink().' '.
- $this->langVersion.'</li>' .
- $license.
- '<li><i>Status</i>: '.$stage->getDescription().'</li>
- </ul>'."\n".
- '<p>'.$additional.'</p>';
- }
-
- /**
- * Gets the submenu connected with the project, i.e. a menu for all
- * pages in the project.
- * @return string XHTML compliant code representing the menu.
- */
- public function getMenu() {
- doInclude('lib_menu');
- $projectMenu = new ProjectMenu(parent::$this->getId());
- $destinations = $projectMenu->getDestinations();
-
- /*
- * Calculate how the menu should look. I'm making a small exception from
- * seperating form and function, there was no other simple way.
- */
- if(count($destinations) > 5) {
- $menuCount = 5;
- } else {
- $menuCount = count($destinations);
- }
- $offsetRow1 = (TOTAL_WIDTH / MENU_ITEM_WIDTH - $menuCount) *
- MENU_ITEM_WIDTH / 2;
- $offsetRow2 = (TOTAL_WIDTH / MENU_ITEM_WIDTH -
- (sizeof($destinations) - 5)) * MENU_ITEM_WIDTH / 2;
-
- //Calculate the output class="firstRow"
- $output = '<ul style="margin-left: '.$offsetRow1.'px;">';
- $rowCount = 0;
- foreach($destinations as $name => $path) {
- if($rowCount == 5) {
- //The first row is filled, start a second. There's only support
- //for two rows at the moment.
- $output .= '</ul><ul style="margin-left: '.
- $offsetRow2.'px;">';
- }
- $output .= '<li><a href="';
- if(strpos($path, 'http://') === false) {
- $output .= PAGE_ROOT;
- }
- $output .= $path.'">'.$name.'</a></li>'."\n";
-
- $rowCount++;
- }
- $output .= '</ul>';
- return $output;
- }
-
- /**
- * Whether or not the project has a menu.
- * @return boolean True if the project has a menu, false otherwise.
- */
- public function hasMenu() {
- doInclude('lib_menu');
- $menu = new ProjectMenu(parent::$this->getId());
- $destinations = $menu->getDestinations();
- return is_array($destinations) && count($destinations) > 0;
- }
-
- /**
- * Gets the path from the site's root to the home directory of the project.
- * @return string A path relative to the root.
- */
- public function getPath() {
- return $this->path;
- }
-
- /**
- * Gets all download items that are connected to the project. The items
- * are grouped by their respective category. The categories should if
- * possible be displayed in the order that they are given.
- * @return array An array where the key is a DownloadCategory instance and
- * the corresponding value is an array of DownloadItem instances,
- * where each such instance represents a downloadable item in the
- * category.
- */
- public function getDownloadsGroupedByCategory() {
- global $db;
-
- doInclude('lib_downloads');
-
- $idFields = array('project_id' => parent::$this->getId());
- return getDownloadsGroupedByCategory($db->buildSqlSelector($idFields));
- }
-
- /**
- * Gets all images, and their descriptions, that are connected to the
- * project.
- * @return array The name of the image as key and the description that is
- * connected to the image as value.
- */
- public function getImages() {
- global $db;
-
- $rows = $db->querySelect(TABLE_PROJECT_IMAGES,
- array('image_name', 'description'),
- "WHERE project_id=".$db->escape(parent::$this->getId())." ORDER BY id DESC");
- $images = array();
- foreach($rows as $row) {
- $images[$row['image_name']] = $row['description'];
- }
- return $images;
- }
-
- /**
- * Gets all news entries that are connected to the project.
- * @return array Each entry represents a news item. The items are ordered
- * so that the news item with the timestamp is first.
- */
- public function getNews() {
- doInclude('lib_news');
- return getNews($this->getNewsSqlSelector()." ORDER BY timestamp DESC");
- }
-
- /**
- * Gets an sql selector that selects all news that are connected to the
- * project from the news table.
- * @return string An sql selector. */
- public function getNewsSqlSelector() {
- global $db;
- $id = $db->escape(parent::$this->getId());
- return "WHERE (project_id1=".$id.") OR (project_id2=".$id.") " .
- "OR (project_id3=".$id.")";
- }
-
- /**
- * Gets the header link to the RSS page for the project's news.
- * @return string XHTML compliant code that describes a header link (which should
- * only be placed in the header portion of the page).
- * @access public
- */
- public function getRssHeaderLink() {
- return '<link rel="alternate" href="'.$this->getRssPath().'" ' .
- 'type="application/rss+xml" title="'.$this->name.' progress" />';
- }
-
- /**
- * Gets the path to the RSS feed for the project's news.
- * @return string A path, relative to the site's root, to the project's
- * news RSS feed.
- */
- public function getRssPath() {
- return PAGE_ROOT.'news/rss?project_id='.parent::$this->getId();
- }
-
- /**
- * Gets the submenu of the project.
- * @return ProjectMenu A project submenu.
- */
- public function getSubmenu() {
- doInclude('lib_menu');
- return new ProjectMenu(parent::$this->getId());
- }
-
- /**
- * Checks if the project should be displayed in the menu.
- * @return boolean True if the project should be displayed in the
- * navigational menu, false otherwise.
- */
- public function isMenuDisplayable() {
- return $this->doDisplayInMenu;
- }
-
- /**
- * Gets information about the license under which the project is released.
- * @return string The license information as valid XHTML code.
- */
- public function getLicense() {
- return $this->license;
- }
-
- /**
- * Gets the project's description as valid XHTML code.
- * @return string XHTML compliant code.
- */
- private function getDescriptionAsHtml() {
- if(strlen($this->description) == 0) {
- $this->updateProcessedDescription();
- }
- return $this->description;
- }
-
- /**
- * Processes the raw form of the descripiton and updates the processed form
- * with the new version. This should be done whenever the description
- * changes.
- */
- public function updateProcessedDescription() {
- global $db;
- doInclude("lib_markup");
-
- $description= $db->querySelectFirst(TABLE_PROJECTS, 'description',
- $db->buildSqlSelector(array('id' => parent::$this->getId())));
-
- $description = convertMarkupToHTML($description);
-
- //Update the last time that the description was processed.
- $this->timeProcessed = time();
-
- //Store the new processed version.
- $vars = array(
- 'processed_description' => $description,
- 'timestamp_description_processed' => $this->timeProcessed
- );
- $db->queryUpdate(TABLE_PROJECTS, $vars,
- $db->buildSqlSelector(array('id' => parent::$this->getId())));
- $this->description = $description;
- }
-
- /**
- * Gets the project, and all its subpages, as a sitemap entries.
- * @return string A number of well-formed XML url entry as specified by the
- * google sitemap schema.
- */
- public function getAsSitemapEntries() {
- doInclude('lib_sitemap');
- doInclude('lib_menu');
-
- $output = '';
- $submenu = new ProjectMenu(parent::$this->getId());
- foreach($submenu->getDestinations() as $destination) {
- if(strpos($destination, 'http://') === 0) {
- //The destination is not on the same domain, skip it.
- continue;
- }
- $output .= formatSitemapElement($destination, false, 1);
- }
- return $output;
- }
-
- /**
- * Gets the page description that should be used when displaying a page
- * that is related to this project.
- * @return string A brief description.
- */
- public function getPageDescription() {
- return $this->pageDescription;
- }
- }
-
- /**
- * Describes a project stage. Each stage represents a part of the deveolpment
- * process of a project.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class Stage extends TableEntry {
- /**
- * A description of the stage. The descriptions should be rather short i.e.
- * "Finished", they should not be explaining exactly what the stage is in
- * detail.
- * @var string
- */
- private $description;
-
- /**
- * Constructor for Stage.
- * @param integer $id The unique identifier for the stage.
- */
- public function Stage($id) {
- $fields = array('description');
- parent::__construct(TABLE_PROJECT_STAGES, $id, $fields);
- }
-
- /**
- * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
- */
- protected function readRow($row) {
- $this->description = $row['description'];
- }
-
- /**
- * Gets the description of the stage.
- * @return string A short description.
- * @access public
- */
- function getDescription() {
- return $this->description;
- }
- }
- ?>