kalenjordan/magehero

View on GitHub
code/Model/Post.php

Summary

Maintainability
D
1 day
Test Coverage
<?php

class Model_Post extends Model_Record
{
    protected $_data;
    protected $_user;

    protected function _getTable() { return 'posts'; }
    protected function _getTableIdFieldname() { return 'post_id'; }
    protected function _getColumns()
    {
        return array('user_id', 'is_active', 'is_news', 'image_url', 'subject', 'body');
    }

    /**
     * @var Model_LocalConfig
     */
    protected $_localConfig;

    public function __construct(Model_LocalConfig $config)
    {
        $this->_localConfig = $config;
    }

    public function getSubject() { return $this->get('subject'); }
    public function getBody()    { return $this->get('body'); }

    public function getBodyAsHtml()
    {
        $parseDown = new Parsedown();
        $purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());
        $body = $parseDown->text($this->get('body'));
        $body = $purifier->purify($body);

        return $body;
    }

    public function getUserId()      { return $this->get('user_id'); }
    public function getImageUrl()    { return $this->get('image_url'); }
    public function getIsActive()    { return $this->get('is_active'); }
    public function getCreatedAt()   { return $this->get('created_at'); }
    public function getUpdatedAt()   { return $this->get('updated_at'); }
    public function voteCount()      { return $this->get('vote_count'); }
    public function getUpvotersCsv() { return $this->get('upvoters_csv'); }
    public function isNews()         { return $this->get('is_news'); }
    public function isRecent()       { return $this->get('is_recent'); }

    /**
     * @return \Carbon\Carbon
     */
    public function getCreatedAtDate()
    {
        try {
            return \Carbon\Carbon::parse($this->getCreatedAt());
        } catch (Exception $e) {
            return null;
        }
    }

    public function getCreatedAtFriendly()
    {
        $createdAtDate = $this->getCreatedAtDate();
        if (! $createdAtDate) {
            return $this->getCreatedAt();
        }

        return $createdAtDate->diffForHumans();
    }

    /**
     * @return Model_User
     */
    public function getUser()
    {
        if (isset($this->_user)) {
            return $this->_user;
        }

        if ($this->getUserId()) {
            $this->_user = $this->_getContainer()->User()->load($this->getUserId());
        }
        return $this->_user;
    }

    public function fetchTags()
    {
        $tags = $this->_getContainer()->Tag()->fetchByPostId($this->getId());
        return $tags;
    }

    public function selectAll()
    {
        $table = $this->_getTable();

        $query = $this->_localConfig->database()->select()
            ->from($table)
            ->joinLeft(array('post_vote' => 'post_vote'),
                "post_vote.post_id = $table.post_id",
                array(
                    'vote_count' => 'COUNT(DISTINCT post_vote_id)',
                    'upvoters_csv' => 'GROUP_CONCAT(DISTINCT voting_user.username)'
                )
            )
            ->joinLeft(array('voting_user' => 'users'),
                'voting_user.user_id = post_vote.voting_user_id',
                array()
            )
            ->order(array("COUNT(DISTINCT post_vote_id) DESC", $table . ".created_at DESC"))
            ->group($table . '.post_id');

        return $query;
    }

    public function load($entityId)
    {
        $table = $this->_getTable();
        $tableIdFieldname = $this->_getTableIdFieldname();

        $query = $this->_localConfig->database()->select()
            ->from($table)
            ->joinLeft(array('post_vote' => 'post_vote'),
                "post_vote.post_id = $table.post_id",
                array(
                    'vote_count' => 'COUNT(DISTINCT post_vote_id)',
                )
            )
            ->joinLeft(array('voting_user' => 'users'),
                'voting_user.user_id = post_vote.voting_user_id',
                array(
                    'upvoters_csv' => 'GROUP_CONCAT(DISTINCT voting_user.username)'
                )
            )
            ->group("$table.post_id")
            ->where("$table.$tableIdFieldname = ?", $entityId);

        $this->_data = $this->_localConfig->database()->fetchRow($query);
        return $this;
    }

    public function fetchAllRecent()
    {
        $table = $this->_getTable();

        $recentTimePeriod = $this->_localConfig->getRecentTimePeriod();
        if (! $recentTimePeriod) {
            throw new Exception("Missing recent_time_period in config");
        }

        $query = $this->selectAll()
            ->where("$table.created_at > DATE_SUB(NOW(), INTERVAL $recentTimePeriod)")
            ->where("$table.is_active = 1");
        $results = $this->_localConfig->database()->fetchAll($query);

        return $results;
    }

    public function fetchAllWithAuthor()
    {
        $table = $this->_getTable();

        $query = $this->selectAll()
            ->where("$table.is_active = 1")
            ->joinLeft(
                'users',
                "users.user_id = $table.user_id",
                array('name')
            )
            ->limit(20);
        $rows = $this->_localConfig->database()->fetchAll($query);

        $models = array();
        foreach ($rows as $row) {
            $model = $this->_getContainer()->Post()->setData($row);
            $models[] = $model;
        }

        return $models;
    }

    public function fetchByUserId($userId)
    {
        $table = $this->_getTable();

        $query = $this->selectAll();
        $query->where("$table.user_id = ?", $userId);
        $query->where("$table.is_active = 1", $userId);
        $rows = $this->_localConfig->database()->fetchAll($query);

        $models = array();
        foreach ($rows as $row) {
            $model = $this->_getContainer()->Post()->setData($row);
            $models[] = $model;
        }

        return $models;
    }

    /**
     * Search string within post title and body.
     *
     * Algorithm here is to count mentions of search terms in body and subject colums. Weighting subject by 5.
     * This method isn't known for being particularly performant on large databases but MVP and all that.
     *
     * select posts.subject, (
     *      (subject regexp '[[:<:]]Magento[[:>:]]' and body regexp '[[:<:]]Magento[[:>:]]') * 5
     *          +
     *      (subject regexp '[[:<:]]2[[:>:]]' and body regexp '[[:<:]]2[[:>:]]'))
     *          as hits
     * from posts
     * having hits > 0
     * order by hits desc;
     * @param $term
     *
     * @return array
     */
    public function fetchByTerm($term)
    {
        $terms = explode(" ", $term);

        $searchQuery = array();
        foreach ($terms as $term) {
            $term = $this->_localConfig->database()->quote("[[:<:]]" . $term . "[[:>:]]");
            $searchQuery[] = "(subject regexp $term) * 5 + (body regexp $term)";
        }

        $searchQuery = implode(" + ", $searchQuery);

        $query = $this->selectAll();
        $query->columns(new Zend_Db_Expr("($searchQuery) as hits"));
        $query->having('hits > 0');

        // We need to reset the ordering that was put on in selectAll()
        $query->reset( Zend_Db_Select::ORDER );
        $query->order("hits DESC");

        $rows = $this->_localConfig->database()->fetchAll($query);

        $models = array();
        foreach ($rows as $row) {
            $model = $this->_getContainer()->Post()->setData($row);
            $models[] = $model;
        }

        return $models;
    }

    public function fetchByTagId($tagId)
    {
        $table = $this->_getTable();

        $query = $this->selectAll()
            ->joinLeft(
                'post_tag',
                "post_tag.post_id = $table.post_id",
                array()
            )
            ->joinLeft(
                'tags',
                'post_tag.tag_id = tags.tag_id',
                array()
            )
            ->where("post_tag.tag_id = $tagId");

        $rows = $this->_localConfig->database()->fetchAll($query);

        $models = array();
        foreach ($rows as $row) {
            $model = $this->_getContainer()->Post()->setData($row);
            $models[] = $model;
        }

        return $models;
    }

    public function getUrl()
    {
        $url = implode("/", array($this->_localConfig->get('base_url'), "posts", $this->getId(), $this->getSlug()));
        return $url;
    }
    
    public function getSluglessUrl()
    {
        return implode("/", array($this->_localConfig->get('base_url'), "posts", $this->getId()));
    }

    public function getEditUrl()
    {
        $url = implode("/", array($this->_localConfig->get('base_url'), "posts", $this->getId(), "edit"));
        return $url;
    }

    public function getTweetUrl()
    {
        $text = $this->getSubject() . " " . $this->getUrl();
        $tweetIntentUrl = "https://twitter.com/intent/tweet?text=" . urlencode($text);

        return $tweetIntentUrl;
    }

    public function getTweetPropsUrl()
    {
        $text = "Props to @" . $this->getUser()->getTwitterUsername() . " for " . $this->getUrl();
        $tweetIntentUrl = "https://twitter.com/intent/tweet?text=" . urlencode($text);

        return $tweetIntentUrl;
    }

    public function hasTagId($tagId)
    {
        $tags = $this->fetchTags();

        /** @var $tag Model_Tag */
        foreach ($tags as $tag) {
            if ($tag->getId() == $tagId) {
                return true;
            }
        }

        return false;
    }

    public function getSlug()
    {
        $text = $this->getSubject();

        // replace non letter or digits by -
        $text = preg_replace('~[^\\pL\d]+~u', '-', $text);

        // trim
        $text = trim($text, '-');

        // transliterate
        $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);

        // lowercase
        $text = strtolower($text);

        // remove unwanted characters
        $text = preg_replace('~[^-\w]+~', '', $text);

        return $text;
    }

    protected function _afterSave()
    {
        // Update the updated_at timestamp
        $this->getUser()->save();

        // Add tags
        if ($this->get('tag_ids') && is_array($this->get('tag_ids'))) {
            $this->_localConfig->database()->delete("post_tag", "post_id = " . $this->getId());
            foreach ($this->get('tag_ids') as $tagId) {
                $tagPostRelationship = $this->_getContainer()->PostTag()->setData(array(
                    'post_id' => $this->getId(),
                    'user_id' => $this->getUserId(),
                    'tag_id' => $tagId
                ));
                $tagPostRelationship->save();
            }

        }
    }

    public function isNew()
    {
        $createdAtDate = $this->getCreatedAtDate();
        if (! $createdAtDate) {
            return false;
        }

        return $createdAtDate->diffInHours() < $this->_localConfig->getNumberOfHoursForNew();
    }
}