Completed
Push — master ( 37a579...9117ad )
by Alex
06:23
created

StreamController::getModifiedSince()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 3
cts 4
cp 0.75
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
crap 2.0625
1
<?php
2
3
namespace Debril\RssAtomBundle\Controller;
4
5
use FeedIo\FeedInterface;
6
use Symfony\Component\HttpFoundation\Response;
7
use Symfony\Component\HttpFoundation\Request;
8
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
9
use Debril\RssAtomBundle\Provider\FeedContentProviderInterface;
10
use Debril\RssAtomBundle\Exception\FeedException\FeedNotFoundException;
11
12
/**
13
 * Class StreamController.
14
 */
15
class StreamController extends Controller
16
{
17
    /**
18
     * default provider.
19
     */
20
    const DEFAULT_SOURCE = 'debril.provider.default';
21
22
    /**
23
     * parameter used to force refresh at every hit (skips 'If-Modified-Since' usage).
24
     * set it to true for debug purpose.
25
     */
26
    const FORCE_PARAM_NAME = 'force_refresh';
27
28
    /**
29
     * @var \DateTime
30
     */
31
    protected $since;
32
33
    /**
34
     * @param Request $request
35
     *
36
     * @return Response
37
     */
38 3
    public function indexAction(Request $request)
39
    {
40 3
        $options = $request->attributes->get('_route_params');
41 3
        $this->setModifiedSince($request);
42 3
        $options['Since'] = $this->getModifiedSince();
43
44 3
        return $this->createStreamResponse(
45
            $options,
46 3
            $request->get('format', 'rss'),
47 3
            $request->get('source', self::DEFAULT_SOURCE)
48
        );
49
    }
50
51
    /**
52
     * Extract the 'If-Modified-Since' value from the headers.
53
     *
54
     * @return \DateTime
55
     */
56 3
    protected function getModifiedSince()
57
    {
58 3
        if (is_null($this->since)) {
59
            $this->since = new \DateTime('@0');
60
        }
61
62 3
        return $this->since;
63
    }
64
65
    /**
66
     * @param Request $request
67
     *
68
     * @return $this
69
     */
70 3
    protected function setModifiedSince(Request $request)
71
    {
72 3
        $this->since = new \DateTime();
73 3
        if ($request->headers->has('If-Modified-Since')) {
74 1
            $string = $request->headers->get('If-Modified-Since');
75 1
            $this->since = \DateTime::createFromFormat(\DateTime::RSS, $string);
76
        } else {
77 3
            $this->since->setTimestamp(1);
78
        }
79
80 3
        return $this;
81
    }
82
83
    /**
84
     * Generate the HTTP response
85
     * 200 : a full body containing the stream
86
     * 304 : Not modified.
87
     *
88
     * @param array $options
89
     * @param $format
90
     * @param string $source
91
     *
92
     * @return Response
93
     *
94
     * @throws \Exception
95
     */
96 3
    protected function createStreamResponse(array $options, $format, $source = self::DEFAULT_SOURCE)
97
    {
98 3
        $content = $this->getContent($options, $source);
99
100 1
        if ($this->mustForceRefresh() || $content->getLastModified() > $this->getModifiedSince()) {
101 1
            $response = new Response($this->getFeedIo()->format($content, $format)->saveXML());
102 1
            $response->headers->set('Content-Type', 'application/xhtml+xml');
103 1
            $this->setFeedHeaders($response, $content);
104
105
        } else {
106 1
            $response = new Response();
107 1
            $response->setNotModified();
108
        }
109
110 1
        return $response;
111
    }
112
113
    /**
114
     * @param Response $response
115
     * @param FeedInterface $feed
116
     * @return $this
117
     */
118 1
    protected function setFeedHeaders(Response $response, FeedInterface $feed)
119
    {
120 1
        $response->headers->set('Content-Type', 'application/xhtml+xml');
121 1
        if (! $this->isPrivate() ) {
122 1
            $response->setPublic();
123
        }
124
125 1
        $response->setMaxAge(3600);
126 1
        $response->setLastModified($feed->getLastModified());
127
128 1
        return $this;
129
    }
130
131
    /**
132
     * Get the Stream's content using a FeedContentProviderInterface
133
     * The FeedContentProviderInterface instance is provided as a service
134
     * default : debril.provider.service.
135
     *
136
     * @param array  $options
137
     * @param string $source
138
     *
139
     * @return FeedInterface
140
     *
141
     * @throws \Exception
142
     */
143 3
    protected function getContent(array $options, $source)
144
    {
145 3
        $provider = $this->get($source);
146
147 2
        if (!$provider instanceof FeedContentProviderInterface) {
148
            throw new \Exception('Provider is not a FeedContentProviderInterface instance');
149
        }
150
151
        try {
152 2
            return $provider->getFeedContent($options);
153 1
        } catch (FeedNotFoundException $e) {
154 1
            throw $this->createNotFoundException('feed not found');
155
        }
156
    }
157
158
    /**
159
     * Returns true if the controller must ignore the last modified date.
160
     *
161
     * @return bool
162
     */
163 1
    protected function mustForceRefresh()
164
    {
165 1
        if ($this->container->hasParameter(self::FORCE_PARAM_NAME)) {
166
            return $this->container->getParameter(self::FORCE_PARAM_NAME);
167
        }
168
169 1
        return false;
170
    }
171
172
    /**
173
     * @return boolean true if the feed must be private
174
     */
175 1
    protected function isPrivate()
176
    {
177 1
        return $this->container->getParameter('debril_rss_atom.private_feeds');
178
    }
179
180
    /**
181
     * @return \FeedIo\FeedIo
182
     */
183 1
    protected function getFeedIo()
184
    {
185 1
        return $this->container->get('feedio');
186
    }
187
188
}
189