Issues (21)

src/VersionFeedController.php (2 issues)

1
<?php
2
3
namespace SilverStripe\VersionFeed;
4
5
use SilverStripe\Core\Config\Config;
6
use SilverStripe\Control\RSS\RSSFeed;
7
use SilverStripe\ORM\DataObject;
8
use SilverStripe\Security\Security;
9
use SilverStripe\SiteConfig\SiteConfig;
10
use SilverStripe\ORM\DB;
11
use SilverStripe\Security\Member;
12
use SilverStripe\ORM\ArrayList;
13
use SilverStripe\CMS\Model\SiteTree;
14
use SilverStripe\Core\Convert;
15
use SilverStripe\View\Requirements;
16
use SilverStripe\Core\Extension;
17
use SilverStripe\VersionFeed\Filters\ContentFilter;
18
19
class VersionFeedController extends Extension
20
{
21
    private static $allowed_actions = array(
0 ignored issues
show
The private property $allowed_actions is not used, and could be removed.
Loading history...
22
        'changes',
23
        'allchanges'
24
    );
25
    
26
    /**
27
     * Content handler
28
     *
29
     * @var ContentFilter
30
     */
31
    protected $contentFilter;
32
    
33
    /**
34
     * Sets the content filter
35
     *
36
     * @param ContentFilter $contentFilter
37
     */
38
    public function setContentFilter(ContentFilter $contentFilter)
39
    {
40
        $this->contentFilter = $contentFilter;
41
    }
42
    
43
    /**
44
     * Evaluates the result of the given callback
45
     *
46
     * @param string $key Unique key for this
47
     * @param callable $callback Callback for evaluating the content
48
     * @return mixed Result of $callback()
49
     */
50
    protected function filterContent($key, $callback)
51
    {
52
        if ($this->contentFilter) {
53
            return $this->contentFilter->getContent($key, $callback);
54
        } else {
55
            return call_user_func($callback);
56
        }
57
    }
58
59
    public function onAfterInit()
60
    {
61
        $this->linkToPageRSSFeed();
62
        $this->linkToAllSiteRSSFeed();
63
    }
64
65
    /**
66
     * Get page-specific changes in a RSS feed.
67
     */
68
    public function changes()
69
    {
70
        // Check viewability of changes
71
        if (!Config::inst()->get(VersionFeed::class, 'changes_enabled')
72
            || !$this->owner->PublicHistory
73
            || $this->owner->Version == ''
74
        ) {
75
            return $this->owner->httpError(404, 'Page history not viewable');
76
        }
77
78
        // Cache the diffs to remove DOS possibility.
79
        $target = $this->owner;
80
        $key = implode('_', array('changes', $target->ID, $target->Version));
81
        $entries = $this->filterContent($key, function () use ($target) {
82
            return $target->getDiffList(null, Config::inst()->get(VersionFeed::class, 'changes_limit'));
83
        });
84
85
        // Generate the output.
86
        $title = _t(
87
            'SilverStripe\\VersionFeed\\VersionFeed.SINGLEPAGEFEEDTITLE',
88
            'Updates to {title} page',
89
            ['title' => $this->owner->Title]
90
        );
91
        $rss = new RSSFeed($entries, $this->owner->request->getURL(), $title, '', 'Title', '', null);
92
        $rss->setTemplate('Page_changes_rss');
93
        return $rss->outputToBrowser();
94
    }
95
96
    /**
97
     * Get all changes from the site in a RSS feed.
98
     */
99
    public function allchanges()
100
    {
101
        // Check viewability of allchanges
102
        if (!Config::inst()->get(VersionFeed::class, 'allchanges_enabled')
103
            || !SiteConfig::current_site_config()->AllChangesEnabled
104
        ) {
105
            return $this->owner->httpError(404, 'Global history not viewable');
106
        }
107
108
        $limit = (int)Config::inst()->get(VersionFeed::class, 'allchanges_limit');
109
        $latestChanges = DB::query('
110
			SELECT * FROM "SiteTree_Versions"
111
			WHERE "WasPublished" = \'1\'
112
			AND "CanViewType" IN (\'Anyone\', \'Inherit\')
113
			AND "ShowInSearch" = 1
114
			AND ("PublicHistory" IS NULL OR "PublicHistory" = \'1\')
115
			ORDER BY "LastEdited" DESC LIMIT ' . $limit);
116
        $lastChange = $latestChanges->record();
117
        $latestChanges->rewind();
118
119
        if ($lastChange) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $lastChange of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
120
            // Cache the diffs to remove DOS possibility.
121
            $key = 'allchanges'
122
                . preg_replace('#[^a-zA-Z0-9_]#', '', $lastChange['LastEdited'])
123
                . (Security::getCurrentUser() ? Security::getCurrentUser()->ID : 'public');
124
            $changeList = $this->filterContent($key, function () use ($latestChanges) {
125
                $changeList = new ArrayList();
126
                $canView = array();
127
                foreach ($latestChanges as $record) {
128
                    // Check if the page should be visible.
129
                    // WARNING: although we are providing historical details, we check the current configuration.
130
                    $id = $record['RecordID'];
131
                    if (!isset($canView[$id])) {
132
                        $page = DataObject::get_by_id(SiteTree::class, $id);
133
                        $canView[$id] = $page && $page->canView(Security::getCurrentUser());
134
                    }
135
                    if (!$canView[$id]) {
136
                        continue;
137
                    }
138
139
                    // Get the diff to the previous version.
140
                    $record['ID'] = $record['RecordID'];
141
                    $version = SiteTree::create($record);
142
                    if ($diff = $version->getDiff()) {
143
                        $changeList->push($diff);
144
                    }
145
                }
146
147
                return $changeList;
148
            });
149
        } else {
150
            $changeList = new ArrayList();
151
        }
152
153
        // Produce output
154
        $url = $this->owner->getRequest()->getURL();
155
        $rss = new RSSFeed(
156
            $changeList,
157
            $url,
158
            $this->linkToAllSitesRSSFeedTitle(),
159
            '',
160
            'Title',
161
            '',
162
            null
163
        );
164
        $rss->setTemplate('Page_allchanges_rss');
165
        return $rss->outputToBrowser();
166
    }
167
    
168
    /**
169
     * Generates and embeds the RSS header link for the page-specific version rss feed
170
     */
171
    public function linkToPageRSSFeed()
172
    {
173
        if (!Config::inst()->get(VersionFeed::class, 'changes_enabled') || !$this->owner->PublicHistory) {
174
            return;
175
        }
176
        
177
        RSSFeed::linkToFeed(
178
            $this->owner->Link('changes'),
179
            _t(
180
                'SilverStripe\\VersionFeed\\VersionFeed.SINGLEPAGEFEEDTITLE',
181
                'Updates to {title} page',
182
                ['title' => $this->owner->Title]
183
            )
184
        );
185
    }
186
187
    /**
188
     * Generates and embeds the RSS header link for the global version rss feed
189
     */
190
    public function linkToAllSiteRSSFeed()
191
    {
192
        if (!Config::inst()->get(VersionFeed::class, 'allchanges_enabled')
193
            || !SiteConfig::current_site_config()->AllChangesEnabled
194
        ) {
195
            return;
196
        }
197
        
198
        // RSS feed to all-site changes.
199
        $title = Convert::raw2xml($this->linkToAllSitesRSSFeedTitle());
200
        $url = $this->owner->getSiteRSSLink();
201
202
        Requirements::insertHeadTags(
203
            '<link rel="alternate" type="application/rss+xml" title="' . $title .
204
            '" href="' . $url . '" />'
205
        );
206
    }
207
208
    public function linkToAllSitesRSSFeedTitle()
209
    {
210
        return _t(
211
            'SilverStripe\\VersionFeed\\VersionFeed.SITEFEEDTITLE',
212
            'Updates to {title}',
213
            ['title' => SiteConfig::current_site_config()->Title]
214
        );
215
    }
216
}
217