Completed
Push — master ( 512950...9a6332 )
by Alex
02:30
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
     * @var \DateTime
24
     */
25
    protected $since;
26
27
    /**
28
     * @param Request $request
29
     *
30
     * @return Response
31
     */
32 5
    public function indexAction(Request $request)
33
    {
34 5
        $options = $request->attributes->get('_route_params');
35 5
        $this->setModifiedSince($request);
36 5
        $options['Since'] = $this->getModifiedSince();
37
38 5
        return $this->createStreamResponse(
39 5
            $options,
40 5
            $request->get('format', 'rss'),
41 5
            $request->get('source', self::DEFAULT_SOURCE)
42
        );
43
    }
44
45
    /**
46
     * Extract the 'If-Modified-Since' value from the headers.
47
     *
48
     * @return \DateTime
49
     */
50 5
    protected function getModifiedSince()
51
    {
52 5
        if (is_null($this->since)) {
53
            $this->since = new \DateTime('@0');
54
        }
55
56 5
        return $this->since;
57
    }
58
59
    /**
60
     * @param Request $request
61
     *
62
     * @return $this
63
     */
64 5
    protected function setModifiedSince(Request $request)
65
    {
66 5
        $this->since = new \DateTime();
67 5
        if ($request->headers->has('If-Modified-Since')) {
68 1
            $string = $request->headers->get('If-Modified-Since');
69 1
            $this->since = \DateTime::createFromFormat(\DateTime::RSS, $string);
0 ignored issues
show
Documentation Bug introduced by
It seems like \DateTime::createFromFor...DateTime::RSS, $string) can also be of type false. However, the property $since is declared as type object<DateTime>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
70
        } else {
71 5
            $this->since->setTimestamp(1);
72
        }
73
74 5
        return $this;
75
    }
76
77
    /**
78
     * Generate the HTTP response
79
     * 200 : a full body containing the stream
80
     * 304 : Not modified.
81
     *
82
     * @param array $options
83
     * @param $format
84
     * @param string $source
85
     *
86
     * @return Response
87
     *
88
     * @throws \Exception
89
     */
90 5
    protected function createStreamResponse(array $options, $format, $source = self::DEFAULT_SOURCE)
91
    {
92 5
        $content = $this->getContent($options, $source);
93
94 4
        if ($this->mustForceRefresh() || $content->getLastModified() > $this->getModifiedSince()) {
95 4
            $response = new Response($this->getFeedIo()->format($content, $format));
96 4
            $response->headers->set('Content-Type', 'application/xhtml+xml');
97 4
            $this->setFeedHeaders($response, $content);
98
99
        } else {
100 1
            $response = new Response();
101 1
            $response->setNotModified();
102
        }
103
104 4
        return $response;
105
    }
106
107
    /**
108
     * @param Response $response
109
     * @param FeedInterface $feed
110
     * @return $this
111
     */
112 4
    protected function setFeedHeaders(Response $response, FeedInterface $feed)
113
    {
114 4
        $response->headers->set('Content-Type', 'application/xhtml+xml');
115 4
        if (! $this->isPrivate() ) {
116 4
            $response->setPublic();
117
        }
118
119 4
        $response->setMaxAge(3600);
120 4
        $response->setLastModified($feed->getLastModified());
121
122 4
        return $this;
123
    }
124
125
    /**
126
     * Get the Stream's content using a FeedContentProviderInterface
127
     * The FeedContentProviderInterface instance is provided as a service
128
     * default : debril.provider.service.
129
     *
130
     * @param array  $options
131
     * @param string $source
132
     *
133
     * @return FeedInterface
134
     *
135
     * @throws \Exception
136
     */
137 5
    protected function getContent(array $options, $source)
138
    {
139 5
        $provider = $this->get($source);
140
141 5
        if (!$provider instanceof FeedContentProviderInterface) {
142
            throw new \Exception('Provider is not a FeedContentProviderInterface instance');
143
        }
144
145
        try {
146 5
            return $provider->getFeedContent($options);
147 1
        } catch (FeedNotFoundException $e) {
148 1
            throw $this->createNotFoundException('feed not found');
149
        }
150
    }
151
152
    /**
153
     * Returns true if the controller must ignore the last modified date.
154
     *
155
     * @return bool
156
     */
157 4
    protected function mustForceRefresh()
158
    {
159 4
        return $this->container->getParameter('debril_rss_atom.force_refresh');
160
    }
161
162
    /**
163
     * @return boolean true if the feed must be private
164
     */
165 4
    protected function isPrivate()
166
    {
167 4
        return $this->container->getParameter('debril_rss_atom.private_feeds');
168
    }
169
170
    /**
171
     * @return \FeedIo\FeedIo
172
     */
173 4
    protected function getFeedIo()
174
    {
175 4
        return $this->container->get('feedio');
176
    }
177
178
}
179