Crss   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 223
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 93.69%

Importance

Changes 8
Bugs 0 Features 3
Metric Value
wmc 19
c 8
b 0
f 3
lcom 1
cbo 0
dl 0
loc 223
ccs 104
cts 111
cp 0.9369
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 50 4
A clearRSS() 0 5 1
A connect() 0 22 3
A createDB() 0 5 1
B checkValidity() 0 27 4
B createRSS() 0 38 2
A getRSS() 0 14 3
A insertRSS() 0 5 1
1
<?php
2
3
namespace henaro\rss;
4
5
class Crss
6
{
7
8
    private $table = 'RSSFeed';
9
    private $rssFile;
10
    private $valid = false;
11
    private $dbOptions = [];
12
    private $dbStructure;
13
    private $db;
14
    private $newsCount;
15
    private $feedDescription;
16
    private $sendHeader;
17
    /**
18
     * Initiates the class, takes parameters as input but should work with standard settings.
19
     * Connects to the DB and makes sure the table exists.
20
     * @param $params is the input to adjust standard settings. I recommend to change only the 'feedDescription' part.
21
     */
22 3
    public function __construct($params = [])
23
    {
24 3
        date_default_timezone_set('Europe/Stockholm');
25
        $options = [
26 3
            'rssFile' => REALPATH(__DIR__) . '/rsscache/rss.xml',
27 3
            'table' => $this->table,
28 3
            'newsCount' => 5,
29 3
            'sendHeader' => true,
30
            'db' => [
31 3
                'dsn' => 'sqlite:' . REALPATH(__DIR__) . '/src.sqlite',
32 3
                'username' => null,
33 3
                'password' => null,
34 3
                'driver_options' => null,
35
                'debug' => false
36 3
            ],
37
            'feedDescription' => [
38 3
                'title' => 'CRSS easy feed',
39 3
                'link' => 'http://www.github.com',
40
                'description' => 'Description of the amazing feed.'
41 3
            ]
42 3
        ];
43
44 3
        foreach ($params as $key => $value) {
45 3
            if (is_array($value)) {
46 1
                foreach ($value as $subKey => $subValue) {
47 1
                    $options[$key][$subKey] = $subValue;
48 1
                }
49 1
            } else {
50 2
                $options[$key] = $value;
51
            }
52 3
        }
53
54 3
        $this->rssFile = $options['rssFile'];
55 3
        $this->table = $options['table'];
56 3
        $this->dbOptions = $options['db'];
57 3
        $this->newsCount = $options['newsCount'];
58 3
        $this->feedDescription = $options['feedDescription'];
59 3
        $this->sendHeader = $options['sendHeader'];
60
61 3
        $this->dbStructure = 'CREATE TABLE IF NOT EXISTS ' . $this->table . ' (
62
            ID INTEGER PRIMARY KEY NOT NULL,
63
            TITLE CHAR(50) NOT NULL,
64
            LINK CHAR(50) NOT NULL,
65
            DESCRIPTION CHAR(255) NOT NULL,
66
            CREATED DATETIME
67 3
        )';
68
69 3
        $this->connect();
70 2
        $this->createDB();
71 2
    }
72
73
    /**
74
     * Function to clear the whole database from rss input
75
     *
76
     * @return void
77
     */
78 1
    public function clearRSS()
79
    {
80 1
        $stmt = $this->db->prepare("DELETE FROM " . $this->table);
81 1
        $stmt->execute();
82 1
    }
83
84
    /**
85
     * Internal function for connecting to the database
86
     *
87
     * @return void
88
     */
89 3
    private function connect()
90
    {
91
        try {
92 3
            $this->db = new \PDO(
93 3
                $this->dbOptions['dsn'],
94 3
                $this->dbOptions['username'],
95 3
                $this->dbOptions['password'],
96 3
                $this->dbOptions['driver_options']
97 3
            );
98
99 3
        } catch (\Exception $e) {
100
            //Change to true to debug database connection
101 1
            if ($this->dbOptions['debug']) {
102
                // For debug purpose, shows all connection details
103 1
                throw $e;
104
            } else {
105
                // Hide connection details.
106
                throw new \PDOException("Could not connect to database, hiding connection details.");
107
            }
108
        }
109 2
        $this->db->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_OBJ);
110 2
    }
111
112 2
    public function createDB()
113
    {
114 2
        $stmt = $this->db->prepare($this->dbStructure);
115 2
        $stmt->execute();
116 2
    }
117
118
    /**
119
     * Compares RSS file created timestamp and database timestamp to judge if new RSS file is needed
120
     *
121
     * Sets internal variable $this->valid to true/false depending if new file needs to be generate
122
     * @return void
123
     */
124 2
    private function checkValidity()
125
    {
126
127 2
        if (!is_writable($this->rssFile)) {
128 1
            $this->valid = false;
129 1
            return;
130
        }
131
132 1
        $stmt = $this->db->prepare('SELECT CREATED FROM ' . $this->table . ' ORDER BY CREATED DESC LIMIT 1');
133 1
        $stmt->execute();
134 1
        $res = $stmt->fetchAll();
135
136 1
        if (count($res) == 0) {
137
            $this->valid = false;
138
            return;
139
        }
140
141 1
        $latestInput = strtotime($res[0]->CREATED);
142
143 1
        $rssCreated = filemtime($this->rssFile);
144
145 1
        if ($latestInput > $rssCreated) {
146
            $this->valid = false;
147
        } else {
148 1
            $this->valid = true;
149
        }
150 1
    }
151
152
    /**
153
     * Creates a new RSS File with information from the database. Max amount of news is configured in the initiation.
154
     *
155
     * @return void
156
     */
157 1
    private function createRSS()
158
    {
159 1
        $file = fopen($this->rssFile, "w+");
160
161 1
        $stmt = $this->db->prepare('SELECT * FROM ' . $this->table . ' ORDER BY CREATED DESC LIMIT ?');
162 1
        $stmt->execute([$this->newsCount]);
163 1
        $res = $stmt->fetchAll();
164
165 1
        $xmlVersion = '<?xml version="1.0" encoding="UTF-8" ?>';
166
167
        $startString = <<<EOD
168 1
{$xmlVersion}
169
<rss version="2.0">
170
<channel>
171 1
    <title>{$this->feedDescription['title']}</title>
172 1
    <link>{$this->feedDescription['link']}</link>
173 1
    <description>{$this->feedDescription['description']}</description>
174 1
EOD;
175 1
        fwrite($file, $startString);
176
177 1
        foreach ($res as $post) {
178 1
            $date = date("D, d M y H:i:s O", strtotime($post->CREATED));
179
            $string = <<<EOD
180
181
    <item>
182 1
        <title>{$post->TITLE}</title>
183 1
        <link>{$post->LINK}</link>
184 1
        <description>{$post->DESCRIPTION}</description>
185 1
        <pubDate>{$date}</pubDate>
186 1
    </item>
187 1
EOD;
188 1
            fwrite($file, $string);
189 1
        }
190
191 1
        fwrite($file, '
192
</channel>
193 1
</rss>');
194 1
    }
195
196
    /**
197
     * Function that should be called to receive the RSS feed.
198
     * Checks if the latest RSS File is up to date, if not, generates a new one.
199
     * @return void
200
     */
201 2
    public function getRSS()
202
    {
203 2
        $this->checkValidity();
204
205 2
        if (!$this->valid) {
206 1
            $this->createRSS();
207 1
        }
208
209 2
        if ($this->sendHeader) {
210
            header('Content-type: application/rss+xml; charset=UTF-8');
211
        }
212
213 2
        readfile($this->rssFile);
214 2
    }
215
216
    /**
217
     * Inserts information to RSS database
218
     * @param $input should be an associative array with three pars TITLE, LINK, DESCRIPTION
219
     *
220
     * @return void
221
     */
222 1
    public function insertRSS($input = [])
223
    {
224 1
        $stmt = $this->db->prepare("INSERT INTO  " . $this->table . " (TITLE, LINK, DESCRIPTION, CREATED) VALUES (?, ?, ?, datetime('now', 'localtime'))");
225 1
        $stmt->execute([$input['TITLE'], $input['LINK'], $input['DESCRIPTION']]);
226 1
    }
227
}
228