Alpha Framework alpha--model
[ class tree: alpha--model ] [ index: alpha--model ] [ all elements ]

Source for file ArticleObject.inc

Documentation is available at ArticleObject.inc

  1. <?php
  2.  
  3. require_once $config->get('sysRoot').'alpha/model/AlphaDAO.inc';
  4. require_once $config->get('sysRoot').'alpha/model/ArticleVoteObject.inc';
  5. require_once $config->get('sysRoot').'alpha/model/ArticleCommentObject.inc';
  6. require_once $config->get('sysRoot').'alpha/model/TagObject.inc';
  7. require_once $config->get('sysRoot').'alpha/controller/front/FrontController.inc';
  8.  
  9. /**
  10.  *
  11.  * An article class for the CMS
  12.  * 
  13.  * @package alpha::model
  14.  * @since 1.0
  15.  * @author John Collins <dev@alphaframework.org>
  16.  * @version $Id: ArticleObject.inc 1341 2011-03-17 15:02:02Z johnc $
  17.  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
  18.  * @copyright Copyright (c) 2011, John Collins (founder of Alpha Framework).
  19.  *  All rights reserved.
  20.  * 
  21.  *  <pre>
  22.  *  Redistribution and use in source and binary forms, with or
  23.  *  without modification, are permitted provided that the
  24.  *  following conditions are met:
  25.  * 
  26.  *  * Redistributions of source code must retain the above
  27.  *    copyright notice, this list of conditions and the
  28.  *    following disclaimer.
  29.  *  * Redistributions in binary form must reproduce the above
  30.  *    copyright notice, this list of conditions and the
  31.  *    following disclaimer in the documentation and/or other
  32.  *    materials provided with the distribution.
  33.  *  * Neither the name of the Alpha Framework nor the names
  34.  *    of its contributors may be used to endorse or promote
  35.  *    products derived from this software without specific
  36.  *    prior written permission.
  37.  *   
  38.  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  39.  *  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  40.  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  41.  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  42.  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  43.  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  44.  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  45.  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  46.  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  47.  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  48.  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  49.  *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  50.  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  51.  *  </pre>
  52.  *  
  53.  */
  54. class ArticleObject extends AlphaDAO {
  55.     /**
  56.      * The article title
  57.      * 
  58.      * @var String 
  59.      * @since 1.0
  60.      */
  61.     protected $title;
  62.     
  63.     /**
  64.      * The article site section
  65.      * 
  66.      * @var DEnum 
  67.      * @since 1.0
  68.      */
  69.     protected $section;
  70.     
  71.     /**
  72.      * The description of the article
  73.      * 
  74.      * @var String 
  75.      * @since 1.0
  76.      */
  77.     protected $description;
  78.     
  79.     /**
  80.      * Optional custom body onload Javascript
  81.      * 
  82.      * @var String 
  83.      * @since 1.0
  84.      */
  85.     protected $bodyOnload;
  86.     
  87.     /**
  88.      * Any custom HTML header content (e.g. Javascript) for the article
  89.      * 
  90.      * @var Text 
  91.      * @since 1.0
  92.      */
  93.     protected $headerContent;
  94.     
  95.     /**
  96.      * The article content
  97.      * 
  98.      * @var Text 
  99.      * @since 1.0
  100.      */
  101.     protected $content;
  102.     
  103.     /**
  104.      * The author of the article
  105.      * 
  106.      * @var String 
  107.      * @since 1.0
  108.      */
  109.     protected $author;
  110.     
  111.     /**
  112.      * A boolean to control whether the artcile is publically accessible or not
  113.      * 
  114.      * @var Boolean 
  115.      * @since 1.0
  116.      */
  117.     protected $published;
  118.     
  119.     /**
  120.      * A Relation containing all of the comments on this article
  121.      *
  122.      * @var Relation 
  123.      * @since 1.0
  124.      */
  125.     protected $comments;
  126.     
  127.     /**
  128.      * A Relation containing all of the votes on this article
  129.      *
  130.      * @var Relation 
  131.      * @since 1.0
  132.      */
  133.     protected $votes;
  134.     
  135.     /**
  136.      * A Relation containing all of the tags on this article
  137.      *
  138.      * @var Relation 
  139.      * @since 1.0
  140.      */
  141.     protected $tags;
  142.     
  143.     /**
  144.      * An array of all of the attributes on this BO which are tagged
  145.      *  
  146.      * @var array 
  147.      * @since 1.0
  148.      */
  149.     protected $taggedAttributes = array('title''description''content');
  150.     
  151.     /**
  152.      * Path to a .text file where the content of this article is stored (optional)
  153.      * 
  154.      * @var string 
  155.      * @since 1.0
  156.      */
  157.     private $filePath;
  158.     
  159.     /**
  160.      * An array of data display labels for the class properties
  161.      * 
  162.      * @var array 
  163.      * @since 1.0
  164.      */
  165.     protected $dataLabels = array("OID"=>"Article ID#","title"=>"Title","section"=>"Site Section","description"=>"Description","bodyOnload"=>"Body onload Javascript","content"=>"Content","headerContent"=>"HTML Header Content","author"=>"Author","created_ts"=>"Date Added","updated_ts"=>"Date of last Update","published"=>"Published","URL"=>"URL","printURL"=>"Printer version URL","comments"=>"Comments","votes"=>"Votes","tags"=>"Tags");
  166.     
  167.     /**
  168.      * The name of the database table for the class
  169.      * 
  170.      * @var string 
  171.      * @since 1.0
  172.      */
  173.     const TABLE_NAME = 'Article';
  174.     
  175.     /**
  176.      * The URL for this article (transient)
  177.      * 
  178.      * @var string 
  179.      * @since 1.0
  180.      */
  181.     protected $URL;
  182.     
  183.     /**
  184.      * The print URL for this article (transient)
  185.      * 
  186.      * @var string 
  187.      * @since 1.0
  188.      */
  189.     protected $printURL;
  190.     
  191.     /**
  192.      * Trace logger
  193.      * 
  194.      * @var Logger 
  195.      * @since 1.0
  196.      */
  197.     private static $logger null;
  198.     
  199.     /**
  200.      * The constructor which sets up some housekeeping attributes
  201.      * 
  202.      * @since 1.0
  203.      */
  204.     public function __construct({
  205.         self::$logger new Logger('ArticleObject');
  206.         
  207.         // ensure to call the parent constructor
  208.         parent::__construct();
  209.         
  210.         $this->title = new String();
  211.         $this->title->setHelper('Please provide a title for the article.');
  212.         $this->title->setSize(100);
  213.         $this->title->setRule("/\w+/");
  214.         
  215.         $this->section = new DEnum('ArticleObject::section');        
  216.         
  217.         $this->description = new String();
  218.         $this->description->setHelper('Please provide a brief description of the article.');
  219.         $this->description->setSize(200);
  220.         $this->description->setRule("/\w+/");
  221.         $this->bodyOnload = new String();        
  222.         $this->content = new Text();
  223.         $this->content->setHelper('Please provide some content for the article.');
  224.         $this->content->setRule("/\w+/");
  225.         $this->headerContent = new Text();        
  226.         $this->author = new String();
  227.         $this->author->setHelper('Please state the name of the author of this article');
  228.         $this->author->setSize(70);
  229.         $this->author->setRule("/\w+/");
  230.         $this->published = new Boolean(0);
  231.         
  232.         $this->comments = new Relation();
  233.         $this->markTransient('comments');
  234.         $this->comments->setRelatedClass('ArticleCommentObject');
  235.         $this->comments->setRelatedClassField('articleOID');
  236.         $this->comments->setRelatedClassDisplayField('content');
  237.         $this->comments->setRelationType('ONE-TO-MANY');
  238.         
  239.         $this->votes = new Relation();
  240.         $this->markTransient('votes');
  241.         $this->votes->setRelatedClass('ArticleVoteObject');
  242.         $this->votes->setRelatedClassField('articleOID');
  243.         $this->votes->setRelatedClassDisplayField('score');
  244.         $this->votes->setRelationType('ONE-TO-MANY');
  245.         
  246.         $this->tags = new Relation();        
  247.         $this->markTransient('tags');
  248.         $this->tags->setRelatedClass('TagObject');
  249.         $this->tags->setRelatedClassField('taggedOID');
  250.         $this->tags->setRelatedClassDisplayField('content');
  251.         $this->tags->setRelationType('ONE-TO-MANY');
  252.         $this->tags->setTaggedClass(get_class($this));
  253.         
  254.         $this->URL = '';
  255.         $this->printURL = '';
  256.         // mark the URL attributes as transient
  257.         $this->markTransient('URL');
  258.         $this->markTransient('printURL');
  259.         
  260.         // mark title as unique
  261.         $this->markUnique('title');
  262.         
  263.         $this->markTransient('filePath');
  264.         $this->markTransient('taggedAttributes');
  265.     }
  266.     
  267.     /**
  268.      * After creating a new ArticleObject, tokenize the description field to form a set
  269.      * of automated tags and save them.
  270.      * 
  271.      * @since 1.0
  272.      */
  273.     protected function after_save_callback({
  274.         if($this->getVersion(== && $this->tags instanceof Relation{
  275.             foreach($this->taggedAttributes as $tagged{
  276.                 $tags TagObject::tokenize($this->get($tagged)get_class($this)$this->getOID());
  277.                 foreach($tags as $tag{
  278.                     try {
  279.                         $tag->save();
  280.                     }catch(ValidationException $e){
  281.                         /*
  282.                          * The unique key has most-likely been violated because this BO is already tagged with this
  283.                          * value, so we can ignore in this case.
  284.                          */
  285.                     }
  286.                 }
  287.             }
  288.         }
  289.     }
  290.     
  291.     /**
  292.      * Set up the transient URL attributes for the artcile after it has loaded
  293.      * 
  294.      * @since 1.0
  295.      */
  296.     protected function after_loadByAttribute_callback({
  297.         $this->after_load_callback();
  298.     }
  299.     
  300.     /**
  301.      * Set up the transient URL attributes for the article after it has loaded
  302.      * 
  303.      * @since 1.0
  304.      */
  305.     protected function after_load_callback({
  306.         global $config;
  307.         global $front;
  308.         
  309.         // check the config to see if we are using mod_rewrite
  310.         if($config->get('sysUseModRewrite')) {
  311.             // check to see if an alias is registered for the view_article_title controller, otherwise use the long URL version
  312.             if(isset($front&& $front->hasAlias('ViewArticleTitle')) {
  313.                 $alias $front->getControllerAlias('ViewArticleTitle');
  314.                 
  315.                 $this->URL = $config->get('sysURL').$alias.'/'.str_replace(' ''_'$this->title->getValue());
  316.             }else{
  317.                 $this->URL = $config->get('sysURL').'ViewArticleTitle/title/'.str_replace(' ''_'$this->title->getValue());
  318.             }
  319.         }else{
  320.             $this->URL = $config->get('sysURL').'alpha/controller/ViewArticle.php?oid='.$this->getID();
  321.         }
  322.         
  323.         // now set up the print version URL
  324.         if($config->get('sysUseModRewrite')) {
  325.             // check to see if an alias is registered for the view_article_title controller, otherwise use the long URL version
  326.             if(isset($front&& $front->hasAlias('ViewArticlePrint')) {
  327.                 $alias $front->getControllerAlias('ViewArticlePrint');
  328.                 
  329.                 $this->printURL = $config->get('sysURL').$alias.'/'.str_replace(' ''_'$this->title->getValue());
  330.             }else{
  331.                 $this->printURL = $config->get('sysURL').'ViewArticlePrint/title/'.str_replace(' ''_'$this->title->getValue());
  332.             }
  333.         }else{
  334.             $this->printURL = $config->get('sysURL').'alpha/controller/ViewArticlePrint.php?title='.$this->title->getValue();
  335.         }
  336.     }
  337.     
  338.     /**
  339.      * Gets an array of the OIDs of the most recent articles added to the system (by date), from the newest
  340.      * article to the amount specified by the $limit
  341.      * 
  342.      * @return array 
  343.      * @since 1.0
  344.      * @throws AlphaException
  345.      */
  346.     public function loadRecentWithLimit($limit){
  347.         $denum new DEnum('ArticleObject::section');
  348.         $excludeID $denum->getOptionID('Main');
  349.         
  350.         $sqlQuery "SELECT OID FROM ".self::TABLE_NAME." WHERE published='1' AND section!='$excludeID' ORDER BY dateAdded DESC LIMIT 0, $limit;";        
  351.  
  352.         $this->lastQuery = $sqlQuery;
  353.         
  354.         if(!$result AlphaDAO::getConnection()->query($sqlQuery)) {
  355.             throw new AlphaException('Failed to load the OIDs for the most recent articles, MySql error is ['.AlphaDAO::getConnection()->error.
  356.                 '], query ['.$sqlQuery.']');
  357.             return array();
  358.         }
  359.         
  360.         $OIDs array();
  361.         
  362.         $i 0;
  363.         while($row $result->fetch_array(MYSQLI_ASSOC)) {
  364.             $OIDs[$i$row['OID'];
  365.             $i++;
  366.         }
  367.         
  368.         return $OIDs;
  369.     }
  370.     
  371.     /**
  372.      * Generates the location of the attachments folder for this article
  373.      * 
  374.      * @return string 
  375.      * @since 1.0
  376.      */
  377.     public function getAttachmentsLocation({
  378.         global $config;
  379.         
  380.         return $config->get('sysRoot').'attachments/article_'.$this->getID();
  381.     }
  382.     
  383.     /**
  384.      * Generates the URL of the attachments folder for this article
  385.      * 
  386.      * @return string 
  387.      * @since 1.0
  388.      */
  389.     public function getAttachmentsURL({
  390.         global $config;
  391.         
  392.         return $config->get('sysURL').'attachments/article_'.$this->getID();
  393.     }
  394.     
  395.     /**
  396.      * Generates a secure URL for downloading an attachment file via the ViewAttachment controller
  397.      * 
  398.      * @param string $filename 
  399.      * @since 1.0
  400.      */
  401.     public function getAttachmentSecureURL($filename{
  402.         global $config;
  403.         
  404.         return FrontController::generateSecureURL('act=ViewAttachment&dir='.$this->getAttachmentsLocation().'&filename='.$filename);
  405.     }
  406.     
  407.     /**
  408.      * Creates the attachment folder for the article on the server.
  409.      * 
  410.      * @since 1.0
  411.      * @throws AlphaException
  412.      */
  413.     public function createAttachmentsFolder({
  414.         // create the attachment directory for the article
  415.         try{
  416.             mkdir($this->getAttachmentsLocation());
  417.         }catch (Exception $e{
  418.             throw new AlphaException('Unable to create the folder ['.$this->getAttachmentsLocation().'] for the article.');
  419.         }
  420.             
  421.         // ...and set write permissions on the folder
  422.         try{
  423.             chmod($this->getAttachmentsLocation()0777);
  424.         }catch (Exception $e{
  425.             throw new AlphaException('Unable to set write permissions on the folder ['.$this->getAttachmentsLocation().'].');
  426.         }
  427.     }
  428.     
  429.     /**
  430.      * Method for returning the calculated score for this article
  431.      * 
  432.      * @return double 
  433.      * @since 1.0
  434.      */
  435.     public function getArticleScore({
  436.         $votes $this->getArticleVotes();
  437.         
  438.         $score 0;
  439.         $total_score 0;
  440.         $vote_count count($votes);
  441.         
  442.         for($i 0$i $vote_count$i++){
  443.             $total_score += $votes[$i]->get('score');
  444.         }
  445.         
  446.         if($vote_count 0)
  447.         $score $total_score/$vote_count;
  448.         
  449.         return sprintf("%01.2f"$score);
  450.     }
  451.     
  452.     /**
  453.      * Method for fetching all of the votes for this article
  454.      * 
  455.      * @return array An array of ArticleVoteObject objects
  456.      * @since 1.0
  457.      */
  458.     public function getArticleVotes({
  459.         $votes $this->votes->getRelatedObjects();
  460.         
  461.         return $votes;
  462.     }
  463.     
  464.     /**
  465.      * Method to determine if the logged-in user has already voted for this article
  466.      * 
  467.      * @return boolean True if they have voted already, false otherwise
  468.      * @since 1.0
  469.      * @throws AlphaException
  470.      */
  471.     public function checkUserVoted({
  472.         // just going to return true if nobody is logged in
  473.         if (!isset($_SESSION['currentUser']))
  474.             return true;
  475.         
  476.         $userID $_SESSION['currentUser']->getID();
  477.         
  478.         $sqlQuery "SELECT COUNT(*) AS usersVote FROM ".ArticleVoteObject::TABLE_NAME." WHERE articleOID='".$this->OID."' AND personOID='".$userID."';";        
  479.  
  480.         $this->lastQuery = $sqlQuery;
  481.         
  482.         if(!$result AlphaDAO::getConnection()->query($sqlQuery)) {
  483.             throw new AlphaException('Failed to check if the current user voted for the article ['.$this->OID.'], MySql error is ['.AlphaDAO::getConnection()->error.'], query ['.$sqlQuery.']');
  484.             return false;
  485.         }
  486.         
  487.         $row $result->fetch_array(MYSQLI_ASSOC);
  488.         
  489.         if($row['usersVote'== "0")
  490.             return false;
  491.         else
  492.             return true;            
  493.     }
  494.     
  495.     /**
  496.      * Method for fetching all of the comments for this article
  497.      * 
  498.      * @return array An array of ArticleCommentObject objects
  499.      * @since 1.0
  500.      */
  501.     public function getArticleComments({
  502.         $comments $this->comments->getRelatedObjects();        
  503.         
  504.         return $comments;
  505.     }
  506.     
  507.     /**
  508.      * Loads the content of the ArticleObject from the specified file path
  509.      * 
  510.      * @param $filePath 
  511.      * @since 1.0
  512.      * @throws FileNotFoundException
  513.      */
  514.     public function loadContentFromFile($filePath{
  515.         try{
  516.             $this->content->setValue(file_get_contents($filePath));
  517.             $this->filePath $filePath;
  518.         }catch (Exception $e{
  519.             throw new FileNotFoundException($e->getMessage());
  520.         }
  521.     }
  522.     
  523.     /**
  524.      * Returns true if the article content was loaded from a .text file, false otherwise.
  525.      * 
  526.      * @return boolean 
  527.      * @since 1.0
  528.      */
  529.     public function isLoadedFromFile({
  530.         return ($this->filePath == '' falsetrue);
  531.     }
  532.     
  533.     /**
  534.      * Returns the timestamp of when the content .text file for this article was last
  535.      * modified.
  536.      * 
  537.      * @return string 
  538.      * @since 1.0
  539.      * @throws FileNotFoundException
  540.      */
  541.     public function getContentFileDate({
  542.         if($this->filePath != ''{
  543.             try{                
  544.                 return date("Y-m-d H:i:s"filemtime($this->filePath));
  545.             }catch (Exception $e{
  546.                 throw new FileNotFoundException($e->getMessage());
  547.             }
  548.         }else{
  549.             throw new FileNotFoundException('Error trying to access an article content file when none is set!');
  550.         }
  551.     }
  552. }
  553.  
  554. ?>

Documentation generated on Thu, 17 Mar 2011 16:43:51 +0000 by phpDocumentor 1.4.3